/** * 任务:查看热门 * * 逻辑: * 1. 找到"查看热门"任务卡片 * 2. 点击 toComplete 打开热门页面 * 3. 点击第一个热门项目卡片 * 4. 在新页面停留后关闭 */ const path = require('path'); const logger = require(path.join(__dirname, '..', 'utils', 'logger')); const { openNewPage, openLinkPage, safeClose, waitPageReady, waitForElements, getPageInfo, } = require(path.join(__dirname, '..', 'utils', 'page')); const PROJECT_CARD_SELECTORS = [ '.hot-selection .recommend-card', '.hot-selection-list a.recommend-card', 'a.recommend-card', 'a[href*="source_module=home_hot_selection"]', 'a[href*="source_module=home_recommend"]', 'a[href*="/"][href*="?source_module="]', ]; /** * 执行查看热门任务 * @param {import('playwright').Page} page - 主页面 */ async function dailyTrending(page) { logger.info('👉 执行查看热门'); // 从主页面找到"查看热门"任务卡片 const tasks = await page.locator('.novice-task-item-box').all(); const trendingTask = await findTaskByTitle(tasks, '查看热门'); if (!trendingTask) { throw new Error('未找到"查看热门"任务卡片'); } // ── 第一步:打开热门页面 ── const trendingPage = await openNewPage( page.context(), () => trendingTask.locator('.toComplete').click() ); try { const cards = await findProjectCards(trendingPage); // ── 第二步:点击第一个热门项目,打开详情页 ── const firstCard = cards[0]; const detailPage = await openLinkPage( trendingPage.context(), firstCard, { label: '热门项目详情页' } ); try { // 等待详情页加载 await waitPageReady(detailPage); logger.info('热门项目详情页已打开'); } finally { await safeClose(detailPage); } } finally { await safeClose(trendingPage); } } async function findProjectCards(page) { const cards = await waitForElements(page, PROJECT_CARD_SELECTORS, { interval: 1000, maxRetries: 15, minCount: 1, }); if (cards.length > 0) { logger.info(`热门项目候选数量: ${cards.length}`); return cards; } const info = await getPageInfo(page); throw new Error( `未找到热门项目卡片,页面结构可能已变化。页面标题: ${info.title}, 页面URL: ${info.url}` ); } /** * 根据标题查找任务卡片 */ async function findTaskByTitle(tasks, title) { for (const task of tasks) { try { const text = await task.locator('.task-card-title__label-text').innerText(); if (text.includes(title)) { return task; } } catch (_) { // 跳过 } } return null; } module.exports = dailyTrending;