socials search APIno longer return `avatar_url` and `banner_url` field auto focus search input when loaded
220 lines
6.8 KiB
JavaScript
220 lines
6.8 KiB
JavaScript
document.addEventListener('DOMContentLoaded', () => {
|
|
const searchInput = document.getElementById('searchInput');
|
|
const searchBtn = document.getElementById('searchBtn');
|
|
const postsGallery = document.getElementById('postsGallery');
|
|
const tagsGallery = document.getElementById('tagsGallery');
|
|
const postsTitle = document.getElementById('postsTitle');
|
|
const tagsTitle = document.getElementById('tagsTitle');
|
|
const socialsGallery = document.getElementById('socialsGallery');
|
|
const socialsTitle = document.getElementById('socialsTitle');
|
|
const statusIndicator = document.getElementById('statusIndicator');
|
|
|
|
let currentQuery = '';
|
|
let isLoading = false;
|
|
let hasLoadedPosts = false;
|
|
let hasLoadedTags = false;
|
|
let hasLoadedSocials = false;
|
|
|
|
searchInput.focus()
|
|
|
|
searchBtn.addEventListener('click', initiateSearch);
|
|
searchInput.addEventListener('keypress', (e) => {
|
|
if (e.key === 'Enter') initiateSearch();
|
|
});
|
|
window.addEventListener('scroll', handleScroll);
|
|
|
|
function initiateSearch() {
|
|
const text = searchInput.value.trim();
|
|
if (!text) return;
|
|
if (isLoading) return;
|
|
|
|
currentQuery = text;
|
|
|
|
// 重置页面状态与清空旧数据
|
|
postsGallery.innerHTML = '';
|
|
tagsGallery.innerHTML = '';
|
|
socialsGallery.innerHTML = ''; // 新增
|
|
postsTitle.style.display = 'none';
|
|
tagsTitle.style.display = 'none';
|
|
socialsTitle.style.display = 'none'; // 新增
|
|
hasLoadedPosts = false;
|
|
hasLoadedTags = false;
|
|
hasLoadedSocials = false; // 新增
|
|
|
|
fetchPosts();
|
|
}
|
|
|
|
async function fetchPosts() {
|
|
isLoading = true;
|
|
setStatus('正在搜索作品...');
|
|
|
|
try {
|
|
const response = await fetch(`/api/search/posts?text=${encodeURIComponent(currentQuery)}`);
|
|
const data = await response.json();
|
|
|
|
if (data.posts && data.posts.length > 0) {
|
|
postsTitle.style.display = 'block';
|
|
postsTitle.textContent = `共找到 ${data.posts.length} 个作品,耗时 ${data.time}`;
|
|
renderCards(data.posts, postsGallery, 'post');
|
|
}
|
|
|
|
hasLoadedPosts = true;
|
|
setStatus('');
|
|
|
|
setTimeout(checkIfScreenNeedsMoreContent, 100);
|
|
} catch (error) {
|
|
console.error('获取作品失败:', error);
|
|
setStatus('搜索作品时发生错误');
|
|
} finally {
|
|
isLoading = false;
|
|
}
|
|
}
|
|
|
|
async function fetchTags() {
|
|
if (hasLoadedTags || isLoading) return;
|
|
|
|
isLoading = true;
|
|
setStatus('正在搜索标签...');
|
|
|
|
try {
|
|
const response = await fetch(`/api/search/tags?text=${encodeURIComponent(currentQuery)}`);
|
|
const data = await response.json();
|
|
|
|
if (data.tags && data.tags.length > 0) {
|
|
tagsTitle.style.display = 'block';
|
|
tagsTitle.textContent = `共找到 ${data.tags.length} 个标签,耗时 ${data.time}`;
|
|
renderCards(data.tags, tagsGallery, 'tag');
|
|
}
|
|
|
|
hasLoadedTags = true;
|
|
setStatus(''); // 清空状态,准备接力
|
|
|
|
setTimeout(checkIfScreenNeedsMoreContent, 100);
|
|
} catch (error) {
|
|
console.error('获取标签失败:', error);
|
|
setStatus('加载标签时发生错误');
|
|
} finally {
|
|
isLoading = false;
|
|
}
|
|
}
|
|
|
|
async function fetchSocials() {
|
|
if (hasLoadedSocials || isLoading) return;
|
|
|
|
isLoading = true;
|
|
setStatus('正在加载相关社交账号...');
|
|
|
|
try {
|
|
const response = await fetch(`/api/search/socials?text=${encodeURIComponent(currentQuery)}`);
|
|
const data = await response.json();
|
|
|
|
if (data.socials && data.socials.length > 0) {
|
|
socialsTitle.style.display = 'block';
|
|
socialsTitle.textContent = `共找到 ${data.socials.length} 个社交账号,耗时 ${data.time}`;
|
|
renderCards(data.socials, socialsGallery, 'social');
|
|
}
|
|
|
|
hasLoadedSocials = true;
|
|
setStatus('没有更多结果了'); // 最后一项加载完,展示最终提示
|
|
|
|
} catch (error) {
|
|
console.error('获取社交账号失败:', error);
|
|
setStatus('加载社交账号时发生错误。');
|
|
} finally {
|
|
isLoading = false;
|
|
}
|
|
}
|
|
|
|
// 屏幕高度检查
|
|
function checkIfScreenNeedsMoreContent() {
|
|
const isScreenFilled = document.documentElement.scrollHeight > window.innerHeight;
|
|
|
|
if (!isScreenFilled) {
|
|
if (hasLoadedPosts && !hasLoadedTags) {
|
|
fetchTags();
|
|
} else if (hasLoadedTags && !hasLoadedSocials) {
|
|
fetchSocials();
|
|
}
|
|
}
|
|
}
|
|
|
|
// 滚动事件处理
|
|
function handleScroll() {
|
|
// 如果全部加载完毕,直接拦截
|
|
if (isLoading || hasLoadedSocials) return;
|
|
|
|
const scrollTop = window.scrollY || document.documentElement.scrollTop;
|
|
const windowHeight = window.innerHeight;
|
|
const docHeight = document.documentElement.scrollHeight;
|
|
|
|
if (scrollTop + windowHeight >= docHeight - 150) {
|
|
if (hasLoadedPosts && !hasLoadedTags) {
|
|
fetchTags();
|
|
} else if (hasLoadedTags && !hasLoadedSocials) {
|
|
fetchSocials();
|
|
}
|
|
}
|
|
}
|
|
|
|
function renderCards(items, container, type) {
|
|
const fragment = document.createDocumentFragment();
|
|
|
|
items.forEach(item => {
|
|
const card = document.createElement('a');
|
|
card.className = 'card';
|
|
|
|
let titleText = '';
|
|
let subText = '';
|
|
let imgSrc = '';
|
|
let HTML = '';
|
|
|
|
if (type === 'post') {
|
|
card.href = `/artworks/${item.artwork_id}`;
|
|
imgSrc = `/thumbnails/${item.file_id}.jpg`;
|
|
titleText = item.title;
|
|
subText = item.text || '';
|
|
HTML = `<h3 class="card-title">${titleText ? titleText : ""}</h3><p class="card-subtitle">${escapeHTML(subText)}</p>`;
|
|
} else if (type === 'tag') {
|
|
card.href = `/artworks/${item.artwork_id}`;
|
|
imgSrc = `/thumbnails/${item.file_id}.jpg`;
|
|
HTML = `<span class="badge">#${item.tag}</span><p class="card-subtitle">${item.count} 个作品</p>`;
|
|
} else if (type === 'social') {
|
|
card.href = `/?socials=${item.id}`;
|
|
card.target = '_blank';
|
|
imgSrc = `/socials/${item.id}/avatar`;
|
|
titleText = item.display_name;
|
|
subText = item.platform || '';
|
|
if (item.username) {
|
|
subText += `/@${item.username}`;
|
|
} else if (item.user_id) {
|
|
subText += `/${item.user_id}`
|
|
}
|
|
HTML = `<span class="badge">${titleText}</span><a class="card-subtitle" href=${item.url} target="_blank">${subText}</a>`;
|
|
}
|
|
|
|
card.innerHTML = `
|
|
<img src="${imgSrc}" alt="${titleText}" loading="lazy">
|
|
<div class="card-info">${HTML}</div>
|
|
`;
|
|
|
|
fragment.appendChild(card);
|
|
});
|
|
|
|
container.appendChild(fragment);
|
|
}
|
|
|
|
function setStatus(text) {
|
|
statusIndicator.textContent = text;
|
|
}
|
|
|
|
function escapeHTML(str) {
|
|
if (!str) return '';
|
|
return str.toString()
|
|
.replace(/&/g, '&')
|
|
.replace(/</g, '<')
|
|
.replace(/>/g, '>')
|
|
.replace(/"/g, '"')
|
|
.replace(/'/g, ''');
|
|
}
|
|
})
|