322 lines
14 KiB
HTML
322 lines
14 KiB
HTML
import React, { useState } from 'react';
|
||
import { AlertCircle, CheckCircle, Code, Folder, FileText } from 'lucide-react';
|
||
|
||
const LingChairAndroidPlan = () => {
|
||
const [activeTab, setActiveTab] = useState('structure');
|
||
|
||
const projectStructure = {
|
||
name: 'LingChairApp',
|
||
children: [
|
||
{
|
||
name: 'app/src/main',
|
||
children: [
|
||
{
|
||
name: 'java/com/lingchair',
|
||
children: [
|
||
{ name: 'MainActivity.kt', type: 'file', desc: '主活动入口' },
|
||
{ name: 'LingChairApp.kt', type: 'file', desc: 'Application类' },
|
||
{
|
||
name: 'network/',
|
||
children: [
|
||
{ name: 'SocketClient.kt', type: 'file', desc: 'Socket.IO客户端封装' },
|
||
{ name: 'ApiService.kt', type: 'file', desc: 'RPC方法调用' },
|
||
{ name: 'ApiCallback.kt', type: 'file', desc: '响应数据类' }
|
||
]
|
||
},
|
||
{
|
||
name: 'data/',
|
||
children: [
|
||
{ name: 'model/', children: [
|
||
{ name: 'User.kt', type: 'file' },
|
||
{ name: 'Chat.kt', type: 'file' },
|
||
{ name: 'Message.kt', type: 'file' },
|
||
{ name: 'JoinRequest.kt', type: 'file' }
|
||
]},
|
||
{ name: 'repository/', children: [
|
||
{ name: 'UserRepository.kt', type: 'file' },
|
||
{ name: 'ChatRepository.kt', type: 'file' }
|
||
]}
|
||
]
|
||
},
|
||
{
|
||
name: 'ui/',
|
||
children: [
|
||
{ name: 'auth/', children: [
|
||
{ name: 'LoginActivity.kt', type: 'file' },
|
||
{ name: 'RegisterActivity.kt', type: 'file' }
|
||
]},
|
||
{ name: 'chat/', children: [
|
||
{ name: 'ChatListActivity.kt', type: 'file' },
|
||
{ name: 'ChatActivity.kt', type: 'file' },
|
||
{ name: 'ChatAdapter.kt', type: 'file' }
|
||
]},
|
||
{ name: 'profile/', children: [
|
||
{ name: 'ProfileActivity.kt', type: 'file' }
|
||
]}
|
||
]
|
||
},
|
||
{
|
||
name: 'viewmodel/',
|
||
children: [
|
||
{ name: 'AuthViewModel.kt', type: 'file' },
|
||
{ name: 'ChatViewModel.kt', type: 'file' }
|
||
]
|
||
},
|
||
{
|
||
name: 'util/',
|
||
children: [
|
||
{ name: 'PreferenceManager.kt', type: 'file', desc: 'SharedPreferences封装' },
|
||
{ name: 'HashUtil.kt', type: 'file', desc: 'SHA256加密' }
|
||
]
|
||
}
|
||
]
|
||
},
|
||
{
|
||
name: 'res/',
|
||
children: [
|
||
{ name: 'layout/', type: 'folder', desc: 'XML布局文件' },
|
||
{ name: 'values/', type: 'folder', desc: '字符串、颜色、主题' },
|
||
{ name: 'drawable/', type: 'folder', desc: '图标和图片资源' }
|
||
]
|
||
}
|
||
]
|
||
},
|
||
{ name: 'build.gradle.kts', type: 'file', desc: 'Gradle构建配置' }
|
||
]
|
||
};
|
||
|
||
const dependencies = [
|
||
{ name: 'Socket.IO Client', version: '2.1.0', purpose: 'WebSocket通信' },
|
||
{ name: 'Kotlin Coroutines', version: '1.7.3', purpose: '异步操作' },
|
||
{ name: 'Lifecycle ViewModel', version: '2.7.0', purpose: 'MVVM架构' },
|
||
{ name: 'RecyclerView', version: '1.3.2', purpose: '列表展示' },
|
||
{ name: 'Gson', version: '2.10.1', purpose: 'JSON解析' },
|
||
{ name: 'Material Components', version: '1.11.0', purpose: 'Material Design UI' },
|
||
{ name: 'Glide', version: '4.16.0', purpose: '图片加载' }
|
||
];
|
||
|
||
const coreFeatures = [
|
||
{
|
||
title: '用户认证',
|
||
items: ['注册(昵称、用户名、密码)', '登录(SHA256密码加密)', 'Token刷新机制', '自动重连']
|
||
},
|
||
{
|
||
title: '聊天功能',
|
||
items: ['获取最近聊天列表', '创建私聊/群聊', '发送/接收消息', '消息历史分页加载', '实时消息推送']
|
||
},
|
||
{
|
||
title: '用户管理',
|
||
items: ['个人资料编辑', '头像上传', '联系人管理', '好友列表']
|
||
},
|
||
{
|
||
title: '群组管理',
|
||
items: ['创建群组', '加入请求处理', '群设置修改', '群头像设置']
|
||
}
|
||
];
|
||
|
||
const implementationSteps = [
|
||
{ step: 1, title: '项目初始化', desc: '创建Android项目,配置依赖', status: 'pending' },
|
||
{ step: 2, title: '网络层', desc: '实现Socket.IO客户端和RPC封装', status: 'pending' },
|
||
{ step: 3, title: '数据模型', desc: '创建Bean类对应TypeScript接口', status: 'pending' },
|
||
{ step: 4, title: '认证模块', desc: '实现登录/注册界面和逻辑', status: 'pending' },
|
||
{ step: 5, title: '聊天列表', desc: '实现聊天列表UI和数据加载', status: 'pending' },
|
||
{ step: 6, title: '聊天界面', desc: '实现消息发送/接收和UI展示', status: 'pending' },
|
||
{ step: 7, title: '用户管理', desc: '实现个人资料和设置页面', status: 'pending' },
|
||
{ step: 8, title: '测试优化', desc: '功能测试、性能优化、错误处理', status: 'pending' }
|
||
];
|
||
|
||
const FileTreeNode = ({ node, level = 0 }) => {
|
||
const [expanded, setExpanded] = useState(level < 2);
|
||
const hasChildren = node.children && node.children.length > 0;
|
||
|
||
return (
|
||
<div>
|
||
<div
|
||
className="flex items-center py-1 hover:bg-gray-50 cursor-pointer"
|
||
style={{ paddingLeft: `${level * 20 + 8}px` }}
|
||
onClick={() => hasChildren && setExpanded(!expanded)}
|
||
>
|
||
{hasChildren ? (
|
||
<span className="text-gray-400 mr-2">{expanded ? '▼' : '▶'}</span>
|
||
) : (
|
||
<span className="mr-2 ml-3">
|
||
{node.type === 'file' ? <FileText size={14} className="text-blue-500" /> : <Folder size={14} className="text-yellow-500" />}
|
||
</span>
|
||
)}
|
||
<span className={`${hasChildren ? 'font-semibold text-gray-700' : 'text-gray-600'} text-sm`}>
|
||
{node.name}
|
||
</span>
|
||
{node.desc && <span className="ml-2 text-xs text-gray-400">- {node.desc}</span>}
|
||
</div>
|
||
{expanded && hasChildren && (
|
||
<div>
|
||
{node.children.map((child, idx) => (
|
||
<FileTreeNode key={idx} node={child} level={level + 1} />
|
||
))}
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
};
|
||
|
||
return (
|
||
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100 p-8">
|
||
<div className="max-w-6xl mx-auto">
|
||
<div className="bg-white rounded-2xl shadow-2xl overflow-hidden">
|
||
<div className="bg-gradient-to-r from-blue-600 to-indigo-600 p-8 text-white">
|
||
<h1 className="text-4xl font-bold mb-2">LingChair Android App</h1>
|
||
<p className="text-blue-100">基于 Socket.IO 的原生聊天应用开发方案</p>
|
||
</div>
|
||
|
||
<div className="border-b border-gray-200">
|
||
<div className="flex">
|
||
{['structure', 'features', 'steps', 'tech'].map((tab) => (
|
||
<button
|
||
key={tab}
|
||
onClick={() => setActiveTab(tab)}
|
||
className={`px-6 py-4 font-semibold transition-colors ${
|
||
activeTab === tab
|
||
? 'text-blue-600 border-b-2 border-blue-600'
|
||
: 'text-gray-500 hover:text-gray-700'
|
||
}`}
|
||
>
|
||
{tab === 'structure' && '项目结构'}
|
||
{tab === 'features' && '核心功能'}
|
||
{tab === 'steps' && '实现步骤'}
|
||
{tab === 'tech' && '技术栈'}
|
||
</button>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="p-8">
|
||
{activeTab === 'structure' && (
|
||
<div>
|
||
<h2 className="text-2xl font-bold text-gray-800 mb-4 flex items-center">
|
||
<Folder className="mr-2 text-blue-600" />
|
||
项目目录结构
|
||
</h2>
|
||
<div className="bg-gray-50 rounded-lg p-4 font-mono text-sm border border-gray-200">
|
||
<FileTreeNode node={projectStructure} />
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{activeTab === 'features' && (
|
||
<div>
|
||
<h2 className="text-2xl font-bold text-gray-800 mb-6">核心功能模块</h2>
|
||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||
{coreFeatures.map((feature, idx) => (
|
||
<div key={idx} className="bg-gradient-to-br from-blue-50 to-indigo-50 rounded-xl p-6 border border-blue-200">
|
||
<h3 className="text-xl font-bold text-blue-900 mb-4 flex items-center">
|
||
<CheckCircle className="mr-2" size={20} />
|
||
{feature.title}
|
||
</h3>
|
||
<ul className="space-y-2">
|
||
{feature.items.map((item, i) => (
|
||
<li key={i} className="flex items-start">
|
||
<span className="text-blue-600 mr-2">•</span>
|
||
<span className="text-gray-700">{item}</span>
|
||
</li>
|
||
))}
|
||
</ul>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{activeTab === 'steps' && (
|
||
<div>
|
||
<h2 className="text-2xl font-bold text-gray-800 mb-6">开发实施步骤</h2>
|
||
<div className="space-y-4">
|
||
{implementationSteps.map((step, idx) => (
|
||
<div key={idx} className="flex items-start bg-gray-50 rounded-lg p-4 border-l-4 border-blue-500">
|
||
<div className="flex-shrink-0 w-12 h-12 bg-blue-600 text-white rounded-full flex items-center justify-center font-bold text-lg mr-4">
|
||
{step.step}
|
||
</div>
|
||
<div className="flex-grow">
|
||
<h3 className="text-lg font-bold text-gray-800 mb-1">{step.title}</h3>
|
||
<p className="text-gray-600">{step.desc}</p>
|
||
</div>
|
||
<div className="flex-shrink-0 ml-4">
|
||
<span className="px-3 py-1 bg-yellow-100 text-yellow-800 rounded-full text-sm font-semibold">
|
||
待开发
|
||
</span>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{activeTab === 'tech' && (
|
||
<div>
|
||
<h2 className="text-2xl font-bold text-gray-800 mb-6">技术栈与依赖</h2>
|
||
<div className="bg-gray-50 rounded-xl p-6 border border-gray-200">
|
||
<div className="mb-6">
|
||
<h3 className="text-lg font-bold text-gray-800 mb-3 flex items-center">
|
||
<Code className="mr-2 text-blue-600" />
|
||
开发环境
|
||
</h3>
|
||
<div className="grid grid-cols-2 gap-4">
|
||
<div className="bg-white p-4 rounded-lg border">
|
||
<p className="text-sm text-gray-600">开发语言</p>
|
||
<p className="font-bold text-gray-800">Kotlin</p>
|
||
</div>
|
||
<div className="bg-white p-4 rounded-lg border">
|
||
<p className="text-sm text-gray-600">最低版本</p>
|
||
<p className="font-bold text-gray-800">Android 6.0 (API 23)</p>
|
||
</div>
|
||
<div className="bg-white p-4 rounded-lg border">
|
||
<p className="text-sm text-gray-600">架构模式</p>
|
||
<p className="font-bold text-gray-800">MVVM</p>
|
||
</div>
|
||
<div className="bg-white p-4 rounded-lg border">
|
||
<p className="text-sm text-gray-600">构建工具</p>
|
||
<p className="font-bold text-gray-800">Gradle (Kotlin DSL)</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<h3 className="text-lg font-bold text-gray-800 mb-3">主要依赖库</h3>
|
||
<div className="space-y-2">
|
||
{dependencies.map((dep, idx) => (
|
||
<div key={idx} className="flex items-center justify-between bg-white p-4 rounded-lg border hover:border-blue-300 transition-colors">
|
||
<div className="flex-grow">
|
||
<p className="font-semibold text-gray-800">{dep.name}</p>
|
||
<p className="text-sm text-gray-600">{dep.purpose}</p>
|
||
</div>
|
||
<span className="text-sm font-mono text-blue-600 bg-blue-50 px-3 py-1 rounded">
|
||
v{dep.version}
|
||
</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="mt-8 bg-yellow-50 border-l-4 border-yellow-400 p-6 rounded-lg">
|
||
<div className="flex items-start">
|
||
<AlertCircle className="text-yellow-600 mr-3 flex-shrink-0 mt-1" />
|
||
<div>
|
||
<h3 className="font-bold text-yellow-900 mb-2">注意事项</h3>
|
||
<ul className="text-yellow-800 space-y-1 text-sm">
|
||
<li>• 登录时需要对密码进行 SHA256 加密,注册时直接传明文(需与服务端确认)</li>
|
||
<li>• Socket.IO 事件通道固定为 "The_White_Silk"</li>
|
||
<li>• 所有 RPC 调用需要处理 code != 200 的错误情况</li>
|
||
<li>• 实现 Token 过期自动刷新机制</li>
|
||
<li>• 需要处理 Socket 断线重连逻辑</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default LingChairAndroidPlan; |