【学习通任务一览】支持作业、考试列表 | 电脑端快速查看,绝不错过任何作业与考试

【💡操作简单】学习通任务一览,无需任何配置,安装即可使用。【📅功能专注】专为查看作业和考试列表设计,增加提醒功能,确保不错过任何重要任务。【⏱️快速查看】在电脑端快速显示所有待办的作业和即将到来的考试,帮助及时安排学习计划,有效管理时间。【🚀提升体验】这一功能填补了原版学习通的空白,为学术生活带来了极大的便利和效率。

目前为 2024-05-18 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name 【学习通任务一览】支持作业、考试列表 | 电脑端快速查看,绝不错过任何作业与考试
  3. // @namespace https://github.com/lcandy2/user.js/tree/main/websites/chaoxing.com/chaoxing-assignment
  4. // @version 1.1
  5. // @author 甜檸Cirtron (lcandy2)
  6. // @description 【💡操作简单】学习通任务一览,无需任何配置,安装即可使用。【📅功能专注】专为查看作业和考试列表设计,增加提醒功能,确保不错过任何重要任务。【⏱️快速查看】在电脑端快速显示所有待办的作业和即将到来的考试,帮助及时安排学习计划,有效管理时间。【🚀提升体验】这一功能填补了原版学习通的空白,为学术生活带来了极大的便利和效率。
  7. // @license AGPL-3.0-or-later
  8. // @homepage https://gf.qytechs.cn/scripts/495345
  9. // @homepageURL https://gf.qytechs.cn/scripts/495345
  10. // @source https://github.com/lcandy2/user.js/tree/main/websites/chaoxing.com/chaoxing-assignment
  11. // @match *://mooc1-api.chaoxing.com/work/stu-work*
  12. // @match *://i.chaoxing.com/base*
  13. // @match *://i.mooc.chaoxing.com/space/index*
  14. // @match *://i.mooc.chaoxing.com/settings*
  15. // @match *://mooc1-api.chaoxing.com/exam-ans/exam/phone/examcode*
  16. // @require https://registry.npmmirror.com/vue/3.4.27/files/dist/vue.global.prod.js
  17. // @require data:application/javascript,%3Bwindow.Vue%3DVue%3B
  18. // @require https://registry.npmmirror.com/vuetify/3.6.6/files/dist/vuetify.min.js
  19. // @resource VuetifyStyle https://registry.npmmirror.com/vuetify/3.6.6/files/dist/vuetify.min.css
  20. // @resource material-design-icons-iconfont/dist/material-design-icons.css https://fonts.googlefonts.cn/css?family=Material+Icons
  21. // @grant GM_addStyle
  22. // @grant GM_getResourceText
  23. // @run-at document-end
  24. // ==/UserScript==
  25.  
  26. (function (vuetify, vue) {
  27. 'use strict';
  28.  
  29. const wrapElements = () => {
  30. const wrapper = document.createElement("body");
  31. wrapper.id = "chaoxing-assignment-wrapper";
  32. while (document.body.firstChild) {
  33. wrapper.appendChild(document.body.firstChild);
  34. }
  35. document.body.appendChild(wrapper);
  36. wrapper.style.display = "none";
  37. };
  38. const removeStyles = () => {
  39. const html = document.querySelector("html");
  40. html == null ? void 0 : html.removeAttribute("style");
  41. const styles = document.querySelectorAll("link[rel=stylesheet]");
  42. styles.forEach((style) => {
  43. var _a;
  44. if ((_a = style.getAttribute("href")) == null ? void 0 : _a.includes("chaoxing")) {
  45. style.remove();
  46. }
  47. });
  48. };
  49. const urlDetection = () => {
  50. const url = window.location.href;
  51. const hash = window.location.hash;
  52. if (hash.includes("chaoxing-assignment")) {
  53. if (url.includes("mooc1-api.chaoxing.com/work/stu-work")) {
  54. return "homework";
  55. }
  56. if (url.includes("mooc1-api.chaoxing.com/exam-ans/exam/phone/examcode")) {
  57. return "exam";
  58. }
  59. }
  60. if (url.includes("i.chaoxing.com/base")) {
  61. return "home";
  62. }
  63. if (url.includes("i.mooc.chaoxing.com/space/index") || url.includes("i.mooc.chaoxing.com/settings")) {
  64. return "legacyHome";
  65. }
  66. };
  67. const addMenuItem = () => {
  68. const menubarElement = document.querySelector('div.menubar[role="menubar"]');
  69. if (menubarElement) {
  70. const menuItemElement = document.createElement("a");
  71. menuItemElement.setAttribute("role", "menuitem");
  72. menuItemElement.setAttribute("focus_element", "0");
  73. menuItemElement.setAttribute("tabindex", "-1");
  74. menuItemElement.id = "first1000001";
  75. menuItemElement.setAttribute("imgname", "icon-home");
  76. menuItemElement.setAttribute(
  77. "onclick",
  78. `setUrl('1000001','https://mooc1-api.chaoxing.com/work/stu-work#chaoxing-assignment',this,'0','全部作业')`
  79. );
  80. menuItemElement.setAttribute(
  81. "dataurl",
  82. "https://mooc1-api.chaoxing.com/work/stu-work#chaoxing-assignment"
  83. );
  84. const iconElement = document.createElement("span");
  85. iconElement.className = "icon-space icon-bj";
  86. menuItemElement.appendChild(iconElement);
  87. const titleElement = document.createElement("h5");
  88. titleElement.title = "全部作业";
  89. const boldElement = document.createElement("b");
  90. boldElement.textContent = "全部作业";
  91. titleElement.appendChild(boldElement);
  92. menuItemElement.appendChild(titleElement);
  93. const arrowElement = document.createElement("span");
  94. arrowElement.className = "arrow icon-uniE900";
  95. menuItemElement.appendChild(arrowElement);
  96. menubarElement.prepend(menuItemElement);
  97. }
  98. };
  99. const addMenuItemExam = () => {
  100. const menubarElement = document.querySelector('div.menubar[role="menubar"]');
  101. if (menubarElement) {
  102. const menuItemElement = document.createElement("a");
  103. menuItemElement.setAttribute("role", "menuitem");
  104. menuItemElement.setAttribute("focus_element", "0");
  105. menuItemElement.setAttribute("tabindex", "-1");
  106. menuItemElement.id = "first1000002";
  107. menuItemElement.setAttribute("imgname", "icon-home");
  108. menuItemElement.setAttribute(
  109. "onclick",
  110. `setUrl('1000002','https://mooc1-api.chaoxing.com/exam-ans/exam/phone/examcode#chaoxing-assignment',this,'0','全部考试')`
  111. );
  112. menuItemElement.setAttribute(
  113. "dataurl",
  114. "https://mooc1-api.chaoxing.com/exam-ans/exam/phone/examcode#chaoxing-assignment"
  115. );
  116. const iconElement = document.createElement("span");
  117. iconElement.className = "icon-space icon-cj";
  118. menuItemElement.appendChild(iconElement);
  119. const titleElement = document.createElement("h5");
  120. titleElement.title = "全部考试";
  121. const boldElement = document.createElement("b");
  122. boldElement.textContent = "全部考试";
  123. titleElement.appendChild(boldElement);
  124. menuItemElement.appendChild(titleElement);
  125. const arrowElement = document.createElement("span");
  126. arrowElement.className = "arrow icon-uniE900";
  127. menuItemElement.appendChild(arrowElement);
  128. menubarElement.prepend(menuItemElement);
  129. }
  130. };
  131. const addMenuItemLegacy = () => {
  132. const funclistulElement = document.querySelector("ul.funclistul");
  133. if (funclistulElement) {
  134. const liElement = document.createElement("li");
  135. liElement.id = "li_chaoxing-assignment-task";
  136. const spanElement = document.createElement("span");
  137. liElement.appendChild(spanElement);
  138. const aElement = document.createElement("a");
  139. aElement.id = "chaoxing-assignment-task";
  140. aElement.href = "javascript:switchM('chaoxing-assignment-task','https://mooc1-api.chaoxing.com/work/stu-work#chaoxing-assignment')";
  141. aElement.target = "_top";
  142. aElement.title = "全部作业";
  143. const bIconElement = document.createElement("b");
  144. bIconElement.className = "liticons znewyun zne_bj_icon";
  145. aElement.appendChild(bIconElement);
  146. const emTitleElement = document.createElement("em");
  147. emTitleElement.setAttribute("style", "font-weight: bolder;");
  148. emTitleElement.textContent = "全部作业";
  149. aElement.appendChild(emTitleElement);
  150. liElement.appendChild(aElement);
  151. funclistulElement.prepend(liElement);
  152. }
  153. };
  154. const addMenuItemExamLegacy = () => {
  155. const funclistulElement = document.querySelector("ul.funclistul");
  156. if (funclistulElement) {
  157. const liElement = document.createElement("li");
  158. liElement.id = "li_chaoxing-assignment-exam";
  159. const spanElement = document.createElement("span");
  160. liElement.appendChild(spanElement);
  161. const aElement = document.createElement("a");
  162. aElement.id = "chaoxing-assignment-exam";
  163. aElement.href = "javascript:switchM('chaoxing-assignment-exam','https://mooc1-api.chaoxing.com/exam-ans/exam/phone/examcode#chaoxing-assignment')";
  164. aElement.target = "_top";
  165. aElement.title = "全部考试";
  166. const bIconElement = document.createElement("b");
  167. bIconElement.className = "liticons znewyun zne_jc_icon";
  168. aElement.appendChild(bIconElement);
  169. const emTitleElement = document.createElement("em");
  170. emTitleElement.setAttribute("style", "font-weight: bolder;");
  171. emTitleElement.textContent = "全部考试";
  172. aElement.appendChild(emTitleElement);
  173. liElement.appendChild(aElement);
  174. funclistulElement.prepend(liElement);
  175. }
  176. };
  177. function extractTasks() {
  178. const taskElements = document.querySelectorAll(
  179. "#chaoxing-assignment-wrapper ul.nav > li"
  180. );
  181. const tasks = Array.from(taskElements).map((task) => {
  182. var _a, _b, _c;
  183. const optionElement = task.querySelector('div[role="option"]');
  184. let title = "";
  185. let status = "";
  186. let uncommitted = false;
  187. let course = "";
  188. let leftTime = "";
  189. if (optionElement) {
  190. title = ((_a = optionElement.querySelector("p")) == null ? void 0 : _a.textContent) || "";
  191. const statusElement = optionElement.querySelector("span:nth-of-type(1)");
  192. status = (statusElement == null ? void 0 : statusElement.textContent) || "";
  193. uncommitted = (statusElement == null ? void 0 : statusElement.className.includes("status")) || false;
  194. course = ((_b = optionElement.querySelector("span:nth-of-type(2)")) == null ? void 0 : _b.textContent) || "";
  195. leftTime = ((_c = optionElement.querySelector(".fr")) == null ? void 0 : _c.textContent) || "";
  196. }
  197. const raw = task.getAttribute("data") || "";
  198. let workId = "";
  199. let courseId = "";
  200. let clazzId = "";
  201. if (raw) {
  202. const rawUrl = new URL(raw);
  203. const searchParams = rawUrl.searchParams;
  204. workId = searchParams.get("taskrefId") || "";
  205. courseId = searchParams.get("courseId") || "";
  206. clazzId = searchParams.get("clazzId") || "";
  207. }
  208. return {
  209. title,
  210. status,
  211. uncommitted,
  212. course,
  213. leftTime,
  214. workId,
  215. courseId,
  216. clazzId,
  217. raw
  218. };
  219. });
  220. return tasks;
  221. }
  222. function extractExams() {
  223. const examElements = document.querySelectorAll(
  224. "#chaoxing-assignment-wrapper ul.ks_list > li"
  225. );
  226. const exams = Array.from(examElements).map((exam) => {
  227. var _a, _b, _c, _d;
  228. const dlElement = exam.querySelector("dl");
  229. const imgElement = exam.querySelector("div.ks_pic > img");
  230. let title = "";
  231. let timeLeft = "";
  232. let status = "";
  233. let expired = false;
  234. let examId = "";
  235. let courseId = "";
  236. let classId = "";
  237. if (dlElement) {
  238. title = ((_a = dlElement.querySelector("dt")) == null ? void 0 : _a.textContent) || "";
  239. timeLeft = ((_b = dlElement.querySelector("dd")) == null ? void 0 : _b.textContent) || "";
  240. }
  241. if (imgElement) {
  242. expired = ((_c = imgElement.getAttribute("src")) == null ? void 0 : _c.includes("ks_02")) || false;
  243. }
  244. status = ((_d = exam.querySelector("span.ks_state")) == null ? void 0 : _d.textContent) || "";
  245. const raw = exam.getAttribute("data") || "";
  246. if (raw) {
  247. const rawWithHost = window.location.protocol + "//" + window.location.host + raw;
  248. const rawUrl = new URL(rawWithHost);
  249. const searchParams = rawUrl.searchParams;
  250. examId = searchParams.get("taskrefId") || "";
  251. courseId = searchParams.get("courseId") || "";
  252. classId = searchParams.get("classId") || "";
  253. }
  254. const finished = status.includes("已完成") || status.includes("待批阅");
  255. return {
  256. title,
  257. status,
  258. timeLeft,
  259. expired,
  260. finished,
  261. examId,
  262. courseId,
  263. classId,
  264. raw
  265. };
  266. });
  267. return exams;
  268. }
  269. const API_VISIT_COURSE = "https://mooc1.chaoxing.com/visit/stucoursemiddle?ismooc2=1";
  270. const API_OPEN_EXAM = "https://mooc1-api.chaoxing.com/exam-ans/exam/test/examcode/examnotes";
  271. const cssLoader = (e) => {
  272. const t = GM_getResourceText(e);
  273. return GM_addStyle(t), t;
  274. };
  275. cssLoader("VuetifyStyle");
  276. const _sfc_main$2 = /* @__PURE__ */ vue.defineComponent({
  277. __name: "tasks-list",
  278. setup(__props) {
  279. const extractedData = extractTasks();
  280. const headers = [
  281. { key: "title", title: "作业名称" },
  282. { key: "course", title: "课程" },
  283. { key: "leftTime", title: "剩余时间" },
  284. { key: "status", title: "状态" },
  285. { key: "action", title: "", sortable: false }
  286. ];
  287. const search = vue.ref("");
  288. const getCourseLinkHref = (item) => {
  289. const courseId = item.courseId;
  290. const clazzId = item.clazzId;
  291. const requestUrl = new URL(API_VISIT_COURSE);
  292. requestUrl.searchParams.append("courseid", courseId);
  293. requestUrl.searchParams.append("clazzid", clazzId);
  294. requestUrl.searchParams.append("pageHeader", "8");
  295. return requestUrl.href;
  296. };
  297. return (_ctx, _cache) => {
  298. const _component_v_text_field = vue.resolveComponent("v-text-field");
  299. const _component_v_btn = vue.resolveComponent("v-btn");
  300. const _component_v_data_table = vue.resolveComponent("v-data-table");
  301. const _component_v_card = vue.resolveComponent("v-card");
  302. return vue.openBlock(), vue.createBlock(_component_v_card, {
  303. title: "作业列表",
  304. variant: "flat"
  305. }, {
  306. text: vue.withCtx(() => [
  307. vue.createVNode(_component_v_text_field, {
  308. modelValue: search.value,
  309. "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => search.value = $event),
  310. label: "搜索",
  311. "prepend-inner-icon": "search",
  312. variant: "outlined",
  313. "hide-details": "",
  314. "single-line": ""
  315. }, null, 8, ["modelValue"])
  316. ]),
  317. default: vue.withCtx(() => [
  318. vue.createVNode(_component_v_data_table, {
  319. items: vue.unref(extractedData),
  320. search: search.value,
  321. hover: "",
  322. headers,
  323. sticky: "",
  324. "items-per-page": "-1",
  325. "hide-default-footer": ""
  326. }, {
  327. "item.action": vue.withCtx(({ item }) => [
  328. vue.createVNode(_component_v_btn, {
  329. variant: item.uncommitted ? "tonal" : "plain",
  330. color: "primary",
  331. href: getCourseLinkHref(item),
  332. target: "_blank"
  333. }, {
  334. default: vue.withCtx(() => [
  335. vue.createTextVNode(vue.toDisplayString(item.uncommitted ? "立即完成" : "查看详情"), 1)
  336. ]),
  337. _: 2
  338. }, 1032, ["variant", "href"])
  339. ]),
  340. _: 1
  341. }, 8, ["items", "search"])
  342. ]),
  343. _: 1
  344. });
  345. };
  346. }
  347. });
  348. const _sfc_main$1 = /* @__PURE__ */ vue.defineComponent({
  349. __name: "App",
  350. setup(__props) {
  351. return (_ctx, _cache) => {
  352. return vue.openBlock(), vue.createBlock(_sfc_main$2);
  353. };
  354. }
  355. });
  356. cssLoader("material-design-icons-iconfont/dist/material-design-icons.css");
  357. function isObject(obj) {
  358. return obj !== null && typeof obj === "object" && !Array.isArray(obj);
  359. }
  360. function pick(obj, paths) {
  361. const found = {};
  362. const keys = new Set(Object.keys(obj));
  363. for (const path of paths) {
  364. if (keys.has(path)) {
  365. found[path] = obj[path];
  366. }
  367. }
  368. return found;
  369. }
  370. function mergeDeep() {
  371. let source = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
  372. let target = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
  373. let arrayFn = arguments.length > 2 ? arguments[2] : void 0;
  374. const out = {};
  375. for (const key in source) {
  376. out[key] = source[key];
  377. }
  378. for (const key in target) {
  379. const sourceProperty = source[key];
  380. const targetProperty = target[key];
  381. if (isObject(sourceProperty) && isObject(targetProperty)) {
  382. out[key] = mergeDeep(sourceProperty, targetProperty, arrayFn);
  383. continue;
  384. }
  385. if (Array.isArray(sourceProperty) && Array.isArray(targetProperty) && arrayFn) {
  386. out[key] = arrayFn(sourceProperty, targetProperty);
  387. continue;
  388. }
  389. out[key] = targetProperty;
  390. }
  391. return out;
  392. }
  393. function toKebabCase() {
  394. let str = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : "";
  395. if (toKebabCase.cache.has(str))
  396. return toKebabCase.cache.get(str);
  397. const kebab = str.replace(/[^a-z]/gi, "-").replace(/\B([A-Z])/g, "-$1").toLowerCase();
  398. toKebabCase.cache.set(str, kebab);
  399. return kebab;
  400. }
  401. toKebabCase.cache = /* @__PURE__ */ new Map();
  402. function consoleWarn(message) {
  403. vue.warn(`Vuetify: ${message}`);
  404. }
  405. function propsFactory(props, source) {
  406. return (defaults) => {
  407. return Object.keys(props).reduce((obj, prop) => {
  408. const isObjectDefinition = typeof props[prop] === "object" && props[prop] != null && !Array.isArray(props[prop]);
  409. const definition = isObjectDefinition ? props[prop] : {
  410. type: props[prop]
  411. };
  412. if (defaults && prop in defaults) {
  413. obj[prop] = {
  414. ...definition,
  415. default: defaults[prop]
  416. };
  417. } else {
  418. obj[prop] = definition;
  419. }
  420. if (source && !obj[prop].source) {
  421. obj[prop].source = source;
  422. }
  423. return obj;
  424. }, {});
  425. };
  426. }
  427. const DefaultsSymbol = Symbol.for("vuetify:defaults");
  428. function injectDefaults() {
  429. const defaults = vue.inject(DefaultsSymbol);
  430. if (!defaults)
  431. throw new Error("[Vuetify] Could not find defaults instance");
  432. return defaults;
  433. }
  434. function propIsDefined(vnode, prop) {
  435. var _a, _b;
  436. return typeof ((_a = vnode.props) == null ? void 0 : _a[prop]) !== "undefined" || typeof ((_b = vnode.props) == null ? void 0 : _b[toKebabCase(prop)]) !== "undefined";
  437. }
  438. function internalUseDefaults() {
  439. let props = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
  440. let name = arguments.length > 1 ? arguments[1] : void 0;
  441. let defaults = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : injectDefaults();
  442. const vm = getCurrentInstance("useDefaults");
  443. name = name ?? vm.type.name ?? vm.type.__name;
  444. if (!name) {
  445. throw new Error("[Vuetify] Could not determine component name");
  446. }
  447. const componentDefaults = vue.computed(() => {
  448. var _a;
  449. return (_a = defaults.value) == null ? void 0 : _a[props._as ?? name];
  450. });
  451. const _props = new Proxy(props, {
  452. get(target, prop) {
  453. var _a, _b, _c, _d;
  454. const propValue = Reflect.get(target, prop);
  455. if (prop === "class" || prop === "style") {
  456. return [(_a = componentDefaults.value) == null ? void 0 : _a[prop], propValue].filter((v) => v != null);
  457. } else if (typeof prop === "string" && !propIsDefined(vm.vnode, prop)) {
  458. return ((_b = componentDefaults.value) == null ? void 0 : _b[prop]) ?? ((_d = (_c = defaults.value) == null ? void 0 : _c.global) == null ? void 0 : _d[prop]) ?? propValue;
  459. }
  460. return propValue;
  461. }
  462. });
  463. const _subcomponentDefaults = vue.shallowRef();
  464. vue.watchEffect(() => {
  465. if (componentDefaults.value) {
  466. const subComponents = Object.entries(componentDefaults.value).filter((_ref) => {
  467. let [key] = _ref;
  468. return key.startsWith(key[0].toUpperCase());
  469. });
  470. _subcomponentDefaults.value = subComponents.length ? Object.fromEntries(subComponents) : void 0;
  471. } else {
  472. _subcomponentDefaults.value = void 0;
  473. }
  474. });
  475. function provideSubDefaults() {
  476. const injected = injectSelf(DefaultsSymbol, vm);
  477. vue.provide(DefaultsSymbol, vue.computed(() => {
  478. return _subcomponentDefaults.value ? mergeDeep((injected == null ? void 0 : injected.value) ?? {}, _subcomponentDefaults.value) : injected == null ? void 0 : injected.value;
  479. }));
  480. }
  481. return {
  482. props: _props,
  483. provideSubDefaults
  484. };
  485. }
  486. function defineComponent(options) {
  487. options._setup = options._setup ?? options.setup;
  488. if (!options.name) {
  489. consoleWarn("The component is missing an explicit name, unable to generate default prop value");
  490. return options;
  491. }
  492. if (options._setup) {
  493. options.props = propsFactory(options.props ?? {}, options.name)();
  494. const propKeys = Object.keys(options.props).filter((key) => key !== "class" && key !== "style");
  495. options.filterProps = function filterProps(props) {
  496. return pick(props, propKeys);
  497. };
  498. options.props._as = String;
  499. options.setup = function setup(props, ctx) {
  500. const defaults = injectDefaults();
  501. if (!defaults.value)
  502. return options._setup(props, ctx);
  503. const {
  504. props: _props,
  505. provideSubDefaults
  506. } = internalUseDefaults(props, props._as ?? options.name, defaults);
  507. const setupBindings = options._setup(_props, ctx);
  508. provideSubDefaults();
  509. return setupBindings;
  510. };
  511. }
  512. return options;
  513. }
  514. function genericComponent() {
  515. let exposeDefaults = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : true;
  516. return (options) => (exposeDefaults ? defineComponent : vue.defineComponent)(options);
  517. }
  518. function getCurrentInstance(name, message) {
  519. const vm = vue.getCurrentInstance();
  520. if (!vm) {
  521. throw new Error(`[Vuetify] ${name} ${"must be called from inside a setup function"}`);
  522. }
  523. return vm;
  524. }
  525. function injectSelf(key) {
  526. let vm = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : getCurrentInstance("injectSelf");
  527. const {
  528. provides
  529. } = vm;
  530. if (provides && key in provides) {
  531. return provides[key];
  532. }
  533. return void 0;
  534. }
  535. const IconValue = [String, Function, Object, Array];
  536. const makeIconProps = propsFactory({
  537. icon: {
  538. type: IconValue
  539. },
  540. // Could not remove this and use makeTagProps, types complained because it is not required
  541. tag: {
  542. type: String,
  543. required: true
  544. }
  545. }, "icon");
  546. genericComponent()({
  547. name: "VComponentIcon",
  548. props: makeIconProps(),
  549. setup(props, _ref) {
  550. let {
  551. slots
  552. } = _ref;
  553. return () => {
  554. const Icon = props.icon;
  555. return vue.createVNode(props.tag, null, {
  556. default: () => {
  557. var _a;
  558. return [props.icon ? vue.createVNode(Icon, null, null) : (_a = slots.default) == null ? void 0 : _a.call(slots)];
  559. }
  560. });
  561. };
  562. }
  563. });
  564. defineComponent({
  565. name: "VSvgIcon",
  566. inheritAttrs: false,
  567. props: makeIconProps(),
  568. setup(props, _ref2) {
  569. let {
  570. attrs
  571. } = _ref2;
  572. return () => {
  573. return vue.createVNode(props.tag, vue.mergeProps(attrs, {
  574. "style": null
  575. }), {
  576. default: () => [vue.createVNode("svg", {
  577. "class": "v-icon__svg",
  578. "xmlns": "http://www.w3.org/2000/svg",
  579. "viewBox": "0 0 24 24",
  580. "role": "img",
  581. "aria-hidden": "true"
  582. }, [Array.isArray(props.icon) ? props.icon.map((path) => Array.isArray(path) ? vue.createVNode("path", {
  583. "d": path[0],
  584. "fill-opacity": path[1]
  585. }, null) : vue.createVNode("path", {
  586. "d": path
  587. }, null)) : vue.createVNode("path", {
  588. "d": props.icon
  589. }, null)])]
  590. });
  591. };
  592. }
  593. });
  594. const VLigatureIcon = defineComponent({
  595. name: "VLigatureIcon",
  596. props: makeIconProps(),
  597. setup(props) {
  598. return () => {
  599. return vue.createVNode(props.tag, null, {
  600. default: () => [props.icon]
  601. });
  602. };
  603. }
  604. });
  605. defineComponent({
  606. name: "VClassIcon",
  607. props: makeIconProps(),
  608. setup(props) {
  609. return () => {
  610. return vue.createVNode(props.tag, {
  611. "class": props.icon
  612. }, null);
  613. };
  614. }
  615. });
  616. const aliases = {
  617. collapse: "keyboard_arrow_up",
  618. complete: "check",
  619. cancel: "cancel",
  620. close: "close",
  621. delete: "cancel",
  622. // delete (e.g. v-chip close)
  623. clear: "cancel",
  624. success: "check_circle",
  625. info: "info",
  626. warning: "priority_high",
  627. error: "warning",
  628. prev: "chevron_left",
  629. next: "chevron_right",
  630. checkboxOn: "check_box",
  631. checkboxOff: "check_box_outline_blank",
  632. checkboxIndeterminate: "indeterminate_check_box",
  633. delimiter: "fiber_manual_record",
  634. // for carousel
  635. sortAsc: "arrow_upward",
  636. sortDesc: "arrow_downward",
  637. expand: "keyboard_arrow_down",
  638. menu: "menu",
  639. subgroup: "arrow_drop_down",
  640. dropdown: "arrow_drop_down",
  641. radioOn: "radio_button_checked",
  642. radioOff: "radio_button_unchecked",
  643. edit: "edit",
  644. ratingEmpty: "star_border",
  645. ratingFull: "star",
  646. ratingHalf: "star_half",
  647. loading: "cached",
  648. first: "first_page",
  649. last: "last_page",
  650. unfold: "unfold_more",
  651. file: "attach_file",
  652. plus: "add",
  653. minus: "remove",
  654. calendar: "event",
  655. treeviewCollapse: "arrow_drop_down",
  656. treeviewExpand: "arrow_right",
  657. eyeDropper: "colorize"
  658. };
  659. const md = {
  660. // Not using mergeProps here, functional components merge props by default (?)
  661. component: (props) => vue.h(VLigatureIcon, {
  662. ...props,
  663. class: "material-icons"
  664. })
  665. };
  666. const _sfc_main = /* @__PURE__ */ vue.defineComponent({
  667. __name: "exams-list",
  668. setup(__props) {
  669. const extractedData = extractExams();
  670. const headers = [
  671. { key: "title", title: "考试名称" },
  672. { key: "timeLeft", title: "剩余时间" },
  673. { key: "status", title: "状态" },
  674. { key: "action", title: "", sortable: false }
  675. ];
  676. const search = vue.ref("");
  677. const getCourseLinkHref = (item) => {
  678. const courseId = item.courseId;
  679. const classId = item.classId;
  680. const examId = item.examId;
  681. const requestUrl = new URL(API_OPEN_EXAM);
  682. requestUrl.searchParams.append("courseId", courseId);
  683. requestUrl.searchParams.append("classId", classId);
  684. requestUrl.searchParams.append("examId", examId);
  685. return requestUrl.href;
  686. };
  687. return (_ctx, _cache) => {
  688. const _component_v_text_field = vue.resolveComponent("v-text-field");
  689. const _component_v_btn = vue.resolveComponent("v-btn");
  690. const _component_v_data_table = vue.resolveComponent("v-data-table");
  691. const _component_v_card = vue.resolveComponent("v-card");
  692. return vue.openBlock(), vue.createBlock(_component_v_card, {
  693. title: "考试列表",
  694. variant: "flat"
  695. }, {
  696. text: vue.withCtx(() => [
  697. vue.createVNode(_component_v_text_field, {
  698. modelValue: search.value,
  699. "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => search.value = $event),
  700. label: "搜索",
  701. "prepend-inner-icon": "search",
  702. variant: "outlined",
  703. "hide-details": "",
  704. "single-line": ""
  705. }, null, 8, ["modelValue"])
  706. ]),
  707. default: vue.withCtx(() => [
  708. vue.createVNode(_component_v_data_table, {
  709. items: vue.unref(extractedData),
  710. search: search.value,
  711. hover: "",
  712. headers,
  713. sticky: "",
  714. "items-per-page": "-1",
  715. "hide-default-footer": ""
  716. }, {
  717. "item.action": vue.withCtx(({ item }) => [
  718. vue.createVNode(_component_v_btn, {
  719. variant: item.finished || item.expired ? "plain" : "tonal",
  720. color: "primary",
  721. href: getCourseLinkHref(item),
  722. target: "_blank"
  723. }, {
  724. default: vue.withCtx(() => [
  725. vue.createTextVNode(vue.toDisplayString(item.finished || item.expired ? "查看详情" : "前往考试"), 1)
  726. ]),
  727. _: 2
  728. }, 1032, ["variant", "href"])
  729. ]),
  730. _: 1
  731. }, 8, ["items", "search"])
  732. ]),
  733. _: 1
  734. });
  735. };
  736. }
  737. });
  738. const appendApp = () => {
  739. const vuetify$1 = vuetify.createVuetify({
  740. // components,
  741. // directives,
  742. icons: {
  743. defaultSet: "md",
  744. aliases,
  745. sets: {
  746. md
  747. }
  748. }
  749. });
  750. let app = _sfc_main$1;
  751. const urlDetect2 = urlDetection();
  752. if (urlDetect2 === "homework") {
  753. app = _sfc_main$2;
  754. }
  755. if (urlDetect2 === "exam") {
  756. app = _sfc_main;
  757. }
  758. vue.createApp(app).use(vuetify$1).mount(
  759. (() => {
  760. const app2 = document.createElement("div");
  761. document.body.append(app2);
  762. return app2;
  763. })()
  764. );
  765. };
  766. const urlDetect = urlDetection();
  767. if (urlDetect === "homework") {
  768. wrapElements();
  769. removeStyles();
  770. appendApp();
  771. }
  772. if (urlDetect === "exam") {
  773. wrapElements();
  774. removeStyles();
  775. appendApp();
  776. }
  777. if (urlDetect === "home") {
  778. addMenuItemExam();
  779. addMenuItem();
  780. }
  781. if (urlDetect === "legacyHome") {
  782. addMenuItemExamLegacy();
  783. addMenuItemLegacy();
  784. }
  785.  
  786. })(Vuetify, Vue);

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址