200 lines
5.6 KiB
JavaScript
200 lines
5.6 KiB
JavaScript
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;
|