-
Notifications
You must be signed in to change notification settings - Fork 127
/
cache.json
1 lines (1 loc) · 214 KB
/
cache.json
1
{"src\\api\\answer.ts":{"timeStamp":"2023-03-07T02:25:45.829Z","data":"/* 答案 API */\r\n/**\r\n * @description 获取答案\r\n */\r\nasync function getAnswer(question) {\r\n // 数据\r\n const data = {\r\n txt_name: md5(question),\r\n password: '',\r\n };\r\n try {\r\n const params = new URLSearchParams(data);\r\n // 请求\r\n const res = await fetch(API_CONFIG.answerSearch, {\r\n method: 'POST',\r\n mode: 'cors',\r\n headers: {\r\n 'Content-Type': 'application/x-www-form-urlencoded',\r\n },\r\n body: params.toString(),\r\n });\r\n // 请求成功\r\n if (res.ok) {\r\n const result = await res.json();\r\n const { data, status } = result;\r\n if (status !== 0) {\r\n // 答案列表\r\n const answerList = JSON.parse(data.txt_content);\r\n // 答案\r\n const answers = answerList[0].content.split(/[;\\s]/);\r\n return answers;\r\n }\r\n }\r\n }\r\n catch (error) { }\r\n return [];\r\n}\r\n/**\r\n * @description 保存答案\r\n */\r\nasync function saveAnswer(question, answer) {\r\n try {\r\n // 内容\r\n const content = JSON.stringify([{ title: md5(question), content: answer }]);\r\n // 数据\r\n const data = {\r\n txt_name: md5(question),\r\n txt_content: content,\r\n password: '',\r\n v_id: '',\r\n };\r\n const params = new URLSearchParams(data);\r\n // 请求\r\n const res = await fetch(API_CONFIG.answerSave, {\r\n method: 'POST',\r\n mode: 'cors',\r\n headers: {\r\n 'Content-Type': 'application/x-www-form-urlencoded',\r\n },\r\n body: params.toString(),\r\n });\r\n // 请求成功\r\n if (res.ok) {\r\n const data = await res.json();\r\n return data;\r\n }\r\n }\r\n catch (error) { }\r\n}\r\n\r\n","from":"src\\api\\answer.ts","to":"answer.js"},"src\\api\\data.ts":{"timeStamp":"2023-06-02T06:24:50.525Z","data":"/* 数据 API */\r\n/**\r\n * @description 获取新闻数据\r\n */\r\nasync function getNewsList() {\r\n // 随机\r\n const randNum = ~~(Math.random() * API_CONFIG.todayNews.length);\r\n try {\r\n // 获取重要新闻\r\n const res = await fetch(API_CONFIG.todayNews[randNum], {\r\n method: 'GET',\r\n });\r\n // 请求成功\r\n if (res.ok) {\r\n const data = await res.json();\r\n return data;\r\n }\r\n }\r\n catch (err) { }\r\n}\r\n/**\r\n * @description 获取视频数据\r\n */\r\nasync function getVideoList() {\r\n // 随机\r\n const randNum = ~~(Math.random() * API_CONFIG.todayVideos.length);\r\n try {\r\n // 获取重要新闻\r\n const res = await fetch(API_CONFIG.todayVideos[randNum], {\r\n method: 'GET',\r\n });\r\n // 请求成功\r\n if (res.ok) {\r\n const data = await res.json();\r\n return data;\r\n }\r\n }\r\n catch (err) { }\r\n}\r\n/**\r\n * @description 专项练习数据\r\n */\r\nasync function getExamPaper(pageNo) {\r\n // 链接\r\n const url = `${API_CONFIG.paperList}?pageSize=50&pageNo=${pageNo}`;\r\n try {\r\n // 获取专项练习\r\n const res = await fetch(url, {\r\n method: 'GET',\r\n credentials: 'include',\r\n });\r\n // 请求成功\r\n if (res.ok) {\r\n const data = await res.json();\r\n const paperJson = decodeURIComponent(escape(window.atob(data.data_str.replace(/-/g, '+').replace(/_/g, '/'))));\r\n // JSON格式化\r\n const paper = JSON.parse(paperJson);\r\n return paper;\r\n }\r\n }\r\n catch (err) {\r\n return [];\r\n }\r\n return [];\r\n}\r\n\r\n","from":"src\\api\\data.ts","to":"data.js"},"src\\api\\login.ts":{"timeStamp":"2023-02-11T12:24:53.231Z","data":"/**\r\n * @description 生成二维码\r\n */\r\nasync function generateQRCode() {\r\n try {\r\n // 推送\r\n const res = await fetch(API_CONFIG.generateQRCode, {\r\n method: 'GET',\r\n mode: 'cors',\r\n });\r\n // 请求成功\r\n if (res.ok) {\r\n const data = await res.json();\r\n if (data.success) {\r\n return data.result;\r\n }\r\n }\r\n }\r\n catch (error) { }\r\n}\r\n/**\r\n * @description 用二维码登录\r\n */\r\nasync function loginWithQRCode(qrCode) {\r\n try {\r\n const params = new URLSearchParams({\r\n qrCode,\r\n goto: 'https://oa.xuexi.cn',\r\n pdmToken: '',\r\n });\r\n // 推送\r\n const res = await fetch(API_CONFIG.loginWithQRCode, {\r\n method: 'POST',\r\n mode: 'cors',\r\n credentials: 'include',\r\n headers: {\r\n 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',\r\n },\r\n body: params.toString(),\r\n });\r\n // 请求成功\r\n if (res.ok) {\r\n const data = await res.json();\r\n return data;\r\n }\r\n }\r\n catch (error) { }\r\n}\r\n/**\r\n * @description 签名\r\n */\r\nasync function getSign() {\r\n try {\r\n // 推送\r\n const res = await fetch(API_CONFIG.sign, {\r\n method: 'GET',\r\n mode: 'cors',\r\n credentials: 'include',\r\n });\r\n // 请求成功\r\n if (res.ok) {\r\n const data = await res.json();\r\n if (data.ok) {\r\n return data.data.sign;\r\n }\r\n }\r\n }\r\n catch (error) { }\r\n}\r\n/**\r\n * @description 安全检查\r\n * @param data\r\n */\r\nasync function secureCheck(data) {\r\n try {\r\n const params = new URLSearchParams(data);\r\n const url = `${API_CONFIG.secureCheck}?${params}`;\r\n // 推送\r\n const res = await fetch(url, {\r\n method: 'GET',\r\n mode: 'cors',\r\n credentials: 'include',\r\n });\r\n // 请求成功\r\n if (res.ok) {\r\n const data = await res.json();\r\n return data.success;\r\n }\r\n }\r\n catch (error) { }\r\n return false;\r\n}\r\n\r\n","from":"src\\api\\login.ts","to":"login.js"},"src\\api\\push.ts":{"timeStamp":"2023-02-11T12:24:42.072Z","data":"/* 推送 API */\r\n/**\r\n * @description 推送\r\n */\r\nasync function pushPlus(token, title, content, template, toToken) {\r\n try {\r\n // 参数体\r\n const body = {\r\n token,\r\n title,\r\n content,\r\n template,\r\n };\r\n // 好友令牌\r\n if (toToken) {\r\n body.to = toToken;\r\n }\r\n // 推送\r\n const res = await fetch(API_CONFIG.push, {\r\n method: 'POST',\r\n mode: 'cors',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify(body),\r\n });\r\n // 请求成功\r\n if (res.ok) {\r\n const data = await res.json();\r\n return data;\r\n }\r\n }\r\n catch (error) { }\r\n}\r\n\r\n","from":"src\\api\\push.ts","to":"push.js"},"src\\api\\user.ts":{"timeStamp":"2023-02-12T08:26:02.766Z","data":"/* 用户 API */\r\n/**\r\n * @description 获取用户信息\r\n */\r\nasync function getUserInfo() {\r\n try {\r\n const res = await fetch(API_CONFIG.userInfo, {\r\n method: 'GET',\r\n credentials: 'include',\r\n });\r\n // 请求成功\r\n if (res.ok) {\r\n const { data } = await res.json();\r\n return data;\r\n }\r\n }\r\n catch (err) { }\r\n}\r\n/**\r\n * @description 获取总积分\r\n */\r\nasync function getTotalScore() {\r\n try {\r\n const res = await fetch(API_CONFIG.totalScore, {\r\n method: 'GET',\r\n credentials: 'include',\r\n });\r\n // 请求成功\r\n if (res.ok) {\r\n const { data } = await res.json();\r\n // 总分\r\n const { score } = data;\r\n return score;\r\n }\r\n }\r\n catch (err) { }\r\n}\r\n/**\r\n * @description 获取当天总积分\r\n */\r\nasync function getTodayScore() {\r\n try {\r\n const res = await fetch(API_CONFIG.todayScore, {\r\n method: 'GET',\r\n credentials: 'include',\r\n });\r\n // 请求成功\r\n if (res.ok) {\r\n const { data } = await res.json();\r\n // 当天总分\r\n const { score } = data;\r\n return score;\r\n }\r\n }\r\n catch (err) { }\r\n}\r\n/**\r\n * @description 获取任务列表\r\n */\r\nasync function getTaskList() {\r\n try {\r\n const res = await fetch(API_CONFIG.taskList, {\r\n method: 'GET',\r\n credentials: 'include',\r\n });\r\n // 请求成功\r\n if (res.ok) {\r\n const { data } = await res.json();\r\n // 进度和当天总分\r\n const { taskProgress } = data;\r\n return taskProgress;\r\n }\r\n }\r\n catch (err) { }\r\n}\r\n\r\n","from":"src\\api\\user.ts","to":"user.js"},"src\\config\\task.ts":{"timeStamp":"2023-07-12T05:19:25.996Z","data":"/* task·配置 */\r\n/**\r\n * @description 单次最大新闻数\r\n */\r\nconst maxNewsNum = 6;\r\n/**\r\n * @description 单次最大视频数\r\n */\r\nconst maxVideoNum = 6;\r\n/**\r\n * @description 二维码最大刷新次数\r\n */\r\nconst maxRefreshCount = 10;\r\n/**\r\n * @description 二维码自动刷新间隔\r\n */\r\nconst autoRefreshQRCodeInterval = 100000;\r\n\r\n","from":"src\\config\\task.ts","to":"task.js"},"src\\config\\url.ts":{"timeStamp":"2023-01-11T12:31:08.253Z","data":"/**\r\n * @description url配置\r\n */\r\nconst URL_CONFIG = {\r\n // 主页正则\r\n home: /^https\\:\\/\\/www\\.xuexi\\.cn(\\/(index\\.html)?)?$/,\r\n // 主页\r\n homeOrigin: 'https://www.xuexi.cn',\r\n // 每日答题页面\r\n examPractice: 'https://pc.xuexi.cn/points/exam-practice.html',\r\n // 专项练习页面\r\n examPaper: 'https://pc.xuexi.cn/points/exam-paper-detail.html',\r\n};\r\n\r\n","from":"src\\config\\url.ts","to":"url.js"},"src\\config\\api.ts":{"timeStamp":"2023-03-21T07:23:02.891Z","data":"/**\r\n * @description api配置\r\n */\r\nconst API_CONFIG = {\r\n // 用户信息\r\n userInfo: 'https://pc-api.xuexi.cn/open/api/user/info',\r\n // 总分\r\n totalScore: 'https://pc-proxy-api.xuexi.cn/delegate/score/get',\r\n // 当天分数\r\n todayScore: 'https://pc-proxy-api.xuexi.cn/delegate/score/today/query',\r\n // 任务列表\r\n taskList: 'https://pc-proxy-api.xuexi.cn/delegate/score/days/listScoreProgress?sence=score&deviceType=2',\r\n // 新闻数据\r\n todayNews: [\r\n 'https://www.xuexi.cn/lgdata/35il6fpn0ohq.json',\r\n 'https://www.xuexi.cn/lgdata/1ap1igfgdn2.json',\r\n 'https://www.xuexi.cn/lgdata/vdppiu92n1.json',\r\n 'https://www.xuexi.cn/lgdata/152mdtl3qn1.json',\r\n ],\r\n // 视频数据\r\n todayVideos: [\r\n 'https://www.xuexi.cn/lgdata/525pi8vcj24p.json',\r\n 'https://www.xuexi.cn/lgdata/11vku6vt6rgom.json',\r\n 'https://www.xuexi.cn/lgdata/2qfjjjrprmdh.json',\r\n 'https://www.xuexi.cn/lgdata/3o3ufqgl8rsn.json',\r\n 'https://www.xuexi.cn/lgdata/591ht3bc22pi.json',\r\n 'https://www.xuexi.cn/lgdata/1742g60067k.json',\r\n 'https://www.xuexi.cn/lgdata/1novbsbi47k.json',\r\n ],\r\n // 专项练习列表\r\n paperList: 'https://pc-proxy-api.xuexi.cn/api/exam/service/paper/pc/list',\r\n // 文本服务器保存答案\r\n answerSave: 'https://a6.qikekeji.com/txt/data/save',\r\n // 文本服务器获取答案\r\n answerSearch: 'https://a6.qikekeji.com/txt/data/detail',\r\n // 推送\r\n push: 'https://www.pushplus.plus/send',\r\n // 生成二维码\r\n generateQRCode: 'https://login.xuexi.cn/user/qrcode/generate',\r\n //二维码登录\r\n loginWithQRCode: 'https://login.xuexi.cn/login/login_with_qr',\r\n // 签名\r\n sign: 'https://pc-api.xuexi.cn/open/api/sns/sign',\r\n // 安全检查\r\n secureCheck: 'https://pc-api.xuexi.cn/login/secure_check',\r\n // 二维码\r\n qrcode: 'https://api.qrserver.com/v1/create-qr-code',\r\n};\r\n\r\n","from":"src\\config\\api.ts","to":"api.js"},"src\\config\\version.ts":{"timeStamp":"2023-07-13T13:35:55.841Z","data":"/**\r\n * @description 版本号\r\n */\r\nconst version = '1.7.5';\r\n\r\n","from":"src\\config\\version.ts","to":"version.js"},"src\\types\\index.ts":{"timeStamp":"2023-07-12T05:59:43.153Z","data":"/**\r\n * @description 任务类型\r\n */\r\nvar TaskType;\r\n(function (TaskType) {\r\n TaskType[TaskType[\"LOGIN\"] = 0] = \"LOGIN\";\r\n TaskType[TaskType[\"READ\"] = 1] = \"READ\";\r\n TaskType[TaskType[\"WATCH\"] = 2] = \"WATCH\";\r\n TaskType[TaskType[\"PRACTICE\"] = 3] = \"PRACTICE\";\r\n})(TaskType || (TaskType = {}));\r\n/**\r\n * @description 设置类型\r\n */\r\nvar SettingType;\r\n(function (SettingType) {\r\n SettingType[SettingType[\"AUTO_START\"] = 0] = \"AUTO_START\";\r\n SettingType[SettingType[\"SAME_TAB\"] = 1] = \"SAME_TAB\";\r\n SettingType[SettingType[\"SILENT_RUN\"] = 2] = \"SILENT_RUN\";\r\n SettingType[SettingType[\"SCHEDULE_RUN\"] = 3] = \"SCHEDULE_RUN\";\r\n SettingType[SettingType[\"VIDEO_MUTED\"] = 4] = \"VIDEO_MUTED\";\r\n SettingType[SettingType[\"RANDOM_EXAM\"] = 5] = \"RANDOM_EXAM\";\r\n SettingType[SettingType[\"AUTO_ANSWER\"] = 6] = \"AUTO_ANSWER\";\r\n SettingType[SettingType[\"REMOTE_PUSH\"] = 7] = \"REMOTE_PUSH\";\r\n})(SettingType || (SettingType = {}));\r\n/**\r\n * @description 进度类型\r\n */\r\nvar TaskStatusType;\r\n(function (TaskStatusType) {\r\n TaskStatusType[TaskStatusType[\"LOADING\"] = 0] = \"LOADING\";\r\n TaskStatusType[TaskStatusType[\"LOADED\"] = 1] = \"LOADED\";\r\n TaskStatusType[TaskStatusType[\"START\"] = 2] = \"START\";\r\n TaskStatusType[TaskStatusType[\"PAUSE\"] = 3] = \"PAUSE\";\r\n TaskStatusType[TaskStatusType[\"FINISH\"] = 4] = \"FINISH\";\r\n})(TaskStatusType || (TaskStatusType = {}));\r\n\r\n","from":"src\\types\\index.ts","to":"index.js"},"src\\utils\\composition.ts":{"timeStamp":"2023-03-07T10:10:48.749Z","data":"// 当前订阅\r\nlet currentSub;\r\n// 订阅\r\nconst subscription = new WeakMap();\r\n/**\r\n * @description Proxy Map\r\n */\r\nconst proxyMap = new WeakMap();\r\n/**\r\n * @description 收集 Ref 依赖\r\n * @param target\r\n * @param key\r\n */\r\nconst trackRef = (target) => {\r\n // 当前订阅\r\n if (!currentSub) {\r\n return;\r\n }\r\n // target 订阅列表\r\n let subList = subscription.get(target);\r\n // 不存在订阅列表\r\n if (!subList) {\r\n subList = new Map();\r\n // 键订阅\r\n const subkeyList = new Set();\r\n // 添加订阅\r\n subkeyList.add(currentSub);\r\n subList.set('value', subkeyList);\r\n subscription.set(target, subList);\r\n return;\r\n }\r\n // 键订阅\r\n let subkeyList = subList.get('value');\r\n if (!subkeyList) {\r\n // 键订阅\r\n subkeyList = new Set();\r\n // 添加订阅\r\n subkeyList.add(currentSub);\r\n subList.set('value', subkeyList);\r\n subscription.set(target, subList);\r\n return;\r\n }\r\n // 添加订阅\r\n subkeyList.add(currentSub);\r\n};\r\n/**\r\n * @description 通知 Ref 订阅\r\n * @param terget\r\n * @param key\r\n * @returns\r\n */\r\nfunction triggerRef(target, newVal, oldVal) {\r\n // target 订阅列表\r\n const subList = subscription.get(target);\r\n if (!subList) {\r\n return;\r\n }\r\n // 键订阅\r\n let subkeyList = subList.get('value');\r\n if (!subkeyList) {\r\n return;\r\n }\r\n // 通知订阅\r\n for (const fn of subkeyList) {\r\n if (fn instanceof Function) {\r\n fn(newVal, oldVal);\r\n }\r\n }\r\n}\r\n/**\r\n * @description 收集依赖\r\n * @param target\r\n * @param key\r\n */\r\nconst track = (target, key) => {\r\n // 当前订阅\r\n if (!currentSub) {\r\n return;\r\n }\r\n // proxy\r\n const proxyTarget = proxyMap.get(target);\r\n if (!proxyTarget) {\r\n return;\r\n }\r\n // target 订阅列表\r\n let subList = subscription.get(target);\r\n // 不存在订阅列表\r\n if (!subList) {\r\n subList = new Map();\r\n // 键订阅\r\n const subkeyList = new Set();\r\n // 添加订阅\r\n subkeyList.add(currentSub);\r\n subList.set(key, subkeyList);\r\n subscription.set(target, subList);\r\n return;\r\n }\r\n // 键订阅\r\n let subkeyList = subList.get(key);\r\n if (!subkeyList) {\r\n // 键订阅\r\n subkeyList = new Set();\r\n // 添加订阅\r\n subkeyList.add(currentSub);\r\n subList.set(key, subkeyList);\r\n subscription.set(target, subList);\r\n return;\r\n }\r\n // 添加订阅\r\n subkeyList.add(currentSub);\r\n};\r\n/**\r\n * @description 通知订阅\r\n * @param terget\r\n * @param key\r\n * @returns\r\n */\r\nfunction trigger(target, key, newVal, oldVal) {\r\n // proxy\r\n const proxyTarget = proxyMap.get(target);\r\n if (!proxyTarget) {\r\n return;\r\n }\r\n // proxyTarget 订阅列表\r\n const subList = subscription.get(target);\r\n if (!subList) {\r\n return;\r\n }\r\n // 键订阅\r\n let subkeyList = subList.get(key);\r\n if (!subkeyList) {\r\n return;\r\n }\r\n // 通知订阅\r\n for (const fn of subkeyList) {\r\n fn(newVal, oldVal);\r\n }\r\n}\r\n/**\r\n * @description 只读键\r\n */\r\nvar ReactiveFlags;\r\n(function (ReactiveFlags) {\r\n ReactiveFlags[\"IS_REF\"] = \"_isRef\";\r\n ReactiveFlags[\"IS_SHALLOW\"] = \"_isShallow\";\r\n ReactiveFlags[\"IS_REACTIVE\"] = \"_isReactive\";\r\n ReactiveFlags[\"IS_READONLY\"] = \"_isReadonly\";\r\n})(ReactiveFlags || (ReactiveFlags = {}));\r\n/**\r\n * @description Ref\r\n */\r\nclass Ref {\r\n _isShallow = false;\r\n _isRef = true;\r\n _value;\r\n value;\r\n constructor(val, shallow = false) {\r\n const _this = this;\r\n this._isShallow = shallow;\r\n if (val && typeof val === 'object' && shallow) {\r\n const reactiveVal = reactive(val);\r\n this._value = reactiveVal;\r\n this.value = reactiveVal;\r\n }\r\n else {\r\n this._value = val;\r\n this.value = val;\r\n }\r\n // 定义属性\r\n Object.defineProperty(this, 'value', {\r\n get() {\r\n // 收集依赖\r\n trackRef(this);\r\n return _this._value;\r\n },\r\n set(newVal) {\r\n // 旧数据\r\n const oldVal = this._value;\r\n // 数据变化\r\n if (oldVal !== newVal) {\r\n // 设置新数据值\r\n _this._value = newVal;\r\n // 通知依赖\r\n triggerRef(this, newVal, oldVal);\r\n }\r\n },\r\n });\r\n }\r\n toJSON() {\r\n return this._value;\r\n }\r\n}\r\n/**\r\n * @description ref\r\n * @param v\r\n * @returns\r\n */\r\nconst isRef = (v) => {\r\n return !!(v && v[ReactiveFlags.IS_REF]);\r\n};\r\n/**\r\n * @description 浅层 shallow\r\n * @param v\r\n * @returns\r\n */\r\nconst isShallow = (v) => {\r\n return !!(v && v[ReactiveFlags.IS_SHALLOW]);\r\n};\r\n/**\r\n * @description 创建 ref\r\n * @param v\r\n * @returns\r\n */\r\nconst createRef = (rawVal, shallow) => {\r\n return new Ref(rawVal, shallow);\r\n};\r\n/**\r\n * @description 解除 ref\r\n * @param val\r\n * @returns\r\n */\r\nconst unref = (val) => {\r\n return (isRef(val) ? val.value : val);\r\n};\r\n/**\r\n * @description 顶层 ref\r\n * @param v\r\n * @returns\r\n */\r\nconst ref = (value) => {\r\n return isRef(value)\r\n ? value\r\n : createRef(value, true);\r\n};\r\n/**\r\n * @description ref\r\n * @param value\r\n * @returns\r\n */\r\nconst shallowRef = (value) => {\r\n return isRef(value)\r\n ? value\r\n : createRef(value, false);\r\n};\r\n/**\r\n * @description 创建处理 reactive\r\n * @param isReadonly\r\n * @param isShallow\r\n * @returns\r\n */\r\nconst createReactiveHandlers = (isReadonly, isShallow) => {\r\n return {\r\n get: createGetters(isReadonly, isShallow),\r\n set: createSetters(isReadonly, isShallow),\r\n };\r\n};\r\n/**\r\n * @description getters\r\n * @param isReadonly\r\n * @param isShallow\r\n * @returns\r\n */\r\nconst createGetters = (isReadonly, isShallow) => {\r\n return function get(target, key, receiver) {\r\n if (key === ReactiveFlags.IS_REACTIVE) {\r\n return !isReadonly;\r\n }\r\n if (key === ReactiveFlags.IS_READONLY) {\r\n return isReadonly;\r\n }\r\n if (key === ReactiveFlags.IS_SHALLOW) {\r\n return isShallow;\r\n }\r\n // 结果\r\n const res = Reflect.get(target, key, receiver);\r\n if (!isReadonly) {\r\n // 收集依赖\r\n track(target, key);\r\n }\r\n if (isShallow) {\r\n return res;\r\n }\r\n if (isRef(res)) {\r\n return res.value;\r\n }\r\n if (res && typeof res === 'object') {\r\n if (res instanceof Element) {\r\n return res;\r\n }\r\n return isReadonly ? readonly(res) : reactive(res);\r\n }\r\n return res;\r\n };\r\n};\r\n/**\r\n * @description setters\r\n * @param readonly\r\n * @param shallow\r\n * @returns\r\n */\r\nconst createSetters = (readonly, shallow) => {\r\n return function set(target, key, newVal, receiver) {\r\n // 只读\r\n if (readonly) {\r\n return false;\r\n }\r\n // 旧值\r\n const oldVal = target[key];\r\n if (isReadonly(oldVal) && isRef(oldVal) && !isRef(newVal)) {\r\n return false;\r\n }\r\n if (!shallow) {\r\n if (isRef(oldVal) && !isRef(newVal)) {\r\n oldVal.value = newVal;\r\n return true;\r\n }\r\n }\r\n const res = Reflect.set(target, key, newVal, receiver);\r\n // length\r\n if (Array.isArray(target) && key === 'length') {\r\n // 通知依赖\r\n trigger(target, key, newVal, oldVal);\r\n return res;\r\n }\r\n // 数据变化\r\n if (oldVal !== newVal) {\r\n // 通知依赖\r\n trigger(target, key, newVal, oldVal);\r\n }\r\n return res;\r\n };\r\n};\r\n/**\r\n * @description reactive object\r\n */\r\nconst createReactiveObj = (target, isReadonly, shallow) => {\r\n // 存在 Proxy\r\n const existingProxy = proxyMap.get(target);\r\n if (existingProxy) {\r\n return existingProxy;\r\n }\r\n // 新建\r\n const proxy = new Proxy(target, createReactiveHandlers(isReadonly, shallow));\r\n proxyMap.set(target, proxy);\r\n return proxy;\r\n};\r\n/**\r\n * @description reactive\r\n * @param val\r\n * @returns\r\n */\r\nconst isReactive = (val) => {\r\n return !!(val && val[ReactiveFlags.IS_REACTIVE]);\r\n};\r\n/**\r\n * @description 创建 reactive\r\n * @param target\r\n * @returns\r\n */\r\nconst createReactive = (target) => {\r\n return createReactiveObj(target, false, false);\r\n};\r\n/**\r\n * @description 顶层 reactive\r\n * @param target\r\n * @returns\r\n */\r\nconst shallowReactive = (target) => {\r\n return createReactiveObj(target, false, true);\r\n};\r\n/**\r\n * @description reactive\r\n * @param val\r\n * @returns\r\n */\r\nconst isReadonly = (val) => {\r\n return !!(val && val[ReactiveFlags.IS_READONLY]);\r\n};\r\n/**\r\n * @description 创建 readonly\r\n * @param target\r\n * @returns\r\n */\r\nconst createReadonly = (target) => {\r\n return createReactiveObj(target, true, false);\r\n};\r\n/**\r\n * @description 顶层 readonly\r\n * @param target\r\n * @returns\r\n */\r\nconst shallowReadonly = (target) => {\r\n return createReactiveObj(target, true, true);\r\n};\r\n/**\r\n * @description proxy\r\n * @param val\r\n * @returns\r\n */\r\nconst isProxy = (val) => {\r\n return isReactive(val) || isReadonly(val);\r\n};\r\n/**\r\n * @description reactive\r\n * @param target\r\n * @returns\r\n */\r\nconst reactive = (target) => {\r\n return createReactive(target);\r\n};\r\n/**\r\n * @description readonly\r\n * @param target\r\n * @returns\r\n */\r\nconst readonly = (target) => {\r\n return createReadonly(target);\r\n};\r\n/**\r\n * @description 监听数据变化\r\n * @param source\r\n * @param callback\r\n */\r\nconst watch = (source, callback, immediate = false) => {\r\n // 立刻执行\r\n immediate && callback(unref(source), unref(source));\r\n // array\r\n if (Array.isArray(source) && source.every((s) => isRef(s))) {\r\n for (const i in source) {\r\n // Proxy\r\n if (isProxy(source[i])) {\r\n watch(source[i], () => {\r\n const res = source.map((s) => unref(s));\r\n callback(res, res);\r\n });\r\n }\r\n }\r\n watch(() => source.map((s) => unref(s)), callback);\r\n return;\r\n }\r\n // function\r\n if (source instanceof Function) {\r\n watch(watchEffectRef(source), (n, o) => {\r\n callback(unref(n), unref(o));\r\n });\r\n return;\r\n }\r\n // Proxy\r\n if (isProxy(source)) {\r\n for (const key in source) {\r\n currentSub = () => {\r\n callback(source, source);\r\n };\r\n // sub source\r\n const subSource = source[key];\r\n currentSub = undefined;\r\n watch(subSource, () => {\r\n callback(source, source);\r\n });\r\n }\r\n return;\r\n }\r\n // Ref\r\n if (isRef(source)) {\r\n // Ref.value Proxy\r\n if (isProxy(source.value)) {\r\n watch(source.value, () => {\r\n callback(unref(source), unref(source));\r\n });\r\n }\r\n currentSub = callback;\r\n // 收集依赖\r\n trackRef(source);\r\n currentSub = undefined;\r\n return;\r\n }\r\n};\r\n/**\r\n * @description 监听数据变化影响\r\n * @param callback\r\n * @returns\r\n */\r\nconst watchEffect = (callback) => {\r\n currentSub = callback;\r\n // 收集依赖\r\n callback();\r\n currentSub = undefined;\r\n};\r\n/**\r\n * @description 监听影响 ref\r\n * @param refVal\r\n * @param callback\r\n * @returns\r\n */\r\nconst watchRef = (source, callback) => {\r\n // 收集依赖\r\n const effectRes = shallowRef(callback());\r\n // 监听\r\n watch(source, () => (effectRes.value = unref(callback())));\r\n return effectRes;\r\n};\r\n/**\r\n * @description 监听影响 ref\r\n * @param refVal\r\n * @param callback\r\n * @returns\r\n */\r\nconst watchEffectRef = (callback) => {\r\n // 收集依赖\r\n const effectRes = shallowRef(undefined);\r\n // 监听\r\n watchEffect(() => (effectRes.value = unref(callback())));\r\n return effectRes;\r\n};\r\n\r\n","from":"src\\utils\\composition.ts","to":"composition.js"},"src\\utils\\element.ts":{"timeStamp":"2023-03-07T11:28:14.066Z","data":"/**\r\n * @description 创建元素节点\r\n * @param eleName\r\n * @param props\r\n * @param attrs\r\n * @param children\r\n * @returns\r\n */\r\nfunction createElementNode(tagName, props, attrs, children, options) {\r\n // 挂载状态\r\n let beforemount = ref(false);\r\n // 挂载状态\r\n let mounted = ref(false);\r\n const { onCreated, beforeCreat, onMounted, beforeMount } = options || {};\r\n // 订阅\r\n const subscribe = (e) => {\r\n const { onMounted, beforeMount } = e;\r\n if (beforeMount) {\r\n watch(beforemount, () => {\r\n if (beforemount.value) {\r\n beforeMount();\r\n return;\r\n }\r\n }, true);\r\n }\r\n if (onMounted) {\r\n watch(mounted, () => {\r\n if (mounted.value) {\r\n onMounted();\r\n return;\r\n }\r\n }, true);\r\n }\r\n };\r\n // 取消订阅\r\n const unsubscribe = (e) => {\r\n //懒得写\r\n };\r\n // 创建元素前\r\n beforeCreat && beforeCreat();\r\n // 创建普通元素\r\n const ele = document.createElement(tagName);\r\n // 处理属性\r\n handleProps(ele, props);\r\n // 处理属性\r\n handleAttributes(ele, attrs, subscribe, unsubscribe);\r\n // 处理子元素\r\n handleChildren(ele, children, subscribe, unsubscribe);\r\n // 收集挂载前\r\n const collectBeforeMount = () => {\r\n beforemount.value = true;\r\n beforeMount && beforeMount();\r\n };\r\n // 收集挂载\r\n const collectOnMounted = () => {\r\n mounted.value = true;\r\n onMounted && onMounted();\r\n };\r\n // 创建元素后\r\n onCreated && onCreated();\r\n return { ele, beforeMount: collectBeforeMount, onMounted: collectOnMounted };\r\n}\r\n/**\r\n * @description 创建svg元素\r\n * @param tagName\r\n * @param props\r\n * @param attrs\r\n * @param children\r\n * @returns\r\n */\r\nfunction createNSElementNode(tagName, props, attrs, children, options) {\r\n // 挂载状态\r\n let beforemount = ref(false);\r\n // 挂载状态\r\n let mounted = ref(false);\r\n const { onCreated, beforeCreat, onMounted, beforeMount } = options || {};\r\n // 订阅\r\n const subscribe = (e) => {\r\n const { onMounted, beforeMount } = e;\r\n if (beforeMount) {\r\n watch(beforemount, () => {\r\n if (beforemount.value) {\r\n beforeMount();\r\n return;\r\n }\r\n }, true);\r\n }\r\n if (onMounted) {\r\n watch(mounted, () => {\r\n if (mounted.value) {\r\n onMounted();\r\n return;\r\n }\r\n }, true);\r\n }\r\n };\r\n // 取消订阅\r\n const unsubscribe = (e) => {\r\n //懒得写\r\n };\r\n // 创建元素前\r\n beforeCreat && beforeCreat();\r\n // svg元素命名空间\r\n const ns = 'http://www.w3.org/2000/svg';\r\n // 创建svg元素\r\n const ele = document.createElementNS(ns, tagName);\r\n // 处理属性\r\n handleProps(ele, props);\r\n // 处理属性\r\n handleAttributes(ele, attrs, subscribe, unsubscribe);\r\n // 处理子元素\r\n handleChildren(ele, children, subscribe, unsubscribe);\r\n // 收集挂载前\r\n const collectBeforeMount = () => {\r\n beforemount.value = true;\r\n beforeMount && beforeMount();\r\n };\r\n // 收集挂载\r\n const collectOnMounted = () => {\r\n mounted.value = true;\r\n onMounted && onMounted();\r\n };\r\n // 创建元素后\r\n onCreated && onCreated();\r\n return { ele, beforeMount: collectBeforeMount, onMounted: collectOnMounted };\r\n}\r\n/**\r\n * @description 处理属性\r\n * @param ele\r\n * @param props\r\n */\r\nfunction handleProps(ele, props) {\r\n // props属性设置\r\n for (const key in props) {\r\n // Ref 属性\r\n if (isRef(props[key])) {\r\n const refVal = props[key];\r\n watchEffect(() => (ele[key] = refVal.value));\r\n continue;\r\n }\r\n ele[key] = props[key];\r\n }\r\n}\r\n/**\r\n * @description 处理svg属性\r\n * @param ele\r\n * @param attrs\r\n */\r\nfunction handleAttributes(ele, attrs, subscribe, unsubscribe) {\r\n // 属性存在\r\n if (attrs) {\r\n // attrs属性设置\r\n for (const key in attrs) {\r\n // 处理普通属性\r\n handleAttribute(ele, key, attrs[key], subscribe, unsubscribe);\r\n }\r\n }\r\n}\r\n/**\r\n * @description 处理事件选项\r\n */\r\nfunction handleEventOptions(option) {\r\n if (option.length) {\r\n const options = {\r\n capture: option.includes('capture'),\r\n once: option.includes('once'),\r\n passive: option.includes('passive'),\r\n };\r\n return options;\r\n }\r\n}\r\n/**\r\n * @description 处理属性\r\n * @param ele\r\n * @param key\r\n * @param value\r\n */\r\nfunction handleAttribute(ele, key, value, subscribe, unsubscribe) {\r\n // 处理完的key\r\n const formatKey = key.toLowerCase();\r\n // 事件绑定\r\n if (formatKey.startsWith('on')) {\r\n // 事件监听\r\n const [event] = formatKey.match(/(?<=on).*/);\r\n // 事件类型\r\n if (event) {\r\n const [eventType, ...option] = event.split('_');\r\n const options = handleEventOptions(option);\r\n // Ref 函数\r\n if (isRef(value)) {\r\n const refVal = value;\r\n const refListener = watchRef(refVal, () => refVal.value\r\n ? (e) => {\r\n option.includes('prevent') && e.preventDefault();\r\n option.includes('stop') && e.stopPropagation();\r\n const callback = refVal.value;\r\n callback(e);\r\n }\r\n : undefined);\r\n // 设置事件监听\r\n refListener.value &&\r\n ele.addEventListener(eventType, refListener.value, options);\r\n // 监听事件变化\r\n watch(refListener, (newVal, oldVal) => {\r\n // 移除旧事件监听\r\n oldVal && ele.removeEventListener(eventType, oldVal);\r\n // 设置新事件监听\r\n newVal && ele.addEventListener(eventType, newVal, options);\r\n });\r\n return;\r\n }\r\n // 普通函数\r\n if (value instanceof Function) {\r\n // 设置事件监听\r\n ele.addEventListener(eventType, value, options);\r\n }\r\n }\r\n return;\r\n }\r\n // 特殊属性\r\n const specificAttrs = ['checked', 'selected', 'disabled', 'enabled'];\r\n // 特殊 key\r\n if (specificAttrs.includes(formatKey)) {\r\n // Ref\r\n if (isRef(value)) {\r\n const refVal = value;\r\n watchEffect(() => {\r\n if (refVal.value) {\r\n ele.setAttribute(formatKey, '');\r\n }\r\n else {\r\n ele.removeAttribute(formatKey);\r\n }\r\n });\r\n return;\r\n }\r\n // 普通属性值\r\n if (value) {\r\n ele.setAttribute(formatKey, '');\r\n }\r\n else {\r\n ele.removeAttribute(formatKey);\r\n }\r\n return;\r\n }\r\n // ref 属性名\r\n if (key === 'ref') {\r\n // Ref\r\n if (isRef(value)) {\r\n const refVal = value;\r\n subscribe &&\r\n subscribe({\r\n onMounted() {\r\n refVal.value = ele;\r\n },\r\n });\r\n return;\r\n }\r\n // Ref 函数\r\n if (value instanceof Function) {\r\n const refFn = value;\r\n subscribe &&\r\n subscribe({\r\n onMounted() {\r\n refFn(ele);\r\n },\r\n });\r\n return;\r\n }\r\n return;\r\n }\r\n // xlink命名空间\r\n if (key.startsWith('xlink:')) {\r\n // xlink属性命名空间\r\n const attrNS = 'http://www.w3.org/1999/xlink';\r\n if (value) {\r\n ele.setAttributeNS(attrNS, key, value);\r\n }\r\n else {\r\n ele.removeAttributeNS(attrNS, key);\r\n }\r\n return;\r\n }\r\n // Ref 属性值\r\n if (key && isRef(value)) {\r\n const refVal = value;\r\n // 监听影响\r\n watchEffect(() => {\r\n ele.setAttribute(key, refVal.value);\r\n });\r\n return;\r\n }\r\n // 普通属性\r\n if (key) {\r\n // 普通属性\r\n ele.setAttribute(key, value);\r\n }\r\n}\r\n/**\r\n * @description 处理子元素\r\n * @param ele\r\n * @param children\r\n */\r\nfunction handleChildren(ele, children, subscribe, unsubscribe) {\r\n // Ref\r\n if (isRef(children)) {\r\n // 注释元素\r\n const comment = document.createComment('');\r\n // 监听元素变化\r\n watch(children, async (newEle, oldEle) => {\r\n if (!newEle && oldEle) {\r\n // Promise\r\n if (oldEle instanceof Promise) {\r\n const oldEleRes = await oldEle;\r\n if (oldEleRes) {\r\n oldEleRes.forEach((ele) => {\r\n unsubscribe && unsubscribe(ele);\r\n });\r\n }\r\n }\r\n // unPromise\r\n if (!(oldEle instanceof Promise)) {\r\n oldEle.forEach((ele) => {\r\n unsubscribe && unsubscribe(ele);\r\n });\r\n }\r\n ele.replaceChildren(comment);\r\n return;\r\n }\r\n if (newEle) {\r\n if (oldEle) {\r\n // Promise\r\n if (oldEle instanceof Promise) {\r\n const oldEleRes = await oldEle;\r\n if (oldEleRes) {\r\n oldEleRes.forEach((ele) => {\r\n unsubscribe && unsubscribe(ele);\r\n });\r\n }\r\n }\r\n // unPromise\r\n if (!(oldEle instanceof Promise)) {\r\n oldEle.forEach((ele) => {\r\n unsubscribe && unsubscribe(ele);\r\n });\r\n }\r\n }\r\n // Promise\r\n if (newEle instanceof Promise) {\r\n const newEleRes = await newEle;\r\n if (newEleRes) {\r\n const eles = newEleRes.map((v) => {\r\n if (v.beforeMount || v.onMounted) {\r\n subscribe && subscribe(v);\r\n }\r\n return v.ele;\r\n });\r\n ele.replaceChildren(createElementBlock(eles));\r\n }\r\n return;\r\n }\r\n // unPromise\r\n const eles = newEle.map((v) => {\r\n if (v.beforeMount || v.onMounted) {\r\n subscribe && subscribe(v);\r\n }\r\n return v.ele;\r\n });\r\n ele.replaceChildren(createElementBlock(eles));\r\n return;\r\n }\r\n });\r\n // Promise\r\n if (children.value instanceof Promise) {\r\n // 插入注释元素\r\n ele.appendChild(comment);\r\n children.value.then((childrenEle) => {\r\n if (childrenEle) {\r\n const eles = childrenEle.map((v) => {\r\n if (v.beforeMount || v.onMounted) {\r\n subscribe && subscribe(v);\r\n }\r\n return v.ele;\r\n });\r\n ele.replaceChildren(createElementBlock(eles));\r\n }\r\n });\r\n return;\r\n }\r\n // unPromise\r\n if (children.value) {\r\n const eles = children.value.map((v) => {\r\n if (v.beforeMount || v.onMounted) {\r\n subscribe && subscribe(v);\r\n }\r\n return v.ele;\r\n });\r\n ele.appendChild(createElementBlock(eles));\r\n return;\r\n }\r\n // 插入元素\r\n ele.appendChild(comment);\r\n return;\r\n }\r\n // Promise\r\n if (children instanceof Promise) {\r\n // 注释元素\r\n const comment = document.createComment('');\r\n // 插入注释元素\r\n ele.appendChild(comment);\r\n // 异步替换元素\r\n children.then((childEle) => {\r\n if (childEle) {\r\n const { beforeMount, onMounted } = childEle;\r\n if (beforeMount || onMounted) {\r\n subscribe && subscribe(childEle);\r\n }\r\n comment.replaceWith(childEle.ele);\r\n }\r\n });\r\n return;\r\n }\r\n // Array\r\n if (Array.isArray(children)) {\r\n // 处理过后\r\n const resChildren = [];\r\n for (const i in children) {\r\n const child = children[i];\r\n // Ref\r\n if (isRef(child)) {\r\n // 注释\r\n const comment = document.createComment('');\r\n // 监听影响\r\n watch(child, async (newEle, oldEle) => {\r\n // 新元素为空\r\n if (!newEle && oldEle) {\r\n // Promise\r\n if (oldEle instanceof Promise) {\r\n const oldEleRes = await oldEle;\r\n if (oldEleRes) {\r\n handleChangeElement(newEle, oldEleRes, comment, subscribe, unsubscribe);\r\n }\r\n return;\r\n }\r\n handleChangeElement(newEle, oldEle, comment, subscribe, unsubscribe);\r\n return;\r\n }\r\n // 旧元素为空\r\n if (newEle && !oldEle) {\r\n // Promise\r\n if (newEle instanceof Promise) {\r\n const newEleRes = await newEle;\r\n if (newEleRes) {\r\n handleChangeElement(newEleRes, oldEle, comment, subscribe, unsubscribe);\r\n }\r\n return;\r\n }\r\n handleChangeElement(newEle, oldEle, comment, subscribe, unsubscribe);\r\n return;\r\n }\r\n // 存在\r\n if (newEle && oldEle) {\r\n // Promise\r\n if (newEle instanceof Promise && oldEle instanceof Promise) {\r\n const newEleRes = await newEle;\r\n const oldEleRes = await oldEle;\r\n // 处理元素变化\r\n handleChangeElement(newEleRes, oldEleRes, comment, subscribe, unsubscribe);\r\n return;\r\n }\r\n // Promise\r\n if (newEle instanceof Promise && !(oldEle instanceof Promise)) {\r\n const newEleRes = await newEle;\r\n // 处理元素变化\r\n handleChangeElement(newEleRes, oldEle, comment, subscribe, unsubscribe);\r\n return;\r\n }\r\n // Promise\r\n if (!(newEle instanceof Promise) && oldEle instanceof Promise) {\r\n const oldEleRes = await oldEle;\r\n // 处理元素变化\r\n handleChangeElement(newEle, oldEleRes, comment, subscribe, unsubscribe);\r\n return;\r\n }\r\n // 非 Promise\r\n if (!(oldEle instanceof Promise) && !(newEle instanceof Promise)) {\r\n // 处理元素变化\r\n handleChangeElement(newEle, oldEle, comment, subscribe, unsubscribe);\r\n return;\r\n }\r\n }\r\n });\r\n // Promise\r\n if (child.value instanceof Promise) {\r\n // 注释\r\n resChildren[i] = { ele: comment };\r\n // 异步替换\r\n child.value.then((childEle) => {\r\n if (childEle) {\r\n const { beforeMount, onMounted } = childEle;\r\n if (beforeMount || onMounted) {\r\n subscribe && subscribe(childEle);\r\n }\r\n comment.replaceWith(childEle.ele);\r\n }\r\n });\r\n continue;\r\n }\r\n // unPromise\r\n if (child.value) {\r\n const { beforeMount, onMounted, ele } = child.value;\r\n resChildren[i] = { ele, beforeMount, onMounted };\r\n continue;\r\n }\r\n resChildren[i] = { ele: comment };\r\n continue;\r\n }\r\n // Promise\r\n if (child instanceof Promise) {\r\n // 注释\r\n const comment = document.createComment('');\r\n resChildren[i] = { ele: comment };\r\n // 异步替换元素\r\n child.then((childEle) => {\r\n if (childEle) {\r\n const { beforeMount, onMounted } = childEle;\r\n if (beforeMount || onMounted) {\r\n subscribe && subscribe(childEle);\r\n }\r\n comment.replaceWith(childEle.ele);\r\n }\r\n });\r\n continue;\r\n }\r\n // 普通元素\r\n if (child) {\r\n const { beforeMount, onMounted, ele } = child;\r\n resChildren[i] = { ele, beforeMount, onMounted };\r\n }\r\n }\r\n const eles = resChildren.map((v) => {\r\n if (v.beforeMount || v.onMounted) {\r\n subscribe && subscribe(v);\r\n }\r\n return v.ele;\r\n });\r\n // 插入元素\r\n ele.appendChild(createElementBlock(eles));\r\n return;\r\n }\r\n // 普通元素\r\n if (children) {\r\n const { beforeMount, onMounted } = children;\r\n if (beforeMount || onMounted) {\r\n subscribe && subscribe(children);\r\n }\r\n // 插入元素\r\n ele.appendChild(children.ele);\r\n return;\r\n }\r\n return;\r\n}\r\n/**\r\n * @description 元素变化\r\n * @param newEle\r\n * @param oldEle\r\n * @param comment\r\n */\r\nfunction handleChangeElement(newEle, oldEle, comment, subscribe, unsubscribe) {\r\n if (newEle && oldEle) {\r\n const { beforeMount, onMounted } = newEle;\r\n if (beforeMount || onMounted) {\r\n subscribe && subscribe(newEle);\r\n }\r\n oldEle.ele.replaceWith(newEle.ele);\r\n return;\r\n }\r\n if (newEle && !oldEle) {\r\n const { beforeMount, onMounted } = newEle;\r\n if (beforeMount || onMounted) {\r\n subscribe && subscribe(newEle);\r\n }\r\n comment.replaceWith(newEle.ele);\r\n return;\r\n }\r\n if (!newEle && oldEle) {\r\n unsubscribe && unsubscribe(oldEle);\r\n oldEle.ele.replaceWith(comment);\r\n return;\r\n }\r\n}\r\n/**\r\n * @description 创建文字节点\r\n * @param text\r\n * @returns\r\n */\r\nfunction createTextNode(text, options) {\r\n const { onCreated, beforeCreat, onMounted, beforeMount } = options || {};\r\n // 创建元素前\r\n beforeCreat && beforeCreat();\r\n // Ref\r\n if (isRef(text)) {\r\n // ref\r\n const refVal = text;\r\n // 元素\r\n const ele = document.createTextNode('');\r\n // 订阅变化\r\n watchEffect(() => {\r\n ele.data = refVal.value;\r\n });\r\n // 创建元素后\r\n onCreated && onCreated();\r\n return { ele, beforeMount, onMounted };\r\n }\r\n // 创建元素后\r\n onCreated && onCreated();\r\n return { ele: document.createTextNode(String(text)), beforeMount, onMounted };\r\n}\r\n/**\r\n * @description 挂载元素\r\n * @param eleOptions\r\n * @param parent\r\n */\r\nfunction mountElement(eleOptions, parent = document.body) {\r\n const { ele, beforeMount, onMounted } = eleOptions;\r\n if (ele) {\r\n // 触发挂载前事件\r\n beforeMount && beforeMount();\r\n parent.appendChild(ele);\r\n // 挂在后\r\n onMounted && onMounted();\r\n }\r\n}\r\n/**\r\n * @description 选择器\r\n * @param selector\r\n * @returns\r\n */\r\nfunction $$(selector, parent = document) {\r\n return Array.from(parent.querySelectorAll(selector));\r\n}\r\n/**\r\n * @description 异步选择器\r\n * @param selector\r\n * @returns\r\n */\r\nfunction $_(selector, parent = document, timeout) {\r\n return new Promise((resolve) => {\r\n const timer = setInterval(() => {\r\n const selectors = Array.from(parent.querySelectorAll(selector));\r\n // 存在元素\r\n if (selectors.length) {\r\n clearInterval(timer);\r\n resolve(selectors);\r\n }\r\n }, 10);\r\n // 超时\r\n if (timeout) {\r\n setTimeout(() => {\r\n clearInterval(timer);\r\n resolve([]);\r\n }, timeout);\r\n }\r\n });\r\n}\r\n/**\r\n * @description 创建元素块\r\n * @param eles\r\n * @returns\r\n */\r\nfunction createElementBlock(eles) {\r\n const fragment = document.createDocumentFragment();\r\n for (const i in eles) {\r\n fragment.appendChild(eles[i]);\r\n }\r\n return fragment;\r\n}\r\n\r\n","from":"src\\utils\\element.ts","to":"element.js"},"src\\utils\\log.ts":{"timeStamp":"2023-03-04T04:21:42.715Z","data":"/**\r\n * @description 打印日志\r\n * @param text\r\n */\r\nfunction log(...text) {\r\n printColor('dodgerblue', ...text);\r\n}\r\n/**\r\n * @description 打印错误\r\n * @param text\r\n */\r\nfunction error(...text) {\r\n printColor('red', ...text);\r\n}\r\n/**\r\n * @description 打印信息\r\n * @param text\r\n */\r\nfunction info(...text) {\r\n printColor('yellow', ...text);\r\n}\r\n/**\r\n * @description 打印颜色\r\n * @param text\r\n * @param color\r\n */\r\nfunction printColor(color, ...text) {\r\n const textFormatted = text\r\n .map((t) => (typeof t === 'object' ? JSON.stringify(t) : String(t)))\r\n .join(' ');\r\n console.log(`%c[${formatDateTime()}] %c${textFormatted}`, '', `color: ${color}`);\r\n}\r\n\r\n","from":"src\\utils\\log.ts","to":"log.js"},"src\\utils\\push.ts":{"timeStamp":"2023-07-04T09:34:28.693Z","data":"/**\r\n * @description html进度条\r\n * @param title\r\n * @param percent\r\n * @returns\r\n */\r\nfunction getProgressHTML(title, current, total) {\r\n // html\r\n const progressHTML = `<div\r\n style=\"\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 1px 0;\r\n \"\r\n >\r\n <span>${title}</span>\r\n <span>${getHighlightHTML(`${current}`)} / ${total}</span>\r\n </div>\r\n <div\r\n style=\"\r\n background: white;\r\n border-radius: 10px;\r\n height: 10px;\r\n border: 1px solid #eee;\r\n flex-shrink: 1;\r\n \"\r\n >\r\n <div\r\n style=\"\r\n background: linear-gradient(to left, #188fff80, #1890ff);\r\n height: 100%;\r\n width: ${((100 * current) / total).toFixed(1)}%;\r\n border-radius: 10px;\r\n \"\r\n ></div>\r\n </div>`;\r\n return progressHTML;\r\n}\r\n/**\r\n * @description html高亮文本\r\n * @param text\r\n * @returns\r\n */\r\nfunction getHighlightHTML(text) {\r\n // html\r\n const highlightHTML = `<span style=\"color: #1890ff\">${text}</span>`;\r\n return highlightHTML;\r\n}\r\n/**\r\n * @description 二维码\r\n * @param src\r\n */\r\nfunction getImgHTML(src) {\r\n // 图片\r\n return `\r\n <div style=\"padding: 10px 0\">\r\n <div\r\n style=\"\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n padding: 20px;\r\n background: #f7f7f7;\r\n border-radius: 10px;\r\n \"\r\n >\r\n <img src=\"${src}\" style=\"width:200px;height:200px;\" />\r\n </div>\r\n </div>\r\n`;\r\n}\r\n/**\r\n * @description 创建模态框\r\n * @param options 选项\r\n * @returns\r\n */\r\nfunction createModal(options) {\r\n // 配置\r\n const { title, subTitle = '', to = '用户', content, type, from = 'tech-study.js', } = options;\r\n // 内容文本\r\n let contentText = '';\r\n if (Array.isArray(content)) {\r\n contentText = content.map((ct) => `<div>${ct}</div>`).join('');\r\n }\r\n else {\r\n contentText = content;\r\n }\r\n // 日期\r\n const dateTime = formatDateTime();\r\n // 类型html\r\n let typeHTML = '';\r\n if (type && type.length) {\r\n if (type === 'info') {\r\n typeHTML = `\r\n <svg\r\n viewBox=\"64 64 896 896\"\r\n style=\"color: #1890ff; width: 18px; height: 18px\"\r\n fill=\"currentColor\"\r\n aria-hidden=\"true\"\r\n >\r\n <path\r\n d=\"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm-32 232c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V296zm32 440a48.01 48.01 0 010-96 48.01 48.01 0 010 96z\"\r\n ></path>\r\n </svg>`;\r\n }\r\n if (type === 'warn') {\r\n typeHTML = `\r\n <svg\r\n viewBox=\"64 64 896 896\"\r\n style=\"color: #faad14; width: 18px; height: 18px\"\r\n fill=\"currentColor\"\r\n aria-hidden=\"true\"\r\n >\r\n <path\r\n d=\"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm-32 232c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V296zm32 440a48.01 48.01 0 010-96 48.01 48.01 0 010 96z\"\r\n ></path>\r\n </svg>\r\n `;\r\n }\r\n if (type === 'success') {\r\n typeHTML = `\r\n <svg\r\n viewBox=\"64 64 896 896\"\r\n style=\"color: #52c41a; width: 18px; height: 18px\"\r\n fill=\"currentColor\"\r\n aria-hidden=\"true\"\r\n >\r\n <path\r\n d=\"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm193.5 301.7l-210.6 292a31.8 31.8 0 01-51.7 0L318.5 484.9c-3.8-5.3 0-12.7 6.5-12.7h46.9c10.2 0 19.9 4.9 25.9 13.3l71.2 98.8 157.2-218c6-8.3 15.6-13.3 25.9-13.3H699c6.5 0 10.3 7.4 6.5 12.7z\"\r\n ></path>\r\n </svg>\r\n `;\r\n }\r\n if (type === 'fail') {\r\n typeHTML = `\r\n <svg\r\n viewBox=\"64 64 896 896\"\r\n style=\"color: #ff4d4f; width: 18px; height: 18px\"\r\n fill=\"currentColor\"\r\n aria-hidden=\"true\"\r\n >\r\n <path\r\n d=\"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z\"\r\n ></path>\r\n </svg>\r\n `;\r\n }\r\n }\r\n // 类型\r\n const typeWrap = `\r\n <span\r\n style=\"\r\n padding-right: 5px;\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n \"\r\n >\r\n ${typeHTML}\r\n </span>\r\n `;\r\n // 基础html\r\n const baseHTML = `\r\n <div\r\n style=\"\r\n padding: 5px;\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n \"\r\n>\r\n <div\r\n style=\"\r\n background: #ffffff;\r\n box-shadow: 1px 1px 8px -1px #dadada;\r\n padding: 5px 10px;\r\n border-radius: 5px;\r\n width: 100%;\r\n \"\r\n >\r\n <div\r\n style=\"\r\n display: flex;\r\n justify-content: space-between;\r\n padding: 5px;\r\n border-bottom: 1px solid #eee;\r\n \"\r\n >\r\n <div style=\"display: flex; justify-content: center; align-items: center\">\r\n ${typeWrap}\r\n <span style=\"padding-left: 5px; font-size: 18px\">${title}</span>\r\n </div>\r\n <div style=\"font-size: 16px; color: #999\">${subTitle}</div>\r\n </div>\r\n <div></div>\r\n\r\n <div style=\"padding:10px 5px; font-size: 16px; min-height: 80px\">\r\n <div>\r\n ${getHighlightHTML(to)}, 你好!\r\n </div>\r\n <div style=\"line-height: 28px;\">${contentText}</div>\r\n </div>\r\n <div\r\n style=\"\r\n font-size: 14px;\r\n padding: 5px;\r\n border-top: 1px solid #eee;\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n \"\r\n >\r\n <div style=\"color: #999\">${dateTime}</div>\r\n <div>\r\n <span>来自</span>\r\n <span style=\"color: #1890ff; padding-left: 1px\">${from}</span>\r\n </div>\r\n </div>\r\n </div>\r\n</div> \r\n `;\r\n return baseHTML;\r\n}\r\n/**\r\n * @description 推送消息\r\n */\r\nasync function pushMessage(options) {\r\n // 选项\r\n const { title, content, template, fromToken, toToken } = options;\r\n // 推送\r\n const res = await pushPlus(fromToken, title, content, template, toToken);\r\n return res;\r\n}\r\n/**\r\n * @description 推送模态框\r\n */\r\nasync function pushModal(options, fromToken, toToken) {\r\n // html\r\n const html = createModal(options);\r\n // 推送\r\n const res = await pushMessage({\r\n title: '消息提示',\r\n content: html,\r\n fromToken,\r\n toToken,\r\n template: 'html',\r\n });\r\n if (res && res.code === 200) {\r\n return res;\r\n }\r\n return;\r\n}\r\n\r\n","from":"src\\utils\\push.ts","to":"push.js"},"src\\utils\\random.ts":{"timeStamp":"2023-02-11T12:25:34.984Z","data":"/**\r\n * @description 创建随机点\r\n * @param bounds 范围\r\n * @returns\r\n */\r\nfunction createRandomPoint(bounds) {\r\n // 范围\r\n const { x, y, width, height } = bounds;\r\n // 横坐标\r\n const randX = x + Math.random() * width * 0.5 + width * 0.25;\r\n // 纵坐标\r\n const randY = y + Math.random() * height * 0.5 + height * 0.25;\r\n return {\r\n x: randX,\r\n y: randY,\r\n };\r\n}\r\n/**\r\n * @description 生成随机路径\r\n * @param start\r\n * @param end\r\n * @param steps\r\n * @returns\r\n */\r\nfunction createRandomPath(start, end, steps) {\r\n // 最小水平增量\r\n const minDeltaX = (end.x - start.x) / steps;\r\n // 最大垂直增量\r\n const maxDeltaY = (end.y - start.y) / steps;\r\n const path = [];\r\n // 开始节点\r\n path.push(start);\r\n // 插入点\r\n for (let i = 0; i < steps; i++) {\r\n // 横坐标\r\n const x = path[i].x + Math.random() * 5 + minDeltaX;\r\n // 纵坐标\r\n const y = path[i].y +\r\n Math.random() * 5 * Math.pow(-1, ~~(Math.random() * 2 + 1)) +\r\n maxDeltaY;\r\n path.push({\r\n x,\r\n y,\r\n });\r\n }\r\n return path;\r\n}\r\n/**\r\n * @description 随机数字\r\n * @returns\r\n */\r\nfunction generateNumAsChar() {\r\n return (~~(Math.random() * 10)).toString();\r\n}\r\n/**\r\n * @description 随机大写字母\r\n * @returns\r\n */\r\nfunction generateUpperAsChar() {\r\n return String.fromCharCode(~~(Math.random() * 26) + 65);\r\n}\r\n/**\r\n * @description 随机小写字母\r\n * @returns\r\n */\r\nfunction generateLowerAsChar() {\r\n return String.fromCharCode(~~(Math.random() * 26) + 97);\r\n}\r\n/**\r\n * @description 随机混合字符\r\n * @param length\r\n * @returns\r\n */\r\nfunction generateMix(length = 6) {\r\n // 随机字符串\r\n const randomText = [];\r\n // 生成器\r\n const typeGenerator = [\r\n generateNumAsChar,\r\n generateUpperAsChar,\r\n generateLowerAsChar,\r\n ];\r\n if (length) {\r\n for (let i = 0; i < length; i++) {\r\n // 随机位置\r\n const randomIndex = ~~(Math.random() * typeGenerator.length);\r\n randomText.push(typeGenerator[randomIndex]());\r\n }\r\n }\r\n return randomText.join('');\r\n}\r\n\r\n","from":"src\\utils\\random.ts","to":"random.js"},"src\\utils\\time.ts":{"timeStamp":"2023-02-11T12:25:31.463Z","data":"/**\r\n * @description 格式化日期时间数字\r\n * @param num\r\n * @returns\r\n */\r\nfunction formatDateNum(num) {\r\n return num < 10 ? `0${num}` : `${num}`;\r\n}\r\n/**\r\n * @description 格式化日期时间\r\n * @param time\r\n * @returns\r\n * @example\r\n * formatDateTime() -> \"2022-09-01 08:00:00\"\r\n * formatDateTime(new Date()) -> \"2022-09-01 08:00:00\"\r\n * formatDateTime(Date.now()) -> \"2022-09-01 08:00:00\"\r\n */\r\nfunction formatDateTime(time = Date.now()) {\r\n const date = new Date(time);\r\n const s = date.getSeconds();\r\n const min = date.getMinutes();\r\n const h = date.getHours();\r\n const d = date.getDate();\r\n const m = date.getMonth() + 1;\r\n const y = date.getFullYear();\r\n // 日期\r\n const dateText = [y, m, d].map(formatDateNum).join('-');\r\n // 时间\r\n const timeText = [h, min, s].map(formatDateNum).join(':');\r\n // 日期时间\r\n const dateTimeText = `${dateText} ${timeText}`;\r\n return dateTimeText;\r\n}\r\n/**\r\n * @description 格式化时间\r\n * @param time\r\n * @returns\r\n * @example\r\n * formatTime() -> \"08:00:00\"\r\n * formatTime(new Date()) -> \"08:00:00\"\r\n * formatTime(Date.now()) -> \"08:00:00\"\r\n */\r\nconst formatTime = (time = Date.now()) => {\r\n const date = new Date(time);\r\n const s = date.getSeconds();\r\n const min = date.getMinutes();\r\n const h = date.getHours();\r\n // 时间\r\n const timeText = [h, min, s].map(formatDateNum).join(':');\r\n return timeText;\r\n};\r\n/**\r\n * @description 时间已过\r\n * @param hour\r\n * @param minute\r\n * @returns\r\n */\r\nfunction isLate({ hour, minute }) {\r\n const date = new Date();\r\n const h = date.getHours();\r\n const min = date.getMinutes();\r\n return h > hour || (h === hour && min >= minute);\r\n}\r\n/**\r\n * @description 时间已过\r\n * @param hour\r\n * @param minute\r\n * @returns\r\n */\r\nfunction isNow({ hour, minute }) {\r\n const date = new Date();\r\n const h = date.getHours();\r\n const min = date.getMinutes();\r\n const s = date.getSeconds();\r\n return h === hour && min === minute && s === 0;\r\n}\r\n\r\n","from":"src\\utils\\time.ts","to":"time.js"},"src\\utils\\utils.ts":{"timeStamp":"2023-07-12T04:27:35.825Z","data":"/* 工具函数 */\r\n/**\r\n * @description 设置cookie\r\n * @param name\r\n * @param value\r\n * @param expires\r\n */\r\nfunction setCookie(name, value, expires, domain) {\r\n // 当前日期\r\n const date = new Date();\r\n // 过期日期\r\n date.setTime(date.getTime() + expires);\r\n // 设置cookie\r\n document.cookie = `${name}=${value};expires=${date.toUTCString()};path=/;domain=${domain}`;\r\n}\r\n/**\r\n * @description 获取cookie\r\n * @param name\r\n * @returns\r\n */\r\nfunction getCookie(name) {\r\n // 获取当前所有cookie\r\n const strCookies = document.cookie;\r\n // 截取变成cookie数组\r\n const cookieText = strCookies.split(';');\r\n // 循环每个cookie\r\n for (const i in cookieText) {\r\n // 将cookie截取成两部分\r\n const item = cookieText[i].split('=');\r\n // 判断cookie的name 是否相等\r\n if (item[0].trim() === name) {\r\n return item[1].trim();\r\n }\r\n }\r\n return null;\r\n}\r\n/**\r\n * @description 删除cookie\r\n * @param name\r\n */\r\nfunction delCookie(name, domain) {\r\n // 存在cookie\r\n const value = getCookie(name);\r\n if (value !== null) {\r\n setCookie(name, '', -1, domain);\r\n }\r\n}\r\n/**\r\n * @description 防抖\r\n * @param callback\r\n * @param delay\r\n * @returns\r\n */\r\nfunction debounce(callback, delay) {\r\n let timer = -1;\r\n return function (...args) {\r\n if (timer !== -1) {\r\n clearTimeout(timer);\r\n }\r\n timer = setTimeout(() => {\r\n callback.apply(this, args);\r\n }, delay);\r\n };\r\n}\r\n/**\r\n * @description 判断是否为移动端\r\n * @returns\r\n */\r\nfunction hasMobile() {\r\n let isMobile = false;\r\n if (navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i)) {\r\n log('移动端');\r\n isMobile = true;\r\n }\r\n if (document.body.clientWidth < 800) {\r\n log('小尺寸设备端');\r\n isMobile = true;\r\n }\r\n return isMobile;\r\n}\r\n/**\r\n * @description 等待时间\r\n * @param time\r\n * @returns\r\n */\r\nfunction sleep(time) {\r\n // 延时\r\n let timeDelay = Number(time);\r\n if (!Number.isInteger(timeDelay)) {\r\n timeDelay = 1000;\r\n }\r\n timeDelay += Math.random() * 500 - 250;\r\n return new Promise((resolve) => {\r\n setTimeout(() => {\r\n resolve(undefined);\r\n }, timeDelay);\r\n });\r\n}\r\n/**\r\n * @description 暂停学习锁\r\n */\r\nfunction studyPauseLock(callback) {\r\n return new Promise((resolve) => {\r\n // 暂停\r\n const pauseStudy = GM_getValue('pauseStudy') || false;\r\n if (pauseStudy) {\r\n const doing = setInterval(() => {\r\n // 暂停\r\n const pauseStudy = GM_getValue('pauseStudy') || false;\r\n if (!pauseStudy) {\r\n // 停止定时器\r\n clearInterval(doing);\r\n log('学习等待结束!');\r\n if (callback && callback instanceof Function) {\r\n callback(true);\r\n }\r\n resolve(true);\r\n return;\r\n }\r\n if (callback && callback instanceof Function) {\r\n callback(false);\r\n }\r\n log('学习等待...');\r\n }, 500);\r\n return;\r\n }\r\n resolve(true);\r\n });\r\n}\r\n/**\r\n * @description 加载\r\n * @param match\r\n * @param callback\r\n */\r\nfunction load(match, callback) {\r\n // 链接\r\n const { href } = window.location;\r\n window.addEventListener('load', () => {\r\n // 函数\r\n if (match instanceof Function) {\r\n match(href) && callback();\r\n return;\r\n }\r\n // 布尔\r\n if (typeof match === 'boolean') {\r\n match && callback();\r\n return;\r\n }\r\n // 字符正则\r\n if (href.match(match)) {\r\n callback();\r\n return;\r\n }\r\n });\r\n}\r\n\r\n","from":"src\\utils\\utils.ts","to":"utils.js"},"src\\shared\\index.ts":{"timeStamp":"2023-07-12T05:59:54.970Z","data":"/* 变量 */\r\n/**\r\n * @description 链接\r\n */\r\nconst href = window.location.href;\r\n/**\r\n * @description 任务配置\r\n */\r\nconst taskConfig = reactive([\r\n {\r\n title: '登录',\r\n currentScore: 0,\r\n dayMaxScore: 0,\r\n need: 0,\r\n status: false,\r\n tip: '每日首次登录积1分。',\r\n score: 0,\r\n active: true,\r\n immutable: true,\r\n type: TaskType.LOGIN,\r\n },\r\n {\r\n title: '文章选读',\r\n currentScore: 0,\r\n dayMaxScore: 0,\r\n need: 0,\r\n status: false,\r\n tip: '每有效阅读一篇文章积1分,上限6分。有效阅读文章累计1分钟积1分,上限6分。每日上限积12分。',\r\n score: 0,\r\n active: true,\r\n immutable: false,\r\n type: TaskType.READ,\r\n },\r\n {\r\n title: '视听学习',\r\n currentScore: 0,\r\n dayMaxScore: 0,\r\n need: 0,\r\n status: false,\r\n tip: '每有效一个音频或观看一个视频积1分,上限6分。有效收听音频或观看视频累计1分钟积1分,上限6分。每日上限积12分。',\r\n score: 0,\r\n active: true,\r\n immutable: false,\r\n type: TaskType.WATCH,\r\n },\r\n {\r\n title: '每日答题',\r\n currentScore: 0,\r\n dayMaxScore: 0,\r\n need: 0,\r\n status: false,\r\n tip: '每组答题每答对1道积1分。每日上限积5分。',\r\n score: 0,\r\n active: true,\r\n immutable: false,\r\n type: TaskType.PRACTICE,\r\n },\r\n]);\r\n/**\r\n * @description 设置\r\n */\r\nconst settings = reactive([\r\n false,\r\n false,\r\n false,\r\n false,\r\n false,\r\n false,\r\n false,\r\n false,\r\n]);\r\n/**\r\n * @description 总分\r\n */\r\nconst totalScore = ref(0);\r\n/**\r\n * @description 当天分数\r\n */\r\nconst todayScore = ref(0);\r\n/**\r\n * @description 用户信息\r\n */\r\nconst userinfo = reactive({\r\n nick: '',\r\n avatar: '',\r\n});\r\n/**\r\n * @description 进度\r\n */\r\nconst taskStatus = ref(TaskStatusType.LOADING);\r\n/**\r\n * @description 答题暂停\r\n */\r\nconst examPause = ref(false);\r\n/**\r\n * @description 登录\r\n */\r\nconst login = ref(!!getCookie('token'));\r\n/**\r\n * @description 窗口id\r\n */\r\nconst id = ref('');\r\n/**\r\n * @description 定时刷新列表\r\n */\r\nconst scheduleList = shallowReactive([]);\r\n/**\r\n * @description 推送token\r\n */\r\nconst pushToken = ref('');\r\n/**\r\n * @description 刷新次数\r\n */\r\nconst refreshCount = ref(0);\r\n/**\r\n * @description 窗口关闭\r\n */\r\nconst frame = reactive({\r\n title: '',\r\n show: false,\r\n exist: false,\r\n closed: true,\r\n ele: undefined,\r\n src: '',\r\n});\r\n/**\r\n * @description 页面\r\n */\r\nconst page = ref(undefined);\r\n/**\r\n * @description 开始登录\r\n */\r\nconst loginQRCodeShow = ref(false);\r\n/**\r\n * @description 最大选读时长\r\n */\r\nconst maxRead = ref(100);\r\n/**\r\n * @description 最大视听时长\r\n */\r\nconst maxWatch = ref(120);\r\n/**\r\n * @description 运行其他任务\r\n */\r\nconst running = ref(false);\r\n/**\r\n * @description 主题色\r\n */\r\nconst themeColor = ref('#fa3333');\r\n\r\n","from":"src\\shared\\index.ts","to":"index.js"},"src\\controller\\exam.ts":{"timeStamp":"2023-06-03T04:43:48.117Z","data":"/**\r\n * @description 考试类型\r\n */\r\nvar ExamType;\r\n(function (ExamType) {\r\n ExamType[ExamType[\"PRACTICE\"] = 0] = \"PRACTICE\";\r\n ExamType[ExamType[\"PAPER\"] = 1] = \"PAPER\";\r\n})(ExamType || (ExamType = {}));\r\n/**\r\n * @description 获取答题按钮\r\n */\r\nfunction getNextButton() {\r\n return new Promise((resolve) => {\r\n const timer = setInterval(() => {\r\n // 答题按钮\r\n const nextAll = $$('.ant-btn').filter((next) => next.innerText);\r\n if (nextAll.length) {\r\n // 停止定时器\r\n clearInterval(timer);\r\n if (nextAll.length === 2) {\r\n resolve(nextAll[1]);\r\n return;\r\n }\r\n resolve(nextAll[0]);\r\n }\r\n }, 500);\r\n });\r\n}\r\n/**\r\n * @description 处理滑动验证\r\n */\r\nfunction handleSlideVerify() {\r\n return new Promise(async (resolve) => {\r\n // 滑动验证\r\n const mask = $$('#nc_mask')[0];\r\n if (mask && getComputedStyle(mask).display !== 'none') {\r\n // 创建提示\r\n createTip('等待滑动验证');\r\n // 提高层级\r\n mask.style.zIndex = '999';\r\n // 轨道\r\n const track = (await $_('.nc_scale', undefined, 3000))[0];\r\n // 滑块\r\n const slide = (await $_('.btn_slide', undefined, 3000))[0];\r\n // 延时\r\n await sleep(2000);\r\n // 矩形范围\r\n const rectTrack = track.getBoundingClientRect();\r\n // 矩形范围\r\n const rectSlide = slide.getBoundingClientRect();\r\n // 窗口\r\n const window = unsafeWindow;\r\n // 范围内随机起点\r\n const start = createRandomPoint(rectSlide);\r\n // 终点\r\n const end = {\r\n x: rectTrack.x + rectTrack.width,\r\n y: rectTrack.y + rectTrack.height / 2,\r\n };\r\n // 路径\r\n const path = createRandomPath(start, end, 10);\r\n // 移动端\r\n const mobile = hasMobile();\r\n if (mobile) {\r\n slide.style.touchAction = 'none';\r\n const touchstartTouch = new Touch({\r\n identifier: 0,\r\n target: slide,\r\n clientX: path[0].x,\r\n clientY: path[0].y,\r\n });\r\n const touchstartList = [touchstartTouch];\r\n // 开始触摸\r\n const touchstart = new TouchEvent('touchstart', {\r\n targetTouches: touchstartList,\r\n touches: touchstartList,\r\n changedTouches: touchstartList,\r\n view: window,\r\n bubbles: true,\r\n });\r\n slide.dispatchEvent(touchstart);\r\n // 触摸滑动\r\n for (const i in path) {\r\n const touchmoveTouch = new Touch({\r\n identifier: 0,\r\n target: slide,\r\n clientX: path[i].x,\r\n clientY: path[i].y,\r\n });\r\n const touchmoveList = [touchmoveTouch];\r\n const touchmove = new TouchEvent('touchmove', {\r\n targetTouches: touchmoveList,\r\n touches: touchmoveList,\r\n changedTouches: touchmoveList,\r\n view: window,\r\n bubbles: true,\r\n });\r\n slide.dispatchEvent(touchmove);\r\n await sleep(10);\r\n }\r\n const touchendTouch = new Touch({\r\n identifier: 0,\r\n target: slide,\r\n clientX: path[path.length - 1].x,\r\n clientY: path[path.length - 1].y,\r\n });\r\n // 触摸结束\r\n const touchendList = [touchendTouch];\r\n // 开始触摸\r\n const touchend = new TouchEvent('touchend', {\r\n targetTouches: [],\r\n touches: [],\r\n changedTouches: touchendList,\r\n view: window,\r\n bubbles: true,\r\n });\r\n slide.dispatchEvent(touchend);\r\n }\r\n else {\r\n // 鼠标按下\r\n const mousedown = new MouseEvent('mousedown', {\r\n clientX: path[0].x,\r\n clientY: path[0].y,\r\n bubbles: true,\r\n view: window,\r\n });\r\n slide.dispatchEvent(mousedown);\r\n // 鼠标滑动\r\n for (const i in path) {\r\n const mousemove = new MouseEvent('mousemove', {\r\n clientX: path[i].x,\r\n clientY: path[i].y,\r\n bubbles: true,\r\n view: window,\r\n });\r\n slide.dispatchEvent(mousemove);\r\n await sleep(10);\r\n }\r\n // 鼠标抬起\r\n const mouseup = new MouseEvent('mouseup', {\r\n clientX: path[path.length - 1].x,\r\n clientY: path[path.length - 1].y,\r\n bubbles: true,\r\n view: window,\r\n });\r\n slide.dispatchEvent(mouseup);\r\n }\r\n // 创建提示\r\n createTip('滑动验证完成!');\r\n // 定时器\r\n const timer = setInterval(() => {\r\n // 滑动验证\r\n const mask = $$('#nc_mask')[0];\r\n if (!mask || getComputedStyle(mask).display === 'none') {\r\n log('滑动验证成功!');\r\n // 创建提示\r\n createTip('滑动验证成功!');\r\n clearInterval(timer);\r\n resolve(true);\r\n return;\r\n }\r\n resolve(false);\r\n log('滑动验证失败!');\r\n // 创建提示\r\n createTip('滑动验证失败!');\r\n }, 1000);\r\n return;\r\n }\r\n resolve(true);\r\n });\r\n}\r\n/**\r\n * @description 处理选项\r\n */\r\nfunction handleChoiceBtn(answers) {\r\n // 选项按钮\r\n const allBtns = $$('.q-answer');\r\n // 答案存在\r\n if (answers.length && allBtns.length) {\r\n // 作答\r\n return answers.every((answer) => {\r\n // 答案存在\r\n if (answer && answer.length) {\r\n // 包含答案最短长度选项\r\n let minLengthChoice;\r\n // 遍历\r\n allBtns.forEach((choice) => {\r\n // 选项文本\r\n const choiceText = choice.innerText.trim();\r\n // 无符号选项文本\r\n const unsignedChoiceText = choiceText.replaceAll(/[、,,。 ]/g, '');\r\n // 无符号答案\r\n const unsignedAnswer = answer.replaceAll(/[、,,。 ]/g, '');\r\n // 包含答案\r\n if (choiceText === answer ||\r\n choiceText.includes(answer) ||\r\n answer.includes(choiceText) ||\r\n unsignedChoiceText.includes(unsignedAnswer)) {\r\n // 最小长度选项有值\r\n if (minLengthChoice) {\r\n // 最短长度选项与当前选项比较长度\r\n if (minLengthChoice.innerText.length > choiceText.length) {\r\n minLengthChoice = choice;\r\n }\r\n }\r\n else {\r\n // 最小长度选项赋值\r\n minLengthChoice = choice;\r\n }\r\n }\r\n });\r\n // 存在选项\r\n if (minLengthChoice) {\r\n // 选择\r\n if (!minLengthChoice.classList.contains('chosen')) {\r\n minLengthChoice.click();\r\n }\r\n return true;\r\n }\r\n }\r\n return false;\r\n });\r\n }\r\n return false;\r\n}\r\n/**\r\n * @description 随机处理单选\r\n */\r\nfunction handleSingleChoiceRand() {\r\n // 选项按钮\r\n const allBtns = $$('.q-answer');\r\n // 按钮存在\r\n if (allBtns.length) {\r\n const index = ~~(Math.random() * allBtns.length);\r\n const randBtn = allBtns[index];\r\n // 选择\r\n if (!randBtn.classList.contains('chosen')) {\r\n randBtn.click();\r\n }\r\n }\r\n}\r\n/**\r\n * @description 随机处理多选\r\n */\r\nfunction handleMutiplyChoiceRand() {\r\n // 选项按钮\r\n const allBtns = $$('.q-answer');\r\n // 按钮存在\r\n if (allBtns.length) {\r\n allBtns.forEach((allBtn) => {\r\n // 选择\r\n if (!allBtn.classList.contains('chosen')) {\r\n allBtn.click();\r\n }\r\n });\r\n }\r\n}\r\n/**\r\n * @description 处理填空\r\n */\r\nconst handleBlankInput = (answers) => {\r\n // 所有填空\r\n const blanks = $$('.blank');\r\n // 答案存在\r\n if (blanks.length && answers.length) {\r\n // 填空数量和答案数量一致\r\n if (answers.length === blanks.length) {\r\n return answers.every((answer, i) => {\r\n // 答案存在\r\n if (answer && answer.length) {\r\n // 输入事件\r\n const inputEvent = new Event('input', {\r\n bubbles: true,\r\n });\r\n // 设置答案\r\n blanks[i].setAttribute('value', answer);\r\n // 触发输入input\r\n blanks[i].dispatchEvent(inputEvent);\r\n return true;\r\n }\r\n return false;\r\n });\r\n }\r\n // 填空数量为1和提示数量大于1\r\n if (blanks.length === 1 && answers.length > 1) {\r\n // 直接将所有答案整合填进去\r\n const answer = answers.join('');\r\n // 答案存在\r\n if (answer && answer.length) {\r\n // 输入事件\r\n const inputEvent = new Event('input', {\r\n bubbles: true,\r\n });\r\n // 设置答案\r\n blanks[0].setAttribute('value', answer);\r\n // 触发输入input\r\n blanks[0].dispatchEvent(inputEvent);\r\n return true;\r\n }\r\n }\r\n }\r\n return false;\r\n};\r\n/**\r\n * @description 处理填空随机\r\n */\r\nasync function handleBlankInputRand() {\r\n // 所有填空\r\n const blanks = $$('.blank');\r\n if (blanks.length) {\r\n // 输入事件\r\n const inputEvent = new Event('input', {\r\n bubbles: true,\r\n });\r\n blanks.forEach((blank) => {\r\n // 设置答案\r\n blank.setAttribute('value', '答案');\r\n // 触发输入input\r\n blank.dispatchEvent(inputEvent);\r\n });\r\n }\r\n}\r\n/**\r\n * @description 暂停锁\r\n */\r\nfunction examPauseLock(callback) {\r\n return new Promise((resolve) => {\r\n // 学习暂停\r\n const pauseStudy = (GM_getValue('pauseStudy') || false);\r\n // 全局暂停\r\n if (pauseStudy) {\r\n examPause.value = true;\r\n }\r\n // 暂停\r\n if (examPause.value) {\r\n // 创建提示\r\n createTip('已暂停, 手动开启自动答题! ', 10);\r\n const doing = setInterval(() => {\r\n if (!examPause.value) {\r\n // 停止定时器\r\n clearInterval(doing);\r\n log('答题等待结束!');\r\n if (callback && callback instanceof Function) {\r\n // 创建提示\r\n createTip('已开启, 自动答题!');\r\n callback(true);\r\n }\r\n resolve(true);\r\n return;\r\n }\r\n if (callback && callback instanceof Function) {\r\n callback(false);\r\n }\r\n log('答题等待...');\r\n }, 500);\r\n return;\r\n }\r\n resolve(true);\r\n });\r\n}\r\n/**\r\n * @description 答题\r\n */\r\nasync function doingExam(type) {\r\n // 下一个按钮\r\n let nextButton;\r\n // 下一个文本\r\n let nextText;\r\n // 保存答案\r\n let shouldSaveAnswer = false;\r\n while (true) {\r\n // 先等等再开始做题\r\n await sleep(2500);\r\n // 暂停\r\n await examPauseLock();\r\n // 获取下一个按钮\r\n nextButton = await getNextButton();\r\n // 下一个文本\r\n nextText = nextButton.innerText.replaceAll(' ', '');\r\n // 结束\r\n const finish = ['再练一次', '再来一组', '查看解析'];\r\n if (finish.includes(nextButton.innerText)) {\r\n break;\r\n }\r\n // 点击提示\r\n $$('.tips')[0]?.click();\r\n // 所有提示\r\n const allTips = $$('.line-feed font[color]');\r\n // 答案\r\n const answers = allTips.map((tip) => tip.innerText.trim());\r\n // 获取题目的文本内容\r\n const question = $$('.q-body')[0].innerText;\r\n // 等待一段时间\r\n await sleep(1500);\r\n // 暂停\r\n await examPauseLock();\r\n // 选项按钮\r\n const allBtns = $$('.q-answer');\r\n // 所有填空\r\n const blanks = $$('input[type=text][class=blank]');\r\n // 问题类型\r\n const questionType = ($$('.q-header')[0].innerText.substring(0, 3));\r\n // 暂停\r\n await examPauseLock();\r\n // 题型分类作答\r\n switch (questionType) {\r\n case '填空题': {\r\n // 根据提示作答\r\n if (answers.length) {\r\n const res = handleBlankInput(answers);\r\n // 成功\r\n if (res) {\r\n break;\r\n }\r\n }\r\n // 创建提示\r\n createTip('答案异常, 尝试网络题库获取!');\r\n log('正在获取答案...');\r\n // 尝试题库获取\r\n const answersNetwork = await getAnswer(question);\r\n log(`获取答案${answersNetwork.length ? '成功' : '失败'}!`, {\r\n question,\r\n answersNetwork,\r\n });\r\n // 根据题库作答\r\n if (answersNetwork.length) {\r\n const res = handleBlankInput(answersNetwork);\r\n // 成功\r\n if (res) {\r\n break;\r\n }\r\n }\r\n // 随机作答\r\n if (type === ExamType.PRACTICE || settings[SettingType.RANDOM_EXAM]) {\r\n log('答案不存在, 随机作答!');\r\n // 创建提示\r\n createTip('答案不存在, 随机作答!');\r\n await handleBlankInputRand();\r\n }\r\n else {\r\n // 推送\r\n const res = await pushModal({\r\n title: '学习推送',\r\n to: userinfo.nick,\r\n content: '答题存在异常, 已暂停答题!',\r\n type: 'fail',\r\n }, pushToken.value);\r\n createTip(`学习推送${res ? '成功' : '失败'}!`);\r\n // 暂停\r\n examPause.value = true;\r\n // 提交答案\r\n shouldSaveAnswer = true;\r\n }\r\n break;\r\n }\r\n case '多选题': {\r\n // 根据提示作答\r\n if (answers.length) {\r\n // 选项文本\r\n const choicesText = allBtns.map((btn) => btn.innerText);\r\n // 选项内容\r\n const choicesContent = choicesText\r\n .map((choiceText) => choiceText.split(/[A-Z]./)[1].trim())\r\n .join('');\r\n // 空格\r\n const blanks = question.match(/()/g);\r\n // 填空数量、选项数量、答案数量相同 | 选项全文等于答案全文\r\n if ((blanks && allBtns.length === blanks.length) ||\r\n question === choicesContent ||\r\n allBtns.length === 2) {\r\n // 全选\r\n allBtns.forEach((choice) => {\r\n if (!choice.classList.contains('chosen')) {\r\n choice.click();\r\n }\r\n });\r\n break;\r\n }\r\n // 选项数量大于等于答案\r\n if (allBtns.length >= answers.length) {\r\n const res = handleChoiceBtn(answers);\r\n // 成功\r\n if (res) {\r\n break;\r\n }\r\n }\r\n }\r\n // 创建提示\r\n createTip('答案异常, 尝试网络题库获取!');\r\n log('正在获取答案...');\r\n // 尝试题库获取\r\n const answersNetwork = await getAnswer(question);\r\n log(`获取答案${answersNetwork.length ? '成功' : '失败'}!`, {\r\n question,\r\n answersNetwork,\r\n });\r\n // 答案存在\r\n if (answersNetwork.length) {\r\n const res = handleChoiceBtn(answersNetwork);\r\n // 成功\r\n if (res) {\r\n break;\r\n }\r\n }\r\n // 随机作答\r\n if (type === ExamType.PRACTICE || settings[SettingType.RANDOM_EXAM]) {\r\n log('答案不存在, 随机作答!');\r\n // 创建提示\r\n createTip('答案不存在, 随机作答!');\r\n await handleMutiplyChoiceRand();\r\n }\r\n else {\r\n // 推送\r\n const res = await pushModal({\r\n title: '学习推送',\r\n to: userinfo.nick,\r\n content: '答题存在异常, 已暂停答题!',\r\n type: 'fail',\r\n }, pushToken.value);\r\n createTip(`学习推送${res ? '成功' : '失败'}!`);\r\n // 暂停\r\n examPause.value = true;\r\n // 提交答案\r\n shouldSaveAnswer = true;\r\n }\r\n break;\r\n }\r\n case '单选题': {\r\n // 根据提示作答\r\n if (answers.length) {\r\n // 创建提示为1\r\n if (answers.length === 1) {\r\n const res = handleChoiceBtn(answers);\r\n // 成功\r\n if (res) {\r\n break;\r\n }\r\n }\r\n else {\r\n // 可能的分隔符\r\n const seperator = [\r\n '',\r\n ' ',\r\n ',',\r\n ';',\r\n ',',\r\n '、',\r\n '-',\r\n '|',\r\n '+',\r\n '/',\r\n ];\r\n // 可能的答案\r\n const answersLike = seperator\r\n .map((s) => answers.join(s).trim())\r\n .filter((answer) => answer.length);\r\n // 答案存在\r\n if (answersLike.length) {\r\n // 可能答案是否正确\r\n const res = answersLike.some((answer) => {\r\n // 尝试查找点击\r\n return handleChoiceBtn([answer]);\r\n });\r\n if (res) {\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n // 创建提示\r\n createTip('答案异常, 尝试网络题库获取!');\r\n log('正在获取答案...');\r\n // 尝试题库获取\r\n const answersNetwork = await getAnswer(question);\r\n log(`获取答案${answersNetwork.length ? '成功' : '失败'}!`, {\r\n question,\r\n answersNetwork,\r\n });\r\n // 存在答案\r\n if (answersNetwork.length) {\r\n // 单答案单选项\r\n if (answersNetwork.length === 1) {\r\n // 尝试查找点击\r\n const res = handleChoiceBtn(answersNetwork);\r\n if (res) {\r\n break;\r\n }\r\n }\r\n else {\r\n // 多答案单选项 选项意外拆分\r\n // 可能分隔符\r\n const seperator = ['', ' '];\r\n // 可能答案\r\n const answersLike = seperator.map((s) => answers.join(s));\r\n // 答案存在\r\n if (answersLike.every((answer) => answer.length)) {\r\n // 可能答案是否正确\r\n const res = answersLike.some((answer) => {\r\n // 尝试查找点击\r\n return handleChoiceBtn([answer]);\r\n });\r\n if (res) {\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n // 随机作答\r\n if (type === ExamType.PRACTICE || settings[SettingType.RANDOM_EXAM]) {\r\n log('答案不存在, 随机作答!');\r\n // 创建提示\r\n createTip('答案不存在, 随机作答!');\r\n await handleSingleChoiceRand();\r\n }\r\n else {\r\n // 推送\r\n const res = await pushModal({\r\n title: '学习推送',\r\n to: userinfo.nick,\r\n content: '答题存在异常, 已暂停答题!',\r\n type: 'fail',\r\n }, pushToken.value);\r\n createTip(`学习推送${res ? '成功' : '失败'}!`);\r\n // 暂停\r\n examPause.value = true;\r\n // 提交答案\r\n shouldSaveAnswer = true;\r\n }\r\n break;\r\n }\r\n }\r\n // 暂停\r\n await examPauseLock();\r\n // 获取下一个按钮\r\n nextButton = await getNextButton();\r\n // 下一个文本\r\n nextText = nextButton.innerText.replaceAll(' ', '');\r\n // 需要提交答案\r\n if (shouldSaveAnswer) {\r\n // 答案\r\n const answers = [];\r\n if (questionType === '填空题') {\r\n blanks.forEach((blank) => {\r\n answers.push(blank.value);\r\n });\r\n }\r\n if (questionType === '单选题' || questionType === '多选题') {\r\n allBtns.forEach((choice) => {\r\n if (choice.classList.contains('chosen')) {\r\n // 带字母的选项\r\n const answerTemp = choice.innerText;\r\n // 从字符串中拿出答案\r\n const [, answer] = answerTemp.split('.');\r\n if (answer && answer.length) {\r\n answers.push(answer);\r\n }\r\n }\r\n });\r\n }\r\n // 答案\r\n const answer = answers.join(';');\r\n // 存在答案\r\n if (answer.length) {\r\n log('正在上传答案...');\r\n // 上传答案\r\n const res = await saveAnswer(question, answer);\r\n log(`上传答案${res ? '成功' : '失败'}!`, { question, answer });\r\n }\r\n // 重置\r\n shouldSaveAnswer = false;\r\n }\r\n // 确定\r\n if (nextText === '确定') {\r\n // 确认\r\n nextButton.click();\r\n // 等待一段时间\r\n await sleep(2000);\r\n // 暂停\r\n await examPauseLock();\r\n // 答案解析\r\n const answerBox = $$('.answer')[0];\r\n // 答题错误\r\n if (answerBox) {\r\n const answerTemp = answerBox.innerText;\r\n // 从字符串中拿出答案\r\n const [, answerText] = answerTemp.split(':');\r\n if (answerText && answerText.length) {\r\n const answer = answerText.replaceAll(' ', ';');\r\n log('正在上传答案...');\r\n // 上传答案\r\n const res = await saveAnswer(question, answer);\r\n log(`上传答案${res ? '成功' : '失败'}!`, { question, answer });\r\n }\r\n }\r\n }\r\n // 获取按钮\r\n nextButton = await getNextButton();\r\n // 下一个文本\r\n nextText = nextButton.innerText.replaceAll(' ', '');\r\n if (nextText === '下一题' || nextText === '完成' || nextText === '交卷') {\r\n // 等待一段时间\r\n await sleep(2500);\r\n // 下一题\r\n nextButton.click();\r\n }\r\n // 滑动验证\r\n await handleSlideVerify();\r\n }\r\n // 关闭任务窗口\r\n handleCloseTaskWin();\r\n}\r\n/**\r\n * @description 每日答题\r\n */\r\nasync function doExamPractice() {\r\n // 暂停\r\n await studyPauseLock();\r\n log('正在每日答题...');\r\n // 创建提示\r\n createTip('正在每日答题');\r\n // 链接\r\n const url = URL_CONFIG.examPractice;\r\n // 等待任务窗口\r\n await waitTaskWin(url, '每日答题');\r\n // 创建提示\r\n createTip('完成每日答题!');\r\n // 等待一段时间\r\n await sleep(1500);\r\n // 刷新分数数据\r\n await refreshScoreInfo();\r\n // 刷新任务数据\r\n await refreshTaskList();\r\n // 任务完成状况\r\n if (taskConfig[TaskType.PRACTICE].active &&\r\n !taskConfig[TaskType.PRACTICE].status) {\r\n log('任务未完成, 继续每日答题!');\r\n // 创建提示\r\n createTip('任务未完成, 继续每日答题!');\r\n await doExamPractice();\r\n }\r\n}\r\n/**\r\n * @description 专项练习\r\n */\r\nasync function doExamPaper() {\r\n running.value = true;\r\n log('正在专项练习...');\r\n // 创建提示\r\n createTip('正在专项练习');\r\n // id\r\n const examPaperId = await findExamPaper();\r\n if (examPaperId) {\r\n // 链接\r\n const url = `${URL_CONFIG.examPaper}?id=${examPaperId}`;\r\n log(`链接: ${url}`);\r\n // 等待窗口任务\r\n await waitTaskWin(url, '专项练习');\r\n // 创建提示\r\n createTip('完成专项练习!');\r\n running.value = false;\r\n // 同屏任务\r\n if (settings[SettingType.SAME_TAB]) {\r\n // 窗口不存在\r\n frame.exist = false;\r\n }\r\n return;\r\n }\r\n running.value = false;\r\n // 创建提示\r\n createTip('专项练习均已完成!');\r\n}\r\n/**\r\n * @description 初始化总页数属性\r\n */\r\nasync function initExam() {\r\n // 默认从第一页获取全部页属性\r\n const data = await getExamPaper(1);\r\n if (data) {\r\n // 等待\r\n await sleep(3000);\r\n return data.totalPageCount;\r\n }\r\n}\r\n/**\r\n * @description 查询专项练习列表\r\n */\r\nasync function findExamPaper() {\r\n // 获取总页数\r\n const total = await initExam();\r\n // 当前页数\r\n let current = 1;\r\n log(`正在寻找的专项练习...`);\r\n // 创建提示\r\n createTip(`正在寻找的专项练习...`);\r\n while (current <= total && current) {\r\n // 请求数据\r\n const data = await getExamPaper(current);\r\n if (data) {\r\n // 获取专项练习的列表\r\n const examPapers = data.list;\r\n for (const i in examPapers) {\r\n // 遍历查询有没有没做过的\r\n if (examPapers[i].status !== 2) {\r\n // status: 1 开始答题, 2 已满分/重新答题, 3 继续答题\r\n return examPapers[i].id;\r\n }\r\n }\r\n // 增加页码\r\n current += 1;\r\n // 等待\r\n await sleep(3000);\r\n }\r\n else {\r\n break;\r\n }\r\n }\r\n}\r\n\r\n","from":"src\\controller\\exam.ts","to":"exam.js"},"src\\controller\\frame.ts":{"timeStamp":"2023-03-04T06:19:57.161Z","data":"/**\r\n * @description 初始化主页面\r\n */\r\nfunction initMainListener() {\r\n // 监听关闭\r\n window.addEventListener('message', (msg) => {\r\n const { data } = msg;\r\n if (data.id === id.value && data.closed) {\r\n // 关闭窗口\r\n closeFrame();\r\n return;\r\n }\r\n });\r\n}\r\n/**\r\n * @description 初始化子页面\r\n */\r\nfunction initChildListener() {\r\n window.addEventListener('message', (msg) => {\r\n const { data } = msg;\r\n if (data.id && !data.closed) {\r\n // 设置窗口id\r\n id.value = data.id;\r\n log(`初始化窗口 ID: ${id.value}`);\r\n return;\r\n }\r\n });\r\n}\r\n/**\r\n * @description 打开窗口\r\n * @param url\r\n * @returns\r\n */\r\nasync function openFrame(url, title) {\r\n // 设置 URL\r\n frame.src = url;\r\n // 等待元素\r\n await $_('.egg_frame');\r\n if (frame.ele) {\r\n // id\r\n id.value = generateMix(10);\r\n // 打开\r\n frame.closed = false;\r\n // 设置标题\r\n frame.title = title || '';\r\n // 等待页面加载\r\n await waitFrameLoaded(frame.ele);\r\n // 发送窗口 ID\r\n frame.ele.contentWindow?.postMessage({ id: id.value, closed: false }, url);\r\n return true;\r\n }\r\n return false;\r\n}\r\n/**\r\n * @description 关闭窗口\r\n */\r\nfunction closeFrame() {\r\n log(`关闭窗口 ID: ${id.value}`);\r\n // 窗口显示\r\n frame.show = false;\r\n // 关闭\r\n frame.closed = true;\r\n // 标题\r\n frame.title = '';\r\n // src\r\n frame.src = '';\r\n}\r\n/**\r\n * @description 关闭 frame\r\n */\r\nfunction handleCloseFrame() {\r\n window.parent.postMessage({ id: id.value, closed: true }, URL_CONFIG.homeOrigin);\r\n}\r\n/**\r\n * @description 等待窗口任务结束\r\n * @param id\r\n * @returns\r\n */\r\nfunction waitFrameClose() {\r\n return new Promise((resolve) => {\r\n const timer = setInterval(() => {\r\n // 窗口关闭\r\n if (frame.closed) {\r\n clearInterval(timer);\r\n resolve(true);\r\n }\r\n }, 100);\r\n });\r\n}\r\n// 等待窗口加载\r\nfunction waitFrameLoaded(iframe) {\r\n return new Promise((resolve) => {\r\n iframe.addEventListener('load', () => {\r\n resolve(true);\r\n });\r\n });\r\n}\r\n/**\r\n * @description 打开新窗口\r\n */\r\nfunction openWin(url) {\r\n return GM_openInTab(url, {\r\n active: true,\r\n insert: true,\r\n setParent: true,\r\n });\r\n}\r\n/**\r\n * @description 关闭窗口\r\n */\r\nfunction closeWin() {\r\n page.value && page.value.close();\r\n}\r\n/**\r\n * @description 关闭子窗口\r\n */\r\nfunction handleCloseWin() {\r\n try {\r\n window.opener = window;\r\n const win = window.open('', '_self');\r\n win?.close();\r\n top?.close();\r\n }\r\n catch (e) { }\r\n}\r\n/**\r\n * @description 等待窗口关闭\r\n * @param newPage\r\n * @returns\r\n */\r\nfunction waitWinClose(newPage) {\r\n return new Promise((resolve) => {\r\n newPage.onclose = () => {\r\n resolve(undefined);\r\n };\r\n });\r\n}\r\n/**\r\n * @description 关闭任务窗口\r\n */\r\nfunction closeTaskWin() {\r\n // 同屏任务\r\n if (settings[SettingType.SAME_TAB] && id.value) {\r\n closeFrame();\r\n return;\r\n }\r\n // 非同屏任务\r\n closeWin();\r\n}\r\n/**\r\n * @description 关闭任务窗口\r\n */\r\nfunction handleCloseTaskWin() {\r\n // 同屏任务\r\n if (settings[SettingType.SAME_TAB] && id.value) {\r\n handleCloseFrame();\r\n return;\r\n }\r\n // 子窗口\r\n handleCloseWin();\r\n}\r\n/**\r\n * @description 打开并等待任务结束\r\n */\r\nasync function waitTaskWin(url, title) {\r\n // 同屏任务\r\n if (settings[SettingType.SAME_TAB]) {\r\n // 窗口存在\r\n frame.exist = true;\r\n // 显示窗体\r\n frame.show = !settings[SettingType.SILENT_RUN];\r\n // 新窗口\r\n const res = await openFrame(url, title);\r\n if (res) {\r\n // 等待窗口关闭\r\n await waitFrameClose();\r\n }\r\n return;\r\n }\r\n // 子页面任务\r\n page.value = openWin(url);\r\n await waitWinClose(page.value);\r\n}\r\n\r\n","from":"src\\controller\\frame.ts","to":"frame.js"},"src\\controller\\login.ts":{"timeStamp":"2023-07-04T09:31:09.444Z","data":"/**\r\n * @description 二维码刷新定时器\r\n */\r\nlet refreshTimer = -1;\r\n/**\r\n * @description 尝试登录\r\n */\r\nlet tryLoginTimer = -1;\r\n/**\r\n * @description 生成二维码\r\n */\r\nasync function getQRCode() {\r\n log('正在生成登录二维码...');\r\n const qrCode = await generateQRCode();\r\n if (qrCode) {\r\n log('生成登录二维码成功!');\r\n // 链接\r\n const url = `https://login.xuexi.cn/login/qrcommit?showmenu=false&code=${qrCode}&appId=dingoankubyrfkttorhpou`;\r\n return {\r\n code: qrCode,\r\n src: `${API_CONFIG.qrcode}?data=${encodeURIComponent(url)}`,\r\n url,\r\n };\r\n }\r\n log('生成登录二维码失败!');\r\n}\r\n/**\r\n * @description 验证登录二维码\r\n * @param code\r\n * @returns\r\n */\r\nasync function checkQRCode(code) {\r\n log('尝试用二维码登录...');\r\n // 二维码登录\r\n const res = await loginWithQRCode(code);\r\n if (res) {\r\n const { data, code, success } = res;\r\n // 临时登录验证码\r\n if (success && data) {\r\n return data;\r\n }\r\n // 二维码失效\r\n if (code === '11019') {\r\n return;\r\n }\r\n }\r\n return new Promise((resolve) => {\r\n // 清除定时\r\n clearTimeout(tryLoginTimer);\r\n // 设置定时\r\n tryLoginTimer = setTimeout(async () => {\r\n resolve(await checkQRCode(code));\r\n }, 1000);\r\n });\r\n}\r\n/**\r\n * @description 尝试二维码登录\r\n */\r\nasync function tryLogin(checkCode) {\r\n log('正在获取签名...');\r\n // 获取签名\r\n const sign = await getSign();\r\n if (sign) {\r\n // 生成uuid\r\n const uuid = crypto.randomUUID();\r\n const [, code] = checkCode.split('=');\r\n const state = `${sign}${uuid}`;\r\n // 安全检查\r\n const res = await secureCheck({ code, state });\r\n return res;\r\n }\r\n}\r\n/**\r\n * @description 刷新登录二维码\r\n */\r\nasync function handleLogin() {\r\n // 清除刷新\r\n clearInterval(refreshTimer);\r\n // 每隔一段时间刷新\r\n refreshTimer = setInterval(() => {\r\n // 刷新二维码\r\n handleLogin();\r\n }, autoRefreshQRCodeInterval);\r\n // 是否超出次数\r\n if (refreshCount.value >= maxRefreshCount) {\r\n createTip('超过最大重试次数, 登录失败!');\r\n // 重置刷新数\r\n refreshCount.value = 0;\r\n // 隐藏二维码\r\n loginQRCodeShow.value = false;\r\n // 远程推送\r\n if (settings[SettingType.REMOTE_PUSH]) {\r\n // 推送\r\n const res = await pushModal({\r\n title: '登录推送',\r\n content: '超过最大重试次数, 登录失败!',\r\n type: 'fail',\r\n }, pushToken.value);\r\n createTip(`登录推送${res ? '成功' : '失败'}!`);\r\n }\r\n return;\r\n }\r\n // 配置\r\n const imgWrap = $$('.egg_login_img_wrap')[0];\r\n // 图片\r\n const img = $$('.egg_login_img', imgWrap)[0];\r\n if (imgWrap && img) {\r\n // 刷新二维码\r\n log('刷新登录二维码!');\r\n // 刷新次数累加\r\n refreshCount.value++;\r\n // 获取二维码\r\n const qrCode = await getQRCode();\r\n if (qrCode) {\r\n // 获取连接\r\n const { src, code, url } = qrCode;\r\n // src\r\n img.src = src;\r\n // 开始登录\r\n loginQRCodeShow.value = true;\r\n // 远程推送\r\n if (settings[SettingType.REMOTE_PUSH]) {\r\n // img html\r\n const imgWrap = getImgHTML(src);\r\n // 跳转链接\r\n const aWrap = `\r\n <div>\r\n 或在浏览器\r\n <a\r\n href=\"dtxuexi://appclient/page/study_feeds?url=${encodeURIComponent(url)}\"\r\n style=\"text-decoration: none\"\r\n >${getHighlightHTML('打开学习强国APP')}</a\r\n >\r\n </div>\r\n `;\r\n // 推送\r\n const res = await pushModal({\r\n title: '登录推送',\r\n content: ['扫一扫, 登录学习强国!', aWrap, imgWrap],\r\n type: 'info',\r\n }, pushToken.value);\r\n createTip(`登录推送${res ? '成功' : '失败'}!`);\r\n }\r\n // 获取验证码\r\n const checkCode = await checkQRCode(code);\r\n // 验证成功\r\n if (checkCode) {\r\n // 尝试登录\r\n const loginRes = await tryLogin(checkCode);\r\n if (loginRes) {\r\n // 清除刷新\r\n clearInterval(refreshTimer);\r\n // 二维码显示\r\n loginQRCodeShow.value = false;\r\n // 登录成功\r\n log('登录成功!');\r\n // 创建提示\r\n createTip('登录成功!');\r\n // 登录成功\r\n login.value = true;\r\n // 刷新用户信息\r\n await refreshUserInfo();\r\n // 刷新分数信息\r\n await refreshScoreInfo();\r\n // 刷新任务信息\r\n await refreshTaskList();\r\n // 远程推送\r\n if (settings[SettingType.REMOTE_PUSH]) {\r\n const res = await pushModal({\r\n title: '登录推送',\r\n to: userinfo.nick,\r\n content: [\r\n '学习强国, 登录成功!',\r\n `当天积分: ${getHighlightHTML(todayScore.value)} 分`,\r\n `总积分: ${getHighlightHTML(totalScore.value)} 分`,\r\n ...taskConfig.map((task) => getProgressHTML(task.title, task.currentScore, task.dayMaxScore)),\r\n ],\r\n type: 'success',\r\n }, pushToken.value);\r\n createTip(`登录推送${res ? '成功' : '失败'}!`);\r\n }\r\n }\r\n return;\r\n }\r\n // 二维码失效\r\n log('登录二维码失效!');\r\n // 二维码失效刷新\r\n handleLogin();\r\n }\r\n }\r\n}\r\n/**\r\n * @description 退出登录\r\n */\r\nfunction handleLogout() {\r\n // 删除token\r\n delCookie('token', '.xuexi.cn');\r\n // 关闭窗口\r\n closeFrame();\r\n frame.exist = false;\r\n // 退出登录\r\n login.value = false;\r\n // 清除用户信息\r\n userinfo.nick = '';\r\n userinfo.avatar = '';\r\n // 总分\r\n totalScore.value = 0;\r\n // 当天分数\r\n todayScore.value = 0;\r\n // 任务进度重置\r\n taskConfig.forEach((task) => {\r\n task.currentScore = 0;\r\n });\r\n taskStatus.value = TaskStatusType.LOADING;\r\n // 退出登录\r\n log('退出登录');\r\n}\r\n\r\n","from":"src\\controller\\login.ts","to":"login.js"},"src\\controller\\readAndWatch.ts":{"timeStamp":"2023-07-13T13:15:08.730Z","data":"/**\r\n * @description 新闻\r\n */\r\nlet news = [];\r\n/**\r\n * @description 视频\r\n */\r\nlet videos = [];\r\n/**\r\n * @description 处理文章\r\n */\r\nasync function handleNews() {\r\n // section\r\n const sections = await $_('section', undefined, 5000);\r\n const section = sections[0];\r\n if (!(section && section.innerText.includes('系统正在维护中'))) {\r\n // 文章选读\r\n reading(0);\r\n return;\r\n }\r\n log('未找到文章!');\r\n // 提示\r\n createTip('未找到文章!');\r\n // 关闭页面\r\n handleCloseTaskWin();\r\n}\r\n/**\r\n * @description 处理视频\r\n */\r\nasync function handleVideo() {\r\n // videos\r\n const videos = await $_('video', undefined, 10000);\r\n // 视频\r\n const video = videos[0];\r\n // 播放按键\r\n const playBtn = $$('.prism-play-btn')[0];\r\n if (video && playBtn) {\r\n log('正在尝试播放视频...');\r\n // 播放超时\r\n const timeout = setTimeout(() => {\r\n log('视频播放超时!');\r\n // 提示\r\n createTip('视频播放超时!');\r\n // 关闭页面\r\n handleCloseTaskWin();\r\n }, 20000);\r\n // 设置是否静音\r\n watchEffect(() => (video.muted = settings[SettingType.VIDEO_MUTED]));\r\n // 能播放\r\n video.addEventListener('canplay', () => {\r\n const timer = setInterval(() => {\r\n // 尝试点击播放按钮播放\r\n playBtn.click();\r\n // 播放未成功\r\n if (video.paused) {\r\n // 尝试使用js的方式播放\r\n video.play();\r\n }\r\n }, 1000);\r\n video.addEventListener('playing', () => {\r\n // 清除超时定时器\r\n clearTimeout(timeout);\r\n // 清除定时器\r\n clearInterval(timer);\r\n log('播放视频成功!');\r\n // 视听学习\r\n reading(1);\r\n return;\r\n }, { once: true });\r\n }, { once: true });\r\n return;\r\n }\r\n log('未找到视频!');\r\n // 关闭页面\r\n handleCloseTaskWin();\r\n}\r\n/**\r\n * @description 读新闻或者看视频\r\n * @param type :0为新闻,1为视频\r\n */\r\nasync function reading(type) {\r\n let time = 30;\r\n // 文章选读\r\n if (type === 0) {\r\n // 章节\r\n const sections = $$('section');\r\n // 最大字数\r\n const maxTextCount = Math.max(...sections.map((s) => s.innerText.length), 200);\r\n // 预计时间\r\n const predictTime = ~~((60 * maxTextCount) / 1000);\r\n // min(predictTime, maxWatch.value) 秒后关闭页面\r\n time = Math.min(predictTime, maxRead.value);\r\n }\r\n // 视听学习\r\n if (type === 1) {\r\n // 视频\r\n const video = $$('video')[0];\r\n // 预计时间\r\n const predictTime = ~~video.duration;\r\n // min(predictTime, maxWatch.value) 秒后关闭页面\r\n time = Math.min(predictTime, maxWatch.value);\r\n }\r\n // 随机\r\n time = time - ~~(Math.random() * 10) + 5;\r\n // 第一次滚动时间\r\n const firstTime = time - (~~(Math.random() * 4) + 4);\r\n // 第二次滚动时间\r\n const secendTime = ~~(Math.random() * 4) + 8;\r\n // 窗口\r\n const window = unsafeWindow;\r\n // 创建提示\r\n const tip = createTip('距离关闭页面还剩', time, true, async (time) => {\r\n // 暂停锁\r\n await studyPauseLock((flag) => {\r\n if (type === 1) {\r\n // 视频\r\n const video = $$('video')[0];\r\n // 排除反复设置\r\n if (video.paused === !flag) {\r\n return;\r\n }\r\n // 设置播放状态\r\n video[flag ? 'play' : 'pause']();\r\n }\r\n });\r\n // 第一次滚动\r\n if (time === firstTime) {\r\n // 滚动\r\n window.scrollTo(0, 400);\r\n // 模拟滚动\r\n const scroll = new Event('scroll', {\r\n bubbles: true,\r\n });\r\n document.dispatchEvent(scroll);\r\n // 模拟滑动\r\n const mousemove = new MouseEvent('mousemove', {\r\n bubbles: true,\r\n });\r\n document.dispatchEvent(mousemove);\r\n // 模拟点击\r\n const click = new Event('click', {\r\n bubbles: true,\r\n });\r\n document.dispatchEvent(click);\r\n }\r\n // 第二次滚动\r\n if (time === secendTime) {\r\n // 滚动长度\r\n const scrollLength = document.body.scrollHeight / 2;\r\n // 滚动\r\n window.scrollTo(0, scrollLength);\r\n // 模拟滚动\r\n const scroll = new Event('scroll', {\r\n bubbles: true,\r\n });\r\n document.dispatchEvent(scroll);\r\n // 模拟滑动\r\n const mousemove = new MouseEvent('mousemove', {\r\n bubbles: true,\r\n });\r\n document.dispatchEvent(mousemove);\r\n // 模拟点击\r\n const click = new Event('click', {\r\n bubbles: true,\r\n });\r\n document.dispatchEvent(click);\r\n }\r\n });\r\n // 倒计时结束\r\n await tip.waitCountDown();\r\n // 关闭任务窗口\r\n handleCloseTaskWin();\r\n}\r\n/**\r\n * @description 获取新闻列表\r\n */\r\nasync function getNews() {\r\n // 需要学习的新闻数量\r\n const need = taskConfig[TaskType.READ].need < maxNewsNum\r\n ? taskConfig[TaskType.READ].need\r\n : maxNewsNum;\r\n log(`剩余 ${need} 个新闻`);\r\n // 获取新闻\r\n const data = await getNewsList();\r\n if (data && data.length) {\r\n // 索引\r\n let i = 0;\r\n // 最新新闻\r\n const latestItems = data.slice(0, 100);\r\n // 当前年份\r\n const currentYear = new Date().getFullYear().toString();\r\n // 查找今年新闻\r\n while (i < need) {\r\n const randomIndex = ~~(Math.random() * latestItems.length);\r\n // 新闻\r\n const item = latestItems[randomIndex];\r\n // 是否存在\r\n if (item.publishTime.startsWith(currentYear) && item.type === 'tuwen') {\r\n news[i] = item;\r\n i++;\r\n }\r\n }\r\n }\r\n else {\r\n news = [];\r\n }\r\n}\r\n/**\r\n * @description 获取视频列表\r\n */\r\nasync function getVideos() {\r\n // 需要学习的视频数量\r\n const need = taskConfig[TaskType.WATCH].need < maxVideoNum\r\n ? taskConfig[TaskType.WATCH].need\r\n : maxVideoNum;\r\n log(`剩余 ${need} 个视频`);\r\n // 获取视频\r\n const data = await getVideoList();\r\n if (data && data.length) {\r\n // 索引\r\n let i = 0;\r\n // 最新视频\r\n const latestItems = data.slice(0, 100);\r\n // 当前年份\r\n const currentYear = new Date().getFullYear().toString();\r\n // 查找今年视频\r\n while (i < need) {\r\n const randomIndex = ~~(Math.random() * latestItems.length);\r\n // 新闻\r\n const item = latestItems[randomIndex];\r\n // 是否存在\r\n if (item.publishTime.startsWith(currentYear) &&\r\n (item.type === 'shipin' || item.type === 'juji')) {\r\n videos[i] = item;\r\n i++;\r\n }\r\n }\r\n }\r\n else {\r\n videos = [];\r\n }\r\n}\r\n/**\r\n * @description 阅读文章\r\n */\r\nasync function readNews() {\r\n // 获取文章\r\n await getNews();\r\n // 观看文章\r\n for (const i in news) {\r\n // 任务关闭跳出循环\r\n if (!taskConfig[TaskType.READ].active) {\r\n return;\r\n }\r\n // 暂停\r\n await studyPauseLock();\r\n log(`正在阅读第 ${Number(i) + 1} 个新闻...`);\r\n // 创建提示\r\n createTip(`正在阅读第 ${Number(i) + 1} 个新闻`);\r\n // 链接\r\n const { url } = news[i];\r\n // 链接\r\n GM_setValue('readingUrl', url);\r\n // 等待任务窗口\r\n await waitTaskWin(url, '文章选读');\r\n // 清空链接\r\n GM_setValue('readingUrl', null);\r\n // 创建提示\r\n createTip(`完成阅读第 ${Number(i) + 1} 个新闻!`);\r\n // 等待一段时间\r\n await sleep(1500);\r\n // 刷新分数数据\r\n await refreshScoreInfo();\r\n // 刷新任务数据\r\n await refreshTaskList();\r\n // 任务完成跳出循环\r\n if (taskConfig[TaskType.READ].active && taskConfig[TaskType.READ].status) {\r\n break;\r\n }\r\n }\r\n // 任务关闭跳出循环\r\n if (!taskConfig[TaskType.READ].active) {\r\n return;\r\n }\r\n // 任务完成状况\r\n if (taskConfig[TaskType.READ].active && !taskConfig[TaskType.READ].status) {\r\n log('任务未完成, 继续阅读新闻!');\r\n // 创建提示\r\n createTip('任务未完成, 继续阅读新闻!');\r\n await readNews();\r\n }\r\n}\r\n/**\r\n * @description 观看视频\r\n */\r\nasync function watchVideo() {\r\n // 获取视频\r\n await getVideos();\r\n // 观看视频\r\n for (const i in videos) {\r\n // 任务关闭跳出循环\r\n if (!taskConfig[TaskType.WATCH].active) {\r\n return;\r\n }\r\n // 暂停\r\n await studyPauseLock();\r\n log(`正在观看第 ${Number(i) + 1} 个视频...`);\r\n // 创建提示\r\n createTip(`正在观看第 ${Number(i) + 1} 个视频`);\r\n // 链接\r\n const { url } = videos[i];\r\n // 链接\r\n GM_setValue('watchingUrl', url);\r\n // 等待任务窗口\r\n await waitTaskWin(url, '视听学习');\r\n // 清空链接\r\n GM_setValue('watchingUrl', null);\r\n // 创建提示\r\n createTip(`完成观看第 ${Number(i) + 1} 个视频!`);\r\n // 等待一段时间\r\n await sleep(1500);\r\n // 刷新分数数据\r\n await refreshScoreInfo();\r\n // 刷新任务数据\r\n await refreshTaskList();\r\n // 任务完成跳出循环\r\n if (taskConfig[TaskType.WATCH].active &&\r\n taskConfig[TaskType.WATCH].status) {\r\n break;\r\n }\r\n }\r\n // 任务关闭跳出循环\r\n if (!taskConfig[TaskType.WATCH].active) {\r\n return;\r\n }\r\n // 任务完成状况\r\n if (taskConfig[TaskType.WATCH].active && !taskConfig[TaskType.WATCH].status) {\r\n log('任务未完成, 继续观看视频!');\r\n // 创建提示\r\n createTip('任务未完成, 继续观看看视频!');\r\n await watchVideo();\r\n }\r\n}\r\n\r\n","from":"src\\controller\\readAndWatch.ts","to":"readAndWatch.js"},"src\\controller\\schedule.ts":{"timeStamp":"2023-02-25T03:17:29.804Z","data":"/**\r\n * @description 定时刷新定时器\r\n */\r\nlet scheduleTimer = -1;\r\n/**\r\n * @description 刷新定时任务\r\n */\r\nasync function refreshScheduleTask() {\r\n // 清除定时刷新\r\n clearInterval(scheduleTimer);\r\n // 未登录\r\n if (!login.value) {\r\n // 剩余定时任务\r\n const restList = scheduleList.filter((s) => !isLate(s));\r\n // 存在剩余任务\r\n if (restList.length) {\r\n const rest = restList[0];\r\n log(`已设置 ${rest.time} 的定时任务!`);\r\n // 提示\r\n createTip(`已设置 ${rest.time} 的定时任务!`);\r\n // 时间\r\n let time = 0;\r\n // 刷新间隔\r\n const interval = 10;\r\n scheduleTimer = setInterval(() => {\r\n if (!(time++ % interval)) {\r\n log('定时刷新正在运行...');\r\n }\r\n // 到达定时\r\n if (isNow(rest)) {\r\n clearInterval(scheduleTimer);\r\n log(`执行 ${rest.time} 的定时任务!`);\r\n // 提示\r\n createTip(`执行 ${rest.time} 的定时任务!`);\r\n // 登录\r\n handleLogin();\r\n }\r\n }, 1000);\r\n }\r\n }\r\n}\r\n/**\r\n * @description 清除定时\r\n */\r\nfunction clearScheduleTask() {\r\n clearInterval(scheduleTimer);\r\n}\r\n\r\n","from":"src\\controller\\schedule.ts","to":"schedule.js"},"src\\controller\\tip.ts":{"timeStamp":"2023-06-03T02:54:53.972Z","data":"/**\r\n * @description 创建学习提示\r\n */\r\nfunction createTip(text, delay = 2, countShow = false, callback) {\r\n const tipWrap = $$('.egg_tip_wrap')[0];\r\n // 提前去除\r\n const tips = $$('.egg_tip');\r\n if (tips.length) {\r\n tips.forEach((t) => t.delay());\r\n }\r\n // 延迟\r\n const delayCount = ref(delay);\r\n // 文字\r\n const textContent = ref(text);\r\n //显示\r\n const show = ref(false);\r\n // 延迟显示\r\n const delayShow = ref(false);\r\n // 销毁\r\n let destroyed = false;\r\n // 倒计时结束\r\n let done = false;\r\n // 提示\r\n const tip = Tip({\r\n text: textContent,\r\n count: delayCount,\r\n show,\r\n delayShow,\r\n countShow: ref(countShow),\r\n callback: async (count) => {\r\n callback && (await callback(count));\r\n // 恢复显示\r\n if (delayShow.value && count === delay) {\r\n delayShow.value = false;\r\n }\r\n // 倒计时结束\r\n if (count <= 0) {\r\n done = true;\r\n operate.destroy();\r\n }\r\n },\r\n });\r\n // 操作\r\n const operate = {\r\n destroy() {\r\n if (!destroyed) {\r\n // 隐藏\r\n operate.hide();\r\n // 销毁\r\n destroyed = true;\r\n return new Promise((resolve) => {\r\n setTimeout(() => {\r\n tip.ele.remove();\r\n resolve(undefined);\r\n }, 300);\r\n });\r\n }\r\n },\r\n hide() {\r\n if (!destroyed) {\r\n show.value = false;\r\n }\r\n },\r\n show() {\r\n if (!destroyed) {\r\n return new Promise((resolve) => {\r\n setTimeout(() => {\r\n show.value = true;\r\n resolve(undefined);\r\n }, 300);\r\n });\r\n }\r\n },\r\n setText(text) {\r\n if (!destroyed) {\r\n textContent.value = text;\r\n }\r\n },\r\n waitCountDown() {\r\n return new Promise((resolve) => {\r\n // 计时器\r\n const timer = setInterval(() => {\r\n // 结束\r\n if (done) {\r\n clearInterval(timer);\r\n resolve(true);\r\n }\r\n }, 100);\r\n });\r\n },\r\n delay() {\r\n if (!destroyed) {\r\n delayShow.value = true;\r\n delayCount.value += 2;\r\n }\r\n },\r\n };\r\n Object.assign(tip.ele, operate);\r\n // 插入节点\r\n mountElement(tip, tipWrap);\r\n // 显示\r\n operate.show();\r\n return operate;\r\n}\r\n\r\n","from":"src\\controller\\tip.ts","to":"tip.js"},"src\\controller\\user.ts":{"timeStamp":"2023-07-04T09:34:59.201Z","data":"/**\r\n * @description 刷新用户信息\r\n */\r\nasync function refreshUserInfo() {\r\n // 未登录\r\n if (!login.value) {\r\n throw new Error('用户未登录!');\r\n }\r\n // 已存在信息\r\n if (userinfo.nick) {\r\n return true;\r\n }\r\n log('加载用户信息...');\r\n // 获取用户信息\r\n const res = await getUserInfo();\r\n if (res) {\r\n const { avatarMediaUrl = '', nick: nickRes } = res;\r\n if (nickRes) {\r\n // 设置昵称\r\n userinfo.nick = nickRes;\r\n // 设置头像\r\n userinfo.avatar = avatarMediaUrl;\r\n return true;\r\n }\r\n }\r\n log('加载用户信息失败!');\r\n return false;\r\n}\r\n/**\r\n * @description 刷新分数信息\r\n */\r\nasync function refreshScoreInfo() {\r\n // 未登录\r\n if (!login.value) {\r\n throw new Error('用户未登录!');\r\n }\r\n log('加载分数信息...');\r\n // 获取总分\r\n const totalScoreRes = await getTotalScore();\r\n // 获取当天总分\r\n const todayScoreRes = await getTodayScore();\r\n // 整数值\r\n if (Number.isInteger(totalScoreRes) && Number.isInteger(todayScoreRes)) {\r\n // 设置分数\r\n totalScore.value = totalScoreRes;\r\n todayScore.value = todayScoreRes;\r\n return true;\r\n }\r\n log('加载分数信息失败!');\r\n return false;\r\n}\r\n/**\r\n * @description 刷新任务列表\r\n */\r\nasync function refreshTaskList() {\r\n // 未登录\r\n if (!login.value) {\r\n throw new Error('用户未登录!');\r\n }\r\n log('加载任务进度...');\r\n // 原始任务进度\r\n const taskProgress = await getTaskList();\r\n if (taskProgress) {\r\n // 登录\r\n taskConfig[TaskType.LOGIN].currentScore = taskProgress[2].currentScore;\r\n taskConfig[TaskType.LOGIN].dayMaxScore = taskProgress[2].dayMaxScore;\r\n taskConfig[TaskType.LOGIN].need =\r\n taskProgress[2].dayMaxScore - taskProgress[2].currentScore;\r\n // 文章选读\r\n taskConfig[TaskType.READ].currentScore = taskProgress[0].currentScore;\r\n taskConfig[TaskType.READ].dayMaxScore = taskProgress[0].dayMaxScore;\r\n taskConfig[TaskType.READ].need =\r\n taskProgress[0].dayMaxScore - taskProgress[0].currentScore;\r\n // 视听学习\r\n taskConfig[TaskType.WATCH].currentScore = taskProgress[1].currentScore;\r\n taskConfig[TaskType.WATCH].dayMaxScore = taskProgress[1].dayMaxScore;\r\n taskConfig[TaskType.WATCH].need =\r\n taskProgress[1].dayMaxScore - taskProgress[1].currentScore;\r\n // 每日答题\r\n taskConfig[TaskType.PRACTICE].currentScore = taskProgress[3].currentScore;\r\n taskConfig[TaskType.PRACTICE].dayMaxScore = taskProgress[3].dayMaxScore;\r\n taskConfig[TaskType.PRACTICE].need = taskProgress[3].dayMaxScore;\r\n // 更新数据\r\n for (const i in taskConfig) {\r\n const { currentScore, dayMaxScore } = taskConfig[i];\r\n // 进度\r\n const rate = Number(((100 * currentScore) / dayMaxScore).toFixed(1));\r\n // 分数\r\n taskConfig[i].score = currentScore;\r\n // 完成状态\r\n taskConfig[i].status = rate === 100;\r\n }\r\n return;\r\n }\r\n // 重试\r\n await sleep(2000);\r\n refreshTaskList();\r\n return;\r\n}\r\n\r\n","from":"src\\controller\\user.ts","to":"user.js"},"src\\component\\Tip.ts":{"timeStamp":"2023-03-08T03:09:22.868Z","data":"function Tip({ text, count, show, delayShow, countShow, callback, }) {\r\n return createElementNode('div', undefined, {\r\n class: watchRef([show, delayShow], () => `egg_tip${show.value ? (delayShow.value ? ' active delay' : ' active') : ''}`),\r\n }, [\r\n createElementNode('span', undefined, {\r\n class: 'egg_text',\r\n }, createTextNode(text)),\r\n watchEffectRef(() => countShow.value\r\n ? createElementNode('span', undefined, {\r\n class: 'egg_countdown',\r\n }, createTextNode(watchEffectRef(() => `${count.value}s`)))\r\n : undefined),\r\n ], {\r\n onMounted() {\r\n // 倒计时\r\n const countDown = async () => {\r\n // 倒计时回调\r\n await callback(count.value);\r\n // 倒计时结束\r\n if (!count.value) {\r\n show.value = false;\r\n return;\r\n }\r\n count.value--;\r\n setTimeout(countDown, 1000);\r\n };\r\n countDown();\r\n },\r\n });\r\n}\r\n\r\n","from":"src\\component\\Tip.ts","to":"Tip.js"},"src\\component\\Hr.ts":{"timeStamp":"2023-02-17T10:07:48.523Z","data":"/**\r\n * @description 分隔符\r\n * @returns\r\n */\r\nfunction Hr({ text }) {\r\n return createElementNode('div', undefined, {\r\n class: 'egg_hr_wrap',\r\n }, [\r\n createElementNode('div', undefined, { class: 'egg_hr' }),\r\n createElementNode('div', undefined, { class: 'egg_hr_title' }, createTextNode(text)),\r\n createElementNode('div', undefined, { class: 'egg_hr' }),\r\n ]);\r\n}\r\n\r\n","from":"src\\component\\Hr.ts","to":"Hr.js"},"src\\component\\Select.ts":{"timeStamp":"2023-03-08T14:04:23.134Z","data":"function Select({ data, maxlength, placeholder = '', onchange, onblur, value, keep, }) {\r\n const selectData = reactive(data.map((v) => ({ selected: false, active: false, ele: undefined, ...v })));\r\n const focus = ref(false);\r\n const input = shallowRef(undefined);\r\n const list = shallowRef(undefined);\r\n const valueRef = ref('');\r\n value &&\r\n watch(value, () => {\r\n const item = selectData.find((v) => v.value === value.value);\r\n valueRef.value = item ? item.label : '';\r\n if (!item) {\r\n selectData.forEach((v) => (v.selected = false));\r\n list.value && (list.value.scrollTop = 0);\r\n }\r\n }, true);\r\n return createElementNode('div', undefined, {\r\n class: 'egg_select',\r\n }, [\r\n createElementNode('input', { value: valueRef }, {\r\n class: 'egg_select_input',\r\n type: 'text',\r\n placeholder,\r\n maxlength,\r\n ref: input,\r\n onfocus() {\r\n if (list.value && input.value) {\r\n focus.value = true;\r\n if (input.value.value && valueRef.value) {\r\n const index = selectData.findIndex((v) => v.label === valueRef.value);\r\n if (index + 1) {\r\n list.value.scrollTop = selectData[index].ele?.offsetTop || 0;\r\n selectData.forEach((v, i) => (v.selected = i === index));\r\n }\r\n return;\r\n }\r\n }\r\n },\r\n oninput() {\r\n if (list.value && input.value) {\r\n const { value } = input.value;\r\n // 文本存在\r\n if (value) {\r\n const index = selectData.findIndex((v) => v.label.includes(value));\r\n // 存在匹配\r\n if (index + 1) {\r\n list.value.scrollTop = selectData[index].ele?.offsetTop || 0;\r\n selectData.forEach((v, i) => {\r\n v.active = i === index;\r\n v.active &&\r\n setTimeout(() => {\r\n v.active = false;\r\n }, 300);\r\n });\r\n }\r\n return;\r\n }\r\n // 清除\r\n selectData.forEach((v) => (v.active = v.selected = false));\r\n list.value.scrollTop = 0;\r\n }\r\n },\r\n onblur() {\r\n if (list.value && input.value) {\r\n const item = selectData.find((v) => v.selected);\r\n // 关闭选项\r\n if (item || !input.value.value) {\r\n setTimeout(() => {\r\n focus.value = false;\r\n }, 100);\r\n }\r\n // 恢复文本\r\n if (item && input.value.value !== item.label) {\r\n input.value.value = item.label;\r\n }\r\n // 保留文本\r\n if (!item && keep) {\r\n input.value.value = valueRef.value;\r\n }\r\n onblur &&\r\n onblur(item ? { label: item.label, value: item.value } : undefined);\r\n }\r\n },\r\n }),\r\n createElementNode('div', undefined, {\r\n class: watchEffectRef(() => `egg_select_list${focus.value ? '' : ' hide'}`),\r\n ref: list,\r\n }, selectData.map((v, index) => createElementNode('div', undefined, {\r\n class: watchRef(() => [v.selected, v.active], () => `egg_select_item${v.selected ? ' selected' : v.active ? ' active' : ''}`),\r\n ref: (e) => (v.ele = e),\r\n onclick: debounce(() => {\r\n if (valueRef.value !== v.label) {\r\n onchange && onchange({ label: v.label, value: v.value });\r\n selectData.forEach((v, i) => {\r\n v.selected = i === index;\r\n v.selected && (valueRef.value = v.label);\r\n });\r\n }\r\n focus.value = false;\r\n }, 300),\r\n }, createTextNode(v.label)))),\r\n ]);\r\n}\r\n\r\n","from":"src\\component\\Select.ts","to":"Select.js"},"src\\component\\ExamBtn.ts":{"timeStamp":"2023-07-12T06:10:48.404Z","data":"/**\r\n * @description 答题按钮\r\n */\r\nfunction ExamBtn() {\r\n // 设置初始状态\r\n watchEffect(() => (examPause.value = !settings[SettingType.AUTO_ANSWER]));\r\n return createElementNode('button', undefined, {\r\n class: watchEffectRef(() => `egg_exam_btn${examPause.value ? ' manual' : ''}`),\r\n type: 'button',\r\n onclick(e) {\r\n e.stopPropagation();\r\n examPause.value = !examPause.value;\r\n },\r\n onmousedown(e) {\r\n e.stopPropagation();\r\n },\r\n onmousemove(e) {\r\n e.stopPropagation();\r\n },\r\n onmouseup(e) {\r\n e.stopPropagation();\r\n },\r\n onmouseenter(e) {\r\n e.stopPropagation();\r\n },\r\n onmouseleave(e) {\r\n e.stopPropagation();\r\n },\r\n onmouseover(e) {\r\n e.stopPropagation();\r\n },\r\n ontouchstart(e) {\r\n e.stopPropagation();\r\n },\r\n ontouchmove(e) {\r\n e.stopPropagation();\r\n },\r\n ontouchend(e) {\r\n e.stopPropagation();\r\n },\r\n oninput(e) {\r\n e.stopPropagation();\r\n },\r\n onchange(e) {\r\n e.stopPropagation();\r\n },\r\n onblur(e) {\r\n e.stopPropagation();\r\n },\r\n }, createTextNode(watchEffectRef(() => `${examPause.value ? '开启自动答题' : '关闭自动答题'}`)));\r\n}\r\n\r\n","from":"src\\component\\ExamBtn.ts","to":"ExamBtn.js"},"src\\component\\Frame.ts":{"timeStamp":"2023-07-13T13:32:54.161Z","data":"/**\r\n * @description 任务窗口\r\n * @returns\r\n */\r\nfunction Frame() {\r\n // 最大化\r\n const max = ref(false);\r\n // 容器\r\n return createElementNode('div', undefined, {\r\n class: watchEffectRef(() => `egg_frame_wrap${frame.show ? '' : ' hide'}`),\r\n onclick(e) {\r\n e.stopPropagation();\r\n },\r\n onmousedown(e) {\r\n e.stopPropagation();\r\n },\r\n onmousemove(e) {\r\n e.stopPropagation();\r\n },\r\n onmouseup(e) {\r\n e.stopPropagation();\r\n },\r\n onmouseenter(e) {\r\n e.stopPropagation();\r\n },\r\n onmouseleave(e) {\r\n e.stopPropagation();\r\n },\r\n onmouseover(e) {\r\n e.stopPropagation();\r\n },\r\n ontouchstart(e) {\r\n e.stopPropagation();\r\n },\r\n ontouchmove(e) {\r\n e.stopPropagation();\r\n },\r\n ontouchend(e) {\r\n e.stopPropagation();\r\n },\r\n oninput(e) {\r\n e.stopPropagation();\r\n },\r\n onchange(e) {\r\n e.stopPropagation();\r\n },\r\n onblur(e) {\r\n e.stopPropagation();\r\n },\r\n }, watchRef(() => [login.value, settings[SettingType.SAME_TAB]], () => {\r\n // 同屏任务\r\n if (login.value && settings[SettingType.SAME_TAB]) {\r\n return [\r\n // 遮罩\r\n createElementNode('div', undefined, { class: 'egg_frame_mask' }),\r\n // 窗口内容\r\n createElementNode('div', undefined, {\r\n class: watchEffectRef(() => `egg_frame_content_wrap ${max.value ? ' max' : ''}`),\r\n }, [\r\n // 窗口控制\r\n createElementNode('div', undefined, { class: 'egg_frame_controls_wrap' }, [\r\n // 标题\r\n createElementNode('div', undefined, {\r\n class: 'egg_frame_title',\r\n }),\r\n createElementNode('div', undefined, {\r\n class: 'egg_frame_controls',\r\n }, [\r\n // 隐藏\r\n createElementNode('button', undefined, {\r\n class: 'egg_frame_btn',\r\n type: 'button',\r\n title: '隐藏',\r\n onclick: debounce(() => {\r\n // 隐藏窗口\r\n frame.show = false;\r\n }, 300),\r\n }, createNSElementNode('svg', undefined, {\r\n viewBox: '0 0 1024 1024',\r\n class: 'egg_icon',\r\n }, createNSElementNode('path', undefined, {\r\n d: 'M863.7 552.5H160.3c-10.6 0-19.2-8.6-19.2-19.2v-41.7c0-10.6 8.6-19.2 19.2-19.2h703.3c10.6 0 19.2 8.6 19.2 19.2v41.7c0 10.6-8.5 19.2-19.1 19.2z',\r\n }))),\r\n // 改变大小\r\n createElementNode('button', undefined, {\r\n class: 'egg_frame_btn',\r\n type: 'button',\r\n title: '缩放',\r\n onclick: debounce(() => {\r\n max.value = !max.value;\r\n }, 300),\r\n }, createNSElementNode('svg', undefined, {\r\n viewBox: '0 0 1024 1024',\r\n class: 'egg_icon',\r\n }, createNSElementNode('path', undefined, {\r\n d: 'M609.52 584.92a35.309 35.309 0 0 1 24.98-10.36c9.37 0 18.36 3.73 24.98 10.36l189.29 189.22-0.07-114.3 0.57-6.35c3.25-17.98 19.7-30.5 37.9-28.85 18.2 1.65 32.12 16.92 32.09 35.2v200.23c-0.05 1.49-0.19 2.97-0.42 4.45l-0.21 1.13c-0.22 1.44-0.55 2.85-0.99 4.24l-0.57 1.62-0.56 1.41a34.163 34.163 0 0 1-7.62 11.36l2.12-2.4-0.14 0.14-0.92 1.06-1.06 1.2-0.57 0.57-0.56 0.57a36.378 36.378 0 0 1-16.23 8.39l-3.53 0.5-4.02 0.35h-199.6l-6.35-0.63c-16.73-3.06-28.9-17.63-28.93-34.64l0.56-6.35c3.07-16.76 17.67-28.93 34.71-28.92l114.29-0.14-189.07-189.1-4.09-4.94c-9.71-14.01-8.01-32.95 4.02-45.02z m-162.06 0c12.06 12.05 13.78 30.99 4.09 45.01l-4.09 4.94-189.15 189.08 114.3 0.14c17.04-0.01 31.65 12.17 34.71 28.92l0.57 6.35c-0.03 17.01-12.19 31.58-28.92 34.64l-6.35 0.63H173.09l-4.23-0.42-3.39-0.49a36.38 36.38 0 0 1-17.36-9.52l-1.06-1.13-0.98-1.13 0.98 1.06-1.97-2.26 0.85 1.06-0.42-0.56a35.137 35.137 0 0 1-3.74-5.64l-1.13-2.68a34.71 34.71 0 0 1-2.11-7.33l-0.28-1.13c-0.21-1.47-0.33-2.96-0.36-4.45V659.78c-0.03-18.28 13.89-33.55 32.09-35.2 18.2-1.65 34.65 10.87 37.9 28.85l0.57 6.35-0.07 114.36 189.29-189.22c13.77-13.77 36.11-13.77 49.88 0h-0.09z m-74.71-471.71l6.35 0.57c16.76 3.06 28.93 17.67 28.92 34.71l-0.63 6.35c-3.07 16.76-17.67 28.93-34.71 28.92l-114.3 0.14 189.15 189.08 4.09 4.94c10.26 15.02 7.42 35.37-6.55 47.01-13.98 11.63-34.51 10.74-47.42-2.07L208.29 233.71l0.07 114.3-0.57 6.35c-3.25 17.98-19.7 30.5-37.9 28.85-18.2-1.65-32.12-16.92-32.09-35.2V147.78c0-1.55 0.14-3.03 0.35-4.51l0.21-1.13c0.24-1.44 0.59-2.85 1.06-4.23a34.97 34.97 0 0 1 8.68-14.39l-2.12 2.4-0.42 0.57 1.55-1.84-0.99 1.06 0.92-0.98 2.26-2.33c3.04-2.73 6.52-4.92 10.3-6.49l2.82-1.06c3.45-1.07 7.04-1.62 10.65-1.62l-3.6 0.14h0.49l1.48-0.14h201.31z m512.91 0l1.41 0.14h0.42c2.43 0.29 4.84 0.79 7.19 1.48l2.82 1.06 2.61 1.2 3.04 1.76c2.09 1.33 4.03 2.89 5.78 4.66l1.13 1.2 0.78 0.98 0.21 0.14 0.49 0.64 2.33 3.17c2.35 3.83 3.98 8.07 4.8 12.49l0.21 1.13c0.21 1.48 0.35 2.96 0.35 4.44v200.37c-0.16 18.13-14.03 33.19-32.08 34.83-18.06 1.64-34.42-10.67-37.83-28.48l-0.57-6.35V233.65L659.54 422.87c-12.9 12.95-33.56 13.91-47.59 2.2-14.04-11.71-16.81-32.2-6.38-47.22l4.02-4.86 189.22-189.08-114.29-0.14c-17.06 0.04-31.71-12.14-34.78-28.92l-0.63-6.35c-0.01-17.04 12.16-31.65 28.93-34.71l6.35-0.57h201.27z m0 0',\r\n }))),\r\n // 关闭\r\n createElementNode('button', undefined, {\r\n class: 'egg_frame_btn',\r\n type: 'button',\r\n title: '关闭',\r\n onclick: debounce(() => {\r\n // 关闭窗口\r\n closeFrame();\r\n }, 300),\r\n }, createNSElementNode('svg', undefined, {\r\n viewBox: '0 0 1024 1024',\r\n class: 'egg_icon',\r\n }, createNSElementNode('path', undefined, {\r\n d: 'M453.44 512L161.472 220.032a41.408 41.408 0 0 1 58.56-58.56L512 453.44 803.968 161.472a41.408 41.408 0 0 1 58.56 58.56L570.56 512l291.968 291.968a41.408 41.408 0 0 1-58.56 58.56L512 570.56 220.032 862.528a41.408 41.408 0 0 1-58.56-58.56L453.44 512z',\r\n }))),\r\n ]),\r\n ]),\r\n // 窗口内容\r\n createElementNode('div', undefined, {\r\n class: 'egg_frame_content',\r\n }, watchEffectRef(() => frame.src\r\n ? [\r\n createElementNode('iframe', undefined, {\r\n class: 'egg_frame',\r\n src: frame.src,\r\n ref(ele) {\r\n frame.ele = ele;\r\n },\r\n }, undefined),\r\n ]\r\n : undefined)),\r\n ], {\r\n onMounted() {\r\n // 隐藏窗口\r\n watch(() => [\r\n taskStatus.value,\r\n running.value,\r\n settings[SettingType.SAME_TAB],\r\n settings[SettingType.SILENT_RUN],\r\n ], () => {\r\n // 同屏任务\r\n if (settings[SettingType.SAME_TAB] &&\r\n (taskStatus.value === TaskStatusType.START ||\r\n taskStatus.value === TaskStatusType.PAUSE ||\r\n running.value)) {\r\n // 设置窗口显示\r\n frame.show = !settings[SettingType.SILENT_RUN];\r\n }\r\n });\r\n },\r\n }),\r\n ];\r\n }\r\n }), {\r\n onMounted() {\r\n // 关闭窗口\r\n watch(() => [login.value, settings[SettingType.SAME_TAB]], () => {\r\n if (login.value) {\r\n if (settings[SettingType.SAME_TAB]) {\r\n frame.exist = true;\r\n closeWin();\r\n }\r\n else {\r\n closeFrame();\r\n frame.exist = false;\r\n }\r\n }\r\n else {\r\n closeWin();\r\n closeFrame();\r\n frame.exist = false;\r\n }\r\n });\r\n },\r\n });\r\n}\r\n\r\n","from":"src\\component\\Frame.ts","to":"Frame.js"},"src\\component\\LoginItem.ts":{"timeStamp":"2023-03-04T06:24:38.622Z","data":"/**\r\n * @description 登录\r\n */\r\nfunction LoginItem() {\r\n return watchEffectRef(() => {\r\n return login.value\r\n ? undefined\r\n : createElementNode('div', undefined, {\r\n class: 'egg_login_item',\r\n }, [\r\n // 登录按钮\r\n createElementNode('button', undefined, {\r\n type: 'button',\r\n class: 'egg_login_btn',\r\n onclick: debounce(async () => {\r\n // 开始登录\r\n handleLogin();\r\n }, 300),\r\n }, createTextNode('扫码登录')),\r\n // 窗口\r\n createElementNode('div', undefined, {\r\n class: watchEffectRef(() => `egg_login_img_wrap${loginQRCodeShow.value ? ' active' : ''}`),\r\n }, createElementNode('img', undefined, {\r\n class: 'egg_login_img',\r\n })),\r\n ], {\r\n onMounted() {\r\n watch(() => settings[SettingType.SCHEDULE_RUN], () => {\r\n // 未开启定时展示二维码\r\n if (!settings[SettingType.SCHEDULE_RUN]) {\r\n // 开始登录\r\n handleLogin();\r\n }\r\n }, true);\r\n },\r\n });\r\n });\r\n}\r\n\r\n","from":"src\\component\\LoginItem.ts","to":"LoginItem.js"},"src\\component\\InfoItem.ts":{"timeStamp":"2023-02-22T15:18:21.583Z","data":"/**\r\n * @description 信息\r\n * @returns\r\n */\r\nfunction InfoItem() {\r\n return watchEffectRef(() => {\r\n if (login.value) {\r\n return createElementNode('div', undefined, {\r\n class: 'egg_info_item',\r\n }, [\r\n // 用户信息\r\n createElementNode('div', undefined, { class: 'egg_userinfo' }, [\r\n // 头像\r\n createElementNode('div', undefined, { class: 'egg_avatar' }, watchEffectRef(() => {\r\n return [\r\n userinfo.avatar\r\n ? createElementNode('img', undefined, {\r\n src: userinfo.avatar,\r\n class: 'egg_avatar_img',\r\n })\r\n : createElementNode('div', undefined, {\r\n class: 'egg_avatar_nick',\r\n }, createTextNode(watchEffectRef(() => userinfo.nick.substring(1, 3)))),\r\n ];\r\n })),\r\n // 昵称\r\n createElementNode('div', undefined, { class: 'egg_nick' }, createTextNode(watchEffectRef(() => userinfo.nick))),\r\n ]),\r\n // 退出按钮\r\n createElementNode('button', undefined, {\r\n type: 'button',\r\n class: 'egg_login_btn',\r\n onclick: debounce(() => {\r\n // 退出登录\r\n handleLogout();\r\n }, 300),\r\n }, createTextNode('退出')),\r\n ], {\r\n onMounted() {\r\n // 刷新用户信息\r\n refreshUserInfo();\r\n },\r\n });\r\n }\r\n });\r\n}\r\n\r\n","from":"src\\component\\InfoItem.ts","to":"InfoItem.js"},"src\\component\\ScoreItem.ts":{"timeStamp":"2023-06-02T03:32:53.159Z","data":"/**\r\n * @description 分数详情\r\n */\r\nfunction ScoreItem() {\r\n return watchEffectRef(() => {\r\n if (login.value) {\r\n // 分数显示\r\n const scoreShow = ref(false);\r\n // 分数信息\r\n return createElementNode('div', undefined, {\r\n class: 'egg_score_item',\r\n }, createElementNode('div', undefined, { class: 'egg_scoreinfo' }, [\r\n createElementNode('div', undefined, {\r\n class: 'egg_totalscore',\r\n }, [\r\n createTextNode('总积分'),\r\n createElementNode('span', undefined, undefined, createTextNode(totalScore)),\r\n ]),\r\n createElementNode('div', undefined, {\r\n class: 'egg_todayscore',\r\n }, [\r\n createElementNode('button', undefined, {\r\n type: 'button',\r\n class: 'egg_todayscore_btn',\r\n title: '查看分数详情',\r\n onclick: debounce(() => {\r\n scoreShow.value = !scoreShow.value;\r\n }, 300),\r\n onblur: () => {\r\n scoreShow.value = false;\r\n },\r\n }, [\r\n createTextNode('当天分数'),\r\n // 当天分数\r\n createElementNode('span', undefined, undefined, createTextNode(todayScore)),\r\n // icon\r\n createNSElementNode('svg', undefined, {\r\n viewBox: '0 0 1024 1024',\r\n class: 'egg_icon',\r\n }, createNSElementNode('path', undefined, {\r\n d: 'M332.16 883.84a40.96 40.96 0 0 0 58.24 0l338.56-343.04a40.96 40.96 0 0 0 0-58.24L390.4 140.16a40.96 40.96 0 0 0-58.24 58.24L640 512l-307.84 314.24a40.96 40.96 0 0 0 0 57.6z',\r\n })),\r\n createElementNode('div', undefined, {\r\n class: watchEffectRef(() => `egg_score_details${scoreShow.value ? '' : ' hide'}`),\r\n }, [\r\n createElementNode('div', undefined, { class: 'egg_score_title' }, [\r\n createNSElementNode('svg', undefined, {\r\n viewBox: '0 0 1024 1024',\r\n class: 'egg_icon',\r\n }, [\r\n createNSElementNode('path', undefined, {\r\n d: 'M314.81 304.01h415.86v58.91H314.81zM314.81 440.24h415.86v58.91H314.81z',\r\n }),\r\n createNSElementNode('path', undefined, {\r\n d: 'M814.8 892.74h-8.64l-283.51-182-283.51 182h-8.64A69.85 69.85 0 0 1 160.72 823V188.22a69.85 69.85 0 0 1 69.77-69.77H814.8a69.85 69.85 0 0 1 69.77 69.77V823a69.85 69.85 0 0 1-69.77 69.74zM230.5 177.35a10.87 10.87 0 0 0-10.86 10.86V823a10.86 10.86 0 0 0 5 9.11l298.01-191.42 298.06 191.38a10.86 10.86 0 0 0 5-9.11V188.22a10.87 10.87 0 0 0-10.86-10.86z',\r\n }),\r\n ]),\r\n createElementNode('div', undefined, {\r\n class: 'egg_score_title_text',\r\n }, createTextNode('积分详情')),\r\n ]),\r\n ...taskConfig.map((task) => createElementNode('div', undefined, { class: 'egg_score_item' }, [\r\n createTextNode(task.title),\r\n createElementNode('span', undefined, {\r\n class: 'egg_score_detail',\r\n }, createTextNode(watchEffectRef(() => task.score))),\r\n ])),\r\n ]),\r\n ]),\r\n ]),\r\n ]), {\r\n onMounted() {\r\n // 刷新分数信息\r\n refreshScoreInfo();\r\n },\r\n });\r\n }\r\n });\r\n}\r\n\r\n","from":"src\\component\\ScoreItem.ts","to":"ScoreItem.js"},"src\\component\\NoramlItem.ts":{"timeStamp":"2023-07-14T10:51:00.944Z","data":"/**\r\n * @description 设置普通项\r\n * @returns\r\n */\r\nfunction NormalItem({ title, tip, checked, onchange, }) {\r\n return createElementNode('div', undefined, { class: 'egg_setting_item' }, [\r\n createElementNode('div', undefined, { class: 'egg_label_wrap' }, [\r\n createElementNode('label', undefined, { class: 'egg_task_title' }, [\r\n createTextNode(title),\r\n createElementNode('span', undefined, {\r\n class: 'egg_detail',\r\n title: tip,\r\n }, createTextNode('i')),\r\n ]),\r\n ]),\r\n createElementNode('input', undefined, {\r\n title: tip,\r\n class: 'egg_switch',\r\n type: 'checkbox',\r\n checked,\r\n onchange,\r\n }),\r\n ]);\r\n}\r\n\r\n","from":"src\\component\\NoramlItem.ts","to":"NoramlItem.js"},"src\\component\\TaskItem.ts":{"timeStamp":"2023-07-04T09:36:52.245Z","data":"/**\r\n * @description 设置任务项\r\n * @returns\r\n */\r\nfunction TaskItem({ title, tip, checked, currentScore, dayMaxScore, onchange, immutable, }) {\r\n return createElementNode('div', undefined, {\r\n class: 'egg_task_item',\r\n }, [\r\n createElementNode('div', undefined, { class: 'egg_label_wrap' }, [\r\n createElementNode('div', undefined, { class: 'egg_task_title_wrap' }, [\r\n createElementNode('div', undefined, { class: 'egg_task_title' }, createTextNode(title)),\r\n createElementNode('div', undefined, { class: 'egg_task_progress_wrap' }, [\r\n createElementNode('div', undefined, {\r\n class: 'egg_task_current',\r\n }, createTextNode(currentScore)),\r\n createElementNode('div', undefined, {\r\n class: 'egg_task_max',\r\n }, createTextNode(watchEffectRef(() => `/${dayMaxScore.value}`))),\r\n ]),\r\n ]),\r\n createElementNode('div', undefined, { class: 'egg_progress' }, [\r\n createElementNode('div', undefined, { class: 'egg_track' }, createElementNode('div', undefined, {\r\n class: 'egg_bar',\r\n style: watchEffectRef(() => `width: ${((100 * currentScore.value) /\r\n dayMaxScore.value).toFixed(1)}%;`),\r\n })),\r\n ]),\r\n ]),\r\n createElementNode('input', undefined, {\r\n title: tip,\r\n class: 'egg_switch',\r\n type: 'checkbox',\r\n checked,\r\n onchange,\r\n disabled: immutable,\r\n }),\r\n ]);\r\n}\r\n\r\n","from":"src\\component\\TaskItem.ts","to":"TaskItem.js"},"src\\component\\TaskList.ts":{"timeStamp":"2023-07-04T09:37:38.008Z","data":"/**\r\n * @description 任务\r\n */\r\nfunction TaskList() {\r\n // 处理任务设置变化\r\n const handleTaskChange = (e, type, title) => {\r\n // 开关\r\n const { checked } = e.target;\r\n if (taskConfig[type].active !== checked) {\r\n taskConfig[type].active = checked;\r\n // 设置\r\n GM_setValue('taskConfig', JSON.stringify(taskConfig));\r\n // 创建提示\r\n createTip(`${title} ${checked ? '打开' : '关闭'}!`);\r\n }\r\n };\r\n // 登录加载\r\n watch(login, async () => {\r\n if (login.value) {\r\n // 加载任务列表\r\n await refreshTaskList();\r\n // 未完成任务\r\n if (taskConfig.some((task) => task.active && !task.status)) {\r\n // 全局暂停\r\n GM_setValue('pauseStudy', false);\r\n // 加载完毕\r\n taskStatus.value = TaskStatusType.LOADED;\r\n return;\r\n }\r\n // 任务完毕\r\n taskStatus.value = TaskStatusType.FINISH;\r\n }\r\n }, true);\r\n return createElementNode('div', undefined, {\r\n class: 'egg_task_list',\r\n }, taskConfig.map((label) => label.immutable\r\n ? TaskItem({\r\n title: label.title,\r\n tip: label.tip,\r\n checked: watchEffectRef(() => label.active),\r\n currentScore: watchEffectRef(() => label.currentScore),\r\n dayMaxScore: watchEffectRef(() => label.dayMaxScore),\r\n onchange: debounce((e) => {\r\n handleTaskChange(e, label.type, label.title);\r\n }, 300),\r\n immutable: label.immutable,\r\n })\r\n : TaskItem({\r\n title: label.title,\r\n tip: label.tip,\r\n checked: watchEffectRef(() => label.active),\r\n currentScore: watchEffectRef(() => label.currentScore),\r\n dayMaxScore: watchEffectRef(() => label.dayMaxScore),\r\n onchange: debounce((e) => {\r\n handleTaskChange(e, label.type, label.title);\r\n }, 300),\r\n immutable: label.immutable,\r\n })));\r\n}\r\n\r\n","from":"src\\component\\TaskList.ts","to":"TaskList.js"},"src\\component\\TaskBtn.ts":{"timeStamp":"2023-07-13T12:00:01.869Z","data":"/**\r\n * @description 任务按钮\r\n */\r\nfunction TaskBtn() {\r\n return watchEffectRef(() => {\r\n if (login.value) {\r\n /**\r\n * @description 学习\r\n */\r\n async function study() {\r\n // 创建提示\r\n createTip('开始学习!');\r\n // 暂停\r\n await studyPauseLock();\r\n // 文章选读\r\n if (taskConfig[TaskType.READ].active &&\r\n !taskConfig[TaskType.READ].status) {\r\n log('任务一: 文章选读');\r\n // 创建提示\r\n createTip('任务一: 文章选读');\r\n // 暂停\r\n await studyPauseLock();\r\n // 看新闻\r\n await readNews();\r\n }\r\n log('任务一: 文章选读已完成!');\r\n // 视听学习\r\n if (taskConfig[TaskType.WATCH].active &&\r\n !taskConfig[TaskType.WATCH].status) {\r\n log('任务二: 视听学习');\r\n // 创建提示\r\n createTip('任务二: 视听学习');\r\n // 暂停\r\n await studyPauseLock();\r\n // 看视频\r\n await watchVideo();\r\n }\r\n log('任务二: 视听学习已完成!');\r\n // 每日答题\r\n if (taskConfig[TaskType.PRACTICE].active &&\r\n !taskConfig[TaskType.PRACTICE].status) {\r\n log('任务三: 每日答题');\r\n // 创建提示\r\n createTip('任务三: 每日答题');\r\n // 暂停\r\n await studyPauseLock();\r\n // 做每日答题\r\n await doExamPractice();\r\n }\r\n log('任务三: 每日答题已完成!');\r\n }\r\n /**\r\n * @description 暂停任务\r\n */\r\n function pauseTask() {\r\n // 全局暂停\r\n GM_setValue('pauseStudy', true);\r\n taskStatus.value = TaskStatusType.PAUSE;\r\n }\r\n /**\r\n * @description 继续任务\r\n */\r\n function continueTask() {\r\n // 全局暂停\r\n GM_setValue('pauseStudy', false);\r\n taskStatus.value = TaskStatusType.START;\r\n }\r\n /**\r\n * @description 开始任务\r\n */\r\n async function startTask() {\r\n // 未完成任务\r\n if (taskConfig.some((task) => task.active && !task.status)) {\r\n // 开始任务\r\n taskStatus.value = TaskStatusType.START;\r\n try {\r\n // 学习\r\n await study();\r\n // 同屏任务\r\n if (settings[SettingType.SAME_TAB]) {\r\n // 关闭窗口\r\n closeFrame();\r\n // 窗口不存在\r\n frame.exist = false;\r\n }\r\n }\r\n catch (err) {\r\n if (err instanceof Error) {\r\n // 提示\r\n createTip(err.message);\r\n // 错误\r\n error(err.message);\r\n return;\r\n }\r\n // 提示\r\n createTip(String(err));\r\n // 错误\r\n error(err);\r\n }\r\n }\r\n // 刷新任务\r\n taskStatus.value = TaskStatusType.FINISH;\r\n log('已完成');\r\n // 创建提示\r\n createTip('完成学习!');\r\n // 远程推送\r\n if (settings[SettingType.REMOTE_PUSH]) {\r\n // 推送\r\n const res = await pushModal({\r\n title: '学习推送',\r\n to: userinfo.nick,\r\n content: [\r\n '学习强国, 学习完成!',\r\n `当天积分: ${getHighlightHTML(todayScore.value)} 分`,\r\n `总积分: ${getHighlightHTML(totalScore.value)} 分`,\r\n ...taskConfig.map((task) => getProgressHTML(task.title, task.currentScore, task.dayMaxScore)),\r\n ],\r\n type: 'success',\r\n }, pushToken.value);\r\n createTip(`学习推送${res ? '成功' : '失败'}!`);\r\n }\r\n }\r\n // 已在等待\r\n let flag = false;\r\n // 自动答题\r\n watch(() => [taskStatus.value, settings[SettingType.AUTO_START]], async () => {\r\n // 加载完毕\r\n if (!flag && taskStatus.value === TaskStatusType.LOADED) {\r\n // 自动答题\r\n if (settings[SettingType.AUTO_START]) {\r\n // 等待中\r\n flag = true;\r\n // 创建提示\r\n const tip = createTip('即将自动开始任务', 5, true);\r\n // 等待倒计时结束\r\n await tip.waitCountDown();\r\n // 再次查看是否开启\r\n if (settings[SettingType.AUTO_START] &&\r\n taskStatus.value !== TaskStatusType.START) {\r\n // 创建提示\r\n createTip('自动开始任务');\r\n // 开始任务\r\n startTask();\r\n return;\r\n }\r\n // 取消等待\r\n flag = false;\r\n // 创建提示\r\n createTip('已取消自动开始任务!');\r\n }\r\n }\r\n });\r\n // 切换开关任务未完成\r\n taskConfig.forEach((task) => {\r\n watch(() => [task.active], () => {\r\n if (taskStatus.value === TaskStatusType.FINISH) {\r\n if (task.active && !task.status) {\r\n taskStatus.value = TaskStatusType.LOADED;\r\n }\r\n }\r\n });\r\n });\r\n return createElementNode('div', undefined, { class: 'egg_study_item' }, createElementNode('button', undefined, {\r\n class: watchEffectRef(() => `egg_study_btn${taskStatus.value === TaskStatusType.START ? ' loading' : ''}`),\r\n type: 'button',\r\n disabled: watchRef(() => [running.value, taskStatus.value], () => running.value ||\r\n taskStatus.value === TaskStatusType.LOADING ||\r\n taskStatus.value === TaskStatusType.FINISH),\r\n onclick: watchEffectRef(() => taskStatus.value === TaskStatusType.LOADED\r\n ? debounce(startTask, 300)\r\n : taskStatus.value === TaskStatusType.START\r\n ? debounce(pauseTask, 300)\r\n : taskStatus.value === TaskStatusType.PAUSE\r\n ? debounce(continueTask, 300)\r\n : undefined),\r\n }, createTextNode(watchEffectRef(() => `${taskStatus.value === TaskStatusType.LOADING\r\n ? '等待中'\r\n : taskStatus.value === TaskStatusType.LOADED\r\n ? '开始学习'\r\n : taskStatus.value === TaskStatusType.START\r\n ? '正在学习, 点击暂停'\r\n : taskStatus.value === TaskStatusType.PAUSE\r\n ? '继续学习'\r\n : taskStatus.value === TaskStatusType.FINISH\r\n ? '已完成'\r\n : ''}`))));\r\n }\r\n });\r\n}\r\n\r\n","from":"src\\component\\TaskBtn.ts","to":"TaskBtn.js"},"src\\component\\ScheduleList.ts":{"timeStamp":"2023-03-08T05:39:30.595Z","data":"/**\r\n * @description 定时项目\r\n * @returns\r\n */\r\nfunction ScheduleList() {\r\n return createElementNode('div', undefined, { class: 'egg_schedule_list' }, watchEffectRef(() => {\r\n return scheduleList.length\r\n ? scheduleList.map((schedule) => createElementNode('div', undefined, { class: 'egg_schedule_item' }, [\r\n createElementNode('div', undefined, {\r\n class: `egg_schedule_detail_time_wrap${isLate(schedule) ? ' inactive' : ''}`,\r\n }, [\r\n createElementNode('div', undefined, {\r\n class: 'egg_schedule_detail_icon',\r\n }, createNSElementNode('svg', undefined, {\r\n viewBox: '0 0 1024 1024',\r\n class: 'egg_icon',\r\n }, [\r\n createNSElementNode('path', undefined, {\r\n d: 'M810.137703 213.860762c-164.388001-164.4187-431.887404-164.4187-596.277452 0-164.417677 164.388001-164.417677 431.889451 0 596.278475 164.390048 164.417677 431.890474 164.417677 596.277452 0C974.557426 645.750213 974.557426 378.248763 810.137703 213.860762zM767.347131 767.345596c-140.797723 140.829446-369.927237 140.797723-510.693238 0-140.828422-140.797723-140.828422-369.895515 0-510.708588 140.767024-140.783397 369.896538-140.813073 510.693238 0C908.14383 397.420405 908.14383 626.578572 767.347131 767.345596z',\r\n }),\r\n createNSElementNode('path', undefined, {\r\n d: 'M721.450824 521.495258 515.404028 521.495258l0.028653-227.948619c0-15.124466-12.362562-27.458375-27.501354-27.458375s-27.443026 12.33391-27.443026 27.458375l0 235.115855c0 0.835018-1.013073 20.48659 12.094456 34.459836 8.331759 8.809643 20.038382 13.288654 35.148521 13.288654l213.720569 0.031722c15.140839 0 27.472702-12.304234 27.472702-27.474748C748.922503 533.887496 736.620315 521.584286 721.450824 521.495258z',\r\n }),\r\n ])),\r\n createElementNode('div', undefined, { class: 'egg_schedule_detail_time' }, createTextNode(schedule.time)),\r\n ]),\r\n createElementNode('div', undefined, { class: 'egg_schedule_detail_del_wrap' }, [\r\n createElementNode('button', undefined, {\r\n class: 'egg_schedule_del_btn',\r\n onclick: debounce(() => {\r\n // 定时刷新\r\n if (!settings[SettingType.SCHEDULE_RUN]) {\r\n createTip('未开启定时刷新!');\r\n return;\r\n }\r\n // 索引\r\n const index = scheduleList.findIndex((s) => s === schedule);\r\n // 删除元素\r\n scheduleList.splice(index, 1);\r\n // 存储\r\n GM_setValue('scheduleList', JSON.stringify(scheduleList));\r\n // 刷新任务\r\n refreshScheduleTask();\r\n }, 300),\r\n }, createNSElementNode('svg', undefined, {\r\n viewBox: '0 0 1024 1024',\r\n class: 'egg_icon',\r\n }, [\r\n createNSElementNode('path', undefined, {\r\n d: 'M896.22 896.22c14.262-14.263 11.263-40.449-6.583-58.295L230.473 178.76c-17.847-17.847-44.105-20.846-58.295-6.583-14.263 14.19-11.264 40.448 6.583 58.295l659.164 659.164c17.846 17.846 44.032 20.845 58.294 6.582',\r\n }),\r\n createNSElementNode('path', undefined, {\r\n d: 'M172.178 896.22c-14.263-14.263-11.264-40.449 6.583-58.295L837.925 178.76c17.846-17.847 44.032-20.846 58.294-6.583 14.263 14.19 11.264 40.448-6.582 58.295L230.4 889.637c-17.847 17.846-44.105 20.845-58.295 6.582',\r\n }),\r\n ])),\r\n ]),\r\n ]))\r\n : [\r\n createElementNode('div', undefined, { class: 'egg_schedule_list_none' }, [\r\n createNSElementNode('svg', undefined, {\r\n viewBox: '0 0 1024 1024',\r\n class: 'egg_icon',\r\n }, [\r\n createNSElementNode('path', undefined, {\r\n d: 'M238.1 520.5c-17.6 0-31.9-14.3-31.9-31.9 0-17.6 14.3-31.9 31.9-31.9h293c17.6 0 31.9 14.3 31.9 31.9 0 17.6-14.3 31.9-31.9 31.9h-293zM238.1 733.6c-17.6 0-31.9-14.3-31.9-31.9s14.3-31.9 31.9-31.9h186.5c17.6 0 31.9 14.3 31.9 31.9s-14.3 31.9-31.9 31.9H238.1zM241.6 314.9c-17.6 0-31.9-14.3-31.9-31.9s14.3-31.9 31.9-31.9h426.1c17.6 0 31.9 14.3 31.9 31.9 0 17.5-14.3 31.7-31.8 31.9H241.6z',\r\n }),\r\n createNSElementNode('path', undefined, {\r\n d: 'M160 926.6c-46.9 0-85.1-38.2-85.1-85.1V149.1c0-46.9 38.2-85.1 85.1-85.1h586c46.9 0 85.1 38.2 85.1 85.1v297.4c0 17.6-14.3 31.9-31.9 31.9-17.6 0-31.9-14.3-31.9-31.9V149.1c0-11.8-9.6-21.4-21.4-21.4H160c-11.8 0-21.4 9.6-21.4 21.4v692.4c0 11.8 9.6 21.4 21.4 21.4h304.5c17.5 0 31.8 14.2 31.9 31.8 0 17.6-14.3 31.8-31.9 31.8H160z',\r\n }),\r\n createNSElementNode('path', undefined, {\r\n d: 'M917.2 959.9c-8.5 0-16.5-3.3-22.5-9.3l-78.5-78.5-5.3-0.5-0.6 0.4c-31.7 21.6-68.7 33-107 33-105.2 0-190.8-85.6-190.8-190.8s85.6-190.8 190.8-190.8c105.2 0 190.8 85.6 190.8 190.8 0 38.2-11.4 75.2-33 107l-0.4 0.6 0.5 5.3 78.5 78.5c6 6 9.3 14 9.3 22.5s-3.4 16.5-9.4 22.5c-5.9 6-13.9 9.3-22.4 9.3zM703.4 587c-70.1 0-127.2 57.1-127.2 127.2s57.1 127.2 127.2 127.2 127.2-57.1 127.2-127.2S773.6 587 703.4 587z',\r\n }),\r\n ]),\r\n createElementNode('div', undefined, {\r\n class: 'egg_schedule_list_none_text',\r\n }, createTextNode('暂无定时任务')),\r\n ]),\r\n ];\r\n }));\r\n}\r\n\r\n","from":"src\\component\\ScheduleList.ts","to":"ScheduleList.js"},"src\\component\\TimeInput.ts":{"timeStamp":"2023-03-08T07:30:02.342Z","data":"/**\r\n * @description 时间输入\r\n * @returns\r\n */\r\nfunction TimeInput({ hour, minute, onchange, }) {\r\n // 小时\r\n const hours = new Array(24).fill(undefined).map((v, i) => ({\r\n value: i,\r\n label: formatDateNum(i),\r\n }));\r\n // 分钟\r\n const minutes = new Array(60).fill(undefined).map((v, i) => ({\r\n value: i,\r\n label: formatDateNum(i),\r\n }));\r\n const valueRef = watchEffectRef(() => {\r\n const h = hours.find((h) => h.value === hour.value);\r\n const min = minutes.find((min) => min.value === minute.value);\r\n return {\r\n hour: h ? h.value : -1,\r\n minute: min ? min.value : -1,\r\n };\r\n });\r\n return createElementNode('div', undefined, { class: 'egg_time_input' }, [\r\n createElementNode('div', undefined, { class: 'egg_hour_wrap' }, [\r\n Select({\r\n data: hours,\r\n placeholder: '00',\r\n maxlength: 2,\r\n value: hour,\r\n onchange({ value }) {\r\n valueRef.value.hour = value;\r\n onchange && onchange(valueRef.value);\r\n },\r\n onblur(res) {\r\n if (!res) {\r\n valueRef.value.hour = -1;\r\n onchange && onchange(valueRef.value);\r\n }\r\n },\r\n }),\r\n ]),\r\n createElementNode('span', undefined, { class: 'egg_separator' }, createTextNode(':')),\r\n createElementNode('div', undefined, { class: 'egg_minute_wrap' }, [\r\n Select({\r\n data: minutes,\r\n placeholder: '00',\r\n maxlength: 2,\r\n value: minute,\r\n onchange({ value }) {\r\n valueRef.value.minute = value;\r\n onchange && onchange(valueRef.value);\r\n },\r\n onblur(res) {\r\n if (!res) {\r\n valueRef.value.minute = -1;\r\n onchange && onchange(valueRef.value);\r\n }\r\n },\r\n }),\r\n ]),\r\n ]);\r\n}\r\n\r\n","from":"src\\component\\TimeInput.ts","to":"TimeInput.js"},"src\\component\\SettingsPanel.ts":{"timeStamp":"2023-06-06T09:16:08.312Z","data":"/**\r\n * @description 设置面板组件\r\n * @returns\r\n */\r\nfunction SettingsPanel({ show }) {\r\n // token\r\n let token = '';\r\n // 小时\r\n let hour = ref(-1);\r\n // 分钟\r\n let minute = ref(-1);\r\n return createElementNode('div', undefined, {\r\n class: watchEffectRef(() => `egg_settings${show.value ? ' active' : ''}`),\r\n }, [\r\n createElementNode('div', undefined, { class: 'egg_settings_version_wrap' }, [\r\n createElementNode('div', undefined, { class: 'egg_settings_label' }, createTextNode('版本信息')),\r\n createElementNode('div', undefined, {\r\n class: 'egg_settings_version',\r\n }, [\r\n createTextNode(`v${version}`),\r\n createElementNode('a', undefined, {\r\n class: 'egg_settings_version_detail',\r\n title: 'GitHub Xu22Web/tech-study-js',\r\n href: 'https://github.com/Xu22Web/tech-study-js',\r\n }, createNSElementNode('svg', undefined, {\r\n viewBox: '0 0 16 16',\r\n class: 'egg_icon',\r\n }, createNSElementNode('path', undefined, {\r\n d: 'M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z',\r\n }))),\r\n ]),\r\n ]),\r\n createElementNode('div', undefined, { class: 'egg_settings_theme_wrap' }, [\r\n createElementNode('div', undefined, { class: 'egg_settings_label' }, createTextNode('主题预设')),\r\n createElementNode('div', undefined, { class: 'egg_settings_theme_colors' }, [\r\n {\r\n value: '#fa3333',\r\n title: '强国红',\r\n detail: 'XueXi Red',\r\n code: 'none',\r\n },\r\n {\r\n value: '#bb2649',\r\n title: '非凡洋红',\r\n detail: 'Viva Magenta',\r\n code: '18-1750',\r\n },\r\n {\r\n value: '#35548a',\r\n title: '经典蓝',\r\n detail: 'Classic Blue',\r\n code: '19-4052',\r\n },\r\n {\r\n value: '#f36f63',\r\n title: '活珊瑚橘',\r\n detail: 'Living Coral',\r\n code: '16-1546',\r\n },\r\n {\r\n value: '#6d5b97',\r\n title: '紫外光色',\r\n detail: 'Ultra Violet',\r\n code: '18-3838',\r\n },\r\n {\r\n value: '#86af49',\r\n title: '草木绿',\r\n detail: 'Greenery',\r\n code: '15-0343',\r\n },\r\n {\r\n value: '#fc8bab',\r\n title: 'B站粉',\r\n detail: 'Bilibili Pink',\r\n code: 'none',\r\n },\r\n {\r\n value: '#056de8',\r\n title: '知乎蓝',\r\n detail: 'Zhihu Blue',\r\n code: 'none',\r\n },\r\n ].map((color) => createElementNode('div', undefined, {\r\n class: 'egg_settings_theme_color_wrap',\r\n }, createElementNode('button', undefined, {\r\n class: 'egg_settings_theme_color',\r\n type: 'button',\r\n style: watchEffectRef(() => `color: ${color.value};${themeColor.value === color.value\r\n ? ''\r\n : ` box-shadow: 0rem 0.4rem 0.1rem 0.1rem ${color.value}30;`}`),\r\n title: color.title,\r\n onclick: debounce(() => {\r\n if (themeColor.value !== color.value) {\r\n themeColor.value = color.value;\r\n // 存储\r\n GM_setValue('themeColor', themeColor.value);\r\n }\r\n }, 300),\r\n })))),\r\n ]),\r\n createElementNode('div', undefined, {\r\n class: 'egg_settings_read_time_wrap',\r\n }, [\r\n createElementNode('div', undefined, { class: 'egg_settings_label' }, createTextNode('最大文章时长')),\r\n Select({\r\n data: [\r\n {\r\n label: '40s',\r\n value: 40,\r\n },\r\n {\r\n label: '60s',\r\n value: 60,\r\n },\r\n {\r\n label: '80s',\r\n value: 80,\r\n },\r\n {\r\n label: '100s',\r\n value: 100,\r\n },\r\n ],\r\n value: maxRead,\r\n placeholder: '100s',\r\n maxlength: 4,\r\n keep: true,\r\n onchange({ value }) {\r\n // 创建提示\r\n createTip('最大文章时长 已保存!');\r\n maxRead.value = value;\r\n // 存储\r\n GM_setValue('maxRead', value);\r\n },\r\n }),\r\n ], {\r\n onMounted() {\r\n try {\r\n const maxReadTemp = GM_getValue('maxRead');\r\n if (maxReadTemp) {\r\n maxRead.value = maxReadTemp;\r\n }\r\n }\r\n catch (e) { }\r\n },\r\n }),\r\n createElementNode('div', undefined, {\r\n class: 'egg_settings_watch_time_wrap',\r\n }, [\r\n createElementNode('div', undefined, { class: 'egg_settings_label' }, createTextNode('最大视听时长')),\r\n Select({\r\n data: [\r\n {\r\n label: '40s',\r\n value: 40,\r\n },\r\n {\r\n label: '60s',\r\n value: 60,\r\n },\r\n {\r\n label: '80s',\r\n value: 80,\r\n },\r\n {\r\n label: '100s',\r\n value: 100,\r\n },\r\n {\r\n label: '120s',\r\n value: 120,\r\n },\r\n ],\r\n value: maxWatch,\r\n placeholder: '120s',\r\n maxlength: 4,\r\n keep: true,\r\n onchange({ value }) {\r\n // 创建提示\r\n createTip('最大视听时长 已保存!');\r\n maxWatch.value = value;\r\n // 存储\r\n GM_setValue('maxWatch', value);\r\n },\r\n }),\r\n ], {\r\n onMounted() {\r\n try {\r\n const maxWatchTemp = GM_getValue('maxWatch');\r\n if (maxWatchTemp) {\r\n maxWatch.value = maxWatchTemp;\r\n }\r\n }\r\n catch (e) { }\r\n },\r\n }),\r\n watchEffectRef(() => settings[SettingType.REMOTE_PUSH]\r\n ? createElementNode('div', undefined, { class: 'egg_settings_token_wrap' }, [\r\n createElementNode('div', undefined, { class: 'egg_settings_token' }, [\r\n createElementNode('div', undefined, { class: 'egg_settings_label' }, createTextNode('我的 token')),\r\n createElementNode('input', undefined, {\r\n class: 'egg_settings_token_input',\r\n placeholder: '用户 token',\r\n maxlength: 32,\r\n value: pushToken.value,\r\n onfocus: (e) => {\r\n const input = e.target;\r\n input.classList.add('active');\r\n const btnWrap = $$('.egg_settings_submit_btn_wrap')[0];\r\n btnWrap.classList.add('active');\r\n },\r\n onblur: (e) => {\r\n const input = e.target;\r\n // 去除空格\r\n const value = input.value.trim();\r\n if (/^[0-9a-z]{32}$/.test(value)) {\r\n token = value;\r\n input.value = value;\r\n }\r\n else {\r\n token = '';\r\n }\r\n input.classList.remove('active');\r\n setTimeout(() => {\r\n const btnWrap = $$('.egg_settings_submit_btn_wrap')[0];\r\n btnWrap.classList.remove('active');\r\n input.value = pushToken.value;\r\n }, 200);\r\n },\r\n }),\r\n ]),\r\n createElementNode('div', undefined, { class: 'egg_settings_submit_btn_wrap' }, createElementNode('button', undefined, {\r\n class: 'egg_settings_submit_btn',\r\n onclick: debounce(() => {\r\n // 创建提示\r\n createTip('用户 token 已保存!');\r\n if (token !== pushToken.value) {\r\n pushToken.value = token;\r\n // 存储\r\n GM_setValue('pushToken', token);\r\n }\r\n }, 300),\r\n }, createTextNode('保存'))),\r\n ])\r\n : undefined),\r\n watchEffectRef(() => settings[SettingType.SCHEDULE_RUN]\r\n ? createElementNode('div', undefined, { class: 'egg_schedule' }, [\r\n createElementNode('div', undefined, { class: 'egg_schedule_time_wrap' }, [\r\n createElementNode('div', undefined, { class: 'egg_schedule_time' }, [\r\n createElementNode('div', undefined, { class: 'egg_schedule_label' }, createTextNode('设置时间')),\r\n createElementNode('div', undefined, { class: 'egg_schedule_time_input_wrap' }, [\r\n TimeInput({\r\n hour,\r\n minute,\r\n onchange({ hour: h, minute: min }) {\r\n hour.value = h;\r\n minute.value = min;\r\n },\r\n }),\r\n createElementNode('button', undefined, {\r\n class: 'egg_schedule_add_btn',\r\n onclick: debounce(() => {\r\n // 定时刷新\r\n if (!settings[SettingType.SCHEDULE_RUN]) {\r\n createTip('未开启定时刷新!');\r\n return;\r\n }\r\n if (hour.value === -1 || minute.value === -1) {\r\n createTip('时间格式不符合要求!');\r\n return;\r\n }\r\n // 重复定时存在\r\n const exists = scheduleList.find((schedule) => schedule.hour === hour.value &&\r\n schedule.minute === minute.value);\r\n if (exists) {\r\n createTip('设置定时任务重复!');\r\n return;\r\n }\r\n createTip('设置定时任务成功!');\r\n // 添加\r\n scheduleList.push({\r\n hour: hour.value,\r\n minute: minute.value,\r\n time: `${formatDateNum(hour.value)}:${formatDateNum(minute.value)}`,\r\n });\r\n // 排序\r\n scheduleList.sort((a, b) => a.hour === b.hour\r\n ? a.minute - b.minute\r\n : a.hour - b.hour);\r\n // 存储\r\n GM_setValue('scheduleList', JSON.stringify(scheduleList));\r\n // 清空\r\n hour.value = -1;\r\n minute.value = -1;\r\n const inputs = $$('.egg_time_input input');\r\n inputs.forEach((i) => (i.value = ''));\r\n // 刷新任务\r\n refreshScheduleTask();\r\n }, 300),\r\n }, createNSElementNode('svg', undefined, {\r\n viewBox: '0 0 1024 1024',\r\n class: 'egg_icon',\r\n }, createNSElementNode('path', undefined, {\r\n d: 'M801.171 483.589H544V226.418c0-17.673-14.327-32-32-32s-32 14.327-32 32v257.171H222.83c-17.673 0-32 14.327-32 32s14.327 32 32 32H480v257.17c0 17.673 14.327 32 32 32s32-14.327 32-32v-257.17h257.171c17.673 0 32-14.327 32-32s-14.327-32-32-32z',\r\n }))),\r\n ]),\r\n ]),\r\n ]),\r\n ScheduleList(),\r\n ])\r\n : undefined),\r\n ], {\r\n onMounted() {\r\n // 刷新token\r\n watch(() => settings[SettingType.REMOTE_PUSH], () => {\r\n // 远程推送\r\n if (settings[SettingType.REMOTE_PUSH]) {\r\n try {\r\n const tokenTemp = GM_getValue('pushToken');\r\n if (tokenTemp) {\r\n pushToken.value = tokenTemp;\r\n }\r\n }\r\n catch (e) { }\r\n }\r\n }, true);\r\n // 刷新定时任务\r\n watch(() => settings[SettingType.SCHEDULE_RUN], () => {\r\n // 定时任务打开\r\n if (settings[SettingType.SCHEDULE_RUN]) {\r\n try {\r\n const scheduleTemp = JSON.parse(GM_getValue('scheduleList'));\r\n if (scheduleTemp && Array.isArray(scheduleTemp)) {\r\n for (const i in scheduleTemp) {\r\n scheduleList[i] = scheduleTemp[i];\r\n }\r\n }\r\n }\r\n catch (e) { }\r\n // 刷新定时任务\r\n refreshScheduleTask();\r\n return;\r\n }\r\n // 清除任务\r\n clearScheduleTask();\r\n }, true);\r\n },\r\n });\r\n}\r\n\r\n","from":"src\\component\\SettingsPanel.ts","to":"SettingsPanel.js"},"src\\component\\Panel.ts":{"timeStamp":"2023-07-14T10:51:35.712Z","data":"/**\r\n * @description 面板\r\n * @returns\r\n */\r\nfunction Panel() {\r\n // 运行设置标签\r\n const runLabels = [\r\n {\r\n title: '自动开始',\r\n tip: '启动时, 自动开始任务, 在倒计时结束前自动开始可随时取消; 如果在自动开始前手动开始任务, 此次自动开始将取消',\r\n type: SettingType.AUTO_START,\r\n },\r\n {\r\n title: '同屏任务',\r\n tip: '运行任务时,所有任务均在当前页面以弹窗方式运行',\r\n type: SettingType.SAME_TAB,\r\n },\r\n {\r\n title: '静默运行',\r\n tip: '同屏任务时, 不显示任务弹窗静默运行',\r\n type: SettingType.SILENT_RUN,\r\n },\r\n {\r\n title: '定时刷新',\r\n tip: '定时刷新页面,重新进行任务,此功能需要长时间占用浏览器',\r\n type: SettingType.SCHEDULE_RUN,\r\n },\r\n {\r\n title: '视频静音',\r\n tip: '视听学习时,静音播放视频',\r\n type: SettingType.VIDEO_MUTED,\r\n },\r\n ];\r\n // 运行设置标签\r\n const examLabels = [\r\n {\r\n title: '随机作答',\r\n tip: '无答案时, 随机选择或者填入答案, 不保证正确',\r\n type: SettingType.RANDOM_EXAM,\r\n },\r\n {\r\n title: '自动答题',\r\n tip: '进入答题页面时,自动答题并提交答案',\r\n type: SettingType.AUTO_ANSWER,\r\n },\r\n ];\r\n // 推送设置标签\r\n const pushLabels = [\r\n {\r\n title: '远程推送',\r\n tip: '利用 pushplus 推送, 将登录二维码直接推送到微信公众号',\r\n type: SettingType.REMOTE_PUSH,\r\n },\r\n ];\r\n // 处理设置变化\r\n const handleSettingsChange = (e, type, title) => {\r\n // 开关\r\n const { checked } = e.target;\r\n if (settings[type] !== checked) {\r\n settings[type] = checked;\r\n // 设置\r\n GM_setValue('studySettings', JSON.stringify(settings));\r\n // 创建提示\r\n createTip(`${title} ${checked ? '打开' : '关闭'}!`);\r\n }\r\n };\r\n // 任务显示\r\n const scheduleShow = ref(false);\r\n // 面板显示\r\n const panelShow = ref(false);\r\n return createElementNode('div', undefined, {\r\n class: `egg_panel_wrap${hasMobile() ? ' mobile' : ''}`,\r\n onclick(e) {\r\n e.stopPropagation();\r\n },\r\n onmousedown(e) {\r\n e.stopPropagation();\r\n },\r\n onmousemove(e) {\r\n e.stopPropagation();\r\n },\r\n onmouseup(e) {\r\n e.stopPropagation();\r\n },\r\n onmouseenter(e) {\r\n e.stopPropagation();\r\n },\r\n onmouseleave(e) {\r\n e.stopPropagation();\r\n },\r\n onmouseover(e) {\r\n e.stopPropagation();\r\n },\r\n ontouchstart(e) {\r\n e.stopPropagation();\r\n },\r\n ontouchmove(e) {\r\n e.stopPropagation();\r\n },\r\n ontouchend(e) {\r\n e.stopPropagation();\r\n },\r\n oninput(e) {\r\n e.stopPropagation();\r\n },\r\n onchange(e) {\r\n e.stopPropagation();\r\n },\r\n onblur(e) {\r\n e.stopPropagation();\r\n },\r\n }, createElementNode('div', undefined, {\r\n class: watchEffectRef(() => `egg_panel${panelShow.value ? ' hide' : ''}`),\r\n }, [\r\n // 登录\r\n LoginItem(),\r\n // 信息\r\n InfoItem(),\r\n // 分数\r\n ScoreItem(),\r\n // 任务部分\r\n Hr({ text: '任务' }),\r\n TaskList(),\r\n // 运行部分\r\n Hr({ text: '运行' }),\r\n createElementNode('div', undefined, { class: 'egg_run_list' }, runLabels.map((label) => {\r\n return NormalItem({\r\n title: label.title,\r\n tip: label.tip,\r\n checked: settings[label.type],\r\n onchange: debounce((e) => {\r\n handleSettingsChange(e, label.type, label.title);\r\n }, 300),\r\n });\r\n })),\r\n // 答题部分\r\n Hr({ text: '答题' }),\r\n createElementNode('div', undefined, { class: 'egg_exam_list' }, examLabels.map((label) => {\r\n return NormalItem({\r\n title: label.title,\r\n tip: label.tip,\r\n checked: settings[label.type],\r\n onchange: debounce((e) => {\r\n handleSettingsChange(e, label.type, label.title);\r\n }, 300),\r\n });\r\n })),\r\n // 推送部分\r\n Hr({ text: '推送' }),\r\n createElementNode('div', undefined, { class: 'egg_push_list' }, pushLabels.map((label) => {\r\n return NormalItem({\r\n title: label.title,\r\n tip: label.tip,\r\n checked: settings[label.type],\r\n onchange: debounce((e) => {\r\n handleSettingsChange(e, label.type, label.title);\r\n }, 300),\r\n });\r\n })),\r\n // 提示部分\r\n Hr({ text: '提示' }),\r\n createElementNode('div', undefined, { class: 'egg_tip_list' }, watchRef(login, () => login.value\r\n ? [\r\n createTextNode('专项练习已被移除, 如需使用, 请点击'),\r\n createElementNode('button', undefined, {\r\n class: 'egg_tip_btn',\r\n type: 'button',\r\n onclick: debounce(doExamPaper, 300),\r\n disabled: watchRef(() => [running.value, taskStatus.value], () => running.value ||\r\n taskStatus.value === TaskStatusType.START ||\r\n taskStatus.value === TaskStatusType.PAUSE),\r\n }, createTextNode('去完成')),\r\n ]\r\n : [\r\n createElementNode('div', undefined, { class: 'egg_tip_content' }, createTextNode('请先登录!')),\r\n ])),\r\n // 按钮集合\r\n createElementNode('div', undefined, {\r\n class: 'egg_btns_wrap',\r\n }, [\r\n createElementNode('button', undefined, {\r\n class: watchRef(() => [frame.exist, frame.show], () => `egg_frame_show_btn${!frame.exist || frame.show ? ' hide' : ''}`),\r\n title: '窗口',\r\n type: 'button',\r\n onclick: debounce(() => {\r\n // 窗口显示\r\n frame.show = true;\r\n }, 300),\r\n }, createNSElementNode('svg', undefined, {\r\n viewBox: '0 0 1024 1024',\r\n class: 'egg_icon',\r\n }, createNSElementNode('path', undefined, {\r\n d: 'M836.224 106.666667h-490.666667a85.589333 85.589333 0 0 0-85.333333 85.333333V256h-64a85.589333 85.589333 0 0 0-85.333333 85.333333v490.666667a85.589333 85.589333 0 0 0 85.333333 85.333333h490.666667a85.589333 85.589333 0 0 0 85.333333-85.333333V768h64a85.589333 85.589333 0 0 0 85.333333-85.333333V192a85.589333 85.589333 0 0 0-85.333333-85.333333z m-132.266667 725.333333a20.138667 20.138667 0 0 1-21.333333 21.333333h-490.666667a20.138667 20.138667 0 0 1-21.333333-21.333333V341.333333a20.138667 20.138667 0 0 1 21.333333-21.333333h494.933334a20.138667 20.138667 0 0 1 21.333333 21.333333v490.666667z m153.6-149.333333a20.138667 20.138667 0 0 1-21.333333 21.333333h-64V341.333333a85.589333 85.589333 0 0 0-85.333333-85.333333h-362.666667V192a20.138667 20.138667 0 0 1 21.333333-21.333333h490.666667a20.138667 20.138667 0 0 1 21.333333 21.333333z',\r\n }))),\r\n createElementNode('button', undefined, {\r\n class: 'egg_panel_show_btn',\r\n title: '面板',\r\n type: 'button',\r\n onclick: debounce(() => {\r\n panelShow.value = !panelShow.value;\r\n }, 300),\r\n }, createNSElementNode('svg', undefined, {\r\n viewBox: '0 0 1024 1024',\r\n class: 'egg_icon',\r\n }, createNSElementNode('path', undefined, {\r\n d: 'M332.16 883.84a40.96 40.96 0 0 0 58.24 0l338.56-343.04a40.96 40.96 0 0 0 0-58.24L390.4 140.16a40.96 40.96 0 0 0-58.24 58.24L640 512l-307.84 314.24a40.96 40.96 0 0 0 0 57.6z',\r\n }))),\r\n createElementNode('button', undefined, {\r\n class: watchEffectRef(() => `egg_settings_show_btn${scheduleShow.value ? ' active' : ''}`),\r\n title: '设置',\r\n type: 'button',\r\n onclick: debounce(() => {\r\n scheduleShow.value = !scheduleShow.value;\r\n }, 300),\r\n }, createNSElementNode('svg', undefined, {\r\n viewBox: '0 0 1024 1024',\r\n class: 'egg_icon',\r\n }, [\r\n createNSElementNode('path', undefined, {\r\n d: 'M7.25325 705.466473a503.508932 503.508932 0 0 0 75.26742 121.391295 95.499302 95.499302 0 0 0 93.211173 31.07039 168.59902 168.59902 0 0 1 114.526906 16.257763 148.487566 148.487566 0 0 1 71.052444 83.456515 91.163899 91.163899 0 0 0 75.989987 61.538643 578.053784 578.053784 0 0 0 148.969278 0A91.163899 91.163899 0 0 0 662.380873 957.642436a148.487566 148.487566 0 0 1 72.256723-83.456515 168.59902 168.59902 0 0 1 114.406478-16.257763 95.61973 95.61973 0 0 0 93.331601-31.07039 503.508932 503.508932 0 0 0 75.267419-121.391295 84.29951 84.29951 0 0 0-18.545892-94.897163 138.251197 138.251197 0 0 1 0-197.140426 84.29951 84.29951 0 0 0 18.545892-94.897163 503.508932 503.508932 0 0 0-75.869559-121.391295 95.499302 95.499302 0 0 0-93.211173-31.070391A168.59902 168.59902 0 0 1 734.637596 149.812272a148.848849 148.848849 0 0 1-72.256723-83.456515A91.163899 91.163899 0 0 0 586.631741 4.817115a581.907476 581.907476 0 0 0-148.969277 0A91.163899 91.163899 0 0 0 361.311193 66.355757a148.848849 148.848849 0 0 1-71.413728 83.456515 168.59902 168.59902 0 0 1-114.406478 16.257763 95.378874 95.378874 0 0 0-93.3316 31.070391A503.508932 503.508932 0 0 0 7.25325 318.531721a84.29951 84.29951 0 0 0 18.545893 94.897163 140.057615 140.057615 0 0 1 41.30676 98.509999 140.057615 140.057615 0 0 1-41.30676 98.630427A84.29951 84.29951 0 0 0 7.25325 705.466473z m929.462315-349.240828a219.901294 219.901294 0 0 0 0 312.028615c0.842995 0.842995 2.649413 3.010697 1.806418 5.057971a427.398517 427.398517 0 0 1-63.104205 101.520696 9.513802 9.513802 0 0 1-9.032091 2.167702 255.547944 255.547944 0 0 0-173.777418 24.928569 231.823653 231.823653 0 0 0-111.275354 130.302957 6.984817 6.984817 0 0 1-6.021394 4.937543 492.790851 492.790851 0 0 1-126.328837 0 6.984817 6.984817 0 0 1-6.021394-4.937543 231.823653 231.823653 0 0 0-111.275353-130.302957 255.668372 255.668372 0 0 0-120.427872-30.468252 258.919924 258.919924 0 0 0-52.747408 5.539683 9.513802 9.513802 0 0 1-9.03209-2.167702 427.398517 427.398517 0 0 1-63.104205-101.520696c-0.842995-2.047274 0.963423-4.214976 1.806418-5.057971a221.82814 221.82814 0 0 0 64.910623-156.556233 221.707712 221.707712 0 0 0-65.512762-155.713238c-0.842995-0.842995-2.649413-3.010697-1.806418-5.057971a427.398517 427.398517 0 0 1 63.104205-101.520696 9.393374 9.393374 0 0 1 8.911662-2.167701 255.7888 255.7888 0 0 0 173.897847-24.92857 231.823653 231.823653 0 0 0 111.275353-130.302957 6.984817 6.984817 0 0 1 6.021394-4.937543 492.790851 492.790851 0 0 1 126.328837 0 6.984817 6.984817 0 0 1 6.021394 4.937543 231.823653 231.823653 0 0 0 111.275354 130.302957 255.547944 255.547944 0 0 0 173.777418 24.92857 9.513802 9.513802 0 0 1 9.032091 2.167701 423.063113 423.063113 0 0 1 62.983777 101.520696c0.963423 2.047274-0.842995 4.214976-1.68599 5.057971z',\r\n }),\r\n createNSElementNode('path', undefined, {\r\n d: 'M512.086889 305.766366a206.292944 206.292944 0 1 0 206.172516 206.172517 206.413372 206.413372 0 0 0-206.172516-206.172517z m123.197713 206.172517a123.197713 123.197713 0 1 1-123.197713-123.077285 123.318141 123.318141 0 0 1 123.197713 123.077285z',\r\n }),\r\n ])),\r\n createElementNode('button', undefined, {\r\n class: 'egg_settings_reset_btn',\r\n title: '重置',\r\n type: 'button',\r\n onclick: debounce(() => {\r\n // 任务配置\r\n GM_setValue('taskConfig', null);\r\n // 设置\r\n GM_setValue('studySettings', null);\r\n // 最大阅读\r\n GM_setValue('maxRead', null);\r\n // 最大观看\r\n GM_setValue('maxWatch', null);\r\n // 主题色\r\n GM_setValue('themeColor', null);\r\n // 刷新页面\r\n location.reload();\r\n }, 300),\r\n }, createNSElementNode('svg', undefined, {\r\n viewBox: '0 0 1024 1024',\r\n class: 'egg_icon',\r\n }, [\r\n createNSElementNode('path', undefined, {\r\n d: 'M943.8 484.1c-17.5-13.7-42.8-10.7-56.6 6.8-5.7 7.3-8.5 15.8-8.6 24.4h-0.4c-0.6 78.3-26.1 157-78 223.3-124.9 159.2-356 187.1-515.2 62.3-31.7-24.9-58.2-54-79.3-85.9h77.1c22.4 0 40.7-18.3 40.7-40.7v-3c0-22.4-18.3-40.7-40.7-40.7H105.5c-22.4 0-40.7 18.3-40.7 40.7v177.3c0 22.4 18.3 40.7 40.7 40.7h3c22.4 0 40.7-18.3 40.7-40.7v-73.1c24.2 33.3 53 63.1 86 89 47.6 37.3 101 64.2 158.9 79.9 55.9 15.2 113.5 19.3 171.2 12.3 57.7-7 112.7-24.7 163.3-52.8 52.5-29 98-67.9 135.3-115.4 37.3-47.6 64.2-101 79.9-158.9 10.2-37.6 15.4-76 15.6-114.6h-0.1c-0.3-11.6-5.5-23.1-15.5-30.9zM918.7 135.2h-3c-22.4 0-40.7 18.3-40.7 40.7V249c-24.2-33.3-53-63.1-86-89-47.6-37.3-101-64.2-158.9-79.9-55.9-15.2-113.5-19.3-171.2-12.3-57.7 7-112.7 24.7-163.3 52.8-52.5 29-98 67.9-135.3 115.4-37.3 47.5-64.2 101-79.9 158.8-10.2 37.6-15.4 76-15.6 114.6h0.1c0.2 11.7 5.5 23.2 15.4 30.9 17.5 13.7 42.8 10.7 56.6-6.8 5.7-7.3 8.5-15.8 8.6-24.4h0.4c0.6-78.3 26.1-157 78-223.3 124.9-159.2 356-187.1 515.2-62.3 31.7 24.9 58.2 54 79.3 85.9h-77.1c-22.4 0-40.7 18.3-40.7 40.7v3c0 22.4 18.3 40.7 40.7 40.7h177.3c22.4 0 40.7-18.3 40.7-40.7V175.8c0.1-22.3-18.2-40.6-40.6-40.6z',\r\n }),\r\n ])),\r\n ]),\r\n // 任务按钮\r\n TaskBtn(),\r\n createElementNode('div', undefined, { class: 'egg_settings_item' }, [\r\n SettingsPanel({ show: scheduleShow }),\r\n ]),\r\n ]));\r\n}\r\n\r\n","from":"src\\component\\Panel.ts","to":"Panel.js"}}