Files
nanocode/wanandroid/uniapp_android/wechat.html
T
Ubuntu 32b43f85bd a
2026-07-03 16:58:28 +08:00

651 lines
29 KiB
HTML

<!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 - 公众号</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Roboto', 'Noto Sans SC', sans-serif; background: #F5F5F5; }
/* 容器 */
.container { max-width: 750px; margin: 0 auto; background: white; min-height: 100vh; }
/* 状态栏 */
.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-input { font-size: 16px; color: #212121; flex: 1; border: none; outline: none; background: transparent; }
.search-input::placeholder { color: #757575; }
.search-clear { font-size: 20px; color: #757575; cursor: pointer; display: none; }
.search-clear.active { display: block; }
/* 内容区域 */
.content { padding: 16px; }
/* 公众号分类 */
.category-section { margin-bottom: 24px; }
.section-title { font-size: 18px; font-weight: 500; color: #212121; margin-bottom: 16px; display: flex; align-items: center; }
.section-title-icon { font-size: 20px; margin-right: 8px; color: #6200EE; }
/* 公众号列表 */
.wechat-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 16px; }
.wechat-item { background: white; border-radius: 16px; padding: 20px; text-align: center; box-shadow: 0 2px 8px rgba(0,0,0,0.08); transition: all 0.3s; cursor: pointer; }
.wechat-item:hover { box-shadow: 0 4px 16px rgba(0,0,0,0.12); transform: translateY(-4px); }
.wechat-item.active { background: rgba(98, 0, 238, 0.08); border: 2px solid #6200EE; }
.wechat-icon { font-size: 40px; margin-bottom: 12px; color: #6200EE; }
.wechat-name { font-size: 16px; font-weight: 500; color: #212121; margin-bottom: 4px; }
.wechat-desc { font-size: 12px; color: #757575; }
/* 文章列表 */
.article-section { margin-top: 32px; }
.article-list { margin-top: 16px; }
.article-item { background: white; border-radius: 16px; padding: 20px; margin-bottom: 16px; box-shadow: 0 2px 8px rgba(0,0,0,0.08); transition: all 0.3s; }
.article-item:hover { box-shadow: 0 4px 16px rgba(0,0,0,0.12); }
.article-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 12px; }
.article-title { font-size: 16px; font-weight: 500; color: #212121; line-height: 1.4; flex: 1; }
.article-tag { background: #FF9800; color: white; font-size: 12px; padding: 2px 8px; border-radius: 12px; margin-left: 8px; }
.article-meta { display: flex; align-items: center; font-size: 12px; color: #757575; }
.article-author { margin-right: 12px; }
.article-time { margin-right: 12px; }
.article-actions { display: flex; align-items: center; margin-top: 16px; }
.action-btn { display: flex; align-items: center; margin-right: 16px; font-size: 14px; color: #757575; cursor: pointer; }
.action-icon { font-size: 16px; margin-right: 4px; }
.action-btn.liked .action-icon { color: #FF4081; }
.action-btn.collected .action-icon { color: #FF9800; }
/* 加载更多 */
.load-more { text-align: center; margin: 32px 0; }
.load-btn { background: #6200EE; color: white; border: none; padding: 12px 32px; border-radius: 24px; font-size: 16px; font-weight: 500; cursor: pointer; transition: all 0.3s; }
.load-btn:hover { background: #3700B3; }
.load-btn:disabled { background: #BDBDBD; cursor: not-allowed; }
/* 空状态 */
.empty-state { text-align: center; padding: 60px 20px; }
.empty-icon { font-size: 60px; color: #BDBDBD; margin-bottom: 20px; }
.empty-title { font-size: 18px; font-weight: 500; color: #757575; margin-bottom: 8px; }
.empty-desc { font-size: 14px; color: #9E9E9E; }
/* 加载状态 */
.loading-state { text-align: center; padding: 40px 20px; }
.loading-spinner { width: 40px; height: 40px; border: 3px solid #F5F5F5; border-top: 3px solid #6200EE; border-radius: 50%; animation: spin 1s linear infinite; margin: 0 auto 16px; }
@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
.loading-text { font-size: 14px; color: #757575; }
/* 底部导航 */
.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; z-index: 1000; }
.tab-item { display: flex; flex-direction: column; align-items: center; padding: 8px 16px; border-radius: 12px; transition: all 0.3s; cursor: pointer; }
.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; }
/* 安全区域 */
.safe-area { height: 80px; }
/* 响应式 */
@media (max-width: 600px) {
.wechat-list { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); }
.article-item { padding: 16px; }
}
/* 搜索建议 */
.search-suggestions { position: absolute; top: 100%; left: 0; right: 0; background: white; border-radius: 0 0 16px 16px; box-shadow: 0 4px 20px rgba(0,0,0,0.15); z-index: 100; display: none; }
.search-suggestions.active { display: block; }
.suggestion-item { padding: 12px 16px; border-bottom: 1px solid #EEEEEE; cursor: pointer; transition: all 0.2s; }
.suggestion-item:hover { background: #F5F5F5; }
.suggestion-text { font-size: 14px; color: #212121; }
.suggestion-hint { font-size: 12px; color: #757575; margin-top: 2px; }
/* 搜索容器 */
.search-wrapper { position: relative; }
</style>
</head>
<body>
<div class="container">
<!-- 状态栏 -->
<div class="status-bar"></div>
<!-- 搜索栏 -->
<div class="search-bar">
<div class="search-wrapper">
<div class="search-container">
<div class="search-icon">🔍</div>
<input type="text" class="search-input" id="searchInput" placeholder="搜索公众号文章..." value="">
<div class="search-clear" id="searchClear">✕</div>
</div>
<div class="search-suggestions" id="searchSuggestions">
<div class="suggestion-item" data-keyword="Android">
<div class="suggestion-text">Android</div>
<div class="suggestion-hint">搜索Android相关文章</div>
</div>
<div class="suggestion-item" data-keyword="Kotlin">
<div class="suggestion-text">Kotlin</div>
<div class="suggestion-hint">搜索Kotlin相关文章</div>
</div>
<div class="suggestion-item" data-keyword="Material Design">
<div class="suggestion-text">Material Design</div>
<div class="suggestion-hint">搜索Material Design相关文章</div>
</div>
<div class="suggestion-item" data-keyword="性能优化">
<div class="suggestion-text">性能优化</div>
<div class="suggestion-hint">搜索性能优化相关文章</div>
</div>
</div>
</div>
</div>
<!-- 内容区域 -->
<div class="content">
<!-- 公众号分类 -->
<div class="category-section">
<div class="section-title">
<div class="section-title-icon">📱</div>
<div>技术公众号</div>
</div>
<div class="wechat-list" id="wechatList">
<!-- 公众号列表将通过JavaScript动态加载 -->
</div>
</div>
<!-- 文章列表 -->
<div class="article-section">
<div class="section-title">
<div class="section-title-icon">📰</div>
<div id="currentWechatTitle">鸿洋 - 最新文章</div>
</div>
<div class="article-list" id="articleList">
<!-- 文章列表将通过JavaScript动态加载 -->
</div>
<!-- 加载更多 -->
<div class="load-more" id="loadMoreSection">
<button class="load-btn" id="loadMoreBtn">加载更多</button>
</div>
<!-- 空状态 -->
<div class="empty-state" id="emptyState" style="display: none;">
<div class="empty-icon">📭</div>
<div class="empty-title">暂无文章</div>
<div class="empty-desc">当前公众号还没有发布文章</div>
</div>
<!-- 加载状态 -->
<div class="loading-state" id="loadingState" style="display: none;">
<div class="loading-spinner"></div>
<div class="loading-text">加载中...</div>
</div>
</div>
<!-- 安全区域 -->
<div class="safe-area"></div>
</div>
<!-- 底部导航 -->
<div class="tab-bar">
<div class="tab-item" onclick="switchTab('home', event)">
<div class="tab-icon">🏠</div>
<div class="tab-text">首页</div>
</div>
<div class="tab-item" onclick="switchTab('project', event)">
<div class="tab-icon">📦</div>
<div class="tab-text">项目</div>
</div>
<div class="tab-item active" onclick="switchTab('wechat', event)">
<div class="tab-icon">📱</div>
<div class="tab-text">公众号</div>
</div>
<div class="tab-item" onclick="switchTab('system', event)">
<div class="tab-icon">🌳</div>
<div class="tab-text">体系</div>
</div>
<div class="tab-item" onclick="switchTab('profile', event)">
<div class="tab-icon">👤</div>
<div class="tab-text">我的</div>
</div>
</div>
</div>
<script>
// 全局变量
let currentWechatId = 408; // 默认鸿洋公众号
let currentPage = 1;
let currentKeyword = '';
let isLoading = false;
let hasMore = true;
let wechatList = [];
let articles = [];
// DOM元素
const searchInput = document.getElementById('searchInput');
const searchClear = document.getElementById('searchClear');
const searchSuggestions = document.getElementById('searchSuggestions');
const wechatListEl = document.getElementById('wechatList');
const currentWechatTitle = document.getElementById('currentWechatTitle');
const articleList = document.getElementById('articleList');
const loadMoreSection = document.getElementById('loadMoreSection');
const loadMoreBtn = document.getElementById('loadMoreBtn');
const emptyState = document.getElementById('emptyState');
const loadingState = document.getElementById('loadingState');
// 初始化
document.addEventListener('DOMContentLoaded', function() {
loadWechatList();
loadArticles();
setupEventListeners();
});
// 设置事件监听器
function setupEventListeners() {
// 搜索输入
searchInput.addEventListener('input', function() {
const value = this.value.trim();
searchClear.classList.toggle('active', value.length > 0);
if (value.length > 0) {
searchSuggestions.classList.add('active');
} else {
searchSuggestions.classList.remove('active');
}
});
searchInput.addEventListener('focus', function() {
if (this.value.trim().length > 0) {
searchSuggestions.classList.add('active');
}
});
// 搜索清除
searchClear.addEventListener('click', function() {
searchInput.value = '';
searchClear.classList.remove('active');
searchSuggestions.classList.remove('active');
currentKeyword = '';
currentPage = 1;
loadArticles();
});
// 搜索建议点击
document.querySelectorAll('.suggestion-item').forEach(item => {
item.addEventListener('click', function() {
const keyword = this.getAttribute('data-keyword');
searchInput.value = keyword;
searchClear.classList.add('active');
searchSuggestions.classList.remove('active');
currentKeyword = keyword;
currentPage = 1;
loadArticles();
});
});
// 搜索提交
searchInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
const keyword = this.value.trim();
currentKeyword = keyword;
currentPage = 1;
loadArticles();
searchSuggestions.classList.remove('active');
}
});
// 点击外部关闭搜索建议
document.addEventListener('click', function(e) {
if (!e.target.closest('.search-wrapper')) {
searchSuggestions.classList.remove('active');
}
});
// 加载更多
loadMoreBtn.addEventListener('click', function() {
if (!isLoading && hasMore) {
currentPage++;
loadArticles(true);
}
});
}
// 加载公众号列表
async function loadWechatList() {
try {
const response = await fetch('/api/wxarticle/chapters/json');
const data = await response.json();
if (data.errorCode === 0) {
wechatList = data.data;
renderWechatList();
} else {
console.error('加载公众号列表失败:', data.errorMsg);
}
} catch (error) {
console.error('加载公众号列表出错:', error);
// 使用模拟数据
wechatList = [
{ id: 408, name: "鸿洋", order: 190000 },
{ id: 409, name: "郭霖", order: 190001 },
{ id: 410, name: "玉刚说", order: 190002 },
{ id: 411, name: "承香墨影", order: 190003 },
{ id: 413, name: "Android群英传", order: 190004 },
{ id: 414, name: "code小生", order: 190005 },
{ id: 415, name: "谷歌开发者", order: 190006 }
];
renderWechatList();
}
}
// 渲染公众号列表
function renderWechatList() {
wechatListEl.innerHTML = '';
wechatList.forEach(wechat => {
const item = document.createElement('div');
item.className = `wechat-item ${wechat.id === currentWechatId ? 'active' : ''}`;
item.setAttribute('data-id', wechat.id);
item.setAttribute('data-name', wechat.name);
item.innerHTML = `
<div class="wechat-icon">📱</div>
<div class="wechat-name">${wechat.name}</div>
<div class="wechat-desc">技术公众号</div>
`;
item.addEventListener('click', function() {
const id = parseInt(this.getAttribute('data-id'));
const name = this.getAttribute('data-name');
// 更新选中状态
document.querySelectorAll('.wechat-item').forEach(el => {
el.classList.remove('active');
});
this.classList.add('active');
// 更新当前公众号
currentWechatId = id;
currentPage = 1;
currentKeyword = '';
searchInput.value = '';
searchClear.classList.remove('active');
// 更新标题
currentWechatTitle.textContent = `${name} - 最新文章`;
// 加载文章
loadArticles();
});
wechatListEl.appendChild(item);
});
}
// 加载文章
async function loadArticles(isLoadMore = false) {
if (isLoading) return;
if (!isLoadMore) {
// 首次加载或重新加载
articleList.innerHTML = '';
articles = [];
loadMoreSection.style.display = 'none';
emptyState.style.display = 'none';
loadingState.style.display = 'block';
} else {
// 加载更多
loadMoreBtn.disabled = true;
loadMoreBtn.textContent = '加载中...';
}
isLoading = true;
try {
// 构建API URL
let url = `/api/wxarticle/list/${currentWechatId}/${currentPage}/json`;
if (currentKeyword) {
url += `?k=${encodeURIComponent(currentKeyword)}`;
}
const response = await fetch(url);
const data = await response.json();
if (data.errorCode === 0) {
const newArticles = data.data.datas;
if (!isLoadMore) {
articles = newArticles;
} else {
articles = [...articles, ...newArticles];
}
hasMore = !data.data.over && newArticles.length > 0;
renderArticles();
// 更新UI状态
if (articles.length === 0) {
emptyState.style.display = 'block';
loadMoreSection.style.display = 'none';
} else {
emptyState.style.display = 'none';
loadMoreSection.style.display = hasMore ? 'block' : 'none';
}
} else {
console.error('加载文章失败:', data.errorMsg);
showError('加载文章失败: ' + data.errorMsg);
}
} catch (error) {
console.error('加载文章出错:', error);
showError('网络错误,请稍后重试');
// 使用模拟数据
if (!isLoadMore) {
articles = generateMockArticles();
renderArticles();
emptyState.style.display = 'none';
loadMoreSection.style.display = 'block';
}
} finally {
isLoading = false;
loadingState.style.display = 'none';
if (isLoadMore) {
loadMoreBtn.disabled = false;
loadMoreBtn.textContent = '加载更多';
}
}
}
// 渲染文章列表
function renderArticles() {
if (currentPage === 1) {
articleList.innerHTML = '';
}
articles.forEach(article => {
const item = document.createElement('div');
item.className = 'article-item';
item.setAttribute('data-id', article.id);
// 格式化时间
const date = new Date(article.publishTime);
const timeStr = formatTime(date);
item.innerHTML = `
<div class="article-header">
<div class="article-title">${article.title}</div>
${article.fresh ? '<div class="article-tag">新</div>' : ''}
${article.tags && article.tags.length > 0 ? '<div class="article-tag">置顶</div>' : ''}
</div>
<div class="article-meta">
<div class="article-author">${article.author}</div>
<div class="article-time">${timeStr}</div>
</div>
<div class="article-actions">
<div class="action-btn ${article.collect ? 'collected' : ''}" onclick="toggleCollect(${article.id}, this)">
<div class="action-icon">${article.collect ? '★' : '☆'}</div>
<div>${article.collect ? '已收藏' : '收藏'}</div>
</div>
<div class="action-btn ${article.zan > 0 ? 'liked' : ''}" onclick="toggleLike(${article.id}, this)">
<div class="action-icon">❤️</div>
<div>${article.zan || 0}</div>
</div>
</div>
`;
// 点击文章标题跳转
const titleEl = item.querySelector('.article-title');
titleEl.style.cursor = 'pointer';
titleEl.addEventListener('click', function() {
window.open(article.link, '_blank');
});
articleList.appendChild(item);
});
}
// 生成模拟文章数据
function generateMockArticles() {
const mockArticles = [];
const author = getWechatName(currentWechatId);
for (let i = 1; i <= 8; i++) {
const articleId = (currentPage - 1) * 8 + i;
const title = currentKeyword ?
`${author} - ${currentKeyword}相关文章 ${articleId}` :
`${author} - Android开发技巧 ${articleId}`;
mockArticles.push({
id: articleId,
title: title,
link: `https://www.wanandroid.com/blog/show/${articleId}`,
author: author,
publishTime: Date.now() - (i * 3600000),
collect: i % 3 === 0,
zan: Math.floor(Math.random() * 100) + 20,
fresh: i <= 2,
tags: i === 1 ? [{ name: "置顶", url: "" }] : []
});
}
return mockArticles;
}
// 根据公众号ID获取名称
function getWechatName(id) {
const wechat = wechatList.find(w => w.id === id);
return wechat ? wechat.name : '鸿洋';
}
// 格式化时间
function formatTime(date) {
const now = new Date();
const diff = now - date;
if (diff < 60000) { // 1分钟内
return '刚刚';
} else if (diff < 3600000) { // 1小时内
return Math.floor(diff / 60000) + '分钟前';
} else if (diff < 86400000) { // 1天内
return Math.floor(diff / 3600000) + '小时前';
} else if (diff < 604800000) { // 1周内
return Math.floor(diff / 86400000) + '天前';
} else {
return date.toLocaleDateString();
}
}
// 切换收藏状态
function toggleCollect(articleId, element) {
const isCollected = element.classList.contains('collected');
// 模拟API调用
setTimeout(() => {
if (isCollected) {
element.classList.remove('collected');
element.querySelector('.action-icon').textContent = '☆';
element.querySelector('div:last-child').textContent = '收藏';
// 更新文章数据
const article = articles.find(a => a.id === articleId);
if (article) article.collect = false;
} else {
element.classList.add('collected');
element.querySelector('.action-icon').textContent = '★';
element.querySelector('div:last-child').textContent = '已收藏';
// 更新文章数据
const article = articles.find(a => a.id === articleId);
if (article) article.collect = true;
}
}, 300);
}
// 切换点赞状态
function toggleLike(articleId, element) {
const isLiked = element.classList.contains('liked');
const countEl = element.querySelector('div:last-child');
let count = parseInt(countEl.textContent) || 0;
// 模拟API调用
setTimeout(() => {
if (isLiked) {
element.classList.remove('liked');
count--;
countEl.textContent = count;
// 更新文章数据
const article = articles.find(a => a.id === articleId);
if (article) article.zan = count;
} else {
element.classList.add('liked');
count++;
countEl.textContent = count;
// 更新文章数据
const article = articles.find(a => a.id === articleId);
if (article) article.zan = count;
}
}, 300);
}
// 显示错误
function showError(message) {
// 可以在这里添加更复杂的错误提示
console.error(message);
}
// Tab切换函数
function switchTab(tab, event) {
switch(tab) {
case 'home':
window.location.href = '/index.html';
break;
case 'project':
window.location.href = '/projects_fixed.html';
break;
case 'wechat':
// 当前页面,不需要跳转
break;
case 'system':
window.location.href = '/tree.html';
break;
case 'profile':
window.location.href = '/profile.html';
break;
default:
console.log('未知Tab:', tab);
}
}
// 页面加载完成后的初始化
window.addEventListener('load', function() {
console.log('公众号页面加载完成');
console.log('当前公众号ID:', currentWechatId);
console.log('API地址: /api/wxarticle/chapters/json');
console.log('文章API: /api/wxarticle/list/{id}/{page}/json');
});
</script>
</body>
</html>