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 @@
+
+
+
+
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 @@
+
+
+
+
+ {{ $t(item.meta.title) }}
+ {{
+ $t(item.meta.title)
+ }}
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ tipsFalse }}
+
+ 重置
+ {{ tips }}
+
+ 免密登录
+
+
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+ {{ $t(onlyOneChild.meta.title) }}
+
+
+
+
+
+
+
+
+ {{ $t(item.meta.title) }}
+
+
+
+
+
+
+
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 @@
+
+
+ {{ tag.name }}
+
+
+
+
+
+
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 @@
+
+
+
+
+
+
+ A
+
+
+
+
+
+
+ B
+
+
+ C
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+ CURD Admin
+ 你没有权限去该页面
+ 如有不满请联系你领导
+
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+
+
CURD Admin
+
{{ message }}
+
+ Please check that the URL you entered is correct, or click the button
+ below to return to the homepage.
+
+
Back to home
+
+
+
+
+
+
+
+
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