Files
LingChair-Android-App/index.html
2025-11-17 00:53:14 +08:00

322 lines
14 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;