a
This commit is contained in:
@@ -0,0 +1,540 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Uniapp Material Design项目开发服务器
|
||||
* 绑定到所有IP地址,支持公网访问
|
||||
*/
|
||||
|
||||
const express = require('express');
|
||||
const cors = require('cors');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
// 创建Express应用
|
||||
const app = express();
|
||||
const PORT = process.env.PORT || 8000;
|
||||
const HOST = '0.0.0.0'; // 绑定到所有IP
|
||||
|
||||
// 启用CORS
|
||||
app.use(cors());
|
||||
|
||||
// 解析JSON请求体
|
||||
app.use(express.json());
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
|
||||
// 静态文件服务
|
||||
app.use(express.static(path.join(__dirname)));
|
||||
|
||||
// 模拟Uniapp的页面路由
|
||||
app.get('/pages/:page/:page', (req, res) => {
|
||||
const pagePath = path.join(__dirname, 'pages', req.params.page, `${req.params.page}.vue`);
|
||||
|
||||
if (fs.existsSync(pagePath)) {
|
||||
// 如果是Vue文件,返回一个简单的HTML页面
|
||||
res.send(`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<title>玩Android - ${req.params.page}</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { font-family: 'Roboto', sans-serif; background: #F5F5F5; }
|
||||
.container { max-width: 750px; margin: 0 auto; background: white; min-height: 100vh; }
|
||||
.header { background: #6200EE; color: white; padding: 40px 20px; text-align: center; }
|
||||
.content { padding: 40px 20px; text-align: center; }
|
||||
.icon { font-size: 80px; color: #6200EE; margin-bottom: 24px; }
|
||||
.title { font-size: 28px; font-weight: 500; margin-bottom: 12px; color: #212121; }
|
||||
.desc { font-size: 16px; color: #757575; margin-bottom: 32px; line-height: 1.6; }
|
||||
.info { background: #F5F5F5; padding: 20px; border-radius: 12px; margin-top: 32px; text-align: left; }
|
||||
.info-title { font-size: 16px; font-weight: 500; margin-bottom: 12px; color: #6200EE; }
|
||||
.info-item { margin-bottom: 8px; font-size: 14px; color: #616161; }
|
||||
.btn { display: inline-block; background: #6200EE; color: white; padding: 12px 24px; border-radius: 24px; text-decoration: none; margin-top: 20px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>玩Android Material Design</h1>
|
||||
<p>开发服务器预览</p>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="icon">📱</div>
|
||||
<div class="title">${req.params.page}页面</div>
|
||||
<div class="desc">这是Uniapp Material Design项目的${req.params.page}页面预览</div>
|
||||
|
||||
<div class="info">
|
||||
<div class="info-title">服务器信息</div>
|
||||
<div class="info-item">页面路径: /pages/${req.params.page}/${req.params.page}.vue</div>
|
||||
<div class="info-item">服务器地址: ${req.protocol}://${req.get('host')}</div>
|
||||
<div class="info-item">公网IP: 129.211.173.87:${PORT}</div>
|
||||
<div class="info-item">访问时间: ${new Date().toLocaleString()}</div>
|
||||
</div>
|
||||
|
||||
<a href="/" class="btn">返回首页</a>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
} else {
|
||||
res.status(404).send('页面不存在');
|
||||
}
|
||||
});
|
||||
|
||||
// 首页路由
|
||||
app.get('/', (req, res) => {
|
||||
res.send(`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<title>玩Android Material Design - 首页</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { font-family: 'Roboto', 'Noto Sans SC', sans-serif; background: #F5F5F5; }
|
||||
|
||||
/* Material Design样式 */
|
||||
.container { max-width: 750px; margin: 0 auto; background: white; min-height: 100vh; box-shadow: 0 0 20px rgba(0,0,0,0.1); }
|
||||
|
||||
/* 状态栏 */
|
||||
.status-bar { height: 40px; background: #6200EE; }
|
||||
|
||||
/* 搜索栏 */
|
||||
.search-bar { background: #6200EE; padding: 12px 16px; }
|
||||
.search-container { background: rgba(255,255,255,0.9); border-radius: 24px; padding: 12px 16px; display: flex; align-items: center; }
|
||||
.search-icon { font-size: 20px; margin-right: 12px; color: #6200EE; }
|
||||
.search-placeholder { font-size: 16px; color: #757575; flex: 1; }
|
||||
|
||||
/* 内容区域 */
|
||||
.content { padding: 24px 16px; }
|
||||
|
||||
/* Banner */
|
||||
.banner { background: linear-gradient(135deg, #6200EE, #3700B3); height: 200px; border-radius: 16px; margin-bottom: 24px; display: flex; flex-direction: column; justify-content: center; align-items: center; color: white; }
|
||||
.banner-icon { font-size: 60px; margin-bottom: 16px; }
|
||||
.banner-title { font-size: 24px; font-weight: 500; margin-bottom: 8px; }
|
||||
.banner-desc { font-size: 16px; opacity: 0.9; }
|
||||
|
||||
/* 功能卡片 */
|
||||
.feature-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin: 32px 0; }
|
||||
.feature-card { background: white; border-radius: 16px; padding: 24px; text-align: center; box-shadow: 0 2px 8px rgba(0,0,0,0.08); transition: all 0.3s; }
|
||||
.feature-card:hover { box-shadow: 0 4px 16px rgba(0,0,0,0.12); transform: translateY(-4px); }
|
||||
.feature-icon { font-size: 40px; margin-bottom: 16px; color: #6200EE; }
|
||||
.feature-title { font-size: 18px; font-weight: 500; margin-bottom: 8px; color: #212121; }
|
||||
.feature-desc { font-size: 14px; color: #757575; line-height: 1.5; }
|
||||
|
||||
/* 底部导航模拟 */
|
||||
.tab-bar { position: fixed; bottom: 0; left: 0; right: 0; background: white; border-top: 1px solid #EEEEEE; display: flex; justify-content: space-around; padding: 12px 0; max-width: 750px; margin: 0 auto; }
|
||||
.tab-item { display: flex; flex-direction: column; align-items: center; padding: 8px 16px; border-radius: 12px; transition: all 0.3s; }
|
||||
.tab-item.active { background: rgba(98, 0, 238, 0.08); }
|
||||
.tab-icon { font-size: 24px; margin-bottom: 4px; }
|
||||
.tab-text { font-size: 12px; }
|
||||
.tab-item.active .tab-icon, .tab-item.active .tab-text { color: #6200EE; }
|
||||
.tab-item:not(.active) .tab-icon, .tab-item:not(.active) .tab-text { color: #757575; }
|
||||
|
||||
/* 服务器信息 */
|
||||
.server-info { background: #F5F5F5; border-radius: 16px; padding: 24px; margin-top: 32px; }
|
||||
.server-title { font-size: 18px; font-weight: 500; margin-bottom: 16px; color: #6200EE; }
|
||||
.server-item { margin-bottom: 12px; font-size: 14px; color: #616161; display: flex; }
|
||||
.server-label { font-weight: 500; min-width: 100px; }
|
||||
.server-value { flex: 1; font-family: 'Courier New', monospace; }
|
||||
|
||||
/* 操作按钮 */
|
||||
.action-buttons { display: flex; gap: 16px; margin-top: 24px; }
|
||||
.btn { flex: 1; height: 48px; border-radius: 24px; display: flex; align-items: center; justify-content: center; font-size: 16px; font-weight: 500; text-decoration: none; transition: all 0.3s; }
|
||||
.btn-primary { background: #6200EE; color: white; }
|
||||
.btn-secondary { background: #03DAC6; color: white; }
|
||||
.btn-outline { background: transparent; color: #6200EE; border: 2px solid #6200EE; }
|
||||
.btn:hover { transform: scale(0.98); }
|
||||
|
||||
/* 安全区域 */
|
||||
.safe-area { height: 80px; }
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.feature-grid { grid-template-columns: 1fr; }
|
||||
.action-buttons { flex-direction: column; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<!-- 状态栏 -->
|
||||
<div class="status-bar"></div>
|
||||
|
||||
<!-- 搜索栏 -->
|
||||
<div class="search-bar">
|
||||
<div class="search-container">
|
||||
<div class="search-icon">🔍</div>
|
||||
<div class="search-placeholder">搜索文章、项目、公众号...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<div class="content">
|
||||
<!-- Banner -->
|
||||
<div class="banner">
|
||||
<div class="banner-icon">📱</div>
|
||||
<div class="banner-title">玩Android Material Design</div>
|
||||
<div class="banner-desc">Uniapp开发服务器预览</div>
|
||||
</div>
|
||||
|
||||
<!-- 功能预览 -->
|
||||
<div class="feature-grid">
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon">🏠</div>
|
||||
<div class="feature-title">首页功能</div>
|
||||
<div class="feature-desc">Banner轮播、文章列表、搜索热词、下拉刷新、上拉加载</div>
|
||||
</div>
|
||||
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon">🎨</div>
|
||||
<div class="feature-title">Material Design</div>
|
||||
<div class="feature-desc">遵循Material Design 3规范,紫色主色系统,完整设计语言</div>
|
||||
</div>
|
||||
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon">📱</div>
|
||||
<div class="feature-title">底部导航</div>
|
||||
<div class="feature-desc">5个Tab导航,轮廓/填充双状态图标,平滑切换动画</div>
|
||||
</div>
|
||||
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon">🔌</div>
|
||||
<div class="feature-title">API集成</div>
|
||||
<div class="feature-desc">集成玩Android开放API,统一网络请求和错误处理</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 服务器信息 -->
|
||||
<div class="server-info">
|
||||
<div class="server-title">服务器信息</div>
|
||||
|
||||
<div class="server-item">
|
||||
<div class="server-label">服务器地址:</div>
|
||||
<div class="server-value">${req.protocol}://${req.get('host')}</div>
|
||||
</div>
|
||||
|
||||
<div class="server-item">
|
||||
<div class="server-label">公网IP:</div>
|
||||
<div class="server-value">129.211.173.87:${PORT}</div>
|
||||
</div>
|
||||
|
||||
<div class="server-item">
|
||||
<div class="server-label">项目路径:</div>
|
||||
<div class="server-value">/home/ubuntu/wanandroid/uniapp_android</div>
|
||||
</div>
|
||||
|
||||
<div class="server-item">
|
||||
<div class="server-label">启动时间:</div>
|
||||
<div class="server-value">${new Date().toLocaleString()}</div>
|
||||
</div>
|
||||
|
||||
<div class="server-item">
|
||||
<div class="server-label">Node版本:</div>
|
||||
<div class="server-value">${process.version}</div>
|
||||
</div>
|
||||
|
||||
<div class="server-item">
|
||||
<div class="server-label">平台:</div>
|
||||
<div class="server-value">${process.platform} ${process.arch}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div class="action-buttons">
|
||||
<a href="/material_preview.html" class="btn btn-primary">查看Material预览</a>
|
||||
<a href="http://129.211.173.87:${PORT}/material_preview.html" class="btn btn-secondary">公网访问预览</a>
|
||||
<a href="/quick_test.html" class="btn btn-outline">快速测试</a>
|
||||
</div>
|
||||
|
||||
<!-- 安全区域 -->
|
||||
<div class="safe-area"></div>
|
||||
</div>
|
||||
|
||||
<!-- 底部导航 -->
|
||||
<div class="tab-bar">
|
||||
<div class="tab-item active">
|
||||
<div class="tab-icon">🏠</div>
|
||||
<div class="tab-text">首页</div>
|
||||
</div>
|
||||
<div class="tab-item">
|
||||
<div class="tab-icon">📦</div>
|
||||
<div class="tab-text">项目</div>
|
||||
</div>
|
||||
<div class="tab-item">
|
||||
<div class="tab-icon">📱</div>
|
||||
<div class="tab-text">公众号</div>
|
||||
</div>
|
||||
<div class="tab-item">
|
||||
<div class="tab-icon">🌳</div>
|
||||
<div class="tab-text">体系</div>
|
||||
</div>
|
||||
<div class="tab-item">
|
||||
<div class="tab-icon">👤</div>
|
||||
<div class="tab-text">我的</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 简单的Tab切换
|
||||
document.querySelectorAll('.tab-item').forEach(tab => {
|
||||
tab.addEventListener('click', function() {
|
||||
document.querySelectorAll('.tab-item').forEach(t => t.classList.remove('active'));
|
||||
this.classList.add('active');
|
||||
|
||||
const tabText = this.querySelector('.tab-text').textContent;
|
||||
alert('切换到: ' + tabText + ' 页面 (开发中)');
|
||||
});
|
||||
});
|
||||
|
||||
// 搜索栏点击
|
||||
document.querySelector('.search-container').addEventListener('click', function() {
|
||||
alert('搜索功能 (开发中)');
|
||||
});
|
||||
|
||||
// 显示访问信息
|
||||
console.log('玩Android Material Design开发服务器');
|
||||
console.log('公网访问: http://129.211.173.87:${PORT}');
|
||||
console.log('本地访问: http://localhost:${PORT}');
|
||||
console.log('项目路径: /home/ubuntu/wanandroid/uniapp_android');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
});
|
||||
|
||||
// API模拟 - 玩Android API
|
||||
app.get('/api/banner/json', (req, res) => {
|
||||
res.json({
|
||||
data: [
|
||||
{
|
||||
desc: "Material Design Banner 1",
|
||||
id: 1,
|
||||
imagePath: "https://via.placeholder.com/300x150/6200EE/ffffff?text=Banner1",
|
||||
isVisible: 1,
|
||||
order: 0,
|
||||
title: "玩Android Material Design",
|
||||
type: 0,
|
||||
url: "https://www.wanandroid.com"
|
||||
},
|
||||
{
|
||||
desc: "Material Design Banner 2",
|
||||
id: 2,
|
||||
imagePath: "https://via.placeholder.com/300x150/03DAC6/ffffff?text=Banner2",
|
||||
isVisible: 1,
|
||||
order: 1,
|
||||
title: "Uniapp开发框架",
|
||||
type: 0,
|
||||
url: "https://uniapp.dcloud.io"
|
||||
},
|
||||
{
|
||||
desc: "Material Design Banner 3",
|
||||
id: 3,
|
||||
imagePath: "https://via.placeholder.com/300x150/FF9800/ffffff?text=Banner3",
|
||||
isVisible: 1,
|
||||
order: 2,
|
||||
title: "Android应用开发",
|
||||
type: 0,
|
||||
url: "https://developer.android.com"
|
||||
}
|
||||
],
|
||||
errorCode: 0,
|
||||
errorMsg: ""
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/api/hotkey/json', (req, res) => {
|
||||
res.json({
|
||||
data: [
|
||||
{ id: 1, link: "", name: "Material Design", order: 1, visible: 1 },
|
||||
{ id: 2, link: "", name: "Uniapp", order: 2, visible: 1 },
|
||||
{ id: 3, link: "", name: "Android", order: 3, visible: 1 },
|
||||
{ id: 4, link: "", name: "Vue 3", order: 4, visible: 1 },
|
||||
{ id: 5, link: "", name: "玩Android", order: 5, visible: 1 },
|
||||
{ id: 6, link: "", name: "API开发", order: 6, visible: 1 }
|
||||
],
|
||||
errorCode: 0,
|
||||
errorMsg: ""
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/api/article/list/0/json', (req, res) => {
|
||||
res.json({
|
||||
data: {
|
||||
curPage: 0,
|
||||
datas: [
|
||||
{
|
||||
id: 1,
|
||||
title: "玩Android Material Design客户端发布",
|
||||
link: "https://www.wanandroid.com",
|
||||
author: "Material Design",
|
||||
shareUser: "",
|
||||
chapterName: "前端开发",
|
||||
superChapterName: "移动开发",
|
||||
niceDate: "刚刚",
|
||||
publishTime: Date.now(),
|
||||
collect: false,
|
||||
zan: 42,
|
||||
fresh: true,
|
||||
tags: []
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Uniapp框架Material Design实践指南",
|
||||
link: "https://uniapp.dcloud.io",
|
||||
author: "Uniapp团队",
|
||||
shareUser: "",
|
||||
chapterName: "Uniapp",
|
||||
superChapterName: "跨端开发",
|
||||
niceDate: "1小时前",
|
||||
publishTime: Date.now() - 3600000,
|
||||
collect: true,
|
||||
zan: 28,
|
||||
fresh: false,
|
||||
tags: []
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "Android Material Design 3新特性详解",
|
||||
link: "https://developer.android.com",
|
||||
author: "Google",
|
||||
shareUser: "",
|
||||
chapterName: "Android",
|
||||
superChapterName: "移动开发",
|
||||
niceDate: "3小时前",
|
||||
publishTime: Date.now() - 10800000,
|
||||
collect: false,
|
||||
zan: 56,
|
||||
fresh: false,
|
||||
tags: []
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: "玩Android API接口完整文档",
|
||||
link: "https://www.wanandroid.com/blog/show/2",
|
||||
author: "玩Android",
|
||||
shareUser: "",
|
||||
chapterName: "API文档",
|
||||
superChapterName: "开发资源",
|
||||
niceDate: "1天前",
|
||||
publishTime: Date.now() - 86400000,
|
||||
collect: true,
|
||||
zan: 89,
|
||||
fresh: false,
|
||||
tags: []
|
||||
}
|
||||
],
|
||||
offset: 0,
|
||||
over: false,
|
||||
pageCount: 5,
|
||||
size: 20,
|
||||
total: 20
|
||||
},
|
||||
errorCode: 0,
|
||||
errorMsg: ""
|
||||
});
|
||||
});
|
||||
|
||||
// 健康检查
|
||||
app.get('/health', (req, res) => {
|
||||
res.json({
|
||||
status: 'healthy',
|
||||
timestamp: new Date().toISOString(),
|
||||
service: 'wanandroid-material-server',
|
||||
version: '1.0.0',
|
||||
uptime: process.uptime()
|
||||
});
|
||||
});
|
||||
|
||||
// 404处理
|
||||
app.use((req, res) => {
|
||||
res.status(404).send(`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>404 - 页面未找到</title>
|
||||
<style>
|
||||
body { font-family: 'Roboto', sans-serif; background: #F5F5F5; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; }
|
||||
.error-container { text-align: center; padding: 40px; background: white; border-radius: 20px; box-shadow: 0 4px 20px rgba(0,0,0,0.1); }
|
||||
.error-icon { font-size: 80px; color: #6200EE; margin-bottom: 24px; }
|
||||
.error-title { font-size: 32px; font-weight: 500; color: #212121; margin-bottom: 16px; }
|
||||
.error-message { font-size: 18px; color: #757575; margin-bottom: 32px; }
|
||||
.error-path { font-family: 'Courier New', monospace; background: #F5F5F5; padding: 12px; border-radius: 8px; margin: 20px 0; }
|
||||
.btn { display: inline-block; background: #6200EE; color: white; padding: 12px 24px; border-radius: 24px; text-decoration: none; margin-top: 20px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="error-container">
|
||||
<div class="error-icon">🔍</div>
|
||||
<div class="error-title">404 - 页面未找到</div>
|
||||
<div class="error-message">请求的页面不存在</div>
|
||||
<div class="error-path">${req.originalUrl}</div>
|
||||
<a href="/" class="btn">返回首页</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
});
|
||||
|
||||
// 启动服务器
|
||||
app.listen(PORT, HOST, () => {
|
||||
console.log(`
|
||||
==============================================
|
||||
玩Android Material Design开发服务器
|
||||
==============================================
|
||||
✅ 服务器启动成功!
|
||||
|
||||
📱 本地访问:
|
||||
http://localhost:${PORT}
|
||||
http://127.0.0.1:${PORT}
|
||||
|
||||
🌐 公网访问:
|
||||
http://129.211.173.87:${PORT}
|
||||
|
||||
📁 项目信息:
|
||||
项目路径: /home/ubuntu/wanandroid/uniapp_android
|
||||
服务器IP: ${HOST}
|
||||
服务端口: ${PORT}
|
||||
Node版本: ${process.version}
|
||||
|
||||
🚀 可用路由:
|
||||
/ - 首页预览
|
||||
/material_preview.html - Material Design预览
|
||||
/api/banner/json - Banner数据API
|
||||
/api/hotkey/json - 搜索热词API
|
||||
/api/article/list/0/json - 文章列表API
|
||||
/health - 健康检查
|
||||
|
||||
⏰ 启动时间: ${new Date().toLocaleString()}
|
||||
==============================================
|
||||
`);
|
||||
|
||||
// 打印网络信息
|
||||
const os = require('os');
|
||||
const networkInterfaces = os.networkInterfaces();
|
||||
|
||||
console.log('📡 网络接口信息:');
|
||||
Object.keys(networkInterfaces).forEach(interfaceName => {
|
||||
networkInterfaces[interfaceName].forEach(interface => {
|
||||
if (interface.family === 'IPv4' && !interface.internal) {
|
||||
console.log(` ${interfaceName}: ${interface.address}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
console.log('==============================================\n');
|
||||
});
|
||||
|
||||
// 优雅关闭
|
||||
process.on('SIGINT', () => {
|
||||
console.log('\n🛑 收到关闭信号,正在停止服务器...');
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
process.on('SIGTERM', () => {
|
||||
console.log('\n🛑 收到终止信号,正在停止服务器...');
|
||||
process.exit(0);
|
||||
});
|
||||
Reference in New Issue
Block a user