chore(frontend): move to typescript

This commit is contained in:
Qincheng Zheng 2023-10-10 17:22:03 +08:00 committed by AnnyTerfect
parent 6806700520
commit cb08d35ddf
98 changed files with 777 additions and 482 deletions

4
frontend/.eslintignore Normal file
View File

@ -0,0 +1,4 @@
node_modules
dist
.eslintrc.cjs
encrypt.ts

View File

@ -1,22 +1,28 @@
module.exports = {
root: true,
env: {
browser: true,
es2021: true,
node: true,
},
extends: [
"plugin:vue/vue3-essential",
"plugin:vue/vue3-recommended",
"eslint:recommended",
"@vue/eslint-config-prettier",
"plugin:vue/vue3-essential",
"plugin:@typescript-eslint/recommended",
],
overrides: [],
parser: "vue-eslint-parser",
parserOptions: {
ecmaVersion: "latest",
parser: "@typescript-eslint/parser",
ecmaVersion: 2020,
sourceType: "module",
project: "./tsconfig.eslint.json",
tsconfigRootDir: __dirname,
extraFileExtensions: [".vue"],
},
plugins: ["vue"],
plugins: ["@typescript-eslint", "vue"],
rules: {
"vue/multi-word-component-names": "off",
"@typescript-eslint/explicit-function-return-type": "error",
},
};

View File

