const { sleep } = require('../helpers/automator'); class CourseDetailPage { /** * @param {object} miniProgram - miniprogram-automator 实例 */ constructor(miniProgram) { this.mp = miniProgram; } /** * 等待课程详情页加载完成 */ async waitForLoad() { const page = await this.mp.currentPage(); await page.waitFor('.detail-page', { timeout: 10000 }); await sleep(1500); // 等待异步数据加载 return page; } /** * 获取课程基本信息 * @returns {Promise<{courseName: string, status: string, time: string, location: string, memberCount: string}>} */ async getCourseInfo() { const page = await this.mp.currentPage(); const info = {}; try { // 课程名 const titleEl = await page.$('.detail-title'); info.courseName = titleEl ? (await titleEl.text()).trim() : ''; // 状态标签 const statusEl = await page.$('.cover-status text'); info.status = statusEl ? (await statusEl.text()).trim() : ''; // 信息项 const infoItems = await page.$$('.info-item'); for (const item of infoItems) { try { const labelEl = await item.$('.info-label'); const valueEl = await item.$('.info-value'); if (labelEl && valueEl) { const label = (await labelEl.text()).trim(); const value = (await valueEl.text()).trim(); if (label === '时间') info.time = value; if (label === '地点') info.location = value; if (label === '人数') info.memberCount = value; } } catch (e) { // 跳过 } } } catch (e) { // 忽略 } return info; } /** * 点击开课按钮 * 仅当 course.status == 0 (待开课) 时可用 */ async startCourse() { const page = await this.mp.currentPage(); const startBtn = await page.$('.start-btn'); if (!startBtn) { throw new Error('未找到开课按钮(课程可能不是"待开课"状态)'); } // 检查按钮是否被禁用 const isDisabled = await this._isButtonDisabled(startBtn); if (isDisabled) { throw new Error('开课按钮被禁用(尚未到开课时间)'); } await startBtn.tap(); await sleep(3000); // 等待开课请求完成 } /** * 点击结课按钮 * 仅当 course.status == 3 || 7 (进行中) 时可用 */ async endCourse() { const page = await this.mp.currentPage(); const endBtn = await page.$('.end-btn'); if (!endBtn) { throw new Error('未找到结课按钮(课程可能不是"进行中"状态)'); } const isDisabled = await this._isButtonDisabled(endBtn); if (isDisabled) { throw new Error('结课按钮被禁用(尚未到结课时间)'); } await endBtn.tap(); await sleep(3000); // 等待结课请求完成 } /** * 获取学员列表 * 注意:当前课程详情页设计中没有独立的学员列表区域, * 学员人数信息在 info-card 中展示。 * @returns {Promise<{count: number, max: number}>} */ async getStudentList() { const info = await this.getCourseInfo(); if (info.memberCount) { const match = info.memberCount.match(/(\d+)\s*\/\s*(\d+)/); if (match) { return { count: parseInt(match[1], 10), max: parseInt(match[2], 10) }; } } return { count: 0, max: 0 }; } /** * 生成签到二维码 * 注意:当前课程详情页没有直接的生成二维码按钮。 * 二维码通常通过后端 API 生成,MiniTest 中可通过 evaluate 调用 API。 */ async generateQRCode() { const page = await this.mp.currentPage(); // 通过 evaluate 在小程序环境中生成二维码 // 实际二维码生成逻辑取决于后端 API try { const qrData = await this.mp.evaluate(() => { // 尝试获取当前课程的签到信息 const pages = getCurrentPages(); const currentPage = pages[pages.length - 1]; return { courseId: currentPage.courseId || '', timestamp: Date.now() }; }); return qrData; } catch (e) { console.warn('[CourseDetailPage] 生成二维码失败:', e.message); return null; } } /** * 获取操作按钮状态 */ async getActionButtonStatus() { const page = await this.mp.currentPage(); try { const startBtn = await page.$('.start-btn'); if (startBtn) { const text = (await startBtn.text()).trim(); const isDisabled = await this._isButtonDisabled(startBtn); return { type: 'start', text, disabled: isDisabled }; } const endBtn = await page.$('.end-btn'); if (endBtn) { const text = (await endBtn.text()).trim(); const isDisabled = await this._isButtonDisabled(endBtn); return { type: 'end', text, disabled: isDisabled }; } const disabledBtn = await page.$('.disabled-btn'); if (disabledBtn) { const text = (await disabledBtn.text()).trim(); return { type: 'disabled', text, disabled: true }; } } catch (e) { // 忽略 } return null; } /** * 内部方法:检查按钮是否被禁用 */ async _isButtonDisabled(btnElement) { try { const disabled = await btnElement.attribute('disabled'); if (disabled === 'true' || disabled === true || disabled === '') { return true; } // 也检查 CSS class const className = await btnElement.attribute('class'); return (className || '').includes('disabled'); } catch (e) { return false; } } } module.exports = CourseDetailPage;