Skip to content

Commit

Permalink
feat: 新增智慧树学分课作业脚本
Browse files Browse the repository at this point in the history
  • Loading branch information
enncy committed Apr 17, 2022
1 parent b53c098 commit 978bf47
Show file tree
Hide file tree
Showing 13 changed files with 232 additions and 38 deletions.
9 changes: 5 additions & 4 deletions packages/core/src/components/SearchResults.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ export const SearchResults = defineComponent({

return () => (
<div id="search-results">
{hasResult.value
{hasResult.value
? (
<div>
{currentResult.value
{currentResult.value
? (
<div class="search-result-modal" onClick={(e) => e.stopPropagation()}>
<div>
Expand Down Expand Up @@ -88,7 +88,7 @@ export const SearchResults = defineComponent({
</div>
))}
</div>
)
)
: (
<div></div>
)}
Expand All @@ -105,6 +105,7 @@ export const SearchResults = defineComponent({
class="search-results-title"
onMouseenter={() => (currentResult.value = res)}
style={{ color: res.result?.finish ? '' : 'red' }}
title={res.ctx?.elements.title?.[0].innerText}
>
{StringUtils.of(title?.innerText || '')
.nowrap()
Expand All @@ -115,7 +116,7 @@ export const SearchResults = defineComponent({
})}
</div>
</div>
)
)
: (
<div class="search-results-empty" style={{ textAlign: 'center' }}>
没有搜索结果
Expand Down
26 changes: 26 additions & 0 deletions packages/core/src/components/zhs/CreditWorkSettingPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { defineComponent } from 'vue';
import { createWorkerSetting } from '..';
import { store } from '../../script';
import { WorkSettingPanel } from './WorkSettingPanel';

export const CreditWorkSettingPanel = defineComponent({
setup () {
const settings = store.setting.zhs.work;

return () => (
<WorkSettingPanel v-slots={{
upload: createWorkerSetting(
'作业提交',
{
selected: settings.upload,
options: [
{ value: 'nomove', label: '完成后请自行检查并提交' }
]
},
(e: any) => (settings.upload = e.target.value)
)
}}>
</WorkSettingPanel>
);
}
});
23 changes: 14 additions & 9 deletions packages/core/src/components/zhs/WorkSettingPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,25 @@ import { createWorkerSetting } from '..';
import { store } from '../../script';
import { Tooltip } from '../Tooltip';

// 根据上方 vnode 变量 , 生成 jsx 的渲染函数
export const WorkSettingPanel = defineComponent({
setup () {
setup (props, { slots }) {
const settings = store.setting.zhs.work;

return () => (
<div class="ocs-setting-panel">
<div class="ocs-setting-items">
{createWorkerSetting(
'作业提交',
{
selected: settings.upload
},
(e: any) => (settings.upload = e.target.value)
)}

{slots.upload
? slots.upload()
: (
createWorkerSetting(
'作业提交',
{
selected: settings.upload
},
(e: any) => (settings.upload = e.target.value)
)
)}

<label>答题间隔(秒)</label>
<div>
Expand Down Expand Up @@ -63,6 +67,7 @@ export const WorkSettingPanel = defineComponent({
checked={settings.stopWhenError}
></input>
</div>

</div>
</div>
);
Expand Down
9 changes: 8 additions & 1 deletion packages/core/src/core/utils/common.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { GlobPattern, DefineScript, ScriptPanel, ScriptRoute } from '../define.script';
import { DefineScript, GlobPattern, ScriptPanel, ScriptRoute } from '../define.script';

export async function sleep (period: number): Promise<void> {
return new Promise((resolve) => {
Expand Down Expand Up @@ -83,3 +83,10 @@ export function addFunctionEventListener (obj: any, type: string) {
export function getNumber (...nums: number[]) {
return nums.map((num) => (typeof num === 'number' ? num : undefined)).find((num) => num !== undefined);
}

/**
* 当前是否处于浏览器环境
*/
export function isInBrowser (): boolean {
return typeof window !== 'undefined' && typeof window.document !== 'undefined';
}
4 changes: 2 additions & 2 deletions packages/core/src/core/utils/string.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Rating, findBestMatch } from 'string-similarity';
import { findBestMatch, Rating } from 'string-similarity';

/**
* 删除特殊字符,只保留英文,数字,中文
* 删除特殊字符, 并且全部转小写,只保留英文,数字,中文
* @param str
* @returns
*/
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/core/worker/answer.wrapper.handler.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import get from 'lodash/get';
import { isInBrowser } from '../utils';

/** 题目答案 */
export interface Answer {
Expand Down Expand Up @@ -121,7 +122,7 @@ export async function defaultAnswerWrapperHandler (
} else {
const params = new URLSearchParams();
Reflect.ownKeys(data).forEach((key) => params.set(key.toString(), data[key.toString()]));
response = (await (typeof global === 'undefined' ? fetch : require('node-fetch').default)(
response = (await (isInBrowser() ? fetch : require('node-fetch').default)(
url + '?' + params.toString(),
{
method: wrapper.method
Expand Down
28 changes: 27 additions & 1 deletion packages/core/src/core/worker/question.resolver.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { answerSimilar, clearString, removeRedundant } from '../utils';
import { answerSimilar, clearString, removeRedundant, StringUtils } from '../utils';
import { QuestionResolver, WorkContext } from './interface';
import { isPlainAnswer } from './utils';

/** 默认答案题目处理器 */
export function defaultQuestionResolve<E> (
Expand All @@ -12,6 +13,18 @@ export function defaultQuestionResolve<E> (
* 在多个题库给出的答案中,找出最相似的答案
*/
single (results, options, handler) {
// 是否为纯ABCD答案
for (const result of results) {
for (const answer of result.answers) {
const ans = StringUtils.nowrap(answer.answer).trim();
if (ans.length === 1 && isPlainAnswer(ans)) {
const index = ans.charCodeAt(0) - 65;
options[index].click();
return { finish: true, option: options[index] };
}
}
}

/** 配对选项的相似度 */
const ratings = answerSimilar(
results.map((res) => res.answers.map((ans) => ans.answer)).flat(),
Expand Down Expand Up @@ -48,6 +61,7 @@ export function defaultQuestionResolve<E> (
/** 最终的选项 */
const targetOptions: HTMLElement[][] = [];

// 各个题库的序号
let count = 0;
for (const answers of results.map((res) => res.answers.map((ans) => ans.answer))) {
targetAnswers[count] = [];
Expand All @@ -61,6 +75,18 @@ export function defaultQuestionResolve<E> (
}
});

// 判断是否为纯ABCD答案
for (const answer of answers) {
const ans = StringUtils.nowrap(answer).trim();
if (isPlainAnswer(ans)) {
for (let i = 0; i < ans.length; i++) {
const index = ans.charCodeAt(i) - 65;
targetAnswers[count][i] = options[index].innerText;
targetOptions[count][i] = options[index];
}
}
}

if (targetAnswers[count].length === 0) {
const ratings = answerSimilar(
answers,
Expand Down
26 changes: 25 additions & 1 deletion packages/core/src/core/worker/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { WorkContext, QuestionTypes } from './interface';
import { QuestionTypes, WorkContext } from './interface';

/** 默认题目类型解析器 */
export function defaultWorkTypeResolver (ctx: WorkContext<any>): QuestionTypes | undefined {
Expand All @@ -21,3 +21,27 @@ export function defaultWorkTypeResolver (ctx: WorkContext<any>): QuestionTypes |
? 'completion'
: undefined;
}

/** 判断答案是否为A-Z的文本, 并且字符序号依次递增, 并且 每个字符是否都只出现了一次 */
export function isPlainAnswer (answer: string) {
if (answer.length > 8 || !/[A-Z]/.test(answer)) {
return false;
}
const counter: any = {};
let min = 0;
for (let i = 0; i < answer.length; i++) {
if (answer.charCodeAt(i) < min) {
return false;
}
min = answer.charCodeAt(i);
counter[min] = (counter[min] || 0) + 1;
}
// 判断每个字符是否都只出现了一次
for (const key in counter) {
if (counter[key] !== 1) {
return false;
}
}

return true;
}
5 changes: 4 additions & 1 deletion packages/core/src/script/cx/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const updateURLs = [
'**/work/getAllWork**',
'**/work/doHomeWorkNew**',
'**/exam/test?**',
'**exam/test/reVersionTestStartNew**'
'**exam/test/reVersionTestStartNew**examsystem**'
];

export const CXScript = defineScript({
Expand All @@ -38,6 +38,9 @@ export const CXScript = defineScript({
} else {
const params = new URLSearchParams(window.location.href);
params.set('mooc2', '1');
// 兼容考试切换
params.set('newMooc', 'true');
params.delete('examsystem');
window.location.replace(decodeURIComponent(params.toString()));
}
}
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/script/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import defaultsDeep from 'lodash/defaultsDeep';
import { reactive, watch } from 'vue';
import { OCSLocalStorage, OCSStore } from '../core/store';
import { onReady } from '../core/utils';
import { isInBrowser, onReady } from '../core/utils';
import { logger } from '../logger';
import { defaultOCSSetting } from '../scripts';

Expand All @@ -11,7 +11,7 @@ import { defaultOCSSetting } from '../scripts';
export let store: OCSStore = {} as OCSStore;

// 环境检测
if (typeof global === 'undefined') {
if (isInBrowser()) {
if (typeof unsafeWindow !== 'undefined') {
store = createStore();
}
Expand All @@ -30,7 +30,7 @@ if (typeof global === 'undefined') {
function createStore () {
/** 默认存储数据 */
// eslint-disable-next-line no-undef
const defaultStore = defaultsDeep(typeof global === 'undefined' ? GM_getValue('store', {}) : {}, {
const defaultStore = defaultsDeep(isInBrowser() ? GM_getValue('store', {}) : {}, {
logs: [],
workResults: [],
/** 是否缩小隐藏面板 */
Expand Down
44 changes: 36 additions & 8 deletions packages/core/src/script/zhs/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { store } from '..';
import { createNote, createSearchResultPanel, createTerminalPanel } from '../../components';
import { StudySettingPanel } from '../../components/zhs/StudySettingPanel';
import { WorkSettingPanel } from '../../components/zhs/WorkSettingPanel';
import { defineScript } from '../../core/define.script';
import { defaultSetting } from '../../scripts';
import { creditStudy, study } from './study';
import { sleep } from '../../core/utils';
import { work } from './work';
import { logger } from '../../logger';
import { store } from '..';
import { StudySettingPanel } from '../../components/zhs/StudySettingPanel';
import { WorkSettingPanel } from '../../components/zhs/WorkSettingPanel';
import { defaultSetting } from '../../scripts';
import { CreditWorkSettingPanel } from './../../components/zhs/CreditWorkSettingPanel';
import { creditStudy, study } from './study';
import { creditWork, work } from './work';

export const ZHSScript = defineScript({
name: '知道智慧树',
Expand Down Expand Up @@ -36,7 +37,7 @@ export const ZHSScript = defineScript({
}
},
{
name: '作业脚本',
name: '共享课作业脚本',
url: '**zhihuishu.com/stuExamWeb.html#/webExamList/dohomework**',
async onload (setting = store.setting.zhs.work) {
await sleep(5000);
Expand All @@ -48,6 +49,20 @@ export const ZHSScript = defineScript({
await work(setting);
}
}
},
{
name: '学分课作业脚本',
url: '**zhihuishu.com/atHomeworkExam/stu/homeworkQ/exerciseList**',
async onload (setting = store.setting.zhs.work) {
await sleep(5000);
if (store.setting.answererWrappers.length === 0) {
logger('error', '未设置题库配置!');
confirm('未设置题库配置!请在设置面板设置后刷新重试!');
} else {
/** 运行作业脚本 */
await creditWork(setting);
}
}
}
],
panels: [
Expand Down Expand Up @@ -100,7 +115,7 @@ export const ZHSScript = defineScript({
el: () => createNote('点击任意作业可以使用作业功能', '注意: 考试功能暂未开放')
},
{
name: '作业助手',
name: '共享课作业助手',
url: '**zhihuishu.com/stuExamWeb.html#/webExamList/dohomework**',
el: () => createNote('进入 作业设置面板 可以调整作业设置', '5秒后自动开始作业...'),
children: [
Expand All @@ -111,6 +126,19 @@ export const ZHSScript = defineScript({
createTerminalPanel(),
createSearchResultPanel()
]
},
{
name: '学分课作业助手',
url: '**zhihuishu.com/atHomeworkExam/stu/homeworkQ/exerciseList**',
el: () => createNote('进入 作业设置面板 可以调整作业设置', '5秒后自动开始作业...'),
children: [
{
name: '作业设置',
el: () => CreditWorkSettingPanel
},
createTerminalPanel(),
createSearchResultPanel()
]
}
]
});
Loading

0 comments on commit 978bf47

Please sign in to comment.