@ -9,7 +9,8 @@
"dev:admin": "pnpm --filter admin run dev",
"build:admin": "pnpm --filter admin run build",
"lint": "eslint . --ext .js,.vue,.ts",
"lint:fix": "eslint --fix . --ext .js,.vue,.ts"
"lint:fix": "eslint --fix . --ext .js,.vue,.ts",
"type-check": "tsc --noEmit"
},
"dependencies": {
"vee-validate": "^4.8.4",
@ -23,6 +24,8 @@
"devDependencies": {
"@mdi/font": "^7.2.96",
"@types/node": "^20.8.4",
"@typescript-eslint/eslint-plugin": "^6.7.5",
"@typescript-eslint/parser": "^6.7.5",
"@vitejs/plugin-vue": "^4.1.0",
"@vue/eslint-config-prettier": "^7.1.0",
"eslint": "^8.43.0",

View File

@ -8,6 +8,6 @@
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { ref, computed, watch } from "vue";
import { useStore } from "vuex";
import { useI18n } from "vue-i18n";

View File

@ -1,15 +1,15 @@
<script setup>
<script setup lang="ts">
import { ref } from "vue";
const emits = defineEmits(["confirm"]);
const emits = defineEmits(["confirm"])
const dialog = ref(false);
const dialog = ref<boolean>(false);
function confirm() {
function confirm(): void {
dialog.value = true;
}
function emitConfirm() {
function emitConfirm(): void {
emits("confirm");
dialog.value = false;
}

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { ref, nextTick } from "vue";
const start = ref(false);

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { useStore } from "vuex";
import { ref, onMounted } from "vue";
import { useRouter } from "vue-router";
@ -8,7 +8,7 @@ const router = useRouter();
const store = useStore();
const animateClass = ref([]);
const animateClass = ref<string[]>([]);
onMounted(() => {
animateClass.value = ["animate__animated", "animate__tada"];

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { computed } from "vue";
import { useDisplay } from "vuetify";
import UserList from "./UserList.vue";
@ -50,39 +50,50 @@ const props = defineProps({
},
});
const realCols = computed(() => props[display.name.value] || props.cols);
const realCols = computed(() => {
if (display.name.value === "xs") {
return props.xs;
}
if (display.name.value === "sm") {
return props.sm;
}
if (display.name.value === "md") {
return props.md;
}
return props.cols;
});
const greaterThanXs = computed(() => {
return display.name.value !== "xs";
});
function nextPage() {
function nextPage(): void {
if (props.page < props.pageNum) {
jumpPage(props.page + 1);
}
}
function formerPage() {
function formerPage(): void {
if (props.page > 1) {
jumpPage(props.page - 1);
}
}
function jumpPage(newPage) {
function jumpPage(newPage: number): void {
if (newPage >= 1 && newPage <= props.pageNum) {
emits("pageChange", newPage);
}
}
function handleClickReset(id) {
function handleClickReset(id: string): void {
emits("click:reset", id);
}
function handleClickDelete(id) {
function handleClickDelete(id: string): void {
emits("click:delete", id);
}
function handleClickExport(id) {
function handleClickExport(id: string): void {
emits("click:export", id);
}
</script>

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { ref, onMounted, nextTick } from "vue";
import { useRouter } from "vue-router";
@ -55,7 +55,7 @@ onMounted(() => {
rounded
variant="outlined"
width="90"
@click="router.go()"
@click="router.go(0)"
>
Close
</v-btn>

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { computed } from "vue";
import { useDisplay } from "vuetify";
import oopsImg from "/oops.svg?url";
@ -7,40 +7,50 @@ const emits = defineEmits(["click:reset", "click:delete", "click:export"]);
const display = useDisplay();
const props = defineProps({
export interface Props {
items: {
type: Array,
required: true,
},
cols: {
type: Number,
default: 2,
},
md: {
type: Number,
default: 1,
},
sm: {
type: Number,
default: 1,
},
xs: {
type: Number,
default: 1,
},
id: string;
username: string;
email: string;
verified_learnware_count: number;
unverified_learnware_count: number;
}[],
cols?: number,
md?: number,
sm?: number,
xs?: number,
}
const props = withDefaults(defineProps<Props>(), {
cols: 2,
md: 1,
sm: 1,
xs: 1,
});
const realCols = computed(() => props[display.name.value] || props.cols);
function handleClickReset(id) {
const realCols = computed(() => {
if (display.name.value === "xs") {
return props.xs;
}
if (display.name.value === "sm") {
return props.sm;
}
if (display.name.value === "md") {
return props.md;
}
return props.cols;
})
function handleClickReset(id: string): void {
emits("click:reset", id);
}
function handleClickDelete(id) {
function handleClickDelete(id: string): void {
emits("click:delete", id);
}
function handleClickExport() {
function handleClickExport(): void {
emits("click:export");
}
</script>

View File

@ -7,7 +7,4 @@ import * as directives from "vuetify/directives";
export default createVuetify({
components,
directives,
icons: {
iconfont: "mdi", // default - only for display purposes
},
});

View File

@ -1,5 +1,6 @@
import { createRouter, createWebHashHistory } from "vue-router";
import store from "@main/store";
import { Component } from "vue";
const Router = createRouter({
history: createWebHashHistory(),
@ -7,7 +8,8 @@ const Router = createRouter({
{
path: "/",
name: "Home",
component: () => import("@/views/Home.vue"),
component: (): Promise<Component> => import("@/views/Home.vue"),
meta: {
showInNavBar: true,
icon: "mdi-home",
@ -16,7 +18,7 @@ const Router = createRouter({
{
path: "/summary",
name: "Summary",
component: () => import("@/views/Summary.vue"),
component: (): Promise<Component> => import("@/views/Summary.vue"),
meta: {
showInNavBar: true,
requiredLogin: true,
@ -27,7 +29,7 @@ const Router = createRouter({
{
path: "/alllearnware",
name: "Learnwares",
component: () => import("@/views/Learnwares.vue"),
component: (): Promise<Component> => import("@/views/Learnwares.vue"),
meta: {
showInNavBar: true,
requiredLogin: true,
@ -38,7 +40,7 @@ const Router = createRouter({
{
path: "/submit",
name: "Submit",
component: () => import("@main/views/Submit.vue"),
component: (): Promise<Component> => import("@main/views/Submit.vue"),
meta: {
showInNavBar: false,
requiredLogin: true,
@ -49,7 +51,7 @@ const Router = createRouter({
{
path: "/alluser",
name: "Users",
component: () => import("@/views/Users.vue"),
component: (): Promise<Component> => import("@/views/Users.vue"),
meta: {
showInNavBar: true,
requiredLogin: true,
@ -60,7 +62,7 @@ const Router = createRouter({
{
path: "/learnwaredetail",
name: "LearnwareDetail",
component: () => import("@main/views/LearnwareDetail.vue"),
component: (): Promise<Component> => import("@main/views/LearnwareDetail.vue"),
meta: {
showInNavBar: false,
icon: "mdi-bullseye-arrow",
@ -69,7 +71,7 @@ const Router = createRouter({
{
path: "/userlearnware",
name: "UserLearnware",
component: () => import("@main/views/MyLearnware.vue"),
component: (): Promise<Component> => import("@main/views/MyLearnware.vue"),
meta: {
name: "My Learnware",
showInNavBar: false,
@ -89,7 +91,7 @@ const Router = createRouter({
{
path: "/login",
name: "Login",
component: () => import("@/views/Login.vue"),
component: (): Promise<Component> => import("@/views/Login.vue"),
meta: {
showInNavBar: true,
hideWhenLoggedIn: true,
@ -99,7 +101,7 @@ const Router = createRouter({
{
path: "/logout",
name: "Logout",
component: () => import("@main/views/Logout.vue"),
component: (): Promise<Component> => import("@main/views/Logout.vue"),
meta: {
showInNavBar: true,
requiredLogin: true,
@ -121,7 +123,7 @@ const Router = createRouter({
{
path: "/language/zh",
name: "Chinese",
component: () => import("@main/views/ChangeLanguage.vue"),
component: (): Promise<Component> => import("@main/views/ChangeLanguage.vue"),
meta: {
showInNavBar: true,
icon: "🇨🇳",
@ -131,7 +133,7 @@ const Router = createRouter({
{
path: "/language/en",
name: "English",
component: () => import("@main/views/ChangeLanguage.vue"),
component: (): Promise<Component> => import("@main/views/ChangeLanguage.vue"),
meta: {
showInNavBar: true,
icon: "🇺🇸",
@ -143,7 +145,7 @@ const Router = createRouter({
],
});
Router.beforeEach((to, from, next) => {
Router.beforeEach((to, _from, next) => {
if (to.matched.some((record) => record.meta.requiredLogin)) {
if (store && !store.getters.getLoggedIn) {
store.commit("setShowGlobalError", true);

View File

@ -1,4 +1,4 @@
function downloadLearnware(id) {
function downloadLearnware(id: string): void {
const url = `/api/engine/download_learnware?learnware_id=${id}`;
window.open(url);
}

View File

@ -1,4 +1,4 @@
/* eslint-disable no-unused-vars */
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/*
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
* Digest Algorithm, as defined in RFC 1321.
@ -8,11 +8,10 @@
* See http://pajhome.org.uk/crypt/md5 for more info.
*/
/*
* Configurable variables. You may need to tweak these to be compatible with
* Configurable letiables. You may need to tweak these to be compatible with
* the server-side, but the defaults work in most cases.
*/
const hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
const b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
const chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
/*
* These are the functions you'll usually want to call
@ -21,27 +20,6 @@ const chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
function hex_md5(s) {
return binl2hex(core_md5(str2binl(s), s.length * chrsz));
}
function b64_md5(s) {
return binl2b64(core_md5(str2binl(s), s.length * chrsz));
}
function str_md5(s) {
return binl2str(core_md5(str2binl(s), s.length * chrsz));
}
function hex_hmac_md5(key, data) {
return binl2hex(core_hmac_md5(key, data));
}
function b64_hmac_md5(key, data) {
return binl2b64(core_hmac_md5(key, data));
}
function str_hmac_md5(key, data) {
return binl2str(core_hmac_md5(key, data));
}
/*
* Perform a simple self-test to see if the VM is working
*/
function md5_vm_test() {
return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
}
/*
* Calculate the MD5 of an array of little-endian words, and a bit length
*/
@ -127,7 +105,7 @@ function core_md5(x, len) {
c = safe_add(c, oldc);
d = safe_add(d, oldd);
}
return Array(a, b, c, d);
return [a, b, c, d];
}
/*
* These functions implement the four basic operations the algorithm uses.
@ -147,21 +125,6 @@ function md5_hh(a, b, c, d, x, s, t) {
function md5_ii(a, b, c, d, x, s, t) {
return md5_cmn(c ^ (b | ~d), a, b, x, s, t);
}
/*
* Calculate the HMAC-MD5, of a key and some data
*/
function core_hmac_md5(key, data) {
let bkey = str2binl(key);
if (bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);
const ipad = Array(16);
const opad = Array(16);
for (let i = 0; i < 16; i++) {
ipad[i] = bkey[i] ^ 0x36363636;
opad[i] = bkey[i] ^ 0x5c5c5c5c;
}
const hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
return core_md5(opad.concat(hash), 512 + 128);
}
/*
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
* to work around bugs in some JS interpreters.
@ -182,22 +145,12 @@ function bit_rol(num, cnt) {
* If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
*/
function str2binl(str) {
const bin = Array();
const bin = [];
const mask = (1 << chrsz) - 1;
for (let i = 0; i < str.length * chrsz; i += chrsz)
bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << i % 32;
return bin;
}
/*
* Convert an array of little-endian words to a string
*/
function binl2str(bin) {
let str = "";
const mask = (1 << chrsz) - 1;
for (let i = 0; i < bin.length * 32; i += chrsz)
str += String.fromCharCode((bin[i >> 5] >>> i % 32) & mask);
return str;
}
/*
* Convert an array of little-endian words to a hex string.
*/
@ -211,23 +164,5 @@ function binl2hex(binarray) {
}
return str;
}
/*
* Convert an array of little-endian words to a base-64 string
*/
function binl2b64(binarray) {
const tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
let str = "";
for (let i = 0; i < binarray.length * 4; i += 3) {
const triplet =
(((binarray[i >> 2] >> (8 * (i % 4))) & 0xff) << 16) |
(((binarray[(i + 1) >> 2] >> (8 * ((i + 1) % 4))) & 0xff) << 8) |
((binarray[(i + 2) >> 2] >> (8 * ((i + 2) % 4))) & 0xff);
for (let j = 0; j < 4; j++) {
if (i * 8 + j * 6 > binarray.length * 32) str += b64pad;
else str += tab.charAt((triplet >> (6 * (3 - j))) & 0x3f);
}
}
return str;
}
export { hex_md5 };

View File

@ -1,32 +0,0 @@
import Router from "@/router/index";
import store from "@main/store";
function fetchex(url, options) {
const token = localStorage.getItem("token");
if (token !== null) {
if (options === undefined) {
options = {};
}
if (!("headers" in options)) {
options.headers = {};
}
options.headers["Authorization"] = `Bearer ${token}`;
}
return fetch(url, options).then((response) => {
if (response.status === 200) {
return response;
} else if (response.status === 401) {
// Unauthorized
Router.push("/login");
store.commit("setLoggedIn", false);
} else {
throw new Error(
`Network error: ${response.status}${
response.statusText ? ` - ${response.statusText}` : ""
}`,
);
}
});
}
export { fetchex };

View File

@ -0,0 +1,30 @@
import Router from "../router";
import store from "@main/store";
async function fetchex(url: string, options: RequestInit = {}): Promise<Response | undefined> {
const token = localStorage.getItem("token");
if (token !== null) {
if (!options.headers) {
options.headers = new Headers();
}
(options.headers as Headers).append("Authorization", `Bearer ${token}`);
}
return fetch(url, options).then((response) => {
if (response.status === 200) {
return response;
}
if (response.status === 401) {
// Unauthorized
Router.push("/login");
store.commit("setLoggedIn", false);
return;
}
throw new Error(
`Network error: ${response.status}${
response.statusText ? ` - ${response.statusText}` : ""
}`,
);
});
}
export { fetchex };

View File

@ -1,4 +1,4 @@
export default function saveContentToFile(content, fileName) {
export default function saveContentToFile(content: BlobPart, fileName: string): void {
const blob = new Blob([content], { type: "text/csv;charset=utf-8" });
const url = window.URL.createObjectURL(blob);
const link = document.createElement("a");

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import Slogan from "@/components/Home/Slogan.vue";
</script>

View File

@ -1,21 +1,30 @@
<script setup>
<script setup lang="ts">
import { ref, watch, onMounted, nextTick, onActivated } from "vue";
import { useRouter } from "vue-router";
import { useI18n } from "vue-i18n";
import { fetchex } from "@/utils";
import { fetchex } from "../utils/fetchex";
import UserRequirement from "@main/components/Search/UserRequirement.vue";
import PageLearnwareList from "@main/components/Learnware/PageLearnwareList.vue";
import ConfirmDialog from "@/components/Dialogs/ConfirmDialog.vue";
export interface Filters {
name: string;
dataType: string;
taskType: string;
libraryType: string;
tagList: never[];
files: never[];
}
const router = useRouter();
const { t } = useI18n();
const dialog = ref(null);
const dialog = ref<InstanceType<typeof ConfirmDialog>>();
const deleteId = ref("");
const deleteName = ref("");
const filters = ref({
const filters = ref<Filters>({
name: "",
dataType: "",
taskType: "",
@ -27,22 +36,34 @@ const filters = ref({
const page = ref(1);
const pageSize = ref(10);
const pageNum = ref(1);
const learnwareItems = ref([]);
const learnwareItems = ref<
{
id: string;
username: string;
lastModify: string;
name: string;
description: string;
dataType: string;
taskType: string;
libraryType: string;
tagList: string[];
}[]
>([]);
const isVerify = ref(true);
const loading = ref(false);
const contentRef = ref(null);
const contentRef = ref<HTMLElement | null>(null);
const scrollTop = ref(0);
const success = ref(false);
const showError = ref(false);
const errorMsg = ref("");
const successTimer = ref(null);
const errorTimer = ref(null);
const successTimer = ref<string | number | undefined>();
const errorTimer = ref<string | number | undefined>();
function deleteLearnware(id) {
function deleteLearnware(id: string): void {
showError.value = false;
fetchex("/api/admin/delete_learnware", {
@ -55,7 +76,7 @@ function deleteLearnware(id) {
}),
})
.then((res) => {
if (res.status === 200) {
if (res && res.status === 200) {
return res;
}
throw new Error("Network error");
@ -92,12 +113,17 @@ function deleteLearnware(id) {
});
}
function pageChange(newPage) {
function pageChange(newPage: number): void {
page.value = newPage;
contentRef.value && (contentRef.value.scrollTop = 0);
}
function fetchLearnware(isVerify, page, limit, fd) {
function fetchLearnware(
isVerify: boolean,
page: number,
limit: number,
fd: FormData,
): Promise<Response | undefined> {
if (isVerify) {
return fetchex("/api/engine/search_learnware", {
method: "POST",
@ -118,7 +144,17 @@ function fetchLearnware(isVerify, page, limit, fd) {
}
}
function fetchByFilterAndPage(filters, page) {
function fetchByFilterAndPage(
filters: {
name: string;
dataType: string;
taskType: string;
libraryType: string;
tagList: never[];
files: never[];
},
page: number,
): void {
if (contentRef.value) {
contentRef.value.scrollTop = 0;
}
@ -127,7 +163,12 @@ function fetchByFilterAndPage(filters, page) {
loading.value = true;
fetchex("/api/engine/semantic_specification")
.then((res) => res.json())
.then((res) => {
if (res) {
return res.json();
}
throw new Error("Network error");
})
.then((res) => {
const semanticSpec = res.data.semantic_specification;
semanticSpec.Name.Values = filters.name;
@ -139,15 +180,15 @@ function fetchByFilterAndPage(filters, page) {
const fd = new FormData();
fd.append("semantic_specification", JSON.stringify(semanticSpec));
fd.append("statistical_specification", null);
fd.append("limit", pageSize.value);
fd.append("page", page - 1);
fd.append("statistical_specification", "");
fd.append("limit", String(pageSize.value));
fd.append("page", String(page - 1));
return fd;
})
.then((fd) => {
return fetchLearnware(isVerify.value, page, pageSize.value, fd)
.then((res) => {
if (res.status === 200) {
if (res && res.status === 200) {
return res;
}
throw new Error("Network error");
@ -157,17 +198,31 @@ function fetchByFilterAndPage(filters, page) {
switch (res.code) {
case 0: {
loading.value = false;
learnwareItems.value = res.data.learnware_list_single.map((item) => ({
id: item.learnware_id,
username: item.username,
lastModify: item.last_modify,
name: item.semantic_specification.Name.Values,
description: item.semantic_specification.Description.Values,
dataType: item.semantic_specification.Data.Values[0],
taskType: item.semantic_specification.Task.Values[0],
libraryType: item.semantic_specification.Library.Values[0],
tagList: item.semantic_specification.Scenario.Values,
}));
learnwareItems.value = res.data.learnware_list_single.map(
(item: {
learnware_id: string;
username: string;
last_modify: string;
semantic_specification: {
Name: { Values: string };
Description: { Values: string };
Data: { Values: string[] };
Task: { Values: string[] };
Library: { Values: string[] };
Scenario: { Values: string[] };
};
}) => ({
id: item.learnware_id,
username: item.username,
lastModify: item.last_modify,
name: item.semantic_specification.Name.Values,
description: item.semantic_specification.Description.Values,
dataType: item.semantic_specification.Data.Values[0],
taskType: item.semantic_specification.Task.Values[0],
libraryType: item.semantic_specification.Library.Values[0],
tagList: item.semantic_specification.Scenario.Values,
}),
);
pageNum.value = res.data.total_pages;
return;
}
@ -187,20 +242,20 @@ function fetchByFilterAndPage(filters, page) {
});
}
function handleClickEdit(id) {
function handleClickEdit(id: string): void {
router.push({
path: "/submit",
query: {
edit: true,
edit: "true",
id,
},
});
}
function handleClickDelete(id) {
function handleClickDelete(id: string): void {
dialog.value.confirm();
deleteId.value = id;
deleteName.value = learnwareItems.value.find((item) => item.id === id).name;
deleteName.value = (learnwareItems.value.find((item) => item.id === id) as { name: string }).name;
}
watch(
@ -237,7 +292,7 @@ watch(
watch(
() => [filters.value, page.value],
(newVal) => {
const [newFilters, newPage] = newVal;
const [newFilters, newPage] = newVal as [Filters, number];
fetchByFilterAndPage(newFilters, newPage);
},
@ -245,15 +300,19 @@ watch(
);
onActivated(() => {
contentRef.value.scrollTop = scrollTop.value;
if (contentRef.value) {
contentRef.value.scrollTop = scrollTop.value;
}
fetchByFilterAndPage(filters.value, page.value);
});
onMounted(() => {
nextTick(() => {
contentRef.value.addEventListener("scroll", () => {
scrollTop.value = contentRef.value.scrollTop;
});
if (contentRef.value) {
contentRef.value.addEventListener("scroll", () => {
if (contentRef.value) scrollTop.value = contentRef.value.scrollTop;
});
}
});
});
</script>

View File

@ -1,9 +1,9 @@
<script setup>
<script setup lang="ts">
import { ref, computed } from "vue";
import { useStore } from "vuex";
import { useRouter } from "vue-router";
import { useField, useForm } from "vee-validate";
import { fetchex } from "@/utils";
import { fetchex } from "../utils"
import collaborationImg from "@/assets/images/collaboration.svg?url";
const store = useStore();
@ -31,7 +31,7 @@ const showError = ref(false);
const errorMsg = ref("");
const success = ref(false);
const errorTimer = ref(null);
const errorTimer = ref<number>();
const valid = computed(() => {
return meta.value.valid;
@ -54,7 +54,7 @@ const login = handleSubmit((values) => {
body: JSON.stringify(data),
})
.then((res) => {
if (res.status === 200) {
if (res && res.status === 200) {
return res;
}
throw new Error("Network error");
@ -77,7 +77,7 @@ const login = handleSubmit((values) => {
}),
)
.then((res) => {
if (res.status === 200) {
if (res && res.status === 200) {
return res;
}
throw new Error("Network error");
@ -109,13 +109,13 @@ const login = handleSubmit((values) => {
showError.value = true;
errorMsg.value = err.message;
clearTimeout(errorTimer.value);
errorTimer.value = setTimeout(() => {
errorTimer.value = Number(setTimeout(() => {
showError.value = false;
}, 3000);
}, 3000));
});
});
function closeErrorAlert() {
function closeErrorAlert(): void {
showError.value = false;
clearTimeout(errorTimer.value);
}

View File

@ -1,8 +1,8 @@
<script setup>
<script setup lang="ts">
import { ref, onActivated } from "vue";
import { Pie } from "vue-chartjs";
import { Chart as ChartJS, ArcElement, Tooltip, Legend } from "chart.js";
import { fetchex } from "@/utils";
import { fetchex } from "../utils";
ChartJS.register(ArcElement, Tooltip, Legend);
@ -19,12 +19,18 @@ const options = ref({
const showError = ref(false);
const errorMsg = ref("");
const errorTimer = ref(null);
const errorTimer = ref<number>();
function fetchSummary() {
function fetchSummary(): void {
countDetail.value = {};
fetchex("/api/admin/summary", { method: "POST" })
.then((res) => {
if (res && res.status === 200) {
return res;
}
throw new Error("Network error");
})
.then((res) => res.json())
.then((res) => {
if (res.code !== 0) {
@ -47,7 +53,17 @@ function fetchSummary() {
});
}
function getPieData(counts, key) {
function getPieData(
counts,
key,
): {
labels: string[];
datasets: {
label: string;
backgroundColor: string[];
data: number[];
}[];
} {
return {
labels: Object.keys(counts),
datasets: [

View File

@ -1,8 +1,8 @@
<script setup>
<script setup lang="ts">
import { ref, computed, onActivated, watch } from "vue";
import { useStore } from "vuex";
import { useRouter } from "vue-router";
import { fetchex, saveContentToFile } from "@/utils";
import { fetchex, saveContentToFile } from "../utils";
import SuccessDialog from "@/components/Dialogs/SuccessDialog.vue";
import ConfirmDialog from "@/components/Dialogs/ConfirmDialog.vue";
import PageUserList from "@/components/User/PageUserList.vue";
@ -23,7 +23,7 @@ const newPassword = ref("");
const showError = ref(false);
const errorMsg = ref("");
const errorTimer = ref(null);
const errorTimer = ref<number>();
const userName = ref("");
const email = ref("");
@ -40,7 +40,7 @@ const filters = computed(() => ({
email: email.value,
}));
function fetchByFilterAndPage(filters, page) {
function fetchByFilterAndPage(filters, page): Promise<void> {
loading.value = true;
showError.value = false;
@ -71,7 +71,7 @@ function fetchByFilterAndPage(filters, page) {
}
if (res.code === 11 || res.code === 12) {
store.commit("setLoggedIn", false);
router.go();
router.go(0);
}
throw new Error(res.msg);
})
@ -87,8 +87,8 @@ function fetchByFilterAndPage(filters, page) {
});
}
function resetPassword(id) {
fetchex("/api/admin/reset_password", {
function resetPassword(id): Promise<void> {
return fetchex("/api/admin/reset_password", {
method: "POST",
headers: {
"Content-Type": "application/json",
@ -119,14 +119,14 @@ function resetPassword(id) {
showError.value = true;
errorMsg.value = err.message;
clearTimeout(errorTimer.value);
errorTimer.value = setTimeout(() => {
errorTimer.value = Number(setTimeout(() => {
showError.value = false;
}, 3000);
}, 3000));
});
}
function deleteUser(id) {
fetchex("/api/admin/delete_user", {
function deleteUser(id): Promise<void> {
return fetchex("/api/admin/delete_user", {
method: "POST",
headers: {
"Content-Type": "application/json",
@ -170,24 +170,24 @@ function deleteUser(id) {
});
}
function pageChange(newPage) {
function pageChange(newPage): void {
console.log(newPage);
page.value = newPage;
}
function handleClickReset(id) {
function handleClickReset(id): void {
resetDialog.value.confirm();
resetId.value = id;
resetName.value = userItems.value.find((item) => item.id === id).username;
}
function handleClickDelete(id) {
function handleClickDelete(id): void {
deleteDialog.value.confirm();
deleteId.value = id;
deleteName.value = userItems.value.find((item) => item.id === id).username;
}
async function handleClickExport() {
async function handleClickExport(): Promise<void> {
const table = [["Username", "Email", "Verified", "Unverified"]];
for (let _page = 1; _page <= pageNum.value; _page++) {
await fetchex("/api/admin/list_user", {
@ -217,7 +217,7 @@ async function handleClickExport() {
}
if (res.code === 11 || res.code === 12) {
store.commit("setLoggedIn", false);
router.go();
router.go(0);
}
throw new Error(res.msg);
})

View File

@ -8,6 +8,6 @@
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { ref, computed, watch } from "vue";
import { useStore } from "vuex";
import { useI18n } from "vue-i18n";
@ -24,17 +24,17 @@ const routes = computed(() =>
route.children.forEach((child) => {
child.meta = {
...child.meta,
title: t(`Page.${route.name}.${child.name}`),
title: t(`Page.${String(route.name)}.${String(child.name)}`),
};
route.meta = {
...route.meta,
title: t(`Page.${route.name}.${route.name}`),
title: t(`Page.${String(route.name)}.${String(route.name)}`),
};
});
} else {
route.meta = {
...route.meta,
title: t(`Page.${route.name}`),
title: t(`Page.${String(route.name)}`),
};
}
return route;

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { computed } from "vue";
import { useDisplay } from "vuetify";
import { useRouter } from "vue-router";
@ -23,7 +23,7 @@ const display = useDisplay();
const store = useStore();
function routeFilter(route) {
function routeFilter(route): boolean {
if (route.meta.showInNavBar) {
if (route.meta.hideWhenLoggedIn && store.getters.getLoggedIn) {
return false;

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { computed } from "vue";
import { useStore } from "vuex";
import { useDisplay } from "vuetify";
@ -25,8 +25,22 @@ const drawer = computed({
const store = useStore();
interface Route {
name: string;
path: string;
meta: {
showInNavBar: boolean;
hideWhenLoggedIn: boolean;
requiredLogin: boolean;
icon: string;
title: string;
};
children?: Route[];
parent?: Route;
}
const filteredRoutes = computed(() => {
function filter(route) {
function filter(route: Route): boolean {
if (route.meta.showInNavBar) {
if (route.meta.hideWhenLoggedIn && store.getters.getLoggedIn) {
return false;
@ -40,7 +54,7 @@ const filteredRoutes = computed(() => {
}
}
const routes = [];
const routes: Route[] = [];
props.routes.forEach((route) => {
if (route.children) {
route.children.forEach((child) => {

View File

@ -1,15 +1,15 @@
<script setup>
<script setup lang="ts">
import { ref } from "vue";
const emits = defineEmits(["confirm"]);
const dialog = ref(false);
function confirm() {
function confirm(): void {
dialog.value = true;
}
function emitConfirm() {
function emitConfirm(): void {
emits("confirm");
dialog.value = false;
}

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { ref, computed } from "vue";
const props = defineProps({

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { useRouter } from "vue-router";
import { useI18n } from "vue-i18n";
import BigTitle from "../Public/BigTitle.vue";

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { useI18n } from "vue-i18n";
import process from "../../assets/images/home/process.svg?url";

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { computed } from "vue";
import { useI18n } from "vue-i18n";

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { ref, onMounted, nextTick, onBeforeUnmount } from "vue";
import { useI18n } from "vue-i18n";

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { useI18n } from "vue-i18n";
import analogyImg from "../../assets/images/home/analogy.png";

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { computed } from "vue";
import { useDisplay } from "vuetify";
import { useI18n } from "vue-i18n";

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { ref, computed } from "vue";
import { useDisplay } from "vuetify";
import { useI18n } from "vue-i18n";
@ -52,17 +52,17 @@ const dataTypeBtns = {
Audio: AudioBtn,
};
function getColorByScore(score) {
function getColorByScore(score): string {
if (score > 80) return colors.green.base;
if (score > 50) return colors.orange.base;
return colors.red.base;
}
function handleClickEdit(id) {
function handleClickEdit(id): void {
emit("click:edit", id);
}
function handleClickDelete(id) {
function handleClickDelete(id): void {
emit("click:delete", id);
}
</script>

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { computed } from "vue";
import { useDisplay } from "vuetify";
import { useRouter } from "vue-router";
@ -47,15 +47,15 @@ const props = defineProps({
const realCols = computed(() => props[display.name.value] || props.cols);
function handleClickEdit(id) {
function handleClickEdit(id: string): void {
emit("click:edit", id);
}
function handleClickDelete(id) {
function handleClickDelete(id: string): void {
emit("click:delete", id);
}
function showLearnwareDetail(id) {
function showLearnwareDetail(id: string): void {
router.push({ path: "/learnwaredetail", query: { id } });
}
</script>

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { ref, computed } from "vue";
import { useDisplay } from "vuetify";
import { useStore } from "vuex";
@ -59,11 +59,11 @@ const downloading = ref(false);
const realCols = computed(() => props[display.name.value] || props.cols);
function showLearnwareDetail(id) {
function showLearnwareDetail(id): void {
router.push({ path: "/learnwaredetail", query: { id } });
}
function downloadAll() {
function downloadAll(): void {
downloading.value = true;
const zip = new JSZip();
@ -94,7 +94,7 @@ function downloadAll() {
});
}
function getColorByScore(score) {
function getColorByScore(score): string {
if (score > 80) return colors.green.base;
if (score > 50) return colors.orange.base;
return colors.red.base;

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { computed } from "vue";
import { useDisplay } from "vuetify";
import { VSkeletonLoader } from "vuetify/labs/VSkeletonLoader";
@ -62,29 +62,29 @@ const realCols = computed(() => props[display.name.value] || props.cols);
const greaterThanXs = computed(() => display.name.value !== "xs");
function jumpPage(newPage) {
function jumpPage(newPage): void {
if (newPage >= 1 && newPage <= props.pageNum) {
emit("pageChange", newPage);
}
}
function nextPage() {
function nextPage(): void {
if (props.page < props.pageNum) {
jumpPage(props.page + 1);
}
}
function formerPage() {
function formerPage(): void {
if (props.page > 1) {
jumpPage(props.page - 1);
}
}
function handleClickEdit(id) {
function handleClickEdit(id): void {
emit("click:edit", id);
}
function handleClickDelete(id) {
function handleClickDelete(id): void {
emit("click:delete", id);
}
</script>

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { computed } from "vue";
import { useDisplay } from "vuetify";
@ -36,9 +36,9 @@ const props = defineProps({
},
});
const isStepActive = (index) => props.currentStep === index;
const isStepActive = (index): void => props.currentStep === index;
const activeStep = (index) => {
const activeStep = (index): void => {
emit("active-step", index);
};
</script>

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { ref, computed, watch } from "vue";
import { useRoute } from "vue-router";
import { useI18n } from "vue-i18n";

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { ref, watch } from "vue";
import { useI18n } from "vue-i18n";
import { useDisplay } from "vuetify";

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { ref, computed } from "vue";
import { useI18n } from "vue-i18n";
@ -24,16 +24,16 @@ const props = defineProps({
const dragging = ref(false);
const fileInput = ref(null);
const handleDrop = (event) => {
const handleDrop = (event): void => {
dragging.value = false;
files.value = Array.from(event.dataTransfer.files);
};
const chooseFile = () => {
const chooseFile = (): void => {
fileInput.value.click();
};
const computeFileSize = (byte) => {
const computeFileSize = (byte): string => {
const unit = ["B", "KB", "MB", "GB"];
let k = 0;
while (k < 4) {

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { computed } from "vue";
import { useI18n } from "vue-i18n";
import DataTypeBtns from "../Specification/SpecTag/DataType.vue";

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { ref, watch, computed } from "vue";
import GridBtns from "./GridBtns.vue";
import AudioBtn from "../../../assets/images/specification/dataType/audio.svg?component";

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { ref, computed, watch } from "vue";
import { useDisplay } from "vuetify";
import IconBtn from "./IconBtn.vue";
@ -54,7 +54,7 @@ const realCols = computed(() => {
return cols;
});
function clickBtn(btn) {
function clickBtn(btn): void {
value.value = btn.value === value.value ? "" : btn.value;
}

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
const emit = defineEmits(["click"]);
defineProps({

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { ref, computed, watch } from "vue";
import GridBtns from "./GridBtns.vue";
import TensorFlowBtn from "../../../assets/images/specification/libraryType/tensorflow.svg?component";

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { ref, computed, watch } from "vue";
import { useDisplay } from "vuetify";
import IconBtn from "./IconBtn.vue";
@ -54,7 +54,7 @@ const realCols = computed(() => {
return cols;
});
function clickBtn(btn) {
function clickBtn(btn): void {
if (!value.value) {
value.value = [];
}

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { computed } from "vue";
import { useDisplay } from "vuetify";
import { useI18n } from "vue-i18n";
@ -126,7 +126,7 @@ const selections = computed(() => {
return [];
});
function click(value) {
function click(value): void {
if (props.value && props.value.includes(value)) {
deleteSelect(value);
} else {
@ -134,7 +134,7 @@ function click(value) {
}
}
function addSelect(value) {
function addSelect(value): void {
if (props.value) {
emit("update:value", [...props.value, value]);
} else {
@ -142,7 +142,7 @@ function addSelect(value) {
}
}
function deleteSelect(value) {
function deleteSelect(value): void {
if (props.value) {
emit(
"update:value",

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { ref, computed, watch } from "vue";
import GridBtns from "./GridBtns.vue";
import ClassificationBtn from "../../../assets/images/specification/taskType/classification.svg?component";

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { ref, onMounted, nextTick } from "vue";
import { useRouter } from "vue-router";
import { resendEmail } from "../../request/auth";
@ -22,8 +22,8 @@ onMounted(() => {
});
});
function onResend() {
resendEmail(email.value)
function onResend(): Promise<void> {
return resendEmail(email.value)
.then((res) => {
if (res.code === 0) {
dialog.value = false;
@ -74,7 +74,7 @@ function onResend() {
rounded
variant="outlined"
width="90"
@click="router.go()"
@click="router.go(0)"
>
Close
</v-btn>

View File

@ -2,7 +2,7 @@ import { checkedFetch } from "../utils";
const BASE_URL = "./api/admin";
function listLearnware({ userId, page, limit }) {
function listLearnware({ userId, page, limit }): Promise<Response> {
return checkedFetch(`${BASE_URL}/list_learnware`, {
method: "POST",
headers: {

View File

@ -2,7 +2,7 @@ import { checkedFetch } from "../utils";
const BASE_URL = "./api/auth";
function login({ email, passwordMd5 }) {
function login({ email, passwordMd5 }): Promise<Response> {
return checkedFetch(`${BASE_URL}/login`, {
method: "POST",
headers: {
@ -15,13 +15,13 @@ function login({ email, passwordMd5 }) {
}).then((res) => res.json());
}
function logout() {
function logout(): Promise<Response> {
return checkedFetch(`${BASE_URL}/logout`, {
method: "POST",
}).then((res) => res.json());
}
function register({ username, email, passwordMd5 }) {
function register({ username, email, passwordMd5 }): Promise<Response> {
return checkedFetch(`${BASE_URL}/register`, {
method: "POST",
headers: {
@ -35,19 +35,19 @@ function register({ username, email, passwordMd5 }) {
}).then((res) => res.json());
}
function getRole() {
function getRole(): Promise<Response> {
return checkedFetch(`${BASE_URL}/get_role`, {
method: "POST",
}).then((res) => res.json());
}
function verifyEmail(params) {
function verifyEmail(params): Promise<Response> {
return checkedFetch(`${BASE_URL}/email_confirm?` + params, {
method: "POST",
}).then((res) => res.json());
}
function resendEmail(email) {
function resendEmail(email): Promise<Response> {
return checkedFetch(`${BASE_URL}/resend_email_confirm`, {
method: "POST",
headers: {

View File

@ -2,19 +2,28 @@ import { checkedFetch } from "../utils";
const BASE_URL = "./api/engine";
function downloadLearnware({ id }) {
function downloadLearnware({ id }): Promise<Response> {
return checkedFetch(`${BASE_URL}/download_learnware?learnware_id=${id}`);
}
function getLearnwareDetailById({ id }) {
function getLearnwareDetailById({ id }): Promise<Response> {
return checkedFetch(`${BASE_URL}/learnware_info?learnware_id=${id}`).then((res) => res.json());
}
function getSemanticSpecification() {
function getSemanticSpecification(): Promise<Response> {
return checkedFetch(`${BASE_URL}/semantic_specification`).then((res) => res.json());
}
function searchLearnware({ name, dataType, taskType, libraryType, tagList, files, page, limit }) {
function searchLearnware({
name,
dataType,
taskType,
libraryType,
tagList,
files,
page,
limit,
}): Promise<Response> {
return getSemanticSpecification()
.then((res) => {
const semanticSpec = res.data.semantic_specification;

View File

@ -3,7 +3,7 @@ import { getSemanticSpecification } from "../engine";
const BASE_URL = "./api/user";
function changePassword({ oldPasswordMd5, newPasswordMd5 }) {
function changePassword({ oldPasswordMd5, newPasswordMd5 }): Promise<Response> {
return checkedFetch(`${BASE_URL}/change_password`, {
method: "POST",
headers: {
@ -16,7 +16,7 @@ function changePassword({ oldPasswordMd5, newPasswordMd5 }) {
}).then((res) => res.json());
}
function deleteLearnware({ id }) {
function deleteLearnware({ id }): Promise<Response> {
return checkedFetch(`${BASE_URL}/delete_learnware`, {
method: "POST",
headers: {
@ -28,7 +28,7 @@ function deleteLearnware({ id }) {
}).then((res) => res.json());
}
function getLearnwareList({ page, limit }) {
function getLearnwareList({ page, limit }): Promise<Response> {
return checkedFetch(`${BASE_URL}/list_learnware`, {
method: "POST",
headers: {
@ -54,7 +54,7 @@ function addLearnware({
files,
learnwareId,
onProgress,
}) {
}): Promise<Response> {
const { progressedFetch } = useProgressedFetch(onProgress);
return getSemanticSpecification()
@ -89,7 +89,7 @@ function addLearnware({
.then((res) => res.json());
}
function verifyLog({ learnware_id }) {
function verifyLog({ learnware_id }): Promise<Response> {
return checkedFetch(`${BASE_URL}/verify_log?learnware_id=${learnware_id}`, {
method: "GET",
headers: {
@ -98,7 +98,7 @@ function verifyLog({ learnware_id }) {
}).then((res) => res.json());
}
function createToken() {
function createToken(): Promise<Response> {
return checkedFetch(`${BASE_URL}/create_token`, {
method: "POST",
headers: {
@ -107,7 +107,7 @@ function createToken() {
}).then((res) => res.json());
}
function listToken() {
function listToken(): Promise<Response> {
return checkedFetch(`${BASE_URL}/list_token`, {
method: "POST",
headers: {
@ -116,7 +116,7 @@ function listToken() {
}).then((res) => res.json());
}
function deleteToken({ token }) {
function deleteToken({ token }): Promise<Response> {
return checkedFetch(`${BASE_URL}/delete_token`, {
method: "POST",
headers: {

View File

@ -1,7 +1,7 @@
import Store from "../store";
import Router from "../router";
function checkStatus(res) {
function checkStatus(res): Response {
if (res.status === 200) {
return res;
}
@ -14,7 +14,7 @@ function checkStatus(res) {
throw new Error(`Network error: ${res.status}${res.statusText ? ` - ${res.statusText}` : ""}`);
}
function checkedFetch(url, options) {
function checkedFetch(url, options: RequestInit = {}): Promise<Response> {
// get token from local storage and set in header
const token = localStorage.getItem("token");
@ -33,8 +33,10 @@ function checkedFetch(url, options) {
return fetch(url, options).then(checkStatus);
}
function useProgressedFetch(onProgress) {
const progressedFetch = (url, options) => {
function useProgressedFetch(onProgress): {
progressedFetch: (url: string, options: RequestInit) => Promise<Response>;
} {
const progressedFetch = (url, options): Promise<Response> => {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open(options.method || "get", url);
@ -42,7 +44,7 @@ function useProgressedFetch(onProgress) {
xhr.setRequestHeader(k, options.headers[k]);
}
xhr.setRequestHeader("Authorization", `Bearer ${localStorage.getItem("token")}`);
xhr.onload = (e) => {
xhr.onload = (e): void => {
resolve(e.target);
};
xhr.onerror = reject;
@ -61,8 +63,8 @@ function useProgressedFetch(onProgress) {
})
.then(checkStatus)
.then((res) => ({
json() {
return JSON.parse(res.responseText);
json(): Promise<JSON> {
return res.text().then((text) => JSON.parse(text));
},
}));
};

View File

@ -1,5 +1,6 @@
import { createRouter, createWebHashHistory } from "vue-router";
import store from "../store";
import { Component } from "vue";
const Router = createRouter({
history: createWebHashHistory(),
@ -7,7 +8,7 @@ const Router = createRouter({
{
path: "/",
name: "Home",
component: () => import("../views/Home.vue"),
component: (): Promise<Component> => import("../views/Home.vue"),
meta: {
showInNavBar: true,
icon: "mdi-home",
@ -16,7 +17,7 @@ const Router = createRouter({
{
path: "/search",
name: "Search",
component: () => import("../views/Search.vue"),
component: (): Promise<Component> => import("../views/Search.vue"),
meta: {
showInNavBar: true,
keepAlive: true,
@ -26,7 +27,7 @@ const Router = createRouter({
{
path: "/submit",
name: "Submit",
component: () => import("../views/Submit.vue"),
component: (): Promise<Component> => import("../views/Submit.vue"),
meta: {
showInNavBar: true,
requiredLogin: true,
@ -37,7 +38,7 @@ const Router = createRouter({
{
path: "/docs",
name: "Docs",
component: () => import("../views/Docs.vue"),
component: (): Promise<Component> => import("../views/Docs.vue"),
meta: {
showInNavBar: true,
name: "Docs",
@ -55,7 +56,7 @@ const Router = createRouter({
{
path: "/login",
name: "Login",
component: () => import("../views/Login.vue"),
component: (): Promise<Component> => import("../views/Login.vue"),
meta: {
showInNavBar: true,
hideWhenLoggedIn: true,
@ -65,7 +66,7 @@ const Router = createRouter({
{
path: "/register",
name: "Register",
component: () => import("../views/Register.vue"),
component: (): Promise<Component> => import("../views/Register.vue"),
meta: {
showInNavBar: true,
hideWhenLoggedIn: true,
@ -77,7 +78,7 @@ const Router = createRouter({
{
path: "/changepassword",
name: "ChangePassword",
component: () => import("../views/ChangePassword.vue"),
component: (): Promise<Component> => import("../views/ChangePassword.vue"),
meta: {
showInNavBar: true,
requiredLogin: true,
@ -89,7 +90,7 @@ const Router = createRouter({
{
path: "/mylearnware",
name: "MyLearnware",
component: () => import("../views/MyLearnware.vue"),
component: (): Promise<Component> => import("../views/MyLearnware.vue"),
meta: {
name: "My Learnware",
showInNavBar: true,
@ -101,7 +102,7 @@ const Router = createRouter({
{
path: "/clienttoken",
name: "ClientToken",
component: () => import("../views/ClientToken.vue"),
component: (): Promise<Component> => import("../views/ClientToken.vue"),
meta: {
showInNavBar: true,
requiredLogin: true,
@ -113,7 +114,7 @@ const Router = createRouter({
{
path: "/logout",
name: "Logout",
component: () => import("../views/Logout.vue"),
component: (): Promise<Component> => import("../views/Logout.vue"),
meta: {
showInNavBar: true,
requiredLogin: true,
@ -135,7 +136,7 @@ const Router = createRouter({
{
path: "/language/zh",
name: "Chinese",
component: () => import("../views/ChangeLanguage.vue"),
component: (): Promise<Component> => import("../views/ChangeLanguage.vue"),
meta: {
showInNavBar: true,
icon: "🇨🇳",
@ -145,7 +146,7 @@ const Router = createRouter({
{
path: "/language/en",
name: "English",
component: () => import("../views/ChangeLanguage.vue"),
component: (): Promise<Component> => import("../views/ChangeLanguage.vue"),
meta: {
showInNavBar: true,
icon: "🇺🇸",
@ -157,7 +158,7 @@ const Router = createRouter({
{
path: "/learnwaredetail",
name: "LearnwareDetail",
component: () => import("../views/LearnwareDetail.vue"),
component: (): Promise<Component> => import("../views/LearnwareDetail.vue"),
meta: {
showInNavBar: false,
icon: "mdi-bullseye-arrow",
@ -166,7 +167,7 @@ const Router = createRouter({
{
path: "/verify_email",
name: "VerifyEmail",
component: () => import("../views/VerifyEmail.vue"),
component: (): Promise<Component> => import("../views/VerifyEmail.vue"),
meta: {
showInNavBar: false,
icon: "mdi-email-check-outline",

View File

@ -1,12 +1,16 @@
interface AuthState {
loggedIn: boolean;
}
const auth = {
loggedIn: false,
mutations: {
setLoggedIn(state, loggedIn) {
setLoggedIn(state: AuthState, loggedIn: boolean): void {
state.loggedIn = loggedIn;
},
},
getters: {
getLoggedIn(state) {
getLoggedIn(state: AuthState): boolean {
return state.loggedIn;
},
},

View File

@ -1,21 +1,26 @@
interface ErrorState {
showGlobalError: boolean;
globalErrorMsg: string;
}
const error = {
state: {
showGlobalError: false,
globalErrorMsg: "",
},
getters: {
getShowGlobalError(state) {
getShowGlobalError(state: ErrorState): boolean {
return state.showGlobalError;
},
getGlobalErrorMsg(state) {
getGlobalErrorMsg(state: ErrorState): string {
return state.globalErrorMsg;
},
},
mutations: {
setShowGlobalError(state, value) {
setShowGlobalError(state: ErrorState, value: boolean): void {
state.showGlobalError = value;
},
setGlobalErrorMsg(state, value) {
setGlobalErrorMsg(state: ErrorState, value: string): void {
state.globalErrorMsg = value;
},
},

View File

@ -1,17 +1,21 @@
import i18n from "../../i18n";
interface I18nLocaleState {
locale: string;
}
const i18nLocale = {
state: {
locale: "cn",
},
mutations: {
setLocale(state, locale) {
setLocale(state: I18nLocaleState, locale: string): void {
state.locale = locale;
i18n.global.locale.value = locale;
},
},
getters: {
getLocale(state) {
getLocale(state: I18nLocaleState): string {
return state.locale;
},
},

View File

@ -1,12 +1,16 @@
interface UserState {
isEditing: boolean;
}
const user = {
isEditing: false,
getters: {
getIsEditing(state) {
getIsEditing(state: UserState): boolean {
return state.isEditing;
},
},
mutations: {
setIsEditing(state, value) {
setIsEditing(state: UserState, value: boolean): void {
state.isEditing = value;
},
},

View File

@ -1,27 +0,0 @@
function debounce(fn, delay) {
let timer = null;
return function () {
const context = this;
const args = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(context, args);
}, delay);
};
}
function throttle(fn, delay) {
let timer = null;
return function () {
const context = this;
const args = arguments;
if (!timer) {
timer = setTimeout(function () {
fn.apply(context, args);
timer = null;
}, delay);
}
};
}
export { debounce, throttle };

View File

@ -0,0 +1,23 @@
function debounce(fn, delay): (...args: unknown[]) => void {
let timer = null;
return function (...args: unknown[]) {
clearTimeout(timer);
timer = setTimeout(function () {
fn(...args)
}, delay);
};
}
function throttle(fn, delay): (...args: unknown[]) => void {
let timer = null;
return function (...args: unknown[]) {
if (!timer) {
timer = setTimeout(function () {
fn(...args);
timer = null;
}, delay);
}
};
}
export { debounce, throttle };

View File

@ -1,6 +1,6 @@
const BASE_URL = "./api/engine";
function downloadLearnwareSync(id) {
function downloadLearnwareSync(id): void {
const url = `${BASE_URL}/download_learnware?learnware_id=${id}`;
window.open(url);
}

View File

@ -1,3 +1,5 @@
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable no-unused-vars */
/*
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
* Digest Algorithm, as defined in RFC 1321.
@ -10,8 +12,8 @@
* Configurable variables. You may need to tweak these to be compatible with
* the server-side, but the defaults work in most cases.
*/
var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
const hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
const chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
/*
* These are the functions you'll usually want to call
* They take string arguments and return either hex or base-64 encoded strings
@ -26,15 +28,15 @@ function core_md5(x, len) {
/* append padding */
x[len >> 5] |= 0x80 << len % 32;
x[(((len + 64) >>> 9) << 4) + 14] = len;
var a = 1732584193;
var b = -271733879;
var c = -1732584194;
var d = 271733878;
for (var i = 0; i < x.length; i += 16) {
var olda = a;
var oldb = b;
var oldc = c;
var oldd = d;
let a = 1732584193;
let b = -271733879;
let c = -1732584194;
let d = 271733878;
for (let i = 0; i < x.length; i += 16) {
const olda = a;
const oldb = b;
const oldc = c;
const oldd = d;
a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);
d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
@ -104,7 +106,7 @@ function core_md5(x, len) {
c = safe_add(c, oldc);
d = safe_add(d, oldd);
}
return Array(a, b, c, d);
return [a, b, c, d];
}
/*
* These functions implement the four basic operations the algorithm uses.
@ -129,8 +131,8 @@ function md5_ii(a, b, c, d, x, s, t) {
* to work around bugs in some JS interpreters.
*/
function safe_add(x, y) {
var lsw = (x & 0xffff) + (y & 0xffff);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
const lsw = (x & 0xffff) + (y & 0xffff);
const msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xffff);
}
/*
@ -144,19 +146,16 @@ function bit_rol(num, cnt) {
* If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
*/
function str2binl(str) {
var bin = Array();
var mask = (1 << chrsz) - 1;
for (var i = 0; i < str.length * chrsz; i += chrsz)
const bin = [];
const mask = (1 << chrsz) - 1;
for (let i = 0; i < str.length * chrsz; i += chrsz)
bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << i % 32;
return bin;
}
/*
* Convert an array of little-endian words to a hex string.
*/
function binl2hex(binarray) {
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var str = "";
for (var i = 0; i < binarray.length * 4; i++) {
const hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
let str = "";
for (let i = 0; i < binarray.length * 4; i++) {
str +=
hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8 + 4)) & 0xf) +
hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8)) & 0xf);

View File

@ -1,11 +1,11 @@
function promiseReadFile(file) {
function promiseReadFile(file): Promise<ArrayBuffer> {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = (event) => {
reader.onload = (event): void => {
resolve(event.target.result);
};
reader.onerror = (event) => {
reader.onerror = (event): void => {
reject(event);
};
});

View File

@ -1,7 +1,7 @@
import JSZip from "jszip";
import yaml from "js-yaml";
function getTopFolder(zip) {
function getTopFolder(zip): string {
// return top folder when there is only one top folder
// return '' else
const topFolders = Object.keys(zip.files).filter((key) => {
@ -19,7 +19,7 @@ function getTopFolder(zip) {
return topFolders[0];
}
function verifyLearnware(file) {
function verifyLearnware(file): Promise<string | boolean> {
return JSZip.loadAsync(file).then((zip) => {
const topFolder = getTopFolder(zip);
if (!zip.files[topFolder + "__init__.py"]) {

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { onMounted } from "vue";
import { useStore } from "vuex";
import { useRoute, useRouter } from "vue-router";

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { ref, computed } from "vue";
import { useStore } from "vuex";
import { useRouter } from "vue-router";
@ -90,7 +90,7 @@ const change = handleSubmit((values) => {
});
});
function closeErrorAlert() {
function closeErrorAlert(): void {
clearTimeout(errorTimer.value);
}
</script>

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { ref, onActivated } from "vue";
import { useI18n } from "vue-i18n";
import { createToken, listToken, deleteToken } from "../request/user";
@ -10,9 +10,9 @@ const tokens = ref([]);
const showError = ref(false);
const errorMsg = ref("");
function fetchList() {
function fetchList(): Promise<void> {
showError.value = false;
listToken()
return listToken()
.then((res) => {
switch (res.code) {
case 0: {
@ -31,8 +31,8 @@ function fetchList() {
});
}
function onGenerateClick() {
createToken()
function onGenerateClick(): Promise<void> {
return createToken()
.then((res) => {
switch (res.code) {
case 0: {
@ -51,8 +51,8 @@ function onGenerateClick() {
});
}
function onDeleteClick(token) {
deleteToken({ token })
function onDeleteClick(token): Promise<void> {
return deleteToken({ token })
.then((res) => {
switch (res.code) {
case 0: {

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { useRouter } from "vue-router";
const router = useRouter();

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import HomeSlogan from "../components/Home/HomeSlogan.vue";
import WhatIs from "../components/Home/WhatIs.vue";
import WhyNeed from "../components/Home/WhyNeed.vue";

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { ref, onMounted } from "vue";
import { useDisplay } from "vuetify";
import { useRoute, useRouter } from "vue-router";
@ -20,8 +20,8 @@ const loading = ref(false);
const showError = ref(false);
const errorMsg = ref("");
function getLearnwareDetail(id) {
getLearnwareDetailById({ id })
function getLearnwareDetail(id): Promise<void> {
return getLearnwareDetailById({ id })
.then((res) => {
switch (res.code) {
case 0: {
@ -62,8 +62,8 @@ onMounted(() => {
getLearnwareDetail(learnwareId.value);
});
function onLearnwareVerifyLog(learnware_id) {
verifyLog({ learnware_id }).then((res) => {
function onLearnwareVerifyLog(learnware_id): Promise<void> {
return verifyLog({ learnware_id }).then((res) => {
var blob = new Blob([res.data], { type: "text/plain" });
//var blob = res.blob();
// blob.type = "text/plain";

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { ref, computed } from "vue";
import { useStore } from "vuex";
import { useI18n } from "vue-i18n";
@ -77,7 +77,7 @@ const submit = handleSubmit((values) => {
});
});
function closeErrorAlert() {
function closeErrorAlert(): void {
clearTimeout(errorTimer.value);
}
</script>

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { onMounted } from "vue";
import { useStore } from "vuex";
import { useRouter } from "vue-router";

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { ref, onMounted, nextTick, watch, onActivated } from "vue";
import { useStore } from "vuex";
import { useRoute, useRouter } from "vue-router";
@ -29,10 +29,10 @@ const scrollTop = ref(0);
const showError = ref(false);
const errorMsg = ref("");
function handleConfirm() {
function handleConfirm(): Promise<void> {
showError.value = false;
deleteLearnware({ id: deleteId.value })
return deleteLearnware({ id: deleteId.value })
.then((res) => {
switch (res.code) {
case 0: {
@ -56,11 +56,11 @@ function handleConfirm() {
});
}
function pageChange(newPage) {
function pageChange(newPage): void {
page.value = newPage;
}
function handleClickEdit(id) {
function handleClickEdit(id): void {
router.push({
path: "/submit",
query: {
@ -70,13 +70,13 @@ function handleClickEdit(id) {
});
}
function handleClickDelete(id) {
function handleClickDelete(id): void {
dialog.value.confirm();
deleteId.value = id;
deleteName.value = learnwareItems.value.find((item) => item.id === id).name;
}
function fetchByFilterAndPage(page) {
function fetchByFilterAndPage(page): void {
if (contentRef.value) {
contentRef.value.scrollTop = 0;
}

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { ref, computed } from "vue";
import { useField, useForm } from "vee-validate";
import { useI18n } from "vue-i18n";

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { ref, computed, watch, onMounted, nextTick, onActivated } from "vue";
import { useDisplay } from "vuetify";
import { searchLearnware } from "../request/engine";
@ -6,9 +6,18 @@ import UserRequirement from "../components/Search/UserRequirement.vue";
import PageLearnwareList from "../components/Learnware/PageLearnwareList.vue";
import MultiRecommendedLearnwareList from "../components/Learnware/MultiRecommendedLearnwareList.vue";
interface Filter {
name: string;
dataType: string;
taskType: string;
libraryType: string;
tagList: string[];
files: string[];
}
const display = useDisplay();
const filters = ref({
const filters = ref<Filter>({
name: "",
dataType: "",
taskType: "",
@ -18,7 +27,7 @@ const filters = ref({
});
const multiRecommendedLearnwareItems = ref([]);
const multiRecommendedMatchScore = ref(null);
const multiRecommendedMatchScore = ref<number>(0);
const singleRecommendedLearnwarePage = ref(1);
const singleRecommendedLearnwarePageNum = ref(1);
const singleRecommendedLearnwarePageSize = ref(10);
@ -26,13 +35,13 @@ const singleRecommendedLearnwareItems = ref([]);
const loading = ref(false);
const contentRef = ref(null);
const anchorRef = ref(null);
const anchorRef = ref<HTMLDivElement | null>(null);
const scrollTop = ref(0);
const showError = ref(false);
const errorMsg = ref("");
const errorTimer = ref(null);
const errorTimer = ref();
const showMultiRecommended = computed(
() =>
@ -41,11 +50,11 @@ const showMultiRecommended = computed(
const multiRecommendedTips = ref(true);
const singleRecommendedTips = ref(true);
function pageChange(newPage) {
function pageChange(newPage: number): void {
singleRecommendedLearnwarePage.value = newPage;
}
function fetchByFilterAndPage(filters, page) {
function fetchByFilterAndPage(filters: Filter, page: number): void {
showError.value = false;
loading.value = true;

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { ref, computed, onActivated, onMounted } from "vue";
import { useDisplay } from "vuetify";
import { useRoute, useRouter } from "vue-router";
@ -51,25 +51,25 @@ const { handleSubmit, meta } = useForm({
files: [],
},
validationSchema: {
name(value) {
name(value: string) {
if (value?.length >= 5) {
return true;
}
return t("Submit.Name.Error.AtLeast5Chars");
},
dataType(value) {
dataType(value: string) {
if (value?.length > 0) {
return true;
}
return t("Submit.Tag.DataType.Error.NotEmpty");
},
taskType(value) {
taskType(value: string) {
if (value?.length > 0) {
return true;
}
return t("Submit.Tag.TaskType.Error.NotEmpty");
},
libraryType(value) {
libraryType(value: string) {
if (value?.length > 0) {
return true;
}
@ -89,13 +89,13 @@ const { handleSubmit, meta } = useForm({
taskTypeDescription() {
return true;
},
description(value) {
description(value: string) {
if (value?.length >= 10) {
return true;
}
return t("Submit.Description.Error.AtLeast10Chars");
},
files(value) {
files(value: File[]) {
if (route.query.edit && value[0]?.name === "Your old learnware") {
return true;
}
@ -114,21 +114,21 @@ const { handleSubmit, meta } = useForm({
});
const name = useField("name");
const dataType = useField("dataType");
const taskType = useField("taskType");
const libraryType = useField("libraryType");
const tagList = useField("tagList");
const dataTypeDescription = useField("dataTypeDescription");
const taskTypeDescription = useField("taskTypeDescription");
const description = useField("description");
const files = useField("files");
const dataType = useField<string>("dataType");
const taskType = useField<string>("taskType");
const libraryType = useField<string>("libraryType");
const tagList = useField<string[]>("tagList");
const dataTypeDescription = useField<string>("dataTypeDescription");
const taskTypeDescription = useField<string>("taskTypeDescription");
const description = useField<string>("description");
const files = useField<File[]>("files");
const currentStep = ref(0);
const submiting = ref(false);
const success = ref(false);
const showError = ref(false);
const errorMsg = ref("");
const errorTimer = ref(null);
const errorTimer = ref<number>();
const uploadProgress = ref(0);
const steps = computed(() => [
@ -177,7 +177,7 @@ const allowChangePage = computed(() => {
}
});
function activeStep(index) {
function activeStep(index: number): void {
if (
valid.value ||
index < currentStep.value ||
@ -187,19 +187,19 @@ function activeStep(index) {
}
}
function nextStep() {
function nextStep(): void {
if (currentStep.value < steps.value.length - 1) {
activeStep(currentStep.value + 1);
}
}
function PrevStep() {
function PrevStep(): void {
if (currentStep.value > 0) {
activeStep(currentStep.value - 1);
}
}
function onProgress(progress) {
function onProgress(progress: number): void {
uploadProgress.value = progress * 100;
}
@ -210,7 +210,7 @@ const submit = handleSubmit((values) => {
uploadProgress.value = 0;
addLearnware({
edit: route.query.edit,
edit: Boolean(route.query.edit),
name: values.name,
dataType: values.dataType,
taskType: values.taskType,
@ -253,16 +253,18 @@ const submit = handleSubmit((values) => {
showError.value = true;
errorMsg.value = err.message;
clearTimeout(errorTimer.value);
errorTimer.value = setTimeout(() => {
showError.value = false;
}, 3000);
errorTimer.value = Number(
setTimeout(() => {
showError.value = false;
}, 3000),
);
})
.finally(() => {
submiting.value = false;
});
});
function checkLoginStatus() {
function checkLoginStatus(): Promise<void> {
return getRole()
.then((res) => {
switch (res.code) {
@ -287,16 +289,18 @@ function checkLoginStatus() {
showError.value = true;
errorMsg.value = err.message;
clearTimeout(errorTimer.value);
errorTimer.value = setTimeout(() => {
showError.value = false;
}, 3000);
errorTimer.value = Number(
setTimeout(() => {
showError.value = false;
}, 3000),
);
})
.finally(() => {
submiting.value = false;
});
}
function checkIsEditMode() {
function checkIsEditMode(): undefined | Promise<void> {
if (!!route.query.edit && !!route.query.id) {
return getLearnwareDetailById({ id: route.query.id })
.then((res) => {
@ -353,7 +357,7 @@ function checkIsEditMode() {
}
}
function init() {
function init(): void {
store.commit("setIsEditing", !!route.query.edit);
checkLoginStatus().then(checkIsEditMode);
}

View File

@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { useRoute, useRouter } from "vue-router";
import { ref, onMounted } from "vue";
import { verifyEmail } from "../request/auth";
@ -10,7 +10,7 @@ const icon = ref("");
const color = ref("");
onMounted(() => {
const urlParams = new URLSearchParams(route.query);
const urlParams = new URLSearchParams(String(route.query));
verifyEmail(urlParams)
.then((res) => {
switch (res.code) {

View File

@ -1,3 +1,3 @@
{
"extends": "../../tsconfig.json",
}
"extends": "../../tsconfig.json"
}

View File

@ -36,6 +36,12 @@ importers:
'@types/node':
specifier: ^20.8.4
version: 20.8.4
'@typescript-eslint/eslint-plugin':
specifier: ^6.7.5
version: 6.7.5(@typescript-eslint/parser@6.7.5)(eslint@8.43.0)(typescript@5.2.2)
'@typescript-eslint/parser':
specifier: ^6.7.5
version: 6.7.5(eslint@8.43.0)(typescript@5.2.2)
'@vitejs/plugin-vue':
specifier: ^4.1.0
version: 4.1.0(vite@4.2.0)(vue@3.2.47)
@ -47,7 +53,7 @@ importers:
version: 8.43.0
eslint-plugin-import:
specifier: ^2.27.5
version: 2.27.5(eslint@8.43.0)
version: 2.27.5(@typescript-eslint/parser@6.7.5)(eslint@8.43.0)
eslint-plugin-vue:
specifier: ^9.15.0
version: 9.15.0(eslint@8.43.0)
@ -498,6 +504,141 @@ packages:
undici-types: 5.25.3
dev: true
/@types/semver@7.5.3:
resolution: {integrity: sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw==}
dev: true
/@typescript-eslint/eslint-plugin@6.7.5(@typescript-eslint/parser@6.7.5)(eslint@8.43.0)(typescript@5.2.2):
resolution: {integrity: sha512-JhtAwTRhOUcP96D0Y6KYnwig/MRQbOoLGXTON2+LlyB/N35SP9j1boai2zzwXb7ypKELXMx3DVk9UTaEq1vHEw==}
engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies:
'@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha
eslint: ^7.0.0 || ^8.0.0
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@eslint-community/regexpp': 4.9.1
'@typescript-eslint/parser': 6.7.5(eslint@8.43.0)(typescript@5.2.2)
'@typescript-eslint/scope-manager': 6.7.5
'@typescript-eslint/type-utils': 6.7.5(eslint@8.43.0)(typescript@5.2.2)
'@typescript-eslint/utils': 6.7.5(eslint@8.43.0)(typescript@5.2.2)
'@typescript-eslint/visitor-keys': 6.7.5
debug: 4.3.4
eslint: 8.43.0
graphemer: 1.4.0
ignore: 5.2.4
natural-compare: 1.4.0
semver: 7.5.4
ts-api-utils: 1.0.3(typescript@5.2.2)
typescript: 5.2.2
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/parser@6.7.5(eslint@8.43.0)(typescript@5.2.2):
resolution: {integrity: sha512-bIZVSGx2UME/lmhLcjdVc7ePBwn7CLqKarUBL4me1C5feOd663liTGjMBGVcGr+BhnSLeP4SgwdvNnnkbIdkCw==}
engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies:
eslint: ^7.0.0 || ^8.0.0
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@typescript-eslint/scope-manager': 6.7.5
'@typescript-eslint/types': 6.7.5
'@typescript-eslint/typescript-estree': 6.7.5(typescript@5.2.2)
'@typescript-eslint/visitor-keys': 6.7.5
debug: 4.3.4
eslint: 8.43.0
typescript: 5.2.2
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/scope-manager@6.7.5:
resolution: {integrity: sha512-GAlk3eQIwWOJeb9F7MKQ6Jbah/vx1zETSDw8likab/eFcqkjSD7BI75SDAeC5N2L0MmConMoPvTsmkrg71+B1A==}
engines: {node: ^16.0.0 || >=18.0.0}
dependencies:
'@typescript-eslint/types': 6.7.5
'@typescript-eslint/visitor-keys': 6.7.5
dev: true
/@typescript-eslint/type-utils@6.7.5(eslint@8.43.0)(typescript@5.2.2):
resolution: {integrity: sha512-Gs0qos5wqxnQrvpYv+pf3XfcRXW6jiAn9zE/K+DlmYf6FcpxeNYN0AIETaPR7rHO4K2UY+D0CIbDP9Ut0U4m1g==}
engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies:
eslint: ^7.0.0 || ^8.0.0
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@typescript-eslint/typescript-estree': 6.7.5(typescript@5.2.2)
'@typescript-eslint/utils': 6.7.5(eslint@8.43.0)(typescript@5.2.2)
debug: 4.3.4
eslint: 8.43.0
ts-api-utils: 1.0.3(typescript@5.2.2)
typescript: 5.2.2
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/types@6.7.5:
resolution: {integrity: sha512-WboQBlOXtdj1tDFPyIthpKrUb+kZf2VroLZhxKa/VlwLlLyqv/PwUNgL30BlTVZV1Wu4Asu2mMYPqarSO4L5ZQ==}
engines: {node: ^16.0.0 || >=18.0.0}
dev: true
/@typescript-eslint/typescript-estree@6.7.5(typescript@5.2.2):
resolution: {integrity: sha512-NhJiJ4KdtwBIxrKl0BqG1Ur+uw7FiOnOThcYx9DpOGJ/Abc9z2xNzLeirCG02Ig3vkvrc2qFLmYSSsaITbKjlg==}
engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies:
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@typescript-eslint/types': 6.7.5
'@typescript-eslint/visitor-keys': 6.7.5
debug: 4.3.4
globby: 11.1.0
is-glob: 4.0.3
semver: 7.5.4
ts-api-utils: 1.0.3(typescript@5.2.2)
typescript: 5.2.2
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/utils@6.7.5(eslint@8.43.0)(typescript@5.2.2):
resolution: {integrity: sha512-pfRRrH20thJbzPPlPc4j0UNGvH1PjPlhlCMq4Yx7EGjV7lvEeGX0U6MJYe8+SyFutWgSHsdbJ3BXzZccYggezA==}
engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies:
eslint: ^7.0.0 || ^8.0.0
dependencies:
'@eslint-community/eslint-utils': 4.4.0(eslint@8.43.0)
'@types/json-schema': 7.0.13
'@types/semver': 7.5.3
'@typescript-eslint/scope-manager': 6.7.5
'@typescript-eslint/types': 6.7.5
'@typescript-eslint/typescript-estree': 6.7.5(typescript@5.2.2)
eslint: 8.43.0
semver: 7.5.4
transitivePeerDependencies:
- supports-color
- typescript
dev: true
/@typescript-eslint/visitor-keys@6.7.5:
resolution: {integrity: sha512-3MaWdDZtLlsexZzDSdQWsFQ9l9nL8B80Z4fImSpyllFC/KLqWQRdEcB+gGGO+N3Q2uL40EsG66wZLsohPxNXvg==}
engines: {node: ^16.0.0 || >=18.0.0}
dependencies:
'@typescript-eslint/types': 6.7.5
eslint-visitor-keys: 3.4.3
dev: true
/@vitejs/plugin-vue@4.1.0(vite@4.2.0)(vue@3.2.47):
resolution: {integrity: sha512-++9JOAFdcXI3lyer9UKUV4rfoQ3T1RN8yDqoCLar86s0xQct5yblxAE+yWgRnU5/0FOlVCpTZpYSBV/bGWrSrQ==}
engines: {node: ^14.18.0 || >=16.0.0}
@ -742,6 +883,11 @@ packages:
is-string: 1.0.7
dev: true
/array-union@2.1.0:
resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
engines: {node: '>=8'}
dev: true
/array.prototype.flat@1.3.2:
resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==}
engines: {node: '>= 0.4'}
@ -983,6 +1129,13 @@ packages:
object-keys: 1.1.1
dev: true
/dir-glob@3.0.1:
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
engines: {node: '>=8'}
dependencies:
path-type: 4.0.0
dev: true
/doctrine@2.1.0:
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
engines: {node: '>=0.10.0'}
@ -1152,7 +1305,7 @@ packages:
- supports-color
dev: true
/eslint-module-utils@2.8.0(eslint-import-resolver-node@0.3.9)(eslint@8.43.0):
/eslint-module-utils@2.8.0(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-node@0.3.9)(eslint@8.43.0):
resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==}
engines: {node: '>=4'}
peerDependencies:
@ -1173,6 +1326,7 @@ packages:
eslint-import-resolver-webpack:
optional: true
dependencies:
'@typescript-eslint/parser': 6.7.5(eslint@8.43.0)(typescript@5.2.2)
debug: 3.2.7
eslint: 8.43.0
eslint-import-resolver-node: 0.3.9
@ -1180,7 +1334,7 @@ packages:
- supports-color
dev: true
/eslint-plugin-import@2.27.5(eslint@8.43.0):
/eslint-plugin-import@2.27.5(@typescript-eslint/parser@6.7.5)(eslint@8.43.0):
resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==}
engines: {node: '>=4'}
peerDependencies:
@ -1190,6 +1344,7 @@ packages:
'@typescript-eslint/parser':
optional: true
dependencies:
'@typescript-eslint/parser': 6.7.5(eslint@8.43.0)(typescript@5.2.2)
array-includes: 3.1.7
array.prototype.flat: 1.3.2
array.prototype.flatmap: 1.3.2
@ -1197,7 +1352,7 @@ packages:
doctrine: 2.1.0
eslint: 8.43.0
eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.8.0(eslint-import-resolver-node@0.3.9)(eslint@8.43.0)
eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-node@0.3.9)(eslint@8.43.0)
has: 1.0.4
is-core-module: 2.13.0
is-glob: 4.0.3
@ -1503,6 +1658,18 @@ packages:
define-properties: 1.2.1
dev: true
/globby@11.1.0:
resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
engines: {node: '>=10'}
dependencies:
array-union: 2.1.0
dir-glob: 3.0.1
fast-glob: 3.3.1
ignore: 5.2.4
merge2: 1.4.1
slash: 3.0.0
dev: true
/gopd@1.0.1:
resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
dependencies:
@ -1982,6 +2149,11 @@ packages:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
dev: true
/path-type@4.0.0:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
dev: true
/picocolors@1.0.0:
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
@ -2191,6 +2363,11 @@ packages:
object-inspect: 1.12.3
dev: true
/slash@3.0.0:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'}
dev: true
/source-map-js@1.0.2:
resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
engines: {node: '>=0.10.0'}
@ -2291,6 +2468,15 @@ packages:
is-number: 7.0.0
dev: true
/ts-api-utils@1.0.3(typescript@5.2.2):
resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==}
engines: {node: '>=16.13.0'}
peerDependencies:
typescript: '>=4.2.0'
dependencies:
typescript: 5.2.2
dev: true
/tsconfig-paths@3.14.2:
resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==}
dependencies:

1
frontend/shim-vue.d.ts vendored Normal file
View File

@ -0,0 +1 @@
declare module "*.vue";

View File

@ -0,0 +1,11 @@
{
"extends": "./tsconfig.json",
"include": [
"./**/*.ts",
"./**/*.tsx",
"./**/*.js",
"./**/.*.ts",
"./**/.*.js",
"./**/*.vue"
]
}

View File

@ -3,12 +3,17 @@
"module": "ESNext",
"target": "es2020",
"lib": ["DOM", "ESNext"],
"paths": {},
"types": ["vite/client", "node"],
"strictNullChecks": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
"paths": {
"@main": ["./packages/main/src"],
"@main/*": ["./packages/main/src/*"],
"@admin": ["./packages/admin/src"],
"@admin/*": ["./packages/admin/src/*"]
},
/* Bundler mode */
"moduleResolution": "node",
@ -24,5 +29,5 @@
"noFallthroughCasesInSwitch": true
},
"include": ["./*.ts", "./packages/**/*.ts", "./packages/**/*.vue"],
"exclude": ["**/dist/**", "node_modules"]
"exclude": ["**/dist/**", "node_modules", "**/node_modules", "**/encrypt.ts"]
}