diff --git a/packages/core/src/components/cx/ExamSettingPanel.tsx b/packages/core/src/components/cx/ExamSettingPanel.tsx index d438d8ec..82303bd9 100644 --- a/packages/core/src/components/cx/ExamSettingPanel.tsx +++ b/packages/core/src/components/cx/ExamSettingPanel.tsx @@ -31,9 +31,8 @@ export const ExamSettingPanel = defineComponent({ value={settings.period} min="3" step="1" - onChange={(e: any) => { - settings.period = e.target.valueAsNumber; - }} + onChange={(e: any) => (settings.period = e.target.valueAsNumber)} + onInput={(e: any) => (settings.period = e.target.valueAsNumber)} /> @@ -45,9 +44,8 @@ export const ExamSettingPanel = defineComponent({ value={settings.timeout} min="0" step="1" - onChange={(e: any) => { - settings.timeout = e.target.valueAsNumber; - }} + onChange={(e: any) => (settings.timeout = e.target.valueAsNumber)} + onInput={(e: any) => (settings.timeout = e.target.valueAsNumber)} /> @@ -60,11 +58,23 @@ export const ExamSettingPanel = defineComponent({ min="0" max="2" step="1" - onChange={(e: any) => { - settings.retry = e.target.valueAsNumber; - }} + onChange={(e: any) => (settings.retry = e.target.valueAsNumber)} + onInput={(e: any) => (settings.retry = e.target.valueAsNumber)} /> + +
+ + (settings.waitForCheck = e.target.valueAsNumber)} + onInput={(e: any) => (settings.waitForCheck = e.target.valueAsNumber)} + /> + +
diff --git a/packages/core/src/components/cx/StudySettingPanel.tsx b/packages/core/src/components/cx/StudySettingPanel.tsx index 41cf12e5..4882b2c9 100644 --- a/packages/core/src/components/cx/StudySettingPanel.tsx +++ b/packages/core/src/components/cx/StudySettingPanel.tsx @@ -103,9 +103,8 @@ export const StudySettingPanel = defineComponent({ value={store.setting.cx.work.period} min="3" step="1" - onChange={(e: any) => { - store.setting.cx.work.period = e.target.valueAsNumber; - }} + onChange={(e: any) => (store.setting.cx.work.period = e.target.valueAsNumber)} + onInput={(e: any) => (store.setting.cx.work.period = e.target.valueAsNumber)} /> @@ -117,9 +116,8 @@ export const StudySettingPanel = defineComponent({ value={store.setting.cx.work.timeout} min="0" step="1" - onChange={(e: any) => { - store.setting.cx.work.timeout = e.target.valueAsNumber; - }} + onChange={(e: any) => (store.setting.cx.work.timeout = e.target.valueAsNumber)} + onInput={(e: any) => (store.setting.cx.work.timeout = e.target.valueAsNumber)} /> @@ -132,11 +130,25 @@ export const StudySettingPanel = defineComponent({ min="0" max="2" step="1" - onChange={(e: any) => { - store.setting.cx.work.retry = e.target.valueAsNumber; - }} + onChange={(e: any) => (store.setting.cx.work.retry = e.target.valueAsNumber)} + onInput={(e: any) => (store.setting.cx.work.retry = e.target.valueAsNumber)} /> + + +
+ + (store.setting.cx.work.waitForCheck = e.target.valueAsNumber)} + onInput={(e: any) => (store.setting.cx.work.waitForCheck = e.target.valueAsNumber)} + /> + +
+ ); diff --git a/packages/core/src/components/cx/WorkSettingPanel.tsx b/packages/core/src/components/cx/WorkSettingPanel.tsx index 16e30425..9323e497 100644 --- a/packages/core/src/components/cx/WorkSettingPanel.tsx +++ b/packages/core/src/components/cx/WorkSettingPanel.tsx @@ -23,9 +23,8 @@ export const WorkSettingPanel = defineComponent({ value={settings.period} min="3" step="1" - onChange={(e: any) => { - settings.period = e.target.valueAsNumber; - }} + onChange={(e: any) => (settings.period = e.target.valueAsNumber)} + onInput={(e: any) => (settings.period = e.target.valueAsNumber)} /> @@ -37,9 +36,8 @@ export const WorkSettingPanel = defineComponent({ value={settings.timeout} min="0" step="1" - onChange={(e: any) => { - settings.timeout = e.target.valueAsNumber; - }} + onChange={(e: any) => (settings.timeout = e.target.valueAsNumber)} + onInput={(e: any) => (settings.timeout = e.target.valueAsNumber)} /> @@ -52,11 +50,23 @@ export const WorkSettingPanel = defineComponent({ min="0" max="2" step="1" - onChange={(e: any) => { - settings.retry = e.target.valueAsNumber; - }} + onChange={(e: any) => (settings.retry = e.target.valueAsNumber)} + onInput={(e: any) => (settings.retry = e.target.valueAsNumber)} /> + +
+ + (settings.waitForCheck = e.target.valueAsNumber)} + onInput={(e: any) => (settings.waitForCheck = e.target.valueAsNumber)} + /> + +
diff --git a/packages/core/src/components/zhs/WorkSettingPanel.tsx b/packages/core/src/components/zhs/WorkSettingPanel.tsx index d457420a..c9915465 100644 --- a/packages/core/src/components/zhs/WorkSettingPanel.tsx +++ b/packages/core/src/components/zhs/WorkSettingPanel.tsx @@ -28,6 +28,7 @@ export const WorkSettingPanel = defineComponent({ (settings.period = e.target.valueAsNumber)} + onInput={(e: any) => (settings.period = e.target.valueAsNumber)} value={settings.period} min="3" step="1" @@ -40,6 +41,7 @@ export const WorkSettingPanel = defineComponent({ (settings.timeout = e.target.valueAsNumber)} + onInput={(e: any) => (settings.timeout = e.target.valueAsNumber)} value={settings.timeout} min="0" step="1" @@ -52,6 +54,7 @@ export const WorkSettingPanel = defineComponent({ (settings.retry = e.target.valueAsNumber)} + onInput={(e: any) => (settings.retry = e.target.valueAsNumber)} value={settings.retry} min="0" max="2" diff --git a/packages/core/src/script/cx/study.ts b/packages/core/src/script/cx/study.ts index 64516d1d..ba763768 100644 --- a/packages/core/src/script/cx/study.ts +++ b/packages/core/src/script/cx/study.ts @@ -221,157 +221,155 @@ async function chapterTestTask(setting: ScriptSettings['cx']['work'], frame: HTM if (store.setting.cx.video.upload === 'close') { logger('warn', '自动答题已被关闭!'); - return; - } - - logger('info', '开始自动答题'); - - if (store.setting.answererWrappers.length === 0) { + } else if (store.setting.answererWrappers.length === 0) { logger('warn', '题库配置为空,请设置。'); - return; - } - - // @ts-ignore - if (!frame.contentWindow) { + // @ts-ignore + } else if (!frame.contentWindow) { logger('warn', '元素不可访问'); - return; - } - - // 等待文字识别 - await waitForRecognize(); - - const { window: frameWindow } = frame.contentWindow; - - const { TiMu } = domSearchAll({ TiMu: '.TiMu' }, frameWindow.document); - /** 清空答案 */ - store.workResults = []; - - /** 新建答题器 */ - const worker = new OCSWorker({ - root: TiMu, - elements: { - title: '.Zy_TItle .clearfix', - /** - * 兼容各种选项 - * - * ul li .after 单选多选 - * ul li label:not(.after) 判断题 - * ul li textarea 填空题 - */ - options: 'ul li .after,ul li textarea,ul textarea,ul li label:not(.before)', - type: 'input[id^="answertype"]' - }, - /** 默认搜题方法构造器 */ - answerer: (elements, type) => { - const title = StringUtils.nowrap(elements.title[0].innerText) - .replace(/(\d+)?【.*?题】/, '') - .replace(/(\d+.0分)/, '') - .trim(); - if (title) { - return defaultAnswerWrapperHandler(store.setting.answererWrappers, type, title); - } else { - throw new Error('题目为空,请查看题目是否为空,或者忽略此题'); - } - }, - /** 处理cx作业判断题选项是图片的问题 */ - onElementSearched(elements) { - const typeInput = elements.type[0] as HTMLInputElement; - const type = parseInt(typeInput.value); - if (type === 3) { - elements.options.forEach((option) => { - const ri = option.querySelector('.ri'); - const span = document.createElement('span'); - span.innerText = ri ? '√' : '×'; - option.appendChild(span); - }); - } - }, - work: { - /** - * cx 题目类型 : - * 0 单选题 - * 1 多选题 - * 2 简答题 - * 3 判断题 - * 4 填空题 - */ - type({ elements }) { + } else { + logger('info', '开始自动答题'); + + // 等待文字识别 + await waitForRecognize(); + + const { window: frameWindow } = frame.contentWindow; + + const { TiMu } = domSearchAll({ TiMu: '.TiMu' }, frameWindow.document); + /** 清空答案 */ + store.workResults = []; + + /** 新建答题器 */ + const worker = new OCSWorker({ + root: TiMu, + elements: { + title: '.Zy_TItle .clearfix', + /** + * 兼容各种选项 + * + * ul li .after 单选多选 + * ul li label:not(.after) 判断题 + * ul li textarea 填空题 + */ + options: 'ul li .after,ul li textarea,ul textarea,ul li label:not(.before)', + type: 'input[id^="answertype"]' + }, + /** 默认搜题方法构造器 */ + answerer: (elements, type) => { + const title = StringUtils.nowrap(elements.title[0].innerText) + .replace(/(\d+)?【.*?题】/, '') + .replace(/(\d+.0分)/, '') + .trim(); + if (title) { + return defaultAnswerWrapperHandler(store.setting.answererWrappers, type, title); + } else { + throw new Error('题目为空,请查看题目是否为空,或者忽略此题'); + } + }, + /** 处理cx作业判断题选项是图片的问题 */ + onElementSearched(elements) { const typeInput = elements.type[0] as HTMLInputElement; - const type = parseInt(typeInput.value); - return type === 0 - ? 'single' - : type === 1 - ? 'multiple' - : type === 2 - ? 'completion' - : type === 3 - ? 'judgement' - : elements.options[0].querySelector('textarea') - ? 'completion' - : undefined; + if (type === 3) { + elements.options.forEach((option) => { + const ri = option.querySelector('.ri'); + const span = document.createElement('span'); + span.innerText = ri ? '√' : '×'; + option.appendChild(span); + }); + } }, - /** 自定义处理器 */ - handler(type, answer, option) { - if (type === 'judgement' || type === 'single' || type === 'multiple') { - if (!option.parentElement?.querySelector('input')?.checked) { - // @ts-ignore - option.parentElement?.querySelector('a,label')?.click(); - } - } else if (type === 'completion' && answer.trim()) { - const text = option.parentElement?.querySelector('textarea'); - const textareaFrame = option.parentElement?.querySelector('iframe'); - if (text) { - text.value = answer; - } - if (textareaFrame?.contentDocument) { - textareaFrame.contentDocument.body.innerHTML = answer; + work: { + /** + * cx 题目类型 : + * 0 单选题 + * 1 多选题 + * 2 简答题 + * 3 判断题 + * 4 填空题 + */ + type({ elements }) { + const typeInput = elements.type[0] as HTMLInputElement; + + const type = parseInt(typeInput.value); + return type === 0 + ? 'single' + : type === 1 + ? 'multiple' + : type === 2 + ? 'completion' + : type === 3 + ? 'judgement' + : elements.options[0].querySelector('textarea') + ? 'completion' + : undefined; + }, + /** 自定义处理器 */ + handler(type, answer, option) { + if (type === 'judgement' || type === 'single' || type === 'multiple') { + if (!option.parentElement?.querySelector('input')?.checked) { + // @ts-ignore + option.parentElement?.querySelector('a,label')?.click(); + } + } else if (type === 'completion' && answer.trim()) { + const text = option.parentElement?.querySelector('textarea'); + const textareaFrame = option.parentElement?.querySelector('iframe'); + if (text) { + text.value = answer; + } + if (textareaFrame?.contentDocument) { + textareaFrame.contentDocument.body.innerHTML = answer; + } } } - } - }, - onResult: (res) => { - if (res.ctx) { - store.workResults.push(res); - } - console.log(res); - logger('info', '题目完成结果 : ', res.result?.finish ? '完成' : '未完成'); - }, - - /** 其余配置 */ - period: (period || 3) * 1000, - timeout: (timeout || 30) * 1000, - retry, - stopWhenError: false - }); + }, + onResult: (res) => { + if (res.ctx) { + store.workResults.push(res); + } + console.log(res); + logger('info', '题目完成结果 : ', res.result?.finish ? '完成' : '未完成'); + }, - const results = await worker.doWork(); + /** 其余配置 */ + period: (period || 3) * 1000, + timeout: (timeout || 30) * 1000, + retry, + stopWhenError: false + }); - logger('info', '做题完毕', results); + const results = await worker.doWork(); - // 处理提交 - await worker.uploadHandler({ - uploadRate: store.setting.cx.video.upload, - results, - async callback(finishedRate, uploadable) { - logger('info', '完成率 : ', finishedRate, ' , ', uploadable ? '5秒后将自动提交' : ' 5秒后将自动保存'); + logger('info', '做题完毕', results); - await sleep(5000); + // 处理提交 + await worker.uploadHandler({ + uploadRate: store.setting.cx.video.upload, + results, + async callback(finishedRate, uploadable) { + logger('info', '完成率 : ', finishedRate, ' , ', uploadable ? '5秒后将自动提交' : ' 5秒后将自动保存'); - if (uploadable) { - // @ts-ignore 提交 - frameWindow.btnBlueSubmit(); + await sleep(5000); - await sleep(3000); - /** 确定按钮 */ - // @ts-ignore 确定 - frameWindow.submitCheckTimes(); - } else { - // @ts-ignore 禁止弹窗 - frameWindow.alert = () => { }; - // @ts-ignore 暂时保存 - frameWindow.noSubmit(); + if (uploadable) { + // @ts-ignore 提交 + frameWindow.btnBlueSubmit(); + + await sleep(3000); + /** 确定按钮 */ + // @ts-ignore 确定 + frameWindow.submitCheckTimes(); + } else { + // @ts-ignore 禁止弹窗 + frameWindow.alert = () => { }; + // @ts-ignore 暂时保存 + frameWindow.noSubmit(); + } } - } - }); + }); + } + + if (setting.waitForCheck) { + logger('debug', `正在等待答题检查: 一共 ${setting.waitForCheck} 秒`); + await sleep(setting.waitForCheck * 1000); + } } diff --git a/packages/core/src/script/cx/work.ts b/packages/core/src/script/cx/work.ts index c86e0fe9..0698d408 100644 --- a/packages/core/src/script/cx/work.ts +++ b/packages/core/src/script/cx/work.ts @@ -14,126 +14,127 @@ export async function workOrExam( if (setting.upload === 'close') { logger('warn', '自动答题已被关闭!'); - return; - } - - if (store.setting.answererWrappers.length === 0) { + } else if (store.setting.answererWrappers.length === 0) { logger('warn', '题库配置为空,请设置。'); - return; - } - - /** 清空内容 */ - store.workResults = []; - - // 等待文字识别 - await waitForRecognize(); + } else { + /** 清空内容 */ + store.workResults = []; - /** 新建答题器 */ - const worker = new OCSWorker({ - root: '.questionLi', - elements: { - title: 'h3', - options: '.answerBg .answer_p, .textDIV, .eidtDiv', - type: type === 'exam' ? 'input[name^="type"]' : 'input[id^="answertype"]' - }, - /** 默认搜题方法构造器 */ - answerer: (elements, type) => { - const title: string = StringUtils.nowrap(elements.title[0].innerText) - .replace(/\d+\. \(.*?(题|分)\)/, '') - .trim(); - if (title) { - return defaultAnswerWrapperHandler(store.setting.answererWrappers, type, title); - } else { - throw new Error('题目为空,请查看题目是否为空,或者忽略此题'); - } - }, + // 等待文字识别 + await waitForRecognize(); - work: { - /** - * cx 题目类型 : - * 0 单选题 - * 1 多选题 - * 2 简答题 - * 3 判断题 - * 4 填空题 - */ - type({ elements }) { - const typeInput = elements.type[0] as HTMLInputElement; - const type = parseInt(typeInput.value); - return type === 0 - ? 'single' - : type === 1 - ? 'multiple' - : type === 2 - ? 'completion' - : type === 3 - ? 'judgement' - : type === 4 - ? 'completion' - : undefined; + /** 新建答题器 */ + const worker = new OCSWorker({ + root: '.questionLi', + elements: { + title: 'h3', + options: '.answerBg .answer_p, .textDIV, .eidtDiv', + type: type === 'exam' ? 'input[name^="type"]' : 'input[id^="answertype"]' }, - /** 自定义处理器 */ - handler(type, answer, option) { - if (type === 'judgement' || type === 'single' || type === 'multiple') { - if (option.parentElement?.querySelector('.check_answer,.check_answer_dx') === null) { - option.click(); - } - } else if (type === 'completion' && answer.trim()) { - const text = option.querySelector('textarea'); - const textareaFrame = option.querySelector('iframe'); - if (text) { - text.value = answer; - } - if (textareaFrame?.contentDocument) { - textareaFrame.contentDocument.body.innerHTML = answer; + /** 默认搜题方法构造器 */ + answerer: (elements, type) => { + const title: string = StringUtils.nowrap(elements.title[0].innerText) + .replace(/\d+\. \(.*?(题|分)\)/, '') + .trim(); + if (title) { + return defaultAnswerWrapperHandler(store.setting.answererWrappers, type, title); + } else { + throw new Error('题目为空,请查看题目是否为空,或者忽略此题'); + } + }, + + work: { + /** + * cx 题目类型 : + * 0 单选题 + * 1 多选题 + * 2 简答题 + * 3 判断题 + * 4 填空题 + */ + type({ elements }) { + const typeInput = elements.type[0] as HTMLInputElement; + const type = parseInt(typeInput.value); + return type === 0 + ? 'single' + : type === 1 + ? 'multiple' + : type === 2 + ? 'completion' + : type === 3 + ? 'judgement' + : type === 4 + ? 'completion' + : undefined; + }, + /** 自定义处理器 */ + handler(type, answer, option) { + if (type === 'judgement' || type === 'single' || type === 'multiple') { + if (option.parentElement?.querySelector('.check_answer,.check_answer_dx') === null) { + option.click(); + } + } else if (type === 'completion' && answer.trim()) { + const text = option.querySelector('textarea'); + const textareaFrame = option.querySelector('iframe'); + if (text) { + text.value = answer; + } + if (textareaFrame?.contentDocument) { + textareaFrame.contentDocument.body.innerHTML = answer; + } } } - } - }, - onResult: (res) => { - if (res.ctx) { - store.workResults.push(res); - } - console.log(res); - logger('info', '题目完成结果 : ', res.result?.finish ? '完成' : '未完成'); - }, + }, + onResult: (res) => { + if (res.ctx) { + store.workResults.push(res); + } + console.log(res); + logger('info', '题目完成结果 : ', res.result?.finish ? '完成' : '未完成'); + }, - /** 其余配置 */ + /** 其余配置 */ - period: (period || 3) * 1000, - timeout: (timeout || 30) * 1000, - retry, - stopWhenError: false - }); + period: (period || 3) * 1000, + timeout: (timeout || 30) * 1000, + retry, + stopWhenError: false + }); - const results = await worker.doWork(); + const results = await worker.doWork(); - logger('info', '做题完毕', results); + logger('info', '做题完毕', results); - if (type === 'exam') { - logger('info', '为了安全考虑,请自行检查后自行点击提交!'); - } else { - // 处理提交 - await worker.uploadHandler({ - uploadRate: setting.upload, - results, - async callback(finishedRate, uploadable) { - logger('info', '完成率 : ', finishedRate, ' , ', uploadable ? '5秒后将自动提交' : '5秒后将自动保存'); + if (type === 'exam') { + logger('info', '为了安全考虑,请自行检查后自行点击提交!'); + } else { + // 处理提交 + await worker.uploadHandler({ + uploadRate: setting.upload, + results, + async callback(finishedRate, uploadable) { + logger('info', '完成率 : ', finishedRate, ' , ', uploadable ? '5秒后将自动提交' : '5秒后将自动保存'); - await sleep(5000); - if (uploadable) { - // 提交 - domSearch({ submit: '.completeBtn' }).submit?.click(); - await sleep(2000); - // @ts-ignore 确定 - // eslint-disable-next-line no-undef - submitWork(); - } else { - // @ts-ignore 暂时保存 - // eslint-disable-next-line no-undef - saveWork(); + await sleep(5000); + if (uploadable) { + // 提交 + domSearch({ submit: '.completeBtn' }).submit?.click(); + await sleep(2000); + // @ts-ignore 确定 + // eslint-disable-next-line no-undef + submitWork(); + } else { + // @ts-ignore 暂时保存 + // eslint-disable-next-line no-undef + saveWork(); + } } - } - }); + }); + } + } + + if (setting.waitForCheck) { + logger('debug', `正在等待答题检查: 一共 ${setting.waitForCheck} 秒`); + await sleep(setting.waitForCheck * 1000); } } diff --git a/packages/core/src/scripts.ts b/packages/core/src/scripts.ts index 4b273ef8..840fce72 100644 --- a/packages/core/src/scripts.ts +++ b/packages/core/src/scripts.ts @@ -11,9 +11,9 @@ export interface Setting { restudy: boolean } work: Record & - Pick, 'period' | 'timeout' | 'retry'> & { upload: string } + Pick, 'period' | 'timeout' | 'retry'> & { upload: string, waitForCheck: number } exam: Record & - Pick, 'period' | 'timeout' | 'retry'> & { upload: string } + Pick, 'period' | 'timeout' | 'retry'> & { upload: string, waitForCheck: number } } export type SupportPlatform = 'zhs' | 'cx' @@ -45,14 +45,16 @@ export function defaultSetting(): Setting { timeout: 30, retry: 1, stopWhenError: false, - upload: 'save' + upload: 'save', + waitForCheck: 5 }, exam: { period: 3, timeout: 30, retry: 1, stopWhenError: false, - upload: 'save' + upload: 'save', + waitForCheck: 5 } }; }