diff --git a/README.md b/README.md index 3b5f1e21c..290c9d7aa 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# CURD-TS 正在开发中…… +# Vue3.0版本已开发完成! 一套基于TS的增删改查系统,前端语言Vue3.0、React、Angular,后端语言node+express,采用了三种数据库MySQL、MongoDB、SQLite编写。 A TS based add, delete, modify and query system, the front-end language vue3.0, react, angular, back-end language node + Express, using three kinds of database mysql, mongodb, SQLite diff --git a/frontend/vue-ts/.env b/frontend/vue-ts/.env new file mode 100644 index 000000000..20473ea8b --- /dev/null +++ b/frontend/vue-ts/.env @@ -0,0 +1,5 @@ +# public path +VITE_PUBLIC_PATH = / + +# Cross-domain proxy, you can configure multiple +VITE_PROXY = [ ["/api", "http://127.0.0.1:3000" ] ] diff --git a/frontend/vue-ts/.env.development b/frontend/vue-ts/.env.development new file mode 100644 index 000000000..da2b0d6df --- /dev/null +++ b/frontend/vue-ts/.env.development @@ -0,0 +1,11 @@ +# port +VITE_PORT = 3001 + +# open +VITE_OPEN = false + +# public path +VITE_PUBLIC_PATH = / + +# Cross-domain proxy, you can configure multiple +VITE_PROXY = [ ["/api", "http://127.0.0.1:3000" ] ] diff --git a/frontend/vue-ts/.env.production b/frontend/vue-ts/.env.production new file mode 100644 index 000000000..d6e1ff425 --- /dev/null +++ b/frontend/vue-ts/.env.production @@ -0,0 +1,2 @@ +# public path +VITE_PUBLIC_PATH = /manages/ diff --git a/frontend/vue-ts/.gitignore b/frontend/vue-ts/.gitignore new file mode 100644 index 000000000..6bebcbc99 --- /dev/null +++ b/frontend/vue-ts/.gitignore @@ -0,0 +1,4 @@ +/node_modules +/dist +.DS_Store +src/.DS_Store diff --git a/frontend/vue-ts/README.md b/frontend/vue-ts/README.md index b08ba759c..10d1b78d5 100644 --- a/frontend/vue-ts/README.md +++ b/frontend/vue-ts/README.md @@ -1 +1,55 @@ -# vue-ts \ No newline at end of file +# Vue3.0后台管理系统 + +## 知识库地址 + +帮助你获取最新的 API +[vue3.0 中文文档地址]: https://vue3js.cn/docs/zh/ +[element-plus 中文文档地址]: https://element-plus.org/#/zh-CN +[composition-Api 中文文档地址]: https://composition-api.vuejs.org/zh/ +[vue-router-next 文档地址]: https://next.router.vuejs.org/ +[next.vuex 文档地址]: https://next.vuex.vuejs.org/ +[vite 源码]: https://github.com/vitejs/vite +[vite 文档地址]: https://vitejs.dev/ +[vite 中文文档地址(非官方版本)]: https://vite-design.surge.sh/guide/chinese-doc.html +[vue-i18n-next]: https://vue-i18n-next.intlify.dev/ +[composition-api-vue-i18n-next]: https://vue-i18n-next.intlify.dev/advanced/composition.html#local-scope + +## 安装依赖 + +``` +npm install +``` + +## 项目运行 + +``` +npm run serve +``` + +## 项目打包 + +``` +npm run build +``` + +## 注意点 + +请先全局安装 typescript、ts-node、vite 如安装请忽略 + +``` +npm install -g typescript +npm install -g ts-node +npm install -g create-vite-app +``` + +坑位 +1. +path模块线上部署会遇到process is undefined问题 +解决办法:在源码中开头加入window.process = {} +issues:https://github.com/jinder/path/issues/7 +2. +运行项目时控制台报NODE_ENV not found +解决办法:删除node_modules和package-lock.json文件,重新npm install +3. +运行项目会感觉菜单切换比较卡,这个原因是使用route造成的,watch(route)是隐式的{ deep: true },最好使用watchEffect +issues:https://github.com/vuejs/vue-next/issues/2027 \ No newline at end of file diff --git a/frontend/vue-ts/babel.config.js b/frontend/vue-ts/babel.config.js new file mode 100644 index 000000000..f46c1770c --- /dev/null +++ b/frontend/vue-ts/babel.config.js @@ -0,0 +1,6 @@ + +const productPlugins = [] +process.env.NODE_ENV === "production" && productPlugins.push("transform-remove-console") +module.exports = { + plugins: [...productPlugins], +} diff --git a/frontend/vue-ts/build/proxy.ts b/frontend/vue-ts/build/proxy.ts new file mode 100644 index 000000000..80004cadd --- /dev/null +++ b/frontend/vue-ts/build/proxy.ts @@ -0,0 +1,19 @@ +type ProxyItem = [string, string]; + +type ProxyList = ProxyItem[]; + +const regExps = (value: string,reg: string): string => { + return value.replace(new RegExp(reg, 'g'), ''); +} + +export function createProxy(list: ProxyList = []) { + const ret: any = {}; + for (const [prefix, target] of list) { + ret[prefix] = { + target: target, + changeOrigin: true, + rewrite: (path:string) => regExps(path, prefix) + }; + } + return ret; +} \ No newline at end of file diff --git a/frontend/vue-ts/build/utils.ts b/frontend/vue-ts/build/utils.ts new file mode 100644 index 000000000..f8f9266f3 --- /dev/null +++ b/frontend/vue-ts/build/utils.ts @@ -0,0 +1,38 @@ +import dotenv from 'dotenv'; + +export interface ViteEnv { + VITE_PORT: number; + VITE_OPEN: boolean; + VITE_USE_MOCK: boolean; + VITE_PUBLIC_PATH: string; + VITE_PROXY: [string, string][]; +} + +export function loadEnv(): ViteEnv { + const env = process.env.NODE_ENV; + const ret: any = {}; + const envList = [`.env.${env}.local`, `.env.${env}`, '.env.local', '.env', ,] + envList.forEach((e) => { + dotenv.config({ + path: e, + }); + }); + for (const envName of Object.keys(process.env)) { + let realName = (process.env as any)[envName].replace(/\\n/g, '\n'); + realName = realName === 'true' ? true : realName === 'false' ? false : realName; + if (envName === 'VITE_PORT') { + realName = Number(realName); + } + if (envName === 'VITE_OPEN') { + realName = Boolean(realName); + } + if (envName === 'VITE_PROXY') { + try { + realName = JSON.parse(realName); + } catch (error) { } + } + ret[envName] = realName; + process.env[envName] = realName; + } + return ret; +} \ No newline at end of file diff --git a/frontend/vue-ts/index.html b/frontend/vue-ts/index.html new file mode 100644 index 000000000..89b74b584 --- /dev/null +++ b/frontend/vue-ts/index.html @@ -0,0 +1,258 @@ + + + + + + + + + + 后台管理系统 + + +
+ +
+
+
+
+
加载中,请耐心等待... +
+ V0.0.1 +
+
+
+ + + + \ No newline at end of file diff --git a/frontend/vue-ts/package-lock.json b/frontend/vue-ts/package-lock.json new file mode 100644 index 000000000..815e14aa4 --- /dev/null +++ b/frontend/vue-ts/package-lock.json @@ -0,0 +1,1142 @@ +{ + "name": "vue-ts", + "version": "0.1.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.12.11", + "resolved": "http://192.168.250.101:4873/@babel%2fhelper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", + "integrity": "sha1-yaHwIZF9y1zPDU5FPjmQIpgfye0=" + }, + "@babel/parser": { + "version": "7.12.11", + "resolved": "http://192.168.250.101:4873/@babel%2fparser/-/parser-7.12.11.tgz", + "integrity": "sha1-nONZW810vFxGaQXobFNbiyUBHnk=" + }, + "@babel/types": { + "version": "7.12.11", + "resolved": "http://192.168.250.101:4873/@babel%2ftypes/-/types-7.12.11.tgz", + "integrity": "sha1-qG5NceMKm27hAlkERsmGYliSg84=", + "requires": { + "@babel/helper-validator-identifier": "^7.12.11", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "@intlify/core-base": { + "version": "9.0.0-rc.4", + "resolved": "http://192.168.250.101:4873/@intlify%2fcore-base/-/core-base-9.0.0-rc.4.tgz", + "integrity": "sha1-oPTKtPptRJIovLOQ3cTvB2ySElo=", + "requires": { + "@intlify/message-compiler": "9.0.0-rc.4", + "@intlify/message-resolver": "9.0.0-rc.4", + "@intlify/runtime": "9.0.0-rc.4", + "@intlify/shared": "9.0.0-rc.4" + } + }, + "@intlify/message-compiler": { + "version": "9.0.0-rc.4", + "resolved": "http://192.168.250.101:4873/@intlify%2fmessage-compiler/-/message-compiler-9.0.0-rc.4.tgz", + "integrity": "sha1-DyHIzKjuf40OLj9kYMM3MdQbke4=", + "requires": { + "@intlify/message-resolver": "9.0.0-rc.4", + "@intlify/shared": "9.0.0-rc.4", + "source-map": "0.6.1" + } + }, + "@intlify/message-resolver": { + "version": "9.0.0-rc.4", + "resolved": "http://192.168.250.101:4873/@intlify%2fmessage-resolver/-/message-resolver-9.0.0-rc.4.tgz", + "integrity": "sha1-AUHqu8iMlO1MTIocOgd36m4F4CY=" + }, + "@intlify/runtime": { + "version": "9.0.0-rc.4", + "resolved": "http://192.168.250.101:4873/@intlify%2fruntime/-/runtime-9.0.0-rc.4.tgz", + "integrity": "sha1-u1TAfDiLrGO1f1lelRmF4mmB5qc=", + "requires": { + "@intlify/message-compiler": "9.0.0-rc.4", + "@intlify/message-resolver": "9.0.0-rc.4", + "@intlify/shared": "9.0.0-rc.4" + } + }, + "@intlify/shared": { + "version": "9.0.0-rc.4", + "resolved": "http://192.168.250.101:4873/@intlify%2fshared/-/shared-9.0.0-rc.4.tgz", + "integrity": "sha1-IrJdNkzDauijzlYr5Dgpg9O7tME=" + }, + "@popperjs/core": { + "version": "2.6.0", + "resolved": "http://192.168.250.101:4873/@popperjs%2fcore/-/core-2.6.0.tgz", + "integrity": "sha1-8CIZWv38lC4IjuIQEoWh0xx9cn8=" + }, + "@types/json-schema": { + "version": "7.0.6", + "resolved": "http://192.168.250.101:4873/@types%2fjson-schema/-/json-schema-7.0.6.tgz", + "integrity": "sha1-9MfsQ+gbMZqYFRFQMXCfJph4kfA=", + "dev": true + }, + "@types/node": { + "version": "14.14.14", + "resolved": "http://192.168.250.101:4873/@types%2fnode/-/node-14.14.14.tgz", + "integrity": "sha1-9/1fPMhSEwERn2ORDw+5ZcfXYa4=", + "dev": true + }, + "@types/nprogress": { + "version": "0.2.0", + "resolved": "http://192.168.250.101:4873/@types%2fnprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha1-hsWTaC1BmSEqBQnMPE1WK7vW5F8=" + }, + "@vitejs/plugin-vue": { + "version": "1.1.2", + "resolved": "http://192.168.250.101:4873/@vitejs%2fplugin-vue/-/plugin-vue-1.1.2.tgz", + "integrity": "sha1-ZNHw4HOWdfVxcBX/tNhhxTr4/mA=", + "dev": true + }, + "@vue/compiler-core": { + "version": "3.0.4", + "resolved": "http://192.168.250.101:4873/@vue%2fcompiler-core/-/compiler-core-3.0.4.tgz", + "integrity": "sha1-ASKspuraTLKLOe2TCvkXREdV4zA=", + "requires": { + "@babel/parser": "^7.12.0", + "@babel/types": "^7.12.0", + "@vue/shared": "3.0.4", + "estree-walker": "^2.0.1", + "source-map": "^0.6.1" + } + }, + "@vue/compiler-dom": { + "version": "3.0.4", + "resolved": "http://192.168.250.101:4873/@vue%2fcompiler-dom/-/compiler-dom-3.0.4.tgz", + "integrity": "sha1-g0/UsVxWmM+fRQXCv7zMoFioQ+s=", + "requires": { + "@vue/compiler-core": "3.0.4", + "@vue/shared": "3.0.4" + } + }, + "@vue/compiler-sfc": { + "version": "3.0.4", + "resolved": "http://192.168.250.101:4873/@vue%2fcompiler-sfc/-/compiler-sfc-3.0.4.tgz", + "integrity": "sha1-IRn+HmjSwmiq+iBGHILBOamt+OA=", + "dev": true, + "requires": { + "@babel/parser": "^7.12.0", + "@babel/types": "^7.12.0", + "@vue/compiler-core": "3.0.4", + "@vue/compiler-dom": "3.0.4", + "@vue/compiler-ssr": "3.0.4", + "@vue/shared": "3.0.4", + "consolidate": "^0.16.0", + "estree-walker": "^2.0.1", + "hash-sum": "^2.0.0", + "lru-cache": "^5.1.1", + "magic-string": "^0.25.7", + "merge-source-map": "^1.1.0", + "postcss": "^7.0.32", + "postcss-modules": "^3.2.2", + "postcss-selector-parser": "^6.0.4", + "source-map": "^0.6.1" + } + }, + "@vue/compiler-ssr": { + "version": "3.0.4", + "resolved": "http://192.168.250.101:4873/@vue%2fcompiler-ssr/-/compiler-ssr-3.0.4.tgz", + "integrity": "sha1-zL0fVXNNUdFAL62CWsECACp6B8c=", + "dev": true, + "requires": { + "@vue/compiler-dom": "3.0.4", + "@vue/shared": "3.0.4" + } + }, + "@vue/devtools-api": { + "version": "6.0.0-beta.3", + "resolved": "http://192.168.250.101:4873/@vue%2fdevtools-api/-/devtools-api-6.0.0-beta.3.tgz", + "integrity": "sha1-WmbMi+7WiP4YwnLueovY7X41pUw=" + }, + "@vue/reactivity": { + "version": "3.0.4", + "resolved": "http://192.168.250.101:4873/@vue%2freactivity/-/reactivity-3.0.4.tgz", + "integrity": "sha1-tlmd2CcadFlgoD8FdEzPeZG6XY0=", + "requires": { + "@vue/shared": "3.0.4" + } + }, + "@vue/runtime-core": { + "version": "3.0.4", + "resolved": "http://192.168.250.101:4873/@vue%2fruntime-core/-/runtime-core-3.0.4.tgz", + "integrity": "sha1-pbmgAVYLH9jAGkP2i3ZMVV3ng2w=", + "requires": { + "@vue/reactivity": "3.0.4", + "@vue/shared": "3.0.4" + } + }, + "@vue/runtime-dom": { + "version": "3.0.4", + "resolved": "http://192.168.250.101:4873/@vue%2fruntime-dom/-/runtime-dom-3.0.4.tgz", + "integrity": "sha1-b4GuxUXyRRHSwooxWqM5FCC2nGg=", + "requires": { + "@vue/runtime-core": "3.0.4", + "@vue/shared": "3.0.4", + "csstype": "^2.6.8" + } + }, + "@vue/shared": { + "version": "3.0.4", + "resolved": "http://192.168.250.101:4873/@vue%2fshared/-/shared-3.0.4.tgz", + "integrity": "sha1-bcUPWTvf3qphg9HbwV4tRefGuLM=" + }, + "ajv": { + "version": "6.12.6", + "resolved": "http://192.168.250.101:4873/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha1-uvWmLoArB9l3A0WG+MO69a3ybfQ=", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "http://192.168.250.101:4873/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha1-MfKdpatuANHC0yms97WSlhTVAU0=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "http://192.168.250.101:4873/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.1", + "resolved": "http://192.168.250.101:4873/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha1-xV7PAhheJGklk5kxDBc84xIzsUI=", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "async-validator": { + "version": "3.5.1", + "resolved": "http://192.168.250.101:4873/async-validator/-/async-validator-3.5.1.tgz", + "integrity": "sha1-zWK5aIskZfSEIOJ620d2CrG1VZ8=" + }, + "autoprefixer": { + "version": "9.8.6", + "resolved": "http://192.168.250.101:4873/autoprefixer/-/autoprefixer-9.8.6.tgz", + "integrity": "sha1-O3NZTKG/kmYyDFrPFYjXTep0IQ8=", + "dev": true, + "requires": { + "browserslist": "^4.12.0", + "caniuse-lite": "^1.0.30001109", + "colorette": "^1.2.1", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.32", + "postcss-value-parser": "^4.1.0" + } + }, + "await-to-js": { + "version": "2.1.1", + "resolved": "http://192.168.250.101:4873/await-to-js/-/await-to-js-2.1.1.tgz", + "integrity": "sha1-wgk81aOG8ruUXXmykoF7vD9Bsxs=" + }, + "axios": { + "version": "0.21.0", + "resolved": "http://192.168.250.101:4873/axios/-/axios-0.21.0.tgz", + "integrity": "sha1-Jt8IiAOiNQ3/LCf5b++Z/klEKso=", + "requires": { + "follow-redirects": "^1.10.0" + } + }, + "babel-plugin-transform-remove-console": { + "version": "6.9.4", + "resolved": "http://192.168.250.101:4873/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.4.tgz", + "integrity": "sha1-uYA2DAZzhOJLNXpYjYB9PINSd4A=", + "dev": true + }, + "big.js": { + "version": "5.2.2", + "resolved": "http://192.168.250.101:4873/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha1-ZfCvOC9Xi83HQr2cKB6cstd2gyg=", + "dev": true + }, + "binary-extensions": { + "version": "2.1.0", + "resolved": "http://192.168.250.101:4873/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha1-MPpAyef+B9vIlWeM0ocCTeokHdk=", + "dev": true + }, + "bluebird": { + "version": "3.7.2", + "resolved": "http://192.168.250.101:4873/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha1-nyKcFb4nJFT/qXOs4NvueaGww28=", + "dev": true + }, + "braces": { + "version": "3.0.2", + "resolved": "http://192.168.250.101:4873/braces/-/braces-3.0.2.tgz", + "integrity": "sha1-NFThpGLujVmeI23zNs2epPiv4Qc=", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.16.0", + "resolved": "http://192.168.250.101:4873/browserslist/-/browserslist-4.16.0.tgz", + "integrity": "sha1-QQJ3YnUAvjyyihv+A3WG++35SIs=", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001165", + "colorette": "^1.2.1", + "electron-to-chromium": "^1.3.621", + "escalade": "^3.1.1", + "node-releases": "^1.1.67" + } + }, + "caniuse-lite": { + "version": "1.0.30001168", + "resolved": "http://192.168.250.101:4873/caniuse-lite/-/caniuse-lite-1.0.30001168.tgz", + "integrity": "sha1-b80JjBOdADub1ITLucomy4mQf5o=", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "http://192.168.250.101:4873/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "http://192.168.250.101:4873/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "chokidar": { + "version": "3.4.3", + "resolved": "http://192.168.250.101:4873/chokidar/-/chokidar-3.4.3.tgz", + "integrity": "sha1-wd84IxRI5FykrFiObHlXO6alfVs=", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + } + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "http://192.168.250.101:4873/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha1-wZ/Zvbv4WUK0/ZechNz31fB8I4c=", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "http://192.168.250.101:4873/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg=", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "http://192.168.250.101:4873/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "colorette": { + "version": "1.2.1", + "resolved": "http://192.168.250.101:4873/colorette/-/colorette-1.2.1.tgz", + "integrity": "sha1-TQuSEyXBT6+SYzCGpTbbbolWSxs=", + "dev": true + }, + "consolidate": { + "version": "0.16.0", + "resolved": "http://192.168.250.101:4873/consolidate/-/consolidate-0.16.0.tgz", + "integrity": "sha1-oRhkdokw8vGUMWYKZZBmaPX73BY=", + "dev": true, + "requires": { + "bluebird": "^3.7.2" + } + }, + "cssesc": { + "version": "3.0.0", + "resolved": "http://192.168.250.101:4873/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha1-N3QZGZA7hoVl4cCep0dEXNGJg+4=", + "dev": true + }, + "csstype": { + "version": "2.6.14", + "resolved": "http://192.168.250.101:4873/csstype/-/csstype-2.6.14.tgz", + "integrity": "sha1-AEgipAUDRbVa1NzAC+HZzy9Clt4=" + }, + "dayjs": { + "version": "1.10.4", + "resolved": "http://192.168.250.101:4873/dayjs/-/dayjs-1.10.4.tgz", + "integrity": "sha1-jlRKm4aD9heD9XCYCoqA6vVKseI=" + }, + "dotenv": { + "version": "8.2.0", + "resolved": "http://192.168.250.101:4873/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha1-l+YZJZradQ7qPk6j4mvO6lQksWo=" + }, + "electron-to-chromium": { + "version": "1.3.629", + "resolved": "http://192.168.250.101:4873/electron-to-chromium/-/electron-to-chromium-1.3.629.tgz", + "integrity": "sha1-oI0Ttk2Q48d+xbm/+j77xbSgCWk=", + "dev": true + }, + "element-plus": { + "version": "1.0.2-beta.30", + "resolved": "http://192.168.250.101:4873/element-plus/-/element-plus-1.0.2-beta.30.tgz", + "integrity": "sha1-mxaIK5cWnfC4MsizXEbPRLJW280=", + "requires": { + "@popperjs/core": "^2.4.4", + "async-validator": "^3.4.0", + "dayjs": "1.x", + "lodash": "^4.17.20", + "mitt": "^2.1.0", + "normalize-wheel": "^1.0.1", + "resize-observer-polyfill": "^1.5.1" + } + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "http://192.168.250.101:4873/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha1-VXBmIEatKeLpFucariYKvf9Pang=", + "dev": true + }, + "esbuild": { + "version": "0.8.36", + "resolved": "http://192.168.250.101:4873/esbuild/-/esbuild-0.8.36.tgz", + "integrity": "sha1-9bfGFHNyHH1T/+fIhwjiXzthgvM=", + "dev": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "http://192.168.250.101:4873/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha1-2M/ccACWXFoBdLSoLqpcBVJ0LkA=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "http://192.168.250.101:4873/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "estree-walker": { + "version": "2.0.2", + "resolved": "http://192.168.250.101:4873/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha1-UvAQF4wqTBF6d1fP6UKtt9LaTKw=" + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "http://192.168.250.101:4873/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "http://192.168.250.101:4873/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha1-h0v2nG9ATCtdmcSBNBOZ/VWJJjM=", + "dev": true + }, + "fill-range": { + "version": "7.0.1", + "resolved": "http://192.168.250.101:4873/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha1-GRmmp8df44ssfHflGYU12prN2kA=", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "follow-redirects": { + "version": "1.13.1", + "resolved": "http://192.168.250.101:4873/follow-redirects/-/follow-redirects-1.13.1.tgz", + "integrity": "sha1-X2m4Ezds7k/QR0o6uoNd8Eq3Y7c=" + }, + "fsevents": { + "version": "2.1.3", + "resolved": "http://192.168.250.101:4873/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha1-+3OHA66NL5/pAMM4Nt3r7ouX8j4=", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "http://192.168.250.101:4873/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", + "dev": true + }, + "generic-names": { + "version": "2.0.1", + "resolved": "http://192.168.250.101:4873/generic-names/-/generic-names-2.0.1.tgz", + "integrity": "sha1-+KN46tLMqno08DF7BVVIMq5BuHI=", + "dev": true, + "requires": { + "loader-utils": "^1.1.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "http://192.168.250.101:4873/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha1-tsHvQXxOVmPqSY8cRa+saRa7wik=", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "has": { + "version": "1.0.3", + "resolved": "http://192.168.250.101:4873/has/-/has-1.0.3.tgz", + "integrity": "sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y=", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "http://192.168.250.101:4873/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "hash-sum": { + "version": "2.0.0", + "resolved": "http://192.168.250.101:4873/hash-sum/-/hash-sum-2.0.0.tgz", + "integrity": "sha1-gdAbtd6OpKIUrV1urRtSNGCwtFo=", + "dev": true + }, + "icss-replace-symbols": { + "version": "1.1.0", + "resolved": "http://192.168.250.101:4873/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", + "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=", + "dev": true + }, + "icss-utils": { + "version": "4.1.1", + "resolved": "http://192.168.250.101:4873/icss-utils/-/icss-utils-4.1.1.tgz", + "integrity": "sha1-IRcLU3ie4nRHwvR91oMIFAP5pGc=", + "dev": true, + "requires": { + "postcss": "^7.0.14" + } + }, + "indexes-of": { + "version": "1.0.1", + "resolved": "http://192.168.250.101:4873/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", + "dev": true + }, + "inherits": { + "version": "2.0.3", + "resolved": "http://192.168.250.101:4873/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "http://192.168.250.101:4873/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha1-6h9/O4DwZCNug0cPhsCcJU+0Wwk=", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-core-module": { + "version": "2.2.0", + "resolved": "http://192.168.250.101:4873/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha1-lwN+89UiJNhRY/VZeytj2a/tmBo=", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "http://192.168.250.101:4873/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "http://192.168.250.101:4873/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha1-dWfb6fL14kZ7x3q4PEopSCQHpdw=", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "http://192.168.250.101:4873/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss=", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "http://192.168.250.101:4873/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "http://192.168.250.101:4873/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "http://192.168.250.101:4873/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "http://192.168.250.101:4873/json5/-/json5-1.0.1.tgz", + "integrity": "sha1-d5+wAYYE+oVOrL9iUhgNg1Q+Pb4=", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "http://192.168.250.101:4873/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha1-B8BQNKbDSfoG4k+jWqdttFgM5N0=", + "dev": true + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "http://192.168.250.101:4873/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha1-xXm140yzSxp07cbB+za/o3HVphM=", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "http://192.168.250.101:4873/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha1-tEqbYpe8tpjxxRo1RaKzs2jVnFI=" + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "http://192.168.250.101:4873/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", + "dev": true + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "http://192.168.250.101:4873/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha1-HaJ+ZxAnGUdpXa9oSOhH8B2EuSA=", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "magic-string": { + "version": "0.25.7", + "resolved": "http://192.168.250.101:4873/magic-string/-/magic-string-0.25.7.tgz", + "integrity": "sha1-P0l9b9NMZpxnmNy4IfLvMfVEUFE=", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.4" + } + }, + "merge-source-map": { + "version": "1.1.0", + "resolved": "http://192.168.250.101:4873/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha1-L93n5gIJOfcJBqaPLXrmheTIxkY=", + "dev": true, + "requires": { + "source-map": "^0.6.1" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "http://192.168.250.101:4873/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha1-Z9ZgFLZqaoqqDAg8X9WN9OTpdgI=", + "dev": true + }, + "mitt": { + "version": "2.1.0", + "resolved": "http://192.168.250.101:4873/mitt/-/mitt-2.1.0.tgz", + "integrity": "sha1-90BXfCMXbGIFsSGylzUU6t4bIjA=" + }, + "nanoid": { + "version": "3.1.20", + "resolved": "http://192.168.250.101:4873/nanoid/-/nanoid-3.1.20.tgz", + "integrity": "sha1-utwmPGsdzxS3HvqoX2q0wdbPx4g=", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "http://192.168.250.101:4873/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha1-tKr7k+OustgXTKU88WOrfXMIMF8=", + "dev": true + }, + "node-releases": { + "version": "1.1.67", + "resolved": "http://192.168.250.101:4873/node-releases/-/node-releases-1.1.67.tgz", + "integrity": "sha1-KOv8zNC6pqrY6NTY/ky8Sa4jnBI=", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "http://192.168.250.101:4873/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU=", + "dev": true + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "http://192.168.250.101:4873/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true + }, + "normalize-wheel": { + "version": "1.0.1", + "resolved": "http://192.168.250.101:4873/normalize-wheel/-/normalize-wheel-1.0.1.tgz", + "integrity": "sha1-rsiGr/2wRQcNhWRH32Ls+GFG7EU=" + }, + "nprogress": { + "version": "0.2.0", + "resolved": "http://192.168.250.101:4873/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha1-y480xTIT2JVyP8urkH6UIq28r7E=" + }, + "num2fraction": { + "version": "1.2.2", + "resolved": "http://192.168.250.101:4873/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", + "dev": true + }, + "path": { + "version": "0.12.7", + "resolved": "http://192.168.250.101:4873/path/-/path-0.12.7.tgz", + "integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=", + "requires": { + "process": "^0.11.1", + "util": "^0.10.3" + } + }, + "path-parse": { + "version": "1.0.6", + "resolved": "http://192.168.250.101:4873/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha1-1i27VnlAXXLEc37FhgDp3c8G0kw=", + "dev": true + }, + "path-to-regexp": { + "version": "6.2.0", + "resolved": "http://192.168.250.101:4873/path-to-regexp/-/path-to-regexp-6.2.0.tgz", + "integrity": "sha1-97OAMzYQTDRoia3s5hRmkjBkXzg=" + }, + "picomatch": { + "version": "2.2.2", + "resolved": "http://192.168.250.101:4873/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha1-IfMz6ba46v8CRo9RRupAbTRfTa0=", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "http://192.168.250.101:4873/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "postcss": { + "version": "7.0.35", + "resolved": "http://192.168.250.101:4873/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha1-0r4AuZj38hHYonaXQHny6SuXDiQ=", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-import": { + "version": "12.0.1", + "resolved": "http://192.168.250.101:4873/postcss-import/-/postcss-import-12.0.1.tgz", + "integrity": "sha1-z4x6sLXMq1ZJAkU25WX4QZKLcVM=", + "dev": true, + "requires": { + "postcss": "^7.0.1", + "postcss-value-parser": "^3.2.3", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "http://192.168.250.101:4873/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", + "dev": true + } + } + }, + "postcss-modules": { + "version": "3.2.2", + "resolved": "http://192.168.250.101:4873/postcss-modules/-/postcss-modules-3.2.2.tgz", + "integrity": "sha1-7jkN4PnxjnYeF3jfub4maFwCxR8=", + "dev": true, + "requires": { + "generic-names": "^2.0.1", + "icss-replace-symbols": "^1.1.0", + "lodash.camelcase": "^4.3.0", + "postcss": "^7.0.32", + "postcss-modules-extract-imports": "^2.0.0", + "postcss-modules-local-by-default": "^3.0.2", + "postcss-modules-scope": "^2.2.0", + "postcss-modules-values": "^3.0.0", + "string-hash": "^1.1.1" + } + }, + "postcss-modules-extract-imports": { + "version": "2.0.0", + "resolved": "http://192.168.250.101:4873/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", + "integrity": "sha1-gYcZoa4doyX5gyRGsBE27rSTzX4=", + "dev": true, + "requires": { + "postcss": "^7.0.5" + } + }, + "postcss-modules-local-by-default": { + "version": "3.0.3", + "resolved": "http://192.168.250.101:4873/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz", + "integrity": "sha1-uxTgzHgnnVBNvcv9fgyiiZP/u7A=", + "dev": true, + "requires": { + "icss-utils": "^4.1.1", + "postcss": "^7.0.32", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + } + }, + "postcss-modules-scope": { + "version": "2.2.0", + "resolved": "http://192.168.250.101:4873/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz", + "integrity": "sha1-OFyuATzHdD9afXYC0Qc6iequYu4=", + "dev": true, + "requires": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^6.0.0" + } + }, + "postcss-modules-values": { + "version": "3.0.0", + "resolved": "http://192.168.250.101:4873/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz", + "integrity": "sha1-W1AA1uuuKbQlUwG0o6VFdEI+fxA=", + "dev": true, + "requires": { + "icss-utils": "^4.0.0", + "postcss": "^7.0.6" + } + }, + "postcss-selector-parser": { + "version": "6.0.4", + "resolved": "http://192.168.250.101:4873/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz", + "integrity": "sha1-VgdaE4CgRgTDiwY+p3Z6Epr1wrM=", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1", + "util-deprecate": "^1.0.2" + } + }, + "postcss-value-parser": { + "version": "4.1.0", + "resolved": "http://192.168.250.101:4873/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha1-RD9qIM7WSBor2k+oUypuVdeJoss=", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "http://192.168.250.101:4873/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + }, + "punycode": { + "version": "2.1.1", + "resolved": "http://192.168.250.101:4873/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha1-tYsBCsQMIsVldhbI0sLALHv0eew=", + "dev": true + }, + "read-cache": { + "version": "1.0.0", + "resolved": "http://192.168.250.101:4873/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=", + "dev": true, + "requires": { + "pify": "^2.3.0" + } + }, + "readdirp": { + "version": "3.5.0", + "resolved": "http://192.168.250.101:4873/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha1-m6dMAZsV02UnjS6Ru4xI17TULJ4=", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "http://192.168.250.101:4873/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha1-DpAg3T0hAkRY1OvSfiPkAmmBBGQ=" + }, + "resolve": { + "version": "1.19.0", + "resolved": "http://192.168.250.101:4873/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha1-GvW/YwQJc0oGfK4pMYqsf6KaJnw=", + "dev": true, + "requires": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + } + }, + "rollup": { + "version": "2.38.1", + "resolved": "http://192.168.250.101:4873/rollup/-/rollup-2.38.1.tgz", + "integrity": "sha1-7OoPfObvLB8CP9t5Uk63rrZw6nk=", + "dev": true, + "requires": { + "fsevents": "~2.1.2" + } + }, + "sass": { + "version": "1.30.0", + "resolved": "http://192.168.250.101:4873/sass/-/sass-1.30.0.tgz", + "integrity": "sha1-YLu7r3a6EBF+YcbCTwAWHD1gYQ4=", + "dev": true, + "requires": { + "chokidar": ">=2.0.0 <4.0.0" + } + }, + "sass-loader": { + "version": "8.0.2", + "resolved": "http://192.168.250.101:4873/sass-loader/-/sass-loader-8.0.2.tgz", + "integrity": "sha1-3r7NjDziQ8dkVPLoKQSCFQOACQ0=", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "loader-utils": "^1.2.3", + "neo-async": "^2.6.1", + "schema-utils": "^2.6.1", + "semver": "^6.3.0" + } + }, + "schema-utils": { + "version": "2.7.1", + "resolved": "http://192.168.250.101:4873/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha1-HKTzLRskxZDCA7jnpQvw6kzTlNc=", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + } + }, + "screenfull": { + "version": "5.0.2", + "resolved": "http://192.168.250.101:4873/screenfull/-/screenfull-5.0.2.tgz", + "integrity": "sha1-uazc8exnapSGdN9c0P9muQKwvtc=" + }, + "semver": { + "version": "6.3.0", + "resolved": "http://192.168.250.101:4873/semver/-/semver-6.3.0.tgz", + "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", + "dev": true + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "http://192.168.250.101:4873/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha1-jymBrZJTH1UDWwH7IwdppA4C76M=", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "http://192.168.250.101:4873/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=" + }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "http://192.168.250.101:4873/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha1-6oBL2UhXQC5pktBaOO8a41qatMQ=", + "dev": true + }, + "string-hash": { + "version": "1.1.3", + "resolved": "http://192.168.250.101:4873/string-hash/-/string-hash-1.1.3.tgz", + "integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "http://192.168.250.101:4873/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha1-B2Srxpxj1ayELdSGfo0CXogN+PM=", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "http://192.168.250.101:4873/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "http://192.168.250.101:4873/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ=", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "typescript": { + "version": "4.1.3", + "resolved": "http://192.168.250.101:4873/typescript/-/typescript-4.1.3.tgz", + "integrity": "sha1-UZ1YK9lMugz4k0x9joRn5HP1O7c=", + "dev": true + }, + "uniq": { + "version": "1.0.1", + "resolved": "http://192.168.250.101:4873/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "dev": true + }, + "uri-js": { + "version": "4.4.0", + "resolved": "http://192.168.250.101:4873/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha1-qnFCYd55PoqCNHp7zJznTobyhgI=", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "util": { + "version": "0.10.4", + "resolved": "http://192.168.250.101:4873/util/-/util-0.10.4.tgz", + "integrity": "sha1-OqASW/5mikZy3liFfTrOJ+y3aQE=", + "requires": { + "inherits": "2.0.3" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "http://192.168.250.101:4873/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "v-contextmenu": { + "version": "3.0.0-alpha.4", + "resolved": "http://192.168.250.101:4873/v-contextmenu/-/v-contextmenu-3.0.0-alpha.4.tgz", + "integrity": "sha1-9GWYrJivrF1duMZUDfwSMEztEUA=" + }, + "vite": { + "version": "2.0.0-beta.56", + "resolved": "http://192.168.250.101:4873/vite/-/vite-2.0.0-beta.56.tgz", + "integrity": "sha1-slTsRkeuE4PXxbbz/bAfiXG1vN0=", + "dev": true, + "requires": { + "esbuild": "^0.8.34", + "fsevents": "~2.1.2", + "postcss": "^8.2.1", + "resolve": "^1.19.0", + "rollup": "^2.35.1" + }, + "dependencies": { + "postcss": { + "version": "8.2.4", + "resolved": "http://192.168.250.101:4873/postcss/-/postcss-8.2.4.tgz", + "integrity": "sha1-IKmKOc8wPRUSnChlqew37aADHQQ=", + "dev": true, + "requires": { + "colorette": "^1.2.1", + "nanoid": "^3.1.20", + "source-map": "^0.6.1" + } + } + } + }, + "vue": { + "version": "3.0.4", + "resolved": "http://192.168.250.101:4873/vue/-/vue-3.0.4.tgz", + "integrity": "sha1-hyxlwUP1cXvVOHxhYT2fVfTMD0M=", + "requires": { + "@vue/compiler-dom": "3.0.4", + "@vue/runtime-dom": "3.0.4", + "@vue/shared": "3.0.4" + } + }, + "vue-i18n": { + "version": "9.0.0-rc.4", + "resolved": "http://192.168.250.101:4873/vue-i18n/-/vue-i18n-9.0.0-rc.4.tgz", + "integrity": "sha1-cX2WBOYbyPWvdKAjxAiBoZT4ilg=", + "requires": { + "@intlify/core-base": "9.0.0-rc.4", + "@intlify/shared": "9.0.0-rc.4", + "@vue/devtools-api": "^6.0.0-beta.3" + } + }, + "vue-router": { + "version": "4.0.3", + "resolved": "http://192.168.250.101:4873/vue-router/-/vue-router-4.0.3.tgz", + "integrity": "sha1-iyYFDIiy3sfieoiDX3EEazZYI+w=" + }, + "vuex": { + "version": "4.0.0-rc.2", + "resolved": "http://192.168.250.101:4873/vuex/-/vuex-4.0.0-rc.2.tgz", + "integrity": "sha1-NoHITrb1FxsDntqhfMeBBeIHJPM=" + }, + "vxe-table": { + "version": "4.0.0-beta.3", + "resolved": "http://192.168.250.101:4873/vxe-table/-/vxe-table-4.0.0-beta.3.tgz", + "integrity": "sha1-rz3SkD6vR2XuXemZCSg2k3v+cBY=" + }, + "xe-utils": { + "version": "3.0.4", + "resolved": "http://192.168.250.101:4873/xe-utils/-/xe-utils-3.0.4.tgz", + "integrity": "sha1-27RRgLB/6rZVHM+Od0/xVQAj53M=" + }, + "yallist": { + "version": "3.1.1", + "resolved": "http://192.168.250.101:4873/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha1-27fa+b/YusmrRev2ArjLrQ1dCP0=", + "dev": true + } + } +} diff --git a/frontend/vue-ts/package.json b/frontend/vue-ts/package.json new file mode 100644 index 000000000..c99fc2311 --- /dev/null +++ b/frontend/vue-ts/package.json @@ -0,0 +1,41 @@ +{ + "name": "vue-ts", + "version": "0.1.0", + "private": true, + "scripts": { + "serve": "vite", + "build": "vite build" + }, + "dependencies": { + "@types/nprogress": "^0.2.0", + "await-to-js": "^2.1.1", + "axios": "^0.21.0", + "dotenv": "^8.2.0", + "element-plus": "^1.0.2-beta.30", + "mitt": "^2.1.0", + "nprogress": "^0.2.0", + "path": "^0.12.7", + "path-to-regexp": "^6.2.0", + "resize-observer-polyfill": "^1.5.1", + "screenfull": "^5.0.2", + "v-contextmenu": "^3.0.0-alpha.4", + "vue": "^3.0.4", + "vue-i18n": "^9.0.0-rc.4", + "vue-router": "^4.0.3", + "vuex": "^4.0.0-rc.2", + "vxe-table": "^4.0.0-beta.3", + "xe-utils": "^3.0.4" + }, + "devDependencies": { + "@types/node": "^14.14.14", + "@vitejs/plugin-vue": "^1.1.2", + "@vue/compiler-sfc": "^3.0.4", + "autoprefixer": "^9.8.6", + "babel-plugin-transform-remove-console": "^6.9.4", + "postcss-import": "^12.0.1", + "sass": "^1.26.5", + "sass-loader": "^8.0.2", + "typescript": "^4.1.3", + "vite": "^2.0.0-beta.56" + } +} diff --git a/frontend/vue-ts/postcss.config.js b/frontend/vue-ts/postcss.config.js new file mode 100644 index 000000000..750501a7a --- /dev/null +++ b/frontend/vue-ts/postcss.config.js @@ -0,0 +1,3 @@ +module.exports = { + plugins: [require('autoprefixer'), require('postcss-import')], +}; \ No newline at end of file diff --git a/frontend/vue-ts/public/animate.css b/frontend/vue-ts/public/animate.css new file mode 100644 index 000000000..b6f612953 --- /dev/null +++ b/frontend/vue-ts/public/animate.css @@ -0,0 +1,11 @@ +@charset "UTF-8"; + +/*! + * animate.css -http://daneden.me/animate + * Version - 3.5.1 + * Licensed under the MIT license - http://opensource.org/licenses/MIT + * + * Copyright (c) 2016 Daniel Eden + */ + +.animated{-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.animated.infinite{-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.animated.hinge{-webkit-animation-duration:2s;animation-duration:2s}.animated.bounceIn,.animated.bounceOut,.animated.flipOutX,.animated.flipOutY{-webkit-animation-duration:.75s;animation-duration:.75s}@-webkit-keyframes bounce{0%,20%,53%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1);-webkit-transform:translateZ(0);transform:translateZ(0)}40%,43%{-webkit-transform:translate3d(0,-30px,0);transform:translate3d(0,-30px,0)}40%,43%,70%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);animation-timing-function:cubic-bezier(.755,.05,.855,.06)}70%{-webkit-transform:translate3d(0,-15px,0);transform:translate3d(0,-15px,0)}90%{-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0)}}@keyframes bounce{0%,20%,53%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1);-webkit-transform:translateZ(0);transform:translateZ(0)}40%,43%{-webkit-transform:translate3d(0,-30px,0);transform:translate3d(0,-30px,0)}40%,43%,70%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);animation-timing-function:cubic-bezier(.755,.05,.855,.06)}70%{-webkit-transform:translate3d(0,-15px,0);transform:translate3d(0,-15px,0)}90%{-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0)}}.bounce{-webkit-animation-name:bounce;animation-name:bounce;-webkit-transform-origin:center bottom;transform-origin:center bottom}@-webkit-keyframes flash{0%,50%,to{opacity:1}25%,75%{opacity:0}}@keyframes flash{0%,50%,to{opacity:1}25%,75%{opacity:0}}.flash{-webkit-animation-name:flash;animation-name:flash}@-webkit-keyframes pulse{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}50%{-webkit-transform:scale3d(1.05,1.05,1.05);transform:scale3d(1.05,1.05,1.05)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}@keyframes pulse{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}50%{-webkit-transform:scale3d(1.05,1.05,1.05);transform:scale3d(1.05,1.05,1.05)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}.pulse{-webkit-animation-name:pulse;animation-name:pulse}@-webkit-keyframes rubberBand{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}30%{-webkit-transform:scale3d(1.25,.75,1);transform:scale3d(1.25,.75,1)}40%{-webkit-transform:scale3d(.75,1.25,1);transform:scale3d(.75,1.25,1)}50%{-webkit-transform:scale3d(1.15,.85,1);transform:scale3d(1.15,.85,1)}65%{-webkit-transform:scale3d(.95,1.05,1);transform:scale3d(.95,1.05,1)}75%{-webkit-transform:scale3d(1.05,.95,1);transform:scale3d(1.05,.95,1)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}@keyframes rubberBand{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}30%{-webkit-transform:scale3d(1.25,.75,1);transform:scale3d(1.25,.75,1)}40%{-webkit-transform:scale3d(.75,1.25,1);transform:scale3d(.75,1.25,1)}50%{-webkit-transform:scale3d(1.15,.85,1);transform:scale3d(1.15,.85,1)}65%{-webkit-transform:scale3d(.95,1.05,1);transform:scale3d(.95,1.05,1)}75%{-webkit-transform:scale3d(1.05,.95,1);transform:scale3d(1.05,.95,1)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}.rubberBand{-webkit-animation-name:rubberBand;animation-name:rubberBand}@-webkit-keyframes shake{0%,to{-webkit-transform:translateZ(0);transform:translateZ(0)}10%,30%,50%,70%,90%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}20%,40%,60%,80%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}}@keyframes shake{0%,to{-webkit-transform:translateZ(0);transform:translateZ(0)}10%,30%,50%,70%,90%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}20%,40%,60%,80%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}}.shake{-webkit-animation-name:shake;animation-name:shake}@-webkit-keyframes headShake{0%{-webkit-transform:translateX(0);transform:translateX(0)}6.5%{-webkit-transform:translateX(-6px) rotateY(-9deg);transform:translateX(-6px) rotateY(-9deg)}18.5%{-webkit-transform:translateX(5px) rotateY(7deg);transform:translateX(5px) rotateY(7deg)}31.5%{-webkit-transform:translateX(-3px) rotateY(-5deg);transform:translateX(-3px) rotateY(-5deg)}43.5%{-webkit-transform:translateX(2px) rotateY(3deg);transform:translateX(2px) rotateY(3deg)}50%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes headShake{0%{-webkit-transform:translateX(0);transform:translateX(0)}6.5%{-webkit-transform:translateX(-6px) rotateY(-9deg);transform:translateX(-6px) rotateY(-9deg)}18.5%{-webkit-transform:translateX(5px) rotateY(7deg);transform:translateX(5px) rotateY(7deg)}31.5%{-webkit-transform:translateX(-3px) rotateY(-5deg);transform:translateX(-3px) rotateY(-5deg)}43.5%{-webkit-transform:translateX(2px) rotateY(3deg);transform:translateX(2px) rotateY(3deg)}50%{-webkit-transform:translateX(0);transform:translateX(0)}}.headShake{-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-name:headShake;animation-name:headShake}@-webkit-keyframes swing{20%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}40%{-webkit-transform:rotate(-10deg);transform:rotate(-10deg)}60%{-webkit-transform:rotate(5deg);transform:rotate(5deg)}80%{-webkit-transform:rotate(-5deg);transform:rotate(-5deg)}to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}@keyframes swing{20%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}40%{-webkit-transform:rotate(-10deg);transform:rotate(-10deg)}60%{-webkit-transform:rotate(5deg);transform:rotate(5deg)}80%{-webkit-transform:rotate(-5deg);transform:rotate(-5deg)}to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}.swing{-webkit-transform-origin:top center;transform-origin:top center;-webkit-animation-name:swing;animation-name:swing}@-webkit-keyframes tada{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}10%,20%{-webkit-transform:scale3d(.9,.9,.9) rotate(-3deg);transform:scale3d(.9,.9,.9) rotate(-3deg)}30%,50%,70%,90%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate(3deg);transform:scale3d(1.1,1.1,1.1) rotate(3deg)}40%,60%,80%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate(-3deg);transform:scale3d(1.1,1.1,1.1) rotate(-3deg)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}@keyframes tada{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}10%,20%{-webkit-transform:scale3d(.9,.9,.9) rotate(-3deg);transform:scale3d(.9,.9,.9) rotate(-3deg)}30%,50%,70%,90%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate(3deg);transform:scale3d(1.1,1.1,1.1) rotate(3deg)}40%,60%,80%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate(-3deg);transform:scale3d(1.1,1.1,1.1) rotate(-3deg)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}.tada{-webkit-animation-name:tada;animation-name:tada}@-webkit-keyframes wobble{0%{-webkit-transform:none;transform:none}15%{-webkit-transform:translate3d(-25%,0,0) rotate(-5deg);transform:translate3d(-25%,0,0) rotate(-5deg)}30%{-webkit-transform:translate3d(20%,0,0) rotate(3deg);transform:translate3d(20%,0,0) rotate(3deg)}45%{-webkit-transform:translate3d(-15%,0,0) rotate(-3deg);transform:translate3d(-15%,0,0) rotate(-3deg)}60%{-webkit-transform:translate3d(10%,0,0) rotate(2deg);transform:translate3d(10%,0,0) rotate(2deg)}75%{-webkit-transform:translate3d(-5%,0,0) rotate(-1deg);transform:translate3d(-5%,0,0) rotate(-1deg)}to{-webkit-transform:none;transform:none}}@keyframes wobble{0%{-webkit-transform:none;transform:none}15%{-webkit-transform:translate3d(-25%,0,0) rotate(-5deg);transform:translate3d(-25%,0,0) rotate(-5deg)}30%{-webkit-transform:translate3d(20%,0,0) rotate(3deg);transform:translate3d(20%,0,0) rotate(3deg)}45%{-webkit-transform:translate3d(-15%,0,0) rotate(-3deg);transform:translate3d(-15%,0,0) rotate(-3deg)}60%{-webkit-transform:translate3d(10%,0,0) rotate(2deg);transform:translate3d(10%,0,0) rotate(2deg)}75%{-webkit-transform:translate3d(-5%,0,0) rotate(-1deg);transform:translate3d(-5%,0,0) rotate(-1deg)}to{-webkit-transform:none;transform:none}}.wobble{-webkit-animation-name:wobble;animation-name:wobble}@-webkit-keyframes jello{0%,11.1%,to{-webkit-transform:none;transform:none}22.2%{-webkit-transform:skewX(-12.5deg) skewY(-12.5deg);transform:skewX(-12.5deg) skewY(-12.5deg)}33.3%{-webkit-transform:skewX(6.25deg) skewY(6.25deg);transform:skewX(6.25deg) skewY(6.25deg)}44.4%{-webkit-transform:skewX(-3.125deg) skewY(-3.125deg);transform:skewX(-3.125deg) skewY(-3.125deg)}55.5%{-webkit-transform:skewX(1.5625deg) skewY(1.5625deg);transform:skewX(1.5625deg) skewY(1.5625deg)}66.6%{-webkit-transform:skewX(-.78125deg) skewY(-.78125deg);transform:skewX(-.78125deg) skewY(-.78125deg)}77.7%{-webkit-transform:skewX(.390625deg) skewY(.390625deg);transform:skewX(.390625deg) skewY(.390625deg)}88.8%{-webkit-transform:skewX(-.1953125deg) skewY(-.1953125deg);transform:skewX(-.1953125deg) skewY(-.1953125deg)}}@keyframes jello{0%,11.1%,to{-webkit-transform:none;transform:none}22.2%{-webkit-transform:skewX(-12.5deg) skewY(-12.5deg);transform:skewX(-12.5deg) skewY(-12.5deg)}33.3%{-webkit-transform:skewX(6.25deg) skewY(6.25deg);transform:skewX(6.25deg) skewY(6.25deg)}44.4%{-webkit-transform:skewX(-3.125deg) skewY(-3.125deg);transform:skewX(-3.125deg) skewY(-3.125deg)}55.5%{-webkit-transform:skewX(1.5625deg) skewY(1.5625deg);transform:skewX(1.5625deg) skewY(1.5625deg)}66.6%{-webkit-transform:skewX(-.78125deg) skewY(-.78125deg);transform:skewX(-.78125deg) skewY(-.78125deg)}77.7%{-webkit-transform:skewX(.390625deg) skewY(.390625deg);transform:skewX(.390625deg) skewY(.390625deg)}88.8%{-webkit-transform:skewX(-.1953125deg) skewY(-.1953125deg);transform:skewX(-.1953125deg) skewY(-.1953125deg)}}.jello{-webkit-animation-name:jello;animation-name:jello;-webkit-transform-origin:center;transform-origin:center}@-webkit-keyframes bounceIn{0%,20%,40%,60%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}20%{-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}40%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}60%{opacity:1;-webkit-transform:scale3d(1.03,1.03,1.03);transform:scale3d(1.03,1.03,1.03)}80%{-webkit-transform:scale3d(.97,.97,.97);transform:scale3d(.97,.97,.97)}to{opacity:1;-webkit-transform:scaleX(1);transform:scaleX(1)}}@keyframes bounceIn{0%,20%,40%,60%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}20%{-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}40%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}60%{opacity:1;-webkit-transform:scale3d(1.03,1.03,1.03);transform:scale3d(1.03,1.03,1.03)}80%{-webkit-transform:scale3d(.97,.97,.97);transform:scale3d(.97,.97,.97)}to{opacity:1;-webkit-transform:scaleX(1);transform:scaleX(1)}}.bounceIn{-webkit-animation-name:bounceIn;animation-name:bounceIn}@-webkit-keyframes bounceInDown{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(0,-3000px,0);transform:translate3d(0,-3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,25px,0);transform:translate3d(0,25px,0)}75%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}90%{-webkit-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0)}to{-webkit-transform:none;transform:none}}@keyframes bounceInDown{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(0,-3000px,0);transform:translate3d(0,-3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,25px,0);transform:translate3d(0,25px,0)}75%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}90%{-webkit-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0)}to{-webkit-transform:none;transform:none}}.bounceInDown{-webkit-animation-name:bounceInDown;animation-name:bounceInDown}@-webkit-keyframes bounceInLeft{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(-3000px,0,0);transform:translate3d(-3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(25px,0,0);transform:translate3d(25px,0,0)}75%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}90%{-webkit-transform:translate3d(5px,0,0);transform:translate3d(5px,0,0)}to{-webkit-transform:none;transform:none}}@keyframes bounceInLeft{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(-3000px,0,0);transform:translate3d(-3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(25px,0,0);transform:translate3d(25px,0,0)}75%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}90%{-webkit-transform:translate3d(5px,0,0);transform:translate3d(5px,0,0)}to{-webkit-transform:none;transform:none}}.bounceInLeft{-webkit-animation-name:bounceInLeft;animation-name:bounceInLeft}@-webkit-keyframes bounceInRight{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(3000px,0,0);transform:translate3d(3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}to{-webkit-transform:none;transform:none}}@keyframes bounceInRight{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(3000px,0,0);transform:translate3d(3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}to{-webkit-transform:none;transform:none}}.bounceInRight{-webkit-animation-name:bounceInRight;animation-name:bounceInRight}@-webkit-keyframes bounceInUp{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(0,3000px,0);transform:translate3d(0,3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}75%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}90%{-webkit-transform:translate3d(0,-5px,0);transform:translate3d(0,-5px,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes bounceInUp{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(0,3000px,0);transform:translate3d(0,3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}75%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}90%{-webkit-transform:translate3d(0,-5px,0);transform:translate3d(0,-5px,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.bounceInUp{-webkit-animation-name:bounceInUp;animation-name:bounceInUp}@-webkit-keyframes bounceOut{20%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}50%,55%{opacity:1;-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}to{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}}@keyframes bounceOut{20%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}50%,55%{opacity:1;-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}to{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}}.bounceOut{-webkit-animation-name:bounceOut;animation-name:bounceOut}@-webkit-keyframes bounceOutDown{20%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}to{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}@keyframes bounceOutDown{20%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}to{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}.bounceOutDown{-webkit-animation-name:bounceOutDown;animation-name:bounceOutDown}@-webkit-keyframes bounceOutLeft{20%{opacity:1;-webkit-transform:translate3d(20px,0,0);transform:translate3d(20px,0,0)}to{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}@keyframes bounceOutLeft{20%{opacity:1;-webkit-transform:translate3d(20px,0,0);transform:translate3d(20px,0,0)}to{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}.bounceOutLeft{-webkit-animation-name:bounceOutLeft;animation-name:bounceOutLeft}@-webkit-keyframes bounceOutRight{20%{opacity:1;-webkit-transform:translate3d(-20px,0,0);transform:translate3d(-20px,0,0)}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}@keyframes bounceOutRight{20%{opacity:1;-webkit-transform:translate3d(-20px,0,0);transform:translate3d(-20px,0,0)}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}.bounceOutRight{-webkit-animation-name:bounceOutRight;animation-name:bounceOutRight}@-webkit-keyframes bounceOutUp{20%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,20px,0);transform:translate3d(0,20px,0)}to{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}@keyframes bounceOutUp{20%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,20px,0);transform:translate3d(0,20px,0)}to{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}.bounceOutUp{-webkit-animation-name:bounceOutUp;animation-name:bounceOutUp}@-webkit-keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.fadeIn{-webkit-animation-name:fadeIn;animation-name:fadeIn}@-webkit-keyframes fadeInDown{0%{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInDown{0%{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInDown{-webkit-animation-name:fadeInDown;animation-name:fadeInDown}@-webkit-keyframes fadeInDownBig{0%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInDownBig{0%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInDownBig{-webkit-animation-name:fadeInDownBig;animation-name:fadeInDownBig}@-webkit-keyframes fadeInLeft{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInLeft{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInLeft{-webkit-animation-name:fadeInLeft;animation-name:fadeInLeft}@-webkit-keyframes fadeInLeftBig{0%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInLeftBig{0%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInLeftBig{-webkit-animation-name:fadeInLeftBig;animation-name:fadeInLeftBig}@-webkit-keyframes fadeInRight{0%{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInRight{0%{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInRight{-webkit-animation-name:fadeInRight;animation-name:fadeInRight}@-webkit-keyframes fadeInRightBig{0%{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInRightBig{0%{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInRightBig{-webkit-animation-name:fadeInRightBig;animation-name:fadeInRightBig}@-webkit-keyframes fadeInUp{0%{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInUp{0%{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInUp{-webkit-animation-name:fadeInUp;animation-name:fadeInUp}@-webkit-keyframes fadeInUpBig{0%{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInUpBig{0%{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInUpBig{-webkit-animation-name:fadeInUpBig;animation-name:fadeInUpBig}@-webkit-keyframes fadeOut{0%{opacity:1}to{opacity:0}}@keyframes fadeOut{0%{opacity:1}to{opacity:0}}.fadeOut{-webkit-animation-name:fadeOut;animation-name:fadeOut}@-webkit-keyframes fadeOutDown{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}@keyframes fadeOutDown{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}.fadeOutDown{-webkit-animation-name:fadeOutDown;animation-name:fadeOutDown}@-webkit-keyframes fadeOutDownBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}@keyframes fadeOutDownBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}.fadeOutDownBig{-webkit-animation-name:fadeOutDownBig;animation-name:fadeOutDownBig}@-webkit-keyframes fadeOutLeft{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}@keyframes fadeOutLeft{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.fadeOutLeft{-webkit-animation-name:fadeOutLeft;animation-name:fadeOutLeft}@-webkit-keyframes fadeOutLeftBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}@keyframes fadeOutLeftBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}.fadeOutLeftBig{-webkit-animation-name:fadeOutLeftBig;animation-name:fadeOutLeftBig}@-webkit-keyframes fadeOutRight{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}@keyframes fadeOutRight{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.fadeOutRight{-webkit-animation-name:fadeOutRight;animation-name:fadeOutRight}@-webkit-keyframes fadeOutRightBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}@keyframes fadeOutRightBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}.fadeOutRightBig{-webkit-animation-name:fadeOutRightBig;animation-name:fadeOutRightBig}@-webkit-keyframes fadeOutUp{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}@keyframes fadeOutUp{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}.fadeOutUp{-webkit-animation-name:fadeOutUp;animation-name:fadeOutUp}@-webkit-keyframes fadeOutUpBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}@keyframes fadeOutUpBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}.fadeOutUpBig{-webkit-animation-name:fadeOutUpBig;animation-name:fadeOutUpBig}@-webkit-keyframes flip{0%{-webkit-transform:perspective(400px) rotateY(-1turn);transform:perspective(400px) rotateY(-1turn)}0%,40%{-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}40%{-webkit-transform:perspective(400px) translateZ(150px) rotateY(-190deg);transform:perspective(400px) translateZ(150px) rotateY(-190deg)}50%{-webkit-transform:perspective(400px) translateZ(150px) rotateY(-170deg);transform:perspective(400px) translateZ(150px) rotateY(-170deg)}50%,80%{-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}80%{-webkit-transform:perspective(400px) scale3d(.95,.95,.95);transform:perspective(400px) scale3d(.95,.95,.95)}to{-webkit-transform:perspective(400px);transform:perspective(400px);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}}@keyframes flip{0%{-webkit-transform:perspective(400px) rotateY(-1turn);transform:perspective(400px) rotateY(-1turn)}0%,40%{-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}40%{-webkit-transform:perspective(400px) translateZ(150px) rotateY(-190deg);transform:perspective(400px) translateZ(150px) rotateY(-190deg)}50%{-webkit-transform:perspective(400px) translateZ(150px) rotateY(-170deg);transform:perspective(400px) translateZ(150px) rotateY(-170deg)}50%,80%{-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}80%{-webkit-transform:perspective(400px) scale3d(.95,.95,.95);transform:perspective(400px) scale3d(.95,.95,.95)}to{-webkit-transform:perspective(400px);transform:perspective(400px);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}}.animated.flip{-webkit-backface-visibility:visible;backface-visibility:visible;-webkit-animation-name:flip;animation-name:flip}@-webkit-keyframes flipInX{0%{-webkit-transform:perspective(400px) rotateX(90deg);transform:perspective(400px) rotateX(90deg);opacity:0}0%,40%{-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}40%{-webkit-transform:perspective(400px) rotateX(-20deg);transform:perspective(400px) rotateX(-20deg)}60%{-webkit-transform:perspective(400px) rotateX(10deg);transform:perspective(400px) rotateX(10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotateX(-5deg);transform:perspective(400px) rotateX(-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}@keyframes flipInX{0%{-webkit-transform:perspective(400px) rotateX(90deg);transform:perspective(400px) rotateX(90deg);opacity:0}0%,40%{-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}40%{-webkit-transform:perspective(400px) rotateX(-20deg);transform:perspective(400px) rotateX(-20deg)}60%{-webkit-transform:perspective(400px) rotateX(10deg);transform:perspective(400px) rotateX(10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotateX(-5deg);transform:perspective(400px) rotateX(-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}.flipInX{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipInX;animation-name:flipInX}@-webkit-keyframes flipInY{0%{-webkit-transform:perspective(400px) rotateY(90deg);transform:perspective(400px) rotateY(90deg);opacity:0}0%,40%{-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}40%{-webkit-transform:perspective(400px) rotateY(-20deg);transform:perspective(400px) rotateY(-20deg)}60%{-webkit-transform:perspective(400px) rotateY(10deg);transform:perspective(400px) rotateY(10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotateY(-5deg);transform:perspective(400px) rotateY(-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}@keyframes flipInY{0%{-webkit-transform:perspective(400px) rotateY(90deg);transform:perspective(400px) rotateY(90deg);opacity:0}0%,40%{-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}40%{-webkit-transform:perspective(400px) rotateY(-20deg);transform:perspective(400px) rotateY(-20deg)}60%{-webkit-transform:perspective(400px) rotateY(10deg);transform:perspective(400px) rotateY(10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotateY(-5deg);transform:perspective(400px) rotateY(-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}.flipInY{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipInY;animation-name:flipInY}@-webkit-keyframes flipOutX{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotateX(-20deg);transform:perspective(400px) rotateX(-20deg);opacity:1}to{-webkit-transform:perspective(400px) rotateX(90deg);transform:perspective(400px) rotateX(90deg);opacity:0}}@keyframes flipOutX{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotateX(-20deg);transform:perspective(400px) rotateX(-20deg);opacity:1}to{-webkit-transform:perspective(400px) rotateX(90deg);transform:perspective(400px) rotateX(90deg);opacity:0}}.flipOutX{-webkit-animation-name:flipOutX;animation-name:flipOutX;-webkit-backface-visibility:visible!important;backface-visibility:visible!important}@-webkit-keyframes flipOutY{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotateY(-15deg);transform:perspective(400px) rotateY(-15deg);opacity:1}to{-webkit-transform:perspective(400px) rotateY(90deg);transform:perspective(400px) rotateY(90deg);opacity:0}}@keyframes flipOutY{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotateY(-15deg);transform:perspective(400px) rotateY(-15deg);opacity:1}to{-webkit-transform:perspective(400px) rotateY(90deg);transform:perspective(400px) rotateY(90deg);opacity:0}}.flipOutY{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipOutY;animation-name:flipOutY}@-webkit-keyframes lightSpeedIn{0%{-webkit-transform:translate3d(100%,0,0) skewX(-30deg);transform:translate3d(100%,0,0) skewX(-30deg);opacity:0}60%{-webkit-transform:skewX(20deg);transform:skewX(20deg)}60%,80%{opacity:1}80%{-webkit-transform:skewX(-5deg);transform:skewX(-5deg)}to{-webkit-transform:none;transform:none;opacity:1}}@keyframes lightSpeedIn{0%{-webkit-transform:translate3d(100%,0,0) skewX(-30deg);transform:translate3d(100%,0,0) skewX(-30deg);opacity:0}60%{-webkit-transform:skewX(20deg);transform:skewX(20deg)}60%,80%{opacity:1}80%{-webkit-transform:skewX(-5deg);transform:skewX(-5deg)}to{-webkit-transform:none;transform:none;opacity:1}}.lightSpeedIn{-webkit-animation-name:lightSpeedIn;animation-name:lightSpeedIn;-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}@-webkit-keyframes lightSpeedOut{0%{opacity:1}to{-webkit-transform:translate3d(100%,0,0) skewX(30deg);transform:translate3d(100%,0,0) skewX(30deg);opacity:0}}@keyframes lightSpeedOut{0%{opacity:1}to{-webkit-transform:translate3d(100%,0,0) skewX(30deg);transform:translate3d(100%,0,0) skewX(30deg);opacity:0}}.lightSpeedOut{-webkit-animation-name:lightSpeedOut;animation-name:lightSpeedOut;-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}@-webkit-keyframes rotateIn{0%{transform-origin:center;-webkit-transform:rotate(-200deg);transform:rotate(-200deg);opacity:0}0%,to{-webkit-transform-origin:center}to{transform-origin:center;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateIn{0%{transform-origin:center;-webkit-transform:rotate(-200deg);transform:rotate(-200deg);opacity:0}0%,to{-webkit-transform-origin:center}to{transform-origin:center;-webkit-transform:none;transform:none;opacity:1}}.rotateIn{-webkit-animation-name:rotateIn;animation-name:rotateIn}@-webkit-keyframes rotateInDownLeft{0%{transform-origin:left bottom;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInDownLeft{0%{transform-origin:left bottom;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInDownLeft{-webkit-animation-name:rotateInDownLeft;animation-name:rotateInDownLeft}@-webkit-keyframes rotateInDownRight{0%{transform-origin:right bottom;-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInDownRight{0%{transform-origin:right bottom;-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInDownRight{-webkit-animation-name:rotateInDownRight;animation-name:rotateInDownRight}@-webkit-keyframes rotateInUpLeft{0%{transform-origin:left bottom;-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInUpLeft{0%{transform-origin:left bottom;-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInUpLeft{-webkit-animation-name:rotateInUpLeft;animation-name:rotateInUpLeft}@-webkit-keyframes rotateInUpRight{0%{transform-origin:right bottom;-webkit-transform:rotate(-90deg);transform:rotate(-90deg);opacity:0}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInUpRight{0%{transform-origin:right bottom;-webkit-transform:rotate(-90deg);transform:rotate(-90deg);opacity:0}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInUpRight{-webkit-animation-name:rotateInUpRight;animation-name:rotateInUpRight}@-webkit-keyframes rotateOut{0%{transform-origin:center;opacity:1}0%,to{-webkit-transform-origin:center}to{transform-origin:center;-webkit-transform:rotate(200deg);transform:rotate(200deg);opacity:0}}@keyframes rotateOut{0%{transform-origin:center;opacity:1}0%,to{-webkit-transform-origin:center}to{transform-origin:center;-webkit-transform:rotate(200deg);transform:rotate(200deg);opacity:0}}.rotateOut{-webkit-animation-name:rotateOut;animation-name:rotateOut}@-webkit-keyframes rotateOutDownLeft{0%{transform-origin:left bottom;opacity:1}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}}@keyframes rotateOutDownLeft{0%{transform-origin:left bottom;opacity:1}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}}.rotateOutDownLeft{-webkit-animation-name:rotateOutDownLeft;animation-name:rotateOutDownLeft}@-webkit-keyframes rotateOutDownRight{0%{transform-origin:right bottom;opacity:1}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}}@keyframes rotateOutDownRight{0%{transform-origin:right bottom;opacity:1}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}}.rotateOutDownRight{-webkit-animation-name:rotateOutDownRight;animation-name:rotateOutDownRight}@-webkit-keyframes rotateOutUpLeft{0%{transform-origin:left bottom;opacity:1}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}}@keyframes rotateOutUpLeft{0%{transform-origin:left bottom;opacity:1}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}}.rotateOutUpLeft{-webkit-animation-name:rotateOutUpLeft;animation-name:rotateOutUpLeft}@-webkit-keyframes rotateOutUpRight{0%{transform-origin:right bottom;opacity:1}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:rotate(90deg);transform:rotate(90deg);opacity:0}}@keyframes rotateOutUpRight{0%{transform-origin:right bottom;opacity:1}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:rotate(90deg);transform:rotate(90deg);opacity:0}}.rotateOutUpRight{-webkit-animation-name:rotateOutUpRight;animation-name:rotateOutUpRight}@-webkit-keyframes hinge{0%{transform-origin:top left}0%,20%,60%{-webkit-transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}20%,60%{-webkit-transform:rotate(80deg);transform:rotate(80deg);transform-origin:top left}40%,80%{-webkit-transform:rotate(60deg);transform:rotate(60deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;opacity:1}to{-webkit-transform:translate3d(0,700px,0);transform:translate3d(0,700px,0);opacity:0}}@keyframes hinge{0%{transform-origin:top left}0%,20%,60%{-webkit-transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}20%,60%{-webkit-transform:rotate(80deg);transform:rotate(80deg);transform-origin:top left}40%,80%{-webkit-transform:rotate(60deg);transform:rotate(60deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;opacity:1}to{-webkit-transform:translate3d(0,700px,0);transform:translate3d(0,700px,0);opacity:0}}.hinge{-webkit-animation-name:hinge;animation-name:hinge}@-webkit-keyframes rollIn{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0) rotate(-120deg);transform:translate3d(-100%,0,0) rotate(-120deg)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes rollIn{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0) rotate(-120deg);transform:translate3d(-100%,0,0) rotate(-120deg)}to{opacity:1;-webkit-transform:none;transform:none}}.rollIn{-webkit-animation-name:rollIn;animation-name:rollIn}@-webkit-keyframes rollOut{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(100%,0,0) rotate(120deg);transform:translate3d(100%,0,0) rotate(120deg)}}@keyframes rollOut{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(100%,0,0) rotate(120deg);transform:translate3d(100%,0,0) rotate(120deg)}}.rollOut{-webkit-animation-name:rollOut;animation-name:rollOut}@-webkit-keyframes zoomIn{0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%{opacity:1}}@keyframes zoomIn{0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%{opacity:1}}.zoomIn{-webkit-animation-name:zoomIn;animation-name:zoomIn}@-webkit-keyframes zoomInDown{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInDown{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInDown{-webkit-animation-name:zoomInDown;animation-name:zoomInDown}@-webkit-keyframes zoomInLeft{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(10px,0,0);transform:scale3d(.475,.475,.475) translate3d(10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInLeft{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(10px,0,0);transform:scale3d(.475,.475,.475) translate3d(10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInLeft{-webkit-animation-name:zoomInLeft;animation-name:zoomInLeft}@-webkit-keyframes zoomInRight{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInRight{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInRight{-webkit-animation-name:zoomInRight;animation-name:zoomInRight}@-webkit-keyframes zoomInUp{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInUp{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInUp{-webkit-animation-name:zoomInUp;animation-name:zoomInUp}@-webkit-keyframes zoomOut{0%{opacity:1}50%{-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%,to{opacity:0}}@keyframes zoomOut{0%{opacity:1}50%{-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%,to{opacity:0}}.zoomOut{-webkit-animation-name:zoomOut;animation-name:zoomOut}@-webkit-keyframes zoomOutDown{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomOutDown{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomOutDown{-webkit-animation-name:zoomOutDown;animation-name:zoomOutDown}@-webkit-keyframes zoomOutLeft{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(42px,0,0);transform:scale3d(.475,.475,.475) translate3d(42px,0,0)}to{opacity:0;-webkit-transform:scale(.1) translate3d(-2000px,0,0);transform:scale(.1) translate3d(-2000px,0,0);-webkit-transform-origin:left center;transform-origin:left center}}@keyframes zoomOutLeft{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(42px,0,0);transform:scale3d(.475,.475,.475) translate3d(42px,0,0)}to{opacity:0;-webkit-transform:scale(.1) translate3d(-2000px,0,0);transform:scale(.1) translate3d(-2000px,0,0);-webkit-transform-origin:left center;transform-origin:left center}}.zoomOutLeft{-webkit-animation-name:zoomOutLeft;animation-name:zoomOutLeft}@-webkit-keyframes zoomOutRight{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-42px,0,0);transform:scale3d(.475,.475,.475) translate3d(-42px,0,0)}to{opacity:0;-webkit-transform:scale(.1) translate3d(2000px,0,0);transform:scale(.1) translate3d(2000px,0,0);-webkit-transform-origin:right center;transform-origin:right center}}@keyframes zoomOutRight{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-42px,0,0);transform:scale3d(.475,.475,.475) translate3d(-42px,0,0)}to{opacity:0;-webkit-transform:scale(.1) translate3d(2000px,0,0);transform:scale(.1) translate3d(2000px,0,0);-webkit-transform-origin:right center;transform-origin:right center}}.zoomOutRight{-webkit-animation-name:zoomOutRight;animation-name:zoomOutRight}@-webkit-keyframes zoomOutUp{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomOutUp{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomOutUp{-webkit-animation-name:zoomOutUp;animation-name:zoomOutUp}@-webkit-keyframes slideInDown{0%{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes slideInDown{0%{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.slideInDown{-webkit-animation-name:slideInDown;animation-name:slideInDown}@-webkit-keyframes slideInLeft{0%{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes slideInLeft{0%{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.slideInLeft{-webkit-animation-name:slideInLeft;animation-name:slideInLeft}@-webkit-keyframes slideInRight{0%{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes slideInRight{0%{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.slideInRight{-webkit-animation-name:slideInRight;animation-name:slideInRight}@-webkit-keyframes slideInUp{0%{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes slideInUp{0%{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.slideInUp{-webkit-animation-name:slideInUp;animation-name:slideInUp}@-webkit-keyframes slideOutDown{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}@keyframes slideOutDown{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}.slideOutDown{-webkit-animation-name:slideOutDown;animation-name:slideOutDown}@-webkit-keyframes slideOutLeft{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}@keyframes slideOutLeft{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.slideOutLeft{-webkit-animation-name:slideOutLeft;animation-name:slideOutLeft}@-webkit-keyframes slideOutRight{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}@keyframes slideOutRight{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.slideOutRight{-webkit-animation-name:slideOutRight;animation-name:slideOutRight}@-webkit-keyframes slideOutUp{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}@keyframes slideOutUp{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}.slideOutUp{-webkit-animation-name:slideOutUp;animation-name:slideOutUp} \ No newline at end of file diff --git a/frontend/vue-ts/public/favicon.ico b/frontend/vue-ts/public/favicon.ico new file mode 100644 index 000000000..320593399 Binary files /dev/null and b/frontend/vue-ts/public/favicon.ico differ diff --git a/frontend/vue-ts/public/iconfont.css b/frontend/vue-ts/public/iconfont.css new file mode 100644 index 000000000..6ce17fa07 --- /dev/null +++ b/frontend/vue-ts/public/iconfont.css @@ -0,0 +1,18 @@ +@font-face { + font-family: "iconfont"; /* project id 1098500 */ + src: url("//at.alicdn.com/t/font_1098500_3d6un9zwltz.eot"); + src: url("//at.alicdn.com/t/font_1098500_3d6un9zwltz.eot?#iefix") + format("embedded-opentype"), + url("//at.alicdn.com/t/font_1098500_3d6un9zwltz.woff2") format("woff2"), + url("//at.alicdn.com/t/font_1098500_3d6un9zwltz.woff") format("woff"), + url("//at.alicdn.com/t/font_1098500_3d6un9zwltz.ttf") format("truetype"), + url("//at.alicdn.com/t/font_1098500_3d6un9zwltz.svg#iconfont") format("svg"); +} + +.iconfont { + font-family: "iconfont" !important; + font-size: 16px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/frontend/vue-ts/src/App.vue b/frontend/vue-ts/src/App.vue new file mode 100644 index 000000000..98240aef8 --- /dev/null +++ b/frontend/vue-ts/src/App.vue @@ -0,0 +1,3 @@ + diff --git a/frontend/vue-ts/src/api/user.ts b/frontend/vue-ts/src/api/user.ts new file mode 100644 index 000000000..9e77ac5ac --- /dev/null +++ b/frontend/vue-ts/src/api/user.ts @@ -0,0 +1,16 @@ +import { http } from "../utils/http" + +// 获取验证码 +export const getVerify = (): any => { + return http.request("get", "/captcha") +} + +// 登录 +export const getLogin = (data: object): any => { + return http.request("post", "/login", data) +} + +// 注册 +export const getRegist = (data: object): any => { + return http.request("post", "/register", data) +} \ No newline at end of file diff --git a/frontend/vue-ts/src/assets/401.gif b/frontend/vue-ts/src/assets/401.gif new file mode 100644 index 000000000..cd6e0d943 Binary files /dev/null and b/frontend/vue-ts/src/assets/401.gif differ diff --git a/frontend/vue-ts/src/assets/404.png b/frontend/vue-ts/src/assets/404.png new file mode 100644 index 000000000..3d8e2305c Binary files /dev/null and b/frontend/vue-ts/src/assets/404.png differ diff --git a/frontend/vue-ts/src/assets/404_cloud.png b/frontend/vue-ts/src/assets/404_cloud.png new file mode 100644 index 000000000..c6281d090 Binary files /dev/null and b/frontend/vue-ts/src/assets/404_cloud.png differ diff --git a/frontend/vue-ts/src/assets/bg.png b/frontend/vue-ts/src/assets/bg.png new file mode 100644 index 000000000..c5a8e0dcc Binary files /dev/null and b/frontend/vue-ts/src/assets/bg.png differ diff --git a/frontend/vue-ts/src/assets/ch.png b/frontend/vue-ts/src/assets/ch.png new file mode 100644 index 000000000..94e9cbe9f Binary files /dev/null and b/frontend/vue-ts/src/assets/ch.png differ diff --git a/frontend/vue-ts/src/assets/en.png b/frontend/vue-ts/src/assets/en.png new file mode 100644 index 000000000..27c83aa6f Binary files /dev/null and b/frontend/vue-ts/src/assets/en.png differ diff --git a/frontend/vue-ts/src/assets/iconfont/iconfont.css b/frontend/vue-ts/src/assets/iconfont/iconfont.css new file mode 100644 index 000000000..b894a860e --- /dev/null +++ b/frontend/vue-ts/src/assets/iconfont/iconfont.css @@ -0,0 +1,25 @@ +@font-face {font-family: "iconfont"; + src: url('iconfont.eot?t=1607695324289'); /* IE9 */ + src: url('iconfont.eot?t=1607695324289#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAOYAAsAAAAACDQAAANLAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCCfgqEFIMzATYCJAMMCwgABCAFhG0HRhsBB8gekiQBgDxM4A0kAIgioN8v3Ud3F2KVqgCpNrIc0GFVJBVVWVtFrBIhOx5JmMaWNar/v/v99nGtOz+KOqLjkL7t7ovvDWum0bJoImRoGiKExrYjC6g2lM6fV4PQ9vCs/c/l9Fp+RWXzA+Uyx9aoF2A0gQIaa2iUaIEk6CkMr13sMM8T0GwbFdns/NQS6pLRaQHhwtl8BnVldHIDMWgoaxVrs3BV0YiX4wdcCb4fftkeGkQloXMXToUp8n2d+DqZLlXbDngI/nSXQUHCFCQT1iptC1qj2JRWzVqszRC0rWGBr5NVxdcJj7fZPzyCSKihha1gDNJ4RXxH5tL4iIu49k3U0IwNvGUIvZ6i9FKZzM04f1vGCnHQizTFjAGXOnGWLmi8LgG9xC1WmK8lB4pOtBX0Kg4xYfE2ry5ey8Q6JbR6iyf7Mjpdw0qVKO8Uzh3pmbbum7XpTGXrUPUu9Y7qR9nckW8NQE7IjYWNjrm3/r2srSk+619wmEI3RohhGW4tZLwr/U/zycbfUpLCGCbLAW6wwYFl9c4IGxVz7/1lNW2pbcz0E4xYib5sbUw75r4GyvsNvC+bMxvPTkWYPDcepPTFWegO8LOcLO8GFpzGjRcnxHJeHkVhSpcJ8bkDkc+BJ8vxGUGffT10F1p7Vsv7gfWxseePRJdRGkL1OL1IM1D1JEWKPb/zN6bCpwOHB3f+brRk8Pn/w63AWz3Ouhs0btge+Hn8jjVZF1J9yirP4ZnJZFH76+GAIzpVqKvb33BFX+dCgoa+BKK6QUgahjCZMAVFi2l/TcPRCmk2KYrNLXpwrUJuwoQDAkGnV4jaPYak0w8mE36h6PcPNZ0hQbO10LNni5FwtnlmHTICKM5u4WKuXmO2UfSExQuQX6tkeFoYUAlwqRjEeo0un4xCDfgUC6T1vEEIhhmvV3GEXAaVSh03eL0EOaEpCNFwaLWs6kWaXL2KeszgQIYAKCxrC1aUU1fDvMZCT+HzC0DemooM3lBVYyUAJyn2julp6DpgorJap6pbGSxZl2cgCIydxHB1VVgEFlCxYnVYo3pUCcgRNAoDIg0OWqYe6yrTLK+ovt8uaEZ/l0IMKWQdJy8WhZqtVSpSjgPUemItQgA=') format('woff2'), + url('iconfont.woff?t=1607695324289') format('woff'), + url('iconfont.ttf?t=1607695324289') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */ + url('iconfont.svg?t=1607695324289#iconfont') format('svg'); /* iOS 4.1- */ +} + +.iconfont { + font-family: "iconfont" !important; + font-size: 16px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.team-iconexit-fullscreen:before { + content: "\e62a"; +} + +.team-iconfullscreen:before { + content: "\e62b"; +} + diff --git a/frontend/vue-ts/src/assets/iconfont/iconfont.eot b/frontend/vue-ts/src/assets/iconfont/iconfont.eot new file mode 100644 index 000000000..f966cbb36 Binary files /dev/null and b/frontend/vue-ts/src/assets/iconfont/iconfont.eot differ diff --git a/frontend/vue-ts/src/assets/iconfont/iconfont.js b/frontend/vue-ts/src/assets/iconfont/iconfont.js new file mode 100644 index 000000000..dc74ca8fc --- /dev/null +++ b/frontend/vue-ts/src/assets/iconfont/iconfont.js @@ -0,0 +1 @@ +!function(e){var t,c,l,n,o,i,d='',s=(s=document.getElementsByTagName("script"))[s.length-1].getAttribute("data-injectcss");if(s&&!e.__iconfont__svg__cssinject__){e.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(e){console&&console.log(e)}}function a(){o||(o=!0,l())}t=function(){var e,t,c,l;(l=document.createElement("div")).innerHTML=d,d=null,(c=l.getElementsByTagName("svg")[0])&&(c.setAttribute("aria-hidden","true"),c.style.position="absolute",c.style.width=0,c.style.height=0,c.style.overflow="hidden",e=c,(t=document.body).firstChild?(l=e,(c=t.firstChild).parentNode.insertBefore(l,c)):t.appendChild(e))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(t,0):(c=function(){document.removeEventListener("DOMContentLoaded",c,!1),t()},document.addEventListener("DOMContentLoaded",c,!1)):document.attachEvent&&(l=t,n=e.document,o=!1,(i=function(){try{n.documentElement.doScroll("left")}catch(e){return void setTimeout(i,50)}a()})(),n.onreadystatechange=function(){"complete"==n.readyState&&(n.onreadystatechange=null,a())})}(window); \ No newline at end of file diff --git a/frontend/vue-ts/src/assets/iconfont/iconfont.json b/frontend/vue-ts/src/assets/iconfont/iconfont.json new file mode 100644 index 000000000..f7bf00e9d --- /dev/null +++ b/frontend/vue-ts/src/assets/iconfont/iconfont.json @@ -0,0 +1,23 @@ +{ + "id": "2208059", + "name": "CURD-TS", + "font_family": "iconfont", + "css_prefix_text": "team-icon", + "description": "增删查改xi't", + "glyphs": [ + { + "icon_id": "5698509", + "name": "全屏缩小", + "font_class": "exit-fullscreen", + "unicode": "e62a", + "unicode_decimal": 58922 + }, + { + "icon_id": "5698510", + "name": "全屏显示", + "font_class": "fullscreen", + "unicode": "e62b", + "unicode_decimal": 58923 + } + ] +} diff --git a/frontend/vue-ts/src/assets/iconfont/iconfont.svg b/frontend/vue-ts/src/assets/iconfont/iconfont.svg new file mode 100644 index 000000000..5aaa95d17 --- /dev/null +++ b/frontend/vue-ts/src/assets/iconfont/iconfont.svg @@ -0,0 +1,32 @@ + + + + + +Created by iconfont + + + + + + + + + + + + + + + + + diff --git a/frontend/vue-ts/src/assets/iconfont/iconfont.ttf b/frontend/vue-ts/src/assets/iconfont/iconfont.ttf new file mode 100644 index 000000000..dadb82946 Binary files /dev/null and b/frontend/vue-ts/src/assets/iconfont/iconfont.ttf differ diff --git a/frontend/vue-ts/src/assets/iconfont/iconfont.woff b/frontend/vue-ts/src/assets/iconfont/iconfont.woff new file mode 100644 index 000000000..c0899f6f3 Binary files /dev/null and b/frontend/vue-ts/src/assets/iconfont/iconfont.woff differ diff --git a/frontend/vue-ts/src/assets/iconfont/iconfont.woff2 b/frontend/vue-ts/src/assets/iconfont/iconfont.woff2 new file mode 100644 index 000000000..0e23e45bd Binary files /dev/null and b/frontend/vue-ts/src/assets/iconfont/iconfont.woff2 differ diff --git a/frontend/vue-ts/src/assets/login.png b/frontend/vue-ts/src/assets/login.png new file mode 100644 index 000000000..faa05692f Binary files /dev/null and b/frontend/vue-ts/src/assets/login.png differ diff --git a/frontend/vue-ts/src/assets/welcome - 副本.png b/frontend/vue-ts/src/assets/welcome - 副本.png new file mode 100644 index 000000000..f5e64c8b5 Binary files /dev/null and b/frontend/vue-ts/src/assets/welcome - 副本.png differ diff --git a/frontend/vue-ts/src/assets/welcome.png b/frontend/vue-ts/src/assets/welcome.png new file mode 100644 index 000000000..b23e923d2 Binary files /dev/null and b/frontend/vue-ts/src/assets/welcome.png differ diff --git a/frontend/vue-ts/src/components/breadCrumb/index.vue b/frontend/vue-ts/src/components/breadCrumb/index.vue new file mode 100644 index 000000000..a6be01666 --- /dev/null +++ b/frontend/vue-ts/src/components/breadCrumb/index.vue @@ -0,0 +1,95 @@ + + + + + diff --git a/frontend/vue-ts/src/components/hamBurger/index.vue b/frontend/vue-ts/src/components/hamBurger/index.vue new file mode 100644 index 000000000..956b0ca7c --- /dev/null +++ b/frontend/vue-ts/src/components/hamBurger/index.vue @@ -0,0 +1,50 @@ + + + + + diff --git a/frontend/vue-ts/src/components/info/index.vue b/frontend/vue-ts/src/components/info/index.vue new file mode 100644 index 000000000..c3e12f5d6 --- /dev/null +++ b/frontend/vue-ts/src/components/info/index.vue @@ -0,0 +1,207 @@ + + + + + diff --git a/frontend/vue-ts/src/components/splitPane/index.vue b/frontend/vue-ts/src/components/splitPane/index.vue new file mode 100644 index 000000000..82cb45795 --- /dev/null +++ b/frontend/vue-ts/src/components/splitPane/index.vue @@ -0,0 +1,216 @@ + + + + + diff --git a/frontend/vue-ts/src/components/splitPane/resizer.vue b/frontend/vue-ts/src/components/splitPane/resizer.vue new file mode 100644 index 000000000..83c99f36e --- /dev/null +++ b/frontend/vue-ts/src/components/splitPane/resizer.vue @@ -0,0 +1,59 @@ + + + + + diff --git a/frontend/vue-ts/src/layout/components/AppMain.vue b/frontend/vue-ts/src/layout/components/AppMain.vue new file mode 100644 index 000000000..cf93388d5 --- /dev/null +++ b/frontend/vue-ts/src/layout/components/AppMain.vue @@ -0,0 +1,46 @@ + + + + + + + diff --git a/frontend/vue-ts/src/layout/components/Navbar.vue b/frontend/vue-ts/src/layout/components/Navbar.vue new file mode 100644 index 000000000..f200ad59c --- /dev/null +++ b/frontend/vue-ts/src/layout/components/Navbar.vue @@ -0,0 +1,178 @@ + + + + + diff --git a/frontend/vue-ts/src/layout/components/index.ts b/frontend/vue-ts/src/layout/components/index.ts new file mode 100644 index 000000000..cd1b0b966 --- /dev/null +++ b/frontend/vue-ts/src/layout/components/index.ts @@ -0,0 +1,4 @@ +export { default as Navbar } from './Navbar.vue' +export { default as Sidebar } from './sidebar/index.vue' +export { default as AppMain } from './AppMain.vue' +export { default as setting } from './setting/index.vue' diff --git a/frontend/vue-ts/src/layout/components/panel/index.vue b/frontend/vue-ts/src/layout/components/panel/index.vue new file mode 100644 index 000000000..55c512813 --- /dev/null +++ b/frontend/vue-ts/src/layout/components/panel/index.vue @@ -0,0 +1,133 @@ + + + + + + + diff --git a/frontend/vue-ts/src/layout/components/screenfull/index.vue b/frontend/vue-ts/src/layout/components/screenfull/index.vue new file mode 100644 index 000000000..14c174bcd --- /dev/null +++ b/frontend/vue-ts/src/layout/components/screenfull/index.vue @@ -0,0 +1,77 @@ + + + + + \ No newline at end of file diff --git a/frontend/vue-ts/src/layout/components/setting/index.vue b/frontend/vue-ts/src/layout/components/setting/index.vue new file mode 100644 index 000000000..d3b859fb8 --- /dev/null +++ b/frontend/vue-ts/src/layout/components/setting/index.vue @@ -0,0 +1,74 @@ + + + + + diff --git a/frontend/vue-ts/src/layout/components/sidebar/Link.vue b/frontend/vue-ts/src/layout/components/sidebar/Link.vue new file mode 100644 index 000000000..8f51cac7e --- /dev/null +++ b/frontend/vue-ts/src/layout/components/sidebar/Link.vue @@ -0,0 +1,30 @@ + + + diff --git a/frontend/vue-ts/src/layout/components/sidebar/SidebarItem.vue b/frontend/vue-ts/src/layout/components/sidebar/SidebarItem.vue new file mode 100644 index 000000000..42224dd1f --- /dev/null +++ b/frontend/vue-ts/src/layout/components/sidebar/SidebarItem.vue @@ -0,0 +1,101 @@ + + + diff --git a/frontend/vue-ts/src/layout/components/sidebar/index.vue b/frontend/vue-ts/src/layout/components/sidebar/index.vue new file mode 100644 index 000000000..ddd74c261 --- /dev/null +++ b/frontend/vue-ts/src/layout/components/sidebar/index.vue @@ -0,0 +1,55 @@ + + + diff --git a/frontend/vue-ts/src/layout/components/tag/index.vue b/frontend/vue-ts/src/layout/components/tag/index.vue new file mode 100644 index 000000000..1e67e8da0 --- /dev/null +++ b/frontend/vue-ts/src/layout/components/tag/index.vue @@ -0,0 +1,51 @@ + + + + + diff --git a/frontend/vue-ts/src/layout/index.vue b/frontend/vue-ts/src/layout/index.vue new file mode 100644 index 000000000..428410232 --- /dev/null +++ b/frontend/vue-ts/src/layout/index.vue @@ -0,0 +1,176 @@ + + + + + diff --git a/frontend/vue-ts/src/layout/store.ts b/frontend/vue-ts/src/layout/store.ts new file mode 100644 index 000000000..bc92ac9a5 --- /dev/null +++ b/frontend/vue-ts/src/layout/store.ts @@ -0,0 +1,14 @@ +import { computed, ComputedRef } from "vue"; +import { useStore } from "vuex"; + +export function useMapGetters(keys: T[]) { + const res: Record = {} + // @ts-ignore + const { getters } = useStore() + keys.map(key => { + if (Reflect.has(getters, key)) { + res[key] = computed(() => getters[key]) + } + }) + return res as any as Record +} \ No newline at end of file diff --git a/frontend/vue-ts/src/locales/ch.json b/frontend/vue-ts/src/locales/ch.json new file mode 100644 index 000000000..92b7d4da5 --- /dev/null +++ b/frontend/vue-ts/src/locales/ch.json @@ -0,0 +1,11 @@ +{ + "home": "首页", + "LoginOut": "退出系统", + "usermanagement": "用户管理", + "baseinfo": "基础信息", + "error": "错误页面", + "404": "404", + "401": "401", + "components": "组件", + "split-pane": "切割面板" +} \ No newline at end of file diff --git a/frontend/vue-ts/src/locales/en.json b/frontend/vue-ts/src/locales/en.json new file mode 100644 index 000000000..10cdcbf7e --- /dev/null +++ b/frontend/vue-ts/src/locales/en.json @@ -0,0 +1,11 @@ +{ + "home": "Home", + "LoginOut": "Login Out", + "usermanagement": "User Manage", + "baseinfo": "Base Info", + "error": "Error Page", + "404": "404", + "401": "401", + "components": "Components", + "split-pane": "Split Pane" +} \ No newline at end of file diff --git a/frontend/vue-ts/src/main.ts b/frontend/vue-ts/src/main.ts new file mode 100644 index 000000000..0b7149c40 --- /dev/null +++ b/frontend/vue-ts/src/main.ts @@ -0,0 +1,35 @@ +import { createApp } from 'vue' +import App from './App.vue' +import router from './router' +import store from './store' + +// 内置ElementPlus +import ElementPlus from 'element-plus' +import 'element-plus/lib/theme-chalk/index.css' + +// 内置vxe-table +import 'xe-utils' +import VXETable from 'vxe-table' +import 'vxe-table/lib/style.css' + +// 内置国际化语言包 +import { createI18n } from 'vue-i18n' +import ch from "./locales/ch.json" +import en from "./locales/en.json" +const i18n = createI18n({ + locale: 'ch', //默认使用中文 + messages: { + ch, + en + } +}) + +// 导入公共样式 +import './style/index.scss' +// 导入字体图标 +import "./assets/iconfont/iconfont.js" +import "./assets/iconfont/iconfont.css" + +const app = createApp(App) + +app.use(store).use(router).use(i18n).use(ElementPlus).use(VXETable).mount('#app') diff --git a/frontend/vue-ts/src/router/index.ts b/frontend/vue-ts/src/router/index.ts new file mode 100644 index 000000000..afd1fa146 --- /dev/null +++ b/frontend/vue-ts/src/router/index.ts @@ -0,0 +1,171 @@ +import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router" + +import Layout from '../layout/index.vue' + +import { storageSession } from "../utils/storage" + +const routes: Array = [ + { + path: '/', + name: 'home', + component: Layout, + redirect: "/welcome", + children: [{ + path: '/welcome', + name: 'welcome', + component: () => import(/* webpackChunkName: "home" */ '../views/welcome.vue'), + meta: { + title: 'home', + showLink: true, + savedPosition: false + } + }], + meta: { + icon: 'el-icon-s-home', + showLink: true, + savedPosition: false, + } + }, + { + path: '/components', + name: 'components', + component: Layout, + redirect: '/components/split-pane', + children: [ + { + path: '/components/split-pane', + component: () => import(/* webpackChunkName: "components" */ '../views/components/split-pane/index.vue'), + meta: { + title: 'split-pane', + showLink: false, + savedPosition: true + } + }, + ], + meta: { + icon: 'el-icon-menu', + title: 'components', + showLink: true, + savedPosition: true + } + }, + { + path: '/user', + name: 'user', + component: Layout, + redirect: '/user/base', + children: [ + { + path: '/user/base', + component: () => import(/* webpackChunkName: "user" */ '../views/user.vue'), + meta: { + // icon: 'el-icon-user', + title: 'baseinfo', + showLink: false, + savedPosition: true + } + }, + ], + meta: { + icon: 'el-icon-user', + title: 'usermanagement', + showLink: true, + savedPosition: true + } + }, + { + path: '/error', + name: 'error', + component: Layout, + redirect: '/error/401', + children: [ + { + path: '/error/401', + component: () => import(/* webpackChunkName: "error" */ '../views/error/401.vue'), + meta: { + title: '401', + showLink: false, + savedPosition: true + } + }, + { + path: '/error/404', + component: () => import(/* webpackChunkName: "error" */ '../views/error/404.vue'), + meta: { + title: '404', + showLink: false, + savedPosition: true + } + }, + ], + meta: { + icon: 'el-icon-position', + title: 'error', + showLink: true, + savedPosition: true + } + }, + { + path: '/login', + name: 'login', + component: () => import(/* webpackChunkName: "login" */ '../views/login.vue'), + meta: { + title: '登陆', + showLink: false + } + }, + { + path: '/register', + name: 'register', + component: () => import(/* webpackChunkName: "register" */ '../views/register.vue'), + meta: { + title: '注册', + showLink: false + } + }, + { + // 找不到路由重定向到404页面 + path: '/:pathMatch(.*)', + component: Layout, + redirect: "/error/404", + meta: { + icon: 'el-icon-s-home', + title: '首页', + showLink: false, + savedPosition: false, + } + }, +] + +const router = createRouter({ + history: createWebHistory(process.env.BASE_URL), + routes, + scrollBehavior(to, from, savedPosition) { + return new Promise((resolve, reject) => { + if (savedPosition) { + return savedPosition + } else { + if (from.meta.saveSrollTop) { + const top: number = document.documentElement.scrollTop || document.body.scrollTop + resolve({ left: 0, top }) + } + } + }) + } +}) + +import NProgress from "../utils/progress" + +const whiteList = ["/login", "/register"] + +router.beforeEach((to, _from, next) => { + NProgress.start() + document.title = to.meta.title // 动态title + whiteList.indexOf(to.path) !== -1 || storageSession.getItem("info") ? next() : next("/login") // 全部重定向到登录页 +}) + +router.afterEach(() => { + NProgress.done() +}) + +export default router diff --git a/frontend/vue-ts/src/settings.ts b/frontend/vue-ts/src/settings.ts new file mode 100644 index 000000000..b93803ec5 --- /dev/null +++ b/frontend/vue-ts/src/settings.ts @@ -0,0 +1,9 @@ +export default { + + title: 'CURE Admin', + + fixedHeader: false, + + sidebarLogo: false + +} diff --git a/frontend/vue-ts/src/shims-vue.d.ts b/frontend/vue-ts/src/shims-vue.d.ts new file mode 100644 index 000000000..a89150491 --- /dev/null +++ b/frontend/vue-ts/src/shims-vue.d.ts @@ -0,0 +1,10 @@ +declare module '*.vue' { + import type { DefineComponent } from 'vue' + const component: DefineComponent<{}, {}, any> + export default component +} + +declare module '*.scss' { + const scss: Record + export default scss; +} \ No newline at end of file diff --git a/frontend/vue-ts/src/store/getters.ts b/frontend/vue-ts/src/store/getters.ts new file mode 100644 index 000000000..3824e2173 --- /dev/null +++ b/frontend/vue-ts/src/store/getters.ts @@ -0,0 +1,6 @@ +const getters = { + sidebar: (state: any) => state.app.sidebar, + device: (state: any) => state.app.device, +} + +export default getters diff --git a/frontend/vue-ts/src/store/index.ts b/frontend/vue-ts/src/store/index.ts new file mode 100644 index 000000000..d95d72fa5 --- /dev/null +++ b/frontend/vue-ts/src/store/index.ts @@ -0,0 +1,12 @@ +import { createStore } from 'vuex' +import getters from './getters' +import app from './modules/app' +import settings from './modules/settings' + +export default createStore({ + getters, + modules: { + app, + settings + } +}) diff --git a/frontend/vue-ts/src/store/modules/app.ts b/frontend/vue-ts/src/store/modules/app.ts new file mode 100644 index 000000000..8b20cfb41 --- /dev/null +++ b/frontend/vue-ts/src/store/modules/app.ts @@ -0,0 +1,58 @@ +import { storageLocal } from "../../utils/storage" +interface stateInter { + sidebar: { + opened: Boolean, + withoutAnimation: Boolean + }, + device: String +} + +const state = { + sidebar: { + opened: storageLocal.getItem('sidebarStatus') ? !!+storageLocal.getItem('sidebarStatus') : true, + withoutAnimation: false + }, + device: 'desktop' +} + +const mutations = { + TOGGLE_SIDEBAR: (state: stateInter): void => { + state.sidebar.opened = !state.sidebar.opened + state.sidebar.withoutAnimation = false + if (state.sidebar.opened) { + storageLocal.setItem('sidebarStatus', 1) + } else { + storageLocal.setItem('sidebarStatus', 0) + } + }, + CLOSE_SIDEBAR: (state: stateInter, withoutAnimation: Boolean) => { + storageLocal.setItem('sidebarStatus', 0) + state.sidebar.opened = false + state.sidebar.withoutAnimation = withoutAnimation + }, + TOGGLE_DEVICE: (state: stateInter, device: String) => { + state.device = device + } +} + +const actions = { + // @ts-ignore + toggleSideBar({ commit }) { + commit('TOGGLE_SIDEBAR') + }, + // @ts-ignore + closeSideBar({ commit }, { withoutAnimation }) { + commit('CLOSE_SIDEBAR', withoutAnimation) + }, + // @ts-ignore + toggleDevice({ commit }, device) { + commit('TOGGLE_DEVICE', device) + } +} + +export default { + namespaced: true, + state, + mutations, + actions +} diff --git a/frontend/vue-ts/src/store/modules/settings.ts b/frontend/vue-ts/src/store/modules/settings.ts new file mode 100644 index 000000000..ef4ff05ff --- /dev/null +++ b/frontend/vue-ts/src/store/modules/settings.ts @@ -0,0 +1,29 @@ +import defaultSettings from '../../settings' + +const state = { + title: defaultSettings.title, + fixedHeader: defaultSettings.fixedHeader, + sidebarLogo: defaultSettings.sidebarLogo +} + +const mutations = { + CHANGE_SETTING: (state: any, { key, value }) => { + if (state.hasOwnProperty(key)) { + state[key] = value + } + } +} + +const actions = { + changeSetting({ commit }, data) { + commit('CHANGE_SETTING', data) + } +} + +export default { + namespaced: true, + state, + mutations, + actions +} + diff --git a/frontend/vue-ts/src/style/element-ui.scss b/frontend/vue-ts/src/style/element-ui.scss new file mode 100644 index 000000000..cde8e4098 --- /dev/null +++ b/frontend/vue-ts/src/style/element-ui.scss @@ -0,0 +1,48 @@ +// cover some element-plus styles + +.el-breadcrumb__inner, +.el-breadcrumb__inner a { + font-weight: 400 !important; +} + +.el-upload { + input[type="file"] { + display: none !important; + } +} + +.el-upload__input { + display: none; +} + + +.el-dialog { + transform: none; + left: 0; + position: relative; + margin: 0 auto; +} + +// refine element ui upload +.upload-container { + .el-upload { + width: 100%; + + .el-upload-dragger { + width: 100%; + height: 200px; + } + } +} + +// dropdown +.el-dropdown-menu { + a { + display: block + } +} + +// to fix el-date-picker css style +.el-range-separator { + box-sizing: content-box; +} diff --git a/frontend/vue-ts/src/style/index.scss b/frontend/vue-ts/src/style/index.scss new file mode 100644 index 000000000..32cd332ae --- /dev/null +++ b/frontend/vue-ts/src/style/index.scss @@ -0,0 +1,102 @@ +@import './variables.scss'; +@import './mixin.scss'; +@import './transition.scss'; +@import './element-ui.scss'; +@import './sidebar.scss'; + +body { + height: 100%; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; + font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; +} + +label { + font-weight: 700; +} + +html { + overflow: hidden; + height: 100%; + box-sizing: border-box; +} + +#app { + height: 100%; + overflow: hidden; +} + +*, +*:before, +*:after { + box-sizing: inherit; +} + +a:focus, +a:active { + outline: none; +} + +a, +a:focus, +a:hover { + cursor: pointer; + color: inherit; + text-decoration: none; +} + +div:focus { + outline: none; +} + +ul { + margin: 0; + padding: 0; + list-style: none; +} + +.clearfix { + &:after { + visibility: hidden; + display: block; + font-size: 0; + content: " "; + clear: both; + height: 0; + } +} + +// main-container global css +.app-container { + padding: 20px; +} + +.login, +.register { + width: 100%; + height: 100%; + overflow-x: hidden; + background: url("../assets/bg.png") no-repeat center; + background-size: cover; +} + +/* 头部用户信息样式重置 */ +.hidden { + display: none !important; +} + +.resetTop { + top: 48px !important; +} + +.html-grey { + filter: grayscale(100%); + -webkit-filter: grayscale(100%); + -moz-filter: grayscale(100%); + -ms-filter: grayscale(100%); + -o-filter: grayscale(100%); + filter: url("data:image/svg+xml;utf8,#grayscale"); + filter: progid:DXImageTransform.Microsoft.BasicImage(grayscale=1); + -webkit-filter: grayscale(1); +} \ No newline at end of file diff --git a/frontend/vue-ts/src/style/mixin.scss b/frontend/vue-ts/src/style/mixin.scss new file mode 100644 index 000000000..36b74bbd9 --- /dev/null +++ b/frontend/vue-ts/src/style/mixin.scss @@ -0,0 +1,28 @@ +@mixin clearfix { + &:after { + content: ""; + display: table; + clear: both; + } +} + +@mixin scrollBar { + &::-webkit-scrollbar-track-piece { + background: #d3dce6; + } + + &::-webkit-scrollbar { + width: 6px; + } + + &::-webkit-scrollbar-thumb { + background: #99a9bf; + border-radius: 20px; + } +} + +@mixin relative { + position: relative; + width: 100%; + height: 100%; +} diff --git a/frontend/vue-ts/src/style/sidebar.scss b/frontend/vue-ts/src/style/sidebar.scss new file mode 100644 index 000000000..eeb23c50b --- /dev/null +++ b/frontend/vue-ts/src/style/sidebar.scss @@ -0,0 +1,201 @@ +#app { + + .main-container { + min-height: 100%; + transition: margin-left .28s; + margin-left: $sideBarWidth; + position: relative; + } + + .sidebar-container { + transition: width 0.28s; + width: $sideBarWidth !important; + background-color: $menuBg; + height: 100%; + position: fixed; + font-size: 0px; + top: 0; + bottom: 0; + left: 0; + z-index: 1001; + overflow: hidden; + + // reset element-plus css + .horizontal-collapse-transition { + transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out; + } + + .scrollbar-wrapper { + overflow-x: hidden !important; + } + + .el-scrollbar__bar.is-vertical { + right: 0px; + } + + .el-scrollbar { + height: 100%; + } + + &.has-logo { + .el-scrollbar { + height: calc(100% - 50px); + } + } + + .is-horizontal { + display: none; + } + + a { + display: inline-block; + width: 100%; + overflow: hidden; + } + + .el-menu { + border: none; + height: 100%; + // width: 100% !important; + } + + // menu hover + .submenu-title-noDropdown, + .el-submenu__title { + &:hover { + background-color: $menuHover !important; + } + } + + .is-active>.el-submenu__title { + color: $subMenuActiveText !important; + } + + & .nest-menu .el-submenu>.el-submenu__title, + & .el-submenu .el-menu-item { + min-width: $sideBarWidth !important; + background-color: $subMenuBg !important; + + &:hover { + background-color: $subMenuHover !important; + } + } + } + + .hideSidebar { + + .sidebar-container { + width: 54px !important; + } + + .main-container { + margin-left: 54px; + } + + .submenu-title-noDropdown { + padding: 0 !important; + position: relative; + + .el-tooltip { + padding: 0 !important; + + } + } + + .el-submenu { + overflow: hidden; + &>.el-submenu__title { + + .el-submenu__icon-arrow { + display: none; + } + } + } + + .el-menu--collapse { + margin-left: -5px; //需优化的地方 + .el-submenu { + &>.el-submenu__title { + &>span { + height: 0; + width: 0; + overflow: hidden; + visibility: hidden; + display: inline-block; + } + } + } + } + } + + .el-menu--collapse .el-menu .el-submenu { + min-width: $sideBarWidth !important; + } + + // mobile responsive + .mobile { + .main-container { + margin-left: 0px; + } + + .sidebar-container { + transition: transform .28s; + width: $sideBarWidth !important; + } + + &.hideSidebar { + .sidebar-container { + pointer-events: none; + transition-duration: 0.3s; + transform: translate3d(-$sideBarWidth, 0, 0); + } + } + } + + .withoutAnimation { + + .main-container, + .sidebar-container { + transition: none; + } + } +} + +// when menu collapsed +.el-menu--vertical { + &>.el-menu { + i { + margin-right: 16px; + } + } + + .nest-menu .el-submenu>.el-submenu__title, + .el-menu-item { + &:hover { + // you can use $subMenuHover + background-color: $menuHover !important; + } + } + + // the scroll bar appears when the subMenu is too long + >.el-menu--popup { + max-height: 100vh; + overflow-y: auto; + + &::-webkit-scrollbar-track-piece { + background: #d3dce6; + } + + &::-webkit-scrollbar { + width: 6px; + } + + &::-webkit-scrollbar-thumb { + background: #99a9bf; + border-radius: 20px; + } + } + +} + +.el-scrollbar__wrap { overflow: auto; height: 100%; } \ No newline at end of file diff --git a/frontend/vue-ts/src/style/transition.scss b/frontend/vue-ts/src/style/transition.scss new file mode 100644 index 000000000..fed41982d --- /dev/null +++ b/frontend/vue-ts/src/style/transition.scss @@ -0,0 +1,44 @@ +// global transition css + +/* fade */ +.fade-enter-active, +.fade-leave-active { + transition: opacity 0.28s; +} + +.fade-enter, +.fade-leave-active { + opacity: 0; +} + +/* fade-transform */ +.fade-transform-leave-active, +.fade-transform-enter-active { + transition: all .5s; +} + +.fade-transform-enter-from { + opacity: 0; + transform: translateX(-30px); +} + +.fade-transform-leave-to { + opacity: 0; + transform: translateX(30px); +} + +/* breadcrumb transition */ +.breadcrumb-enter-active, +.breadcrumb-leave-active { + transition: all .5s; +} + +.breadcrumb-enter-from, +.breadcrumb-leave-active { + opacity: 0; + transform: translateX(20px); +} + +.breadcrumb-leave-active { + position: absolute; +} \ No newline at end of file diff --git a/frontend/vue-ts/src/style/variables.scss b/frontend/vue-ts/src/style/variables.scss new file mode 100644 index 000000000..dfa2d0759 --- /dev/null +++ b/frontend/vue-ts/src/style/variables.scss @@ -0,0 +1,22 @@ +// sidebar +$menuText:#bfcbd9; +$menuActiveText:#409EFF; +$subMenuActiveText:#f4f4f5; +$menuBg:#304156; +$menuHover:#263445; + +$subMenuBg:#1f2d3d; +$subMenuHover:#001528; + +$sideBarWidth: 210px; + +:export { + menuText: $menuText; + menuActiveText: $menuActiveText; + subMenuActiveText: $subMenuActiveText; + menuBg: $menuBg; + menuHover: $menuHover; + subMenuBg: $subMenuBg; + subMenuHover: $subMenuHover; + sideBarWidth: $sideBarWidth; +} diff --git a/frontend/vue-ts/src/utils/algorithm/index.ts b/frontend/vue-ts/src/utils/algorithm/index.ts new file mode 100644 index 000000000..ed7266592 --- /dev/null +++ b/frontend/vue-ts/src/utils/algorithm/index.ts @@ -0,0 +1,24 @@ +interface ProxyAlgorithm { + increaseIndexes(val: Array): Array +} + +class algorithmProxy implements ProxyAlgorithm { + + constructor() { } + + // 数组每一项添加索引字段 + public increaseIndexes(val: Array): Array { + return Object.keys(val) + .map((v) => { + return { + // @ts-ignore + ...val[v], + key: v + } + }) + .filter(v => v.meta.showLink) + } + +} + +export const algorithm = new algorithmProxy() \ No newline at end of file diff --git a/frontend/vue-ts/src/utils/debounce/index.ts b/frontend/vue-ts/src/utils/debounce/index.ts new file mode 100644 index 000000000..e5e15aed5 --- /dev/null +++ b/frontend/vue-ts/src/utils/debounce/index.ts @@ -0,0 +1,11 @@ +// 延迟函数 +export const delay = (timeout: number) => new Promise(resolve => setTimeout(resolve, timeout)) + +// 防抖函数 +export const debounce = (fn: () => any, timeout: number) => { + let timmer: any + return () => { + timmer ? clearTimeout(timmer) : null + timmer = setTimeout(fn, timeout) + } +} \ No newline at end of file diff --git a/frontend/vue-ts/src/utils/http/config.ts b/frontend/vue-ts/src/utils/http/config.ts new file mode 100644 index 000000000..1bc2a7e0f --- /dev/null +++ b/frontend/vue-ts/src/utils/http/config.ts @@ -0,0 +1,31 @@ +import { AxiosRequestConfig } from "axios" +import { excludeProps } from "./utils" +/** + * 默认配置 + */ +export const defaultConfig: AxiosRequestConfig = { + baseURL: '/api', + timeout: 10000, //10秒超时 + headers: { + Accept: "application/json, text/plain, */*", + "Content-Type": "application/json", + "X-Requested-With": "XMLHttpRequest" + }, +} + +export function genConfig(config?: AxiosRequestConfig): AxiosRequestConfig { + if (!config) { + return defaultConfig + } + + const { headers } = config + if (headers && typeof headers === "object") { + defaultConfig.headers = { + ...defaultConfig.headers, + ...headers + } + } + return { ...excludeProps(config!, "headers"), ...defaultConfig } +} + +export const METHODS = ["post", "get", "put", "delete", "option", "patch"] diff --git a/frontend/vue-ts/src/utils/http/core.ts b/frontend/vue-ts/src/utils/http/core.ts new file mode 100644 index 000000000..b652ce4c5 --- /dev/null +++ b/frontend/vue-ts/src/utils/http/core.ts @@ -0,0 +1,244 @@ + +import Axios, { + AxiosRequestConfig, + CancelTokenStatic, + AxiosInstance, + Canceler +} from "axios" + +import NProgress from "../progress" + +import { genConfig } from "./config" + +import { transformConfigByMethod } from "./utils" + +import { + cancelTokenType, + RequestMethods, + EnclosureHttpRequestConfig, + EnclosureHttpResoponse, + EnclosureHttpError +} from "./types.d" + +class EnclosureHttp { + constructor() { + this.httpInterceptorsRequest() + this.httpInterceptorsResponse() + } + // 初始化配置对象 + private static initConfig: EnclosureHttpRequestConfig = {}; + + // 保存当前Axios实例对象 + private static axiosInstance: AxiosInstance = Axios.create(genConfig()); + + // 保存 EnclosureHttp实例 + private static EnclosureHttpInstance: EnclosureHttp + + // axios取消对象 + private CancelToken: CancelTokenStatic = Axios.CancelToken; + + // 取消的凭证数组 + private sourceTokenList: Array = []; + + // 记录当前这一次cancelToken的key + private currentCancelTokenKey = ""; + + private beforeRequestCallback: EnclosureHttpRequestConfig["beforeRequestCallback"] = undefined; + + private beforeResponseCallback: EnclosureHttpRequestConfig["beforeResponseCallback"] = undefined; + + public get cancelTokenList(): Array { + return this.sourceTokenList + } + + // eslint-disable-next-line class-methods-use-this + public set cancelTokenList(value) { + throw new Error("cancelTokenList不允许赋值") + } + + /** + * @description 私有构造不允许实例化 + * @returns void 0 + */ + // constructor() {} + + /** + * @description 生成唯一取消key + * @param config axios配置 + * @returns string + */ + // eslint-disable-next-line class-methods-use-this + private genUniqueKey(config: EnclosureHttpRequestConfig): string { + return `${config.url}--${JSON.stringify(config.data)}` + } + + /** + * @description 取消重复请求 + * @returns void 0 + */ + private cancelRepeatRequest(): void { + const temp: { [key: string]: boolean } = {} + + this.sourceTokenList = this.sourceTokenList.reduce>( + (res: Array, cancelToken: cancelTokenType) => { + const { cancelKey, cancelExecutor } = cancelToken + if (!temp[cancelKey]) { + temp[cancelKey] = true + res.push(cancelToken) + } else { + cancelExecutor() + } + return res + }, + [] + ) + } + + /** + * @description 删除指定的CancelToken + * @returns void 0 + */ + private deleteCancelTokenByCancelKey(cancelKey: string): void { + this.sourceTokenList = + this.sourceTokenList.length < 1 + ? this.sourceTokenList.filter( + cancelToken => cancelToken.cancelKey !== cancelKey + ) + : [] + } + + /** + * @description 拦截请求 + * @returns void 0 + */ + + private httpInterceptorsRequest(): void { + EnclosureHttp.axiosInstance.interceptors.request.use( + (config: EnclosureHttpRequestConfig) => { + const $config = config + NProgress.start() // 每次切换页面时,调用进度条 + const cancelKey = this.genUniqueKey($config) + $config.cancelToken = new this.CancelToken((cancelExecutor: (cancel: any) => void) => { + this.sourceTokenList.push({ cancelKey, cancelExecutor }) + }) + this.cancelRepeatRequest() + this.currentCancelTokenKey = cancelKey + // 优先判断post/get等方法是否传入回掉,否则执行初始化设置等回掉 + if (typeof this.beforeRequestCallback === "function") { + this.beforeRequestCallback($config) + this.beforeRequestCallback = undefined + return $config + } + if (EnclosureHttp.initConfig.beforeRequestCallback) { + EnclosureHttp.initConfig.beforeRequestCallback($config) + return $config + } + return $config + }, + error => { + return Promise.reject(error) + } + ) + } + + /** + * @description 清空当前cancelTokenList + * @returns void 0 + */ + public clearCancelTokenList(): void { + this.sourceTokenList.length = 0 + } + + /** + * @description 拦截相应 + * @returns void 0 + */ + private httpInterceptorsResponse(): void { + const instance = EnclosureHttp.axiosInstance + instance.interceptors.response.use( + (response: EnclosureHttpResoponse) => { + // 请求每次成功一次就删除当前canceltoken标记 + const cancelKey = this.genUniqueKey(response.config) + this.deleteCancelTokenByCancelKey(cancelKey) + // 优先判断post/get等方法是否传入回掉,否则执行初始化设置等回掉 + if (typeof this.beforeResponseCallback === "function") { + this.beforeResponseCallback(response) + this.beforeResponseCallback = undefined + return response.data + } + if (EnclosureHttp.initConfig.beforeResponseCallback) { + EnclosureHttp.initConfig.beforeResponseCallback(response) + return response.data + } + NProgress.done() + return response.data + }, + (error: EnclosureHttpError) => { + const $error = error + // 判断当前的请求中是否在 取消token数组理存在,如果存在则移除(单次请求流程) + if (this.currentCancelTokenKey) { + const haskey = this.sourceTokenList.filter( + cancelToken => cancelToken.cancelKey === this.currentCancelTokenKey + ).length + if (haskey) { + this.sourceTokenList = this.sourceTokenList.filter( + cancelToken => + cancelToken.cancelKey !== this.currentCancelTokenKey + ) + this.currentCancelTokenKey = "" + } + } + $error.isCancelRequest = Axios.isCancel($error) + // 所有的响应异常 区分来源为取消请求/非取消请求 + return Promise.reject($error) + } + ) + } + + public request( + method: RequestMethods, + url: string, + param?: AxiosRequestConfig, + axiosConfig?: EnclosureHttpRequestConfig, + ): Promise { + const config = transformConfigByMethod(param, { + method, + url, + ...axiosConfig + } as EnclosureHttpRequestConfig) + // 单独处理自定义请求/响应回掉 + if (axiosConfig?.beforeRequestCallback) { + this.beforeRequestCallback = axiosConfig.beforeRequestCallback + } + if (axiosConfig?.beforeResponseCallback) { + this.beforeResponseCallback = axiosConfig.beforeResponseCallback + } + return new Promise((resolve, reject) => { + EnclosureHttp.axiosInstance.request(config) + .then((response: EnclosureHttpResoponse) => { + resolve(response) + }) + .catch((error: any) => { + reject(error) + }) + }) + } + + public post( + url: string, + params?: T, + config?: EnclosureHttpRequestConfig + ): Promise { + return this.request("post", url, params, config) + } + + public get( + url: string, + params?: T, + config?: EnclosureHttpRequestConfig + ): Promise { + return this.request("get", url, params, config) + } +} + +export default EnclosureHttp diff --git a/frontend/vue-ts/src/utils/http/index.ts b/frontend/vue-ts/src/utils/http/index.ts new file mode 100644 index 000000000..63ed68485 --- /dev/null +++ b/frontend/vue-ts/src/utils/http/index.ts @@ -0,0 +1,3 @@ +import EnclosureHttp from "./core" +export const http = new EnclosureHttp() + diff --git a/frontend/vue-ts/src/utils/http/types.d.ts b/frontend/vue-ts/src/utils/http/types.d.ts new file mode 100644 index 000000000..4c5564fe8 --- /dev/null +++ b/frontend/vue-ts/src/utils/http/types.d.ts @@ -0,0 +1,48 @@ +import Axios, { + AxiosRequestConfig, + Canceler, + AxiosResponse, + Method, + AxiosError +} from "axios" + +import { METHODS } from './config' + +export type cancelTokenType = { cancelKey: string, cancelExecutor: Canceler } + +export type RequestMethods = Extract + +export interface EnclosureHttpRequestConfig extends AxiosRequestConfig { + beforeRequestCallback?: (request: EnclosureHttpRequestConfig) => void // 请求发送之前 + beforeResponseCallback?: (response: EnclosureHttpResoponse) => void // 相应返回之前 +} + +export interface EnclosureHttpResoponse extends AxiosResponse { + config: EnclosureHttpRequestConfig +} + +export interface EnclosureHttpError extends AxiosError { + isCancelRequest?: boolean +} + +export default class EnclosureHttp { + cancelTokenList: Array + clearCancelTokenList(): void + request( + method: RequestMethods, + url: string, + param?: AxiosRequestConfig, + axiosConfig?: EnclosureHttpRequestConfig + ): Promise + post( + url: string, + params?: T, + config?: EnclosureHttpRequestConfig + ): Promise + get( + url: string, + params?: T, + config?: EnclosureHttpRequestConfig + ): Promise +} \ No newline at end of file diff --git a/frontend/vue-ts/src/utils/http/utils.ts b/frontend/vue-ts/src/utils/http/utils.ts new file mode 100644 index 000000000..416248998 --- /dev/null +++ b/frontend/vue-ts/src/utils/http/utils.ts @@ -0,0 +1,29 @@ +import { EnclosureHttpRequestConfig } from "./types.d" + +export function excludeProps( + origin: T, + prop: string +): { [key: string]: T } { + return Object.keys(origin) + .filter(key => !prop.includes(key)) + .reduce((res, key) => { + res[key] = origin[key] + return res + }, {} as { [key: string]: T }) +} + +export function transformConfigByMethod( + params: any, + config: EnclosureHttpRequestConfig +): EnclosureHttpRequestConfig { + const { method } = config + const props = ["delete", "get", "head", "options"].includes( + method!.toLocaleLowerCase() + ) + ? "params" + : "data" + return { + ...config, + [props]: params + } +} diff --git a/frontend/vue-ts/src/utils/loaders/index.ts b/frontend/vue-ts/src/utils/loaders/index.ts new file mode 100644 index 000000000..2ed8bdc47 --- /dev/null +++ b/frontend/vue-ts/src/utils/loaders/index.ts @@ -0,0 +1,54 @@ +interface ProxyLoader { + loadCss(src: string): any + loadScript(src: string): Promise + loadScriptConcurrent(src: Array): Promise +} + +class loaderProxy implements ProxyLoader { + + constructor() { } + + protected scriptLoaderCache: Array = [] + + public loadCss = (src: string): any => { + let element = document.createElement("link") + element.rel = "stylesheet" + element.href = src + document.body.appendChild(element) + } + + public loadScript = async (src: string): Promise => { + if (this.scriptLoaderCache.includes(src)) { + return src + } else { + let element: Element = document.createElement("script") + element.src = src + document.body.appendChild(element) + element.onload = () => { + return this.scriptLoaderCache.push(src) + } + } + } + + public loadScriptConcurrent = async (srcList: Array): Promise => { + if (Array.isArray(srcList)) { + const len: number = srcList.length + if (len > 0) { + let count: number = 0 + srcList.map(src => { + if (src) { + this.loadScript(src).then(() => { + count++ + if (count === len) { + return + } + }) + } + }) + } + } + } + +} + +export const loader = new loaderProxy() \ No newline at end of file diff --git a/frontend/vue-ts/src/utils/message/index.ts b/frontend/vue-ts/src/utils/message/index.ts new file mode 100644 index 000000000..eb0436fda --- /dev/null +++ b/frontend/vue-ts/src/utils/message/index.ts @@ -0,0 +1,43 @@ +import { ElMessage } from "element-plus" + +// 消息 +const Message = (message: string): any => { + return ElMessage({ + showClose: true, + message + }) +} + +// 成功 +const successMessage = (message: string): any => { + return ElMessage({ + showClose: true, + message, + type: "success" + }) +} + +// 警告 +const warnMessage = (message: string): any => { + return ElMessage({ + showClose: true, + message, + type: "warning" + }) +} + +// 失败 +const errorMessage = (message: string): any => { + return ElMessage({ + showClose: true, + message, + type: "error" + }) +} + +export { + Message, + successMessage, + warnMessage, + errorMessage +} \ No newline at end of file diff --git a/frontend/vue-ts/src/utils/operate/index.ts b/frontend/vue-ts/src/utils/operate/index.ts new file mode 100644 index 000000000..e4c9bc169 --- /dev/null +++ b/frontend/vue-ts/src/utils/operate/index.ts @@ -0,0 +1,14 @@ +export const hasClass = (ele: Element, cls:string) :any => { + return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)')) +} + +export const addClass = (ele: Element, cls:string) :any => { + if (!hasClass(ele, cls)) ele.className += ' ' + cls +} + +export const removeClass =(ele: Element, cls:string) :any => { + if (hasClass(ele, cls)) { + const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)') + ele.className = ele.className.replace(reg, ' ') + } +} \ No newline at end of file diff --git a/frontend/vue-ts/src/utils/progress/index.ts b/frontend/vue-ts/src/utils/progress/index.ts new file mode 100644 index 000000000..582cb7413 --- /dev/null +++ b/frontend/vue-ts/src/utils/progress/index.ts @@ -0,0 +1,12 @@ +import NProgress from "nprogress" +import "nprogress/nprogress.css" + +NProgress.configure({ + easing: 'ease', // 动画方式 + speed: 500, // 递增进度条的速度 + showSpinner: true, // 是否显示加载ico + trickleSpeed: 200, // 自动递增间隔 + minimum: 0.3 // 初始化时的最小百分比 +}) + +export default NProgress diff --git a/frontend/vue-ts/src/utils/resize/index.ts b/frontend/vue-ts/src/utils/resize/index.ts new file mode 100644 index 000000000..c0bac19f1 --- /dev/null +++ b/frontend/vue-ts/src/utils/resize/index.ts @@ -0,0 +1,32 @@ +import ResizeObserver from 'resize-observer-polyfill' + +const isServer = typeof window === 'undefined' + +const resizeHandler = (entries: any[]): void => { + for (const entry of entries) { + const listeners = entry.target.__resizeListeners__ || [] + if (listeners.length) { + listeners.forEach((fn: () => any) => { + fn() + }) + } + } +} + +export const addResizeListener = (element: any, fn: () => any): any => { + if (isServer) return + if (!element.__resizeListeners__) { + element.__resizeListeners__ = [] + element.__ro__ = new ResizeObserver(resizeHandler) + element.__ro__.observe(element) + } + element.__resizeListeners__.push(fn) +} + +export const removeResizeListener = (element: any, fn: () => any): any => { + if (!element || !element.__resizeListeners__) return + element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1) + if (!element.__resizeListeners__.length) { + element.__ro__.disconnect() + } +} \ No newline at end of file diff --git a/frontend/vue-ts/src/utils/storage/index.ts b/frontend/vue-ts/src/utils/storage/index.ts new file mode 100644 index 000000000..f34f9af44 --- /dev/null +++ b/frontend/vue-ts/src/utils/storage/index.ts @@ -0,0 +1,42 @@ +interface ProxyStorage { + getItem(key: string): any + setItem(Key: string, value: string): void + removeItem(key: string): void +} + +//sessionStorage operate +class sessionStorageProxy implements ProxyStorage { + + protected storage: ProxyStorage + + constructor(storageModel: ProxyStorage) { + this.storage = storageModel + } + + // 存 + public setItem(key: string, value: any): void { + this.storage.setItem(key, JSON.stringify(value)) + } + + // 取 + public getItem(key: string): any { + return JSON.parse(this.storage.getItem(key)) || null + } + + // 删 + public removeItem(key: string): void { + this.storage.removeItem(key) + } + +} + +//localStorage operate +class localStorageProxy extends sessionStorageProxy implements ProxyStorage { + constructor(localStorage: ProxyStorage) { + super(localStorage) + } +} + +export const storageSession = new sessionStorageProxy(sessionStorage) + +export const storageLocal = new localStorageProxy(localStorage) \ No newline at end of file diff --git a/frontend/vue-ts/src/views/components/split-pane/index.vue b/frontend/vue-ts/src/views/components/split-pane/index.vue new file mode 100644 index 000000000..bb9b73209 --- /dev/null +++ b/frontend/vue-ts/src/views/components/split-pane/index.vue @@ -0,0 +1,85 @@ + + + + + diff --git a/frontend/vue-ts/src/views/error/401.vue b/frontend/vue-ts/src/views/error/401.vue new file mode 100644 index 000000000..d98670df0 --- /dev/null +++ b/frontend/vue-ts/src/views/error/401.vue @@ -0,0 +1,73 @@ + + + + + diff --git a/frontend/vue-ts/src/views/error/404.vue b/frontend/vue-ts/src/views/error/404.vue new file mode 100644 index 000000000..26e634dbb --- /dev/null +++ b/frontend/vue-ts/src/views/error/404.vue @@ -0,0 +1,236 @@ + + + + + diff --git a/frontend/vue-ts/src/views/login.vue b/frontend/vue-ts/src/views/login.vue new file mode 100644 index 000000000..eb48d9d6e --- /dev/null +++ b/frontend/vue-ts/src/views/login.vue @@ -0,0 +1,84 @@ + + + diff --git a/frontend/vue-ts/src/views/register.vue b/frontend/vue-ts/src/views/register.vue new file mode 100644 index 000000000..8ece8a8f6 --- /dev/null +++ b/frontend/vue-ts/src/views/register.vue @@ -0,0 +1,73 @@ + + + diff --git a/frontend/vue-ts/src/views/user.vue b/frontend/vue-ts/src/views/user.vue new file mode 100644 index 000000000..5c09e54e0 --- /dev/null +++ b/frontend/vue-ts/src/views/user.vue @@ -0,0 +1,15 @@ + + + + + diff --git a/frontend/vue-ts/src/views/welcome.vue b/frontend/vue-ts/src/views/welcome.vue new file mode 100644 index 000000000..1cd05575e --- /dev/null +++ b/frontend/vue-ts/src/views/welcome.vue @@ -0,0 +1,26 @@ + + + + + diff --git a/frontend/vue-ts/tsconfig.json b/frontend/vue-ts/tsconfig.json new file mode 100644 index 000000000..f5640dc2a --- /dev/null +++ b/frontend/vue-ts/tsconfig.json @@ -0,0 +1,45 @@ +{ + "compilerOptions": { + "target": "esnext", + "module": "esnext", + "strict": false, + "jsx": "preserve", + "importHelpers": true, + "moduleResolution": "node", + "experimentalDecorators": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "sourceMap": true, + "baseUrl": ".", + "allowJs": true, + "resolveJsonModule": true, // 包含导入的模块。json的扩展 + "lib": [ + "dom", + "esnext" + ], + "incremental": true, + "paths": { + "/@/*": [ + "src/*" + ] + }, + "types": ["node"], + "typeRoots": [ + "node_modules/@types" + ], + }, + "include": [ + "src/**/*.ts", + "src/**/*.tsx", + "src/**/*.vue", + "tests/**/*.ts", + "src/utils/path.js" + ], + "exclude": [ + "node_modules", + "dist", + "**/*.js" + ], +} \ No newline at end of file diff --git a/frontend/vue-ts/vite.config.ts b/frontend/vue-ts/vite.config.ts new file mode 100644 index 000000000..4a3ca4a05 --- /dev/null +++ b/frontend/vue-ts/vite.config.ts @@ -0,0 +1,45 @@ + +import { resolve } from 'path' +import vue from '@vitejs/plugin-vue' +import type { UserConfig } from 'vite' +import { loadEnv } from './build/utils' +import { createProxy } from './build/proxy' + +const pathResolve = (dir: string): any => { + return resolve(__dirname, '.', dir) +} + +const { VITE_PORT, VITE_PUBLIC_PATH, VITE_PROXY, VITE_OPEN } = loadEnv() + +const alias: Record = { + '/@': pathResolve('src'), +} + +const root: string = process.cwd() + +const viteConfig: UserConfig = { + /** + * 基本公共路径 + * @default '/' + */ + base: process.env.NODE_ENV === "production" ? "./" : VITE_PUBLIC_PATH, + root, + alias, + // 服务端渲染 + server: { + // 是否开启 https + https: false, + /** + * 端口号 + * @default 3000 + */ + port: VITE_PORT, + // 本地跨域代理 + proxy: createProxy(VITE_PROXY) + }, + plugins: [ + vue(), + ], +} + +export default viteConfig \ No newline at end of file