🎨 build framework completed
This commit is contained in:
84
.eslintrc-auto-import.json
Normal file
84
.eslintrc-auto-import.json
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
{
|
||||||
|
"globals": {
|
||||||
|
"Component": true,
|
||||||
|
"ComponentPublicInstance": true,
|
||||||
|
"ComputedRef": true,
|
||||||
|
"EffectScope": true,
|
||||||
|
"ExtractDefaultPropTypes": true,
|
||||||
|
"ExtractPropTypes": true,
|
||||||
|
"ExtractPublicPropTypes": true,
|
||||||
|
"InjectionKey": true,
|
||||||
|
"PropType": true,
|
||||||
|
"Ref": true,
|
||||||
|
"VNode": true,
|
||||||
|
"WritableComputedRef": true,
|
||||||
|
"acceptHMRUpdate": true,
|
||||||
|
"computed": true,
|
||||||
|
"createApp": true,
|
||||||
|
"createPinia": true,
|
||||||
|
"customRef": true,
|
||||||
|
"defineAsyncComponent": true,
|
||||||
|
"defineComponent": true,
|
||||||
|
"defineStore": true,
|
||||||
|
"effectScope": true,
|
||||||
|
"getActivePinia": true,
|
||||||
|
"getCurrentInstance": true,
|
||||||
|
"getCurrentScope": true,
|
||||||
|
"h": true,
|
||||||
|
"inject": true,
|
||||||
|
"isProxy": true,
|
||||||
|
"isReactive": true,
|
||||||
|
"isReadonly": true,
|
||||||
|
"isRef": true,
|
||||||
|
"mapActions": true,
|
||||||
|
"mapGetters": true,
|
||||||
|
"mapState": true,
|
||||||
|
"mapStores": true,
|
||||||
|
"mapWritableState": true,
|
||||||
|
"markRaw": true,
|
||||||
|
"nextTick": true,
|
||||||
|
"onActivated": true,
|
||||||
|
"onBeforeMount": true,
|
||||||
|
"onBeforeRouteLeave": true,
|
||||||
|
"onBeforeRouteUpdate": true,
|
||||||
|
"onBeforeUnmount": true,
|
||||||
|
"onBeforeUpdate": true,
|
||||||
|
"onDeactivated": true,
|
||||||
|
"onErrorCaptured": true,
|
||||||
|
"onMounted": true,
|
||||||
|
"onRenderTracked": true,
|
||||||
|
"onRenderTriggered": true,
|
||||||
|
"onScopeDispose": true,
|
||||||
|
"onServerPrefetch": true,
|
||||||
|
"onUnmounted": true,
|
||||||
|
"onUpdated": true,
|
||||||
|
"provide": true,
|
||||||
|
"reactive": true,
|
||||||
|
"readonly": true,
|
||||||
|
"ref": true,
|
||||||
|
"resolveComponent": true,
|
||||||
|
"setActivePinia": true,
|
||||||
|
"setMapStoreSuffix": true,
|
||||||
|
"shallowReactive": true,
|
||||||
|
"shallowReadonly": true,
|
||||||
|
"shallowRef": true,
|
||||||
|
"storeToRefs": true,
|
||||||
|
"toRaw": true,
|
||||||
|
"toRef": true,
|
||||||
|
"toRefs": true,
|
||||||
|
"toValue": true,
|
||||||
|
"triggerRef": true,
|
||||||
|
"unref": true,
|
||||||
|
"useAttrs": true,
|
||||||
|
"useCssModule": true,
|
||||||
|
"useCssVars": true,
|
||||||
|
"useLink": true,
|
||||||
|
"useRoute": true,
|
||||||
|
"useRouter": true,
|
||||||
|
"useSlots": true,
|
||||||
|
"watch": true,
|
||||||
|
"watchEffect": true,
|
||||||
|
"watchPostEffect": true,
|
||||||
|
"watchSyncEffect": true
|
||||||
|
}
|
||||||
|
}
|
83
auto-import.d.ts
vendored
Normal file
83
auto-import.d.ts
vendored
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
/* prettier-ignore */
|
||||||
|
// @ts-nocheck
|
||||||
|
// noinspection JSUnusedGlobalSymbols
|
||||||
|
// Generated by unplugin-auto-import
|
||||||
|
export {}
|
||||||
|
declare global {
|
||||||
|
const EffectScope: typeof import('vue')['EffectScope']
|
||||||
|
const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
|
||||||
|
const computed: typeof import('vue')['computed']
|
||||||
|
const createApp: typeof import('vue')['createApp']
|
||||||
|
const createPinia: typeof import('pinia')['createPinia']
|
||||||
|
const customRef: typeof import('vue')['customRef']
|
||||||
|
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
|
||||||
|
const defineComponent: typeof import('vue')['defineComponent']
|
||||||
|
const defineStore: typeof import('pinia')['defineStore']
|
||||||
|
const effectScope: typeof import('vue')['effectScope']
|
||||||
|
const getActivePinia: typeof import('pinia')['getActivePinia']
|
||||||
|
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
|
||||||
|
const getCurrentScope: typeof import('vue')['getCurrentScope']
|
||||||
|
const h: typeof import('vue')['h']
|
||||||
|
const inject: typeof import('vue')['inject']
|
||||||
|
const isProxy: typeof import('vue')['isProxy']
|
||||||
|
const isReactive: typeof import('vue')['isReactive']
|
||||||
|
const isReadonly: typeof import('vue')['isReadonly']
|
||||||
|
const isRef: typeof import('vue')['isRef']
|
||||||
|
const mapActions: typeof import('pinia')['mapActions']
|
||||||
|
const mapGetters: typeof import('pinia')['mapGetters']
|
||||||
|
const mapState: typeof import('pinia')['mapState']
|
||||||
|
const mapStores: typeof import('pinia')['mapStores']
|
||||||
|
const mapWritableState: typeof import('pinia')['mapWritableState']
|
||||||
|
const markRaw: typeof import('vue')['markRaw']
|
||||||
|
const nextTick: typeof import('vue')['nextTick']
|
||||||
|
const onActivated: typeof import('vue')['onActivated']
|
||||||
|
const onBeforeMount: typeof import('vue')['onBeforeMount']
|
||||||
|
const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
|
||||||
|
const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
|
||||||
|
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
|
||||||
|
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
|
||||||
|
const onDeactivated: typeof import('vue')['onDeactivated']
|
||||||
|
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
|
||||||
|
const onMounted: typeof import('vue')['onMounted']
|
||||||
|
const onRenderTracked: typeof import('vue')['onRenderTracked']
|
||||||
|
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
|
||||||
|
const onScopeDispose: typeof import('vue')['onScopeDispose']
|
||||||
|
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
|
||||||
|
const onUnmounted: typeof import('vue')['onUnmounted']
|
||||||
|
const onUpdated: typeof import('vue')['onUpdated']
|
||||||
|
const provide: typeof import('vue')['provide']
|
||||||
|
const reactive: typeof import('vue')['reactive']
|
||||||
|
const readonly: typeof import('vue')['readonly']
|
||||||
|
const ref: typeof import('vue')['ref']
|
||||||
|
const resolveComponent: typeof import('vue')['resolveComponent']
|
||||||
|
const setActivePinia: typeof import('pinia')['setActivePinia']
|
||||||
|
const setMapStoreSuffix: typeof import('pinia')['setMapStoreSuffix']
|
||||||
|
const shallowReactive: typeof import('vue')['shallowReactive']
|
||||||
|
const shallowReadonly: typeof import('vue')['shallowReadonly']
|
||||||
|
const shallowRef: typeof import('vue')['shallowRef']
|
||||||
|
const storeToRefs: typeof import('pinia')['storeToRefs']
|
||||||
|
const toRaw: typeof import('vue')['toRaw']
|
||||||
|
const toRef: typeof import('vue')['toRef']
|
||||||
|
const toRefs: typeof import('vue')['toRefs']
|
||||||
|
const toValue: typeof import('vue')['toValue']
|
||||||
|
const triggerRef: typeof import('vue')['triggerRef']
|
||||||
|
const unref: typeof import('vue')['unref']
|
||||||
|
const useAttrs: typeof import('vue')['useAttrs']
|
||||||
|
const useCssModule: typeof import('vue')['useCssModule']
|
||||||
|
const useCssVars: typeof import('vue')['useCssVars']
|
||||||
|
const useLink: typeof import('vue-router')['useLink']
|
||||||
|
const useRoute: typeof import('vue-router')['useRoute']
|
||||||
|
const useRouter: typeof import('vue-router')['useRouter']
|
||||||
|
const useSlots: typeof import('vue')['useSlots']
|
||||||
|
const watch: typeof import('vue')['watch']
|
||||||
|
const watchEffect: typeof import('vue')['watchEffect']
|
||||||
|
const watchPostEffect: typeof import('vue')['watchPostEffect']
|
||||||
|
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
|
||||||
|
}
|
||||||
|
// for type re-export
|
||||||
|
declare global {
|
||||||
|
// @ts-ignore
|
||||||
|
export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue'
|
||||||
|
import('vue')
|
||||||
|
}
|
16
components.d.ts
vendored
Normal file
16
components.d.ts
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
// Generated by unplugin-vue-components
|
||||||
|
// Read more: https://github.com/vuejs/core/pull/3399
|
||||||
|
export {}
|
||||||
|
|
||||||
|
/* prettier-ignore */
|
||||||
|
declare module 'vue' {
|
||||||
|
export interface GlobalComponents {
|
||||||
|
AButton: typeof import('ant-design-vue/es')['Button']
|
||||||
|
Login: typeof import('./src/views/login/LoginPage.vue')['default']
|
||||||
|
LoginPage: typeof import('./src/views/login/LoginPage.vue')['default']
|
||||||
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
|
}
|
||||||
|
}
|
@@ -4,7 +4,7 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Vite + Vue + TS</title>
|
<title><%- title %></title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
22
package.json
22
package.json
@@ -4,21 +4,37 @@
|
|||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite --mode development --host",
|
||||||
"build": "vue-tsc -b && vite build",
|
"build": "vue-tsc -b && vite build --mode production",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@ant-design/icons-vue": "^7.0.1",
|
||||||
|
"@types/crypto-js": "^4.2.2",
|
||||||
|
"@types/node": "^22.1.0",
|
||||||
|
"ant-design-vue": "^4.2.3",
|
||||||
|
"axios": "^1.7.3",
|
||||||
|
"crypto-js": "^4.2.0",
|
||||||
"eslint": "9.x",
|
"eslint": "9.x",
|
||||||
"vue": "^3.4.31"
|
"localforage": "^1.10.0",
|
||||||
|
"pinia": "^2.2.1",
|
||||||
|
"pinia-plugin-persistedstate": "^3.2.1",
|
||||||
|
"unplugin-auto-import": "^0.18.2",
|
||||||
|
"vite-plugin-compression": "^0.5.1",
|
||||||
|
"vite-plugin-html": "^3.2.2",
|
||||||
|
"vite-plugin-node-polyfills": "^0.22.0",
|
||||||
|
"vue": "^3.4.31",
|
||||||
|
"vue-router": "^4.4.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.8.0",
|
"@eslint/js": "^9.8.0",
|
||||||
"@vitejs/plugin-vue": "^5.0.5",
|
"@vitejs/plugin-vue": "^5.0.5",
|
||||||
"eslint-plugin-vue": "^9.27.0",
|
"eslint-plugin-vue": "^9.27.0",
|
||||||
"globals": "^15.9.0",
|
"globals": "^15.9.0",
|
||||||
|
"sass": "^1.77.8",
|
||||||
"typescript": "^5.2.2",
|
"typescript": "^5.2.2",
|
||||||
"typescript-eslint": "^8.0.1",
|
"typescript-eslint": "^8.0.1",
|
||||||
|
"unplugin-vue-components": "^0.27.3",
|
||||||
"vite": "^5.3.4",
|
"vite": "^5.3.4",
|
||||||
"vue-tsc": "^2.0.24"
|
"vue-tsc": "^2.0.24"
|
||||||
}
|
}
|
||||||
|
28
src/App.vue
28
src/App.vue
@@ -1,30 +1,4 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import HelloWorld from './components/HelloWorld.vue'
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<router-view></router-view>
|
||||||
<a href="https://vitejs.dev" target="_blank">
|
|
||||||
<img src="/vite.svg" class="logo" alt="Vite logo" />
|
|
||||||
</a>
|
|
||||||
<a href="https://vuejs.org/" target="_blank">
|
|
||||||
<img src="./assets/vue.svg" class="logo vue" alt="Vue logo" />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<HelloWorld msg="Vite + Vue" />
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.logo {
|
|
||||||
height: 6em;
|
|
||||||
padding: 1.5em;
|
|
||||||
will-change: filter;
|
|
||||||
transition: filter 300ms;
|
|
||||||
}
|
|
||||||
.logo:hover {
|
|
||||||
filter: drop-shadow(0 0 2em #646cffaa);
|
|
||||||
}
|
|
||||||
.logo.vue:hover {
|
|
||||||
filter: drop-shadow(0 0 2em #42b883aa);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
26
src/assets/styles/variables.scss
Normal file
26
src/assets/styles/variables.scss
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
::-webkit-scrollbar-button {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: rgba(144, 147, 153, 0.3);
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
::-webkit-scrollbar-corner {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-resizer {
|
||||||
|
display: none;
|
||||||
|
}
|
@@ -1,41 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { ref } from 'vue'
|
|
||||||
|
|
||||||
defineProps<{ msg: string }>()
|
|
||||||
|
|
||||||
const count = ref(0)
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<h1>{{ msg }}</h1>
|
|
||||||
|
|
||||||
<div class="card">
|
|
||||||
<button type="button" @click="count++">count is {{ count }}</button>
|
|
||||||
<p>
|
|
||||||
Edit
|
|
||||||
<code>components/HelloWorld.vue</code> to test HMR
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Check out
|
|
||||||
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
|
|
||||||
>create-vue</a
|
|
||||||
>, the official Vue + Vite starter
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Learn more about IDE Support for Vue in the
|
|
||||||
<a
|
|
||||||
href="https://vuejs.org/guide/scaling-up/tooling.html#ide-support"
|
|
||||||
target="_blank"
|
|
||||||
>Vue Docs Scaling up Guide</a
|
|
||||||
>.
|
|
||||||
</p>
|
|
||||||
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.read-the-docs {
|
|
||||||
color: #888;
|
|
||||||
}
|
|
||||||
</style>
|
|
16
src/main.ts
16
src/main.ts
@@ -1,5 +1,15 @@
|
|||||||
import { createApp } from 'vue'
|
import {createApp} from 'vue'
|
||||||
import './style.css'
|
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
|
import '@/assets/styles/variables.scss'
|
||||||
|
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
|
||||||
|
//Pinia
|
||||||
|
import {createPinia, Pinia} from 'pinia'
|
||||||
|
import router from "@/router/router.ts";
|
||||||
|
|
||||||
createApp(App).mount('#app')
|
const pinia: Pinia = createPinia()
|
||||||
|
pinia.use(piniaPluginPersistedstate)
|
||||||
|
|
||||||
|
createApp(App)
|
||||||
|
.use(router)
|
||||||
|
.use(pinia)
|
||||||
|
.mount('#app')
|
||||||
|
10
src/router/modules/login.ts
Normal file
10
src/router/modules/login.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
export default [
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
name: 'login',
|
||||||
|
component: () => import('@/views/login/LoginPage.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '登录页'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
11
src/router/router.ts
Normal file
11
src/router/router.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import {createRouter, createWebHistory, RouteRecordRaw} from 'vue-router'
|
||||||
|
|
||||||
|
import login from './modules/login'
|
||||||
|
|
||||||
|
const routes: Array<RouteRecordRaw> = [...login]
|
||||||
|
|
||||||
|
const router = createRouter({
|
||||||
|
history: createWebHistory(),
|
||||||
|
routes
|
||||||
|
})
|
||||||
|
export default router
|
7
src/store/index.ts
Normal file
7
src/store/index.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import {useAuthStore} from '@/store/modules/user.ts'
|
||||||
|
|
||||||
|
export default function useStore() {
|
||||||
|
return {
|
||||||
|
user: useAuthStore()
|
||||||
|
}
|
||||||
|
}
|
32
src/store/modules/user.ts
Normal file
32
src/store/modules/user.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import {defineStore} from 'pinia'
|
||||||
|
import {ref} from 'vue'
|
||||||
|
|
||||||
|
export const useAuthStore = defineStore(
|
||||||
|
'user',
|
||||||
|
() => {
|
||||||
|
const user = ref<any>()
|
||||||
|
|
||||||
|
function setUser(data: any) {
|
||||||
|
user.value = data
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUser() {
|
||||||
|
return user.value
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearUser() {
|
||||||
|
user.value = void 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
user,
|
||||||
|
setUser,
|
||||||
|
getUser,
|
||||||
|
clearUser
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// 开启数据持久化
|
||||||
|
persist: true
|
||||||
|
}
|
||||||
|
)
|
@@ -1,79 +0,0 @@
|
|||||||
:root {
|
|
||||||
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
|
||||||
line-height: 1.5;
|
|
||||||
font-weight: 400;
|
|
||||||
|
|
||||||
color-scheme: light dark;
|
|
||||||
color: rgba(255, 255, 255, 0.87);
|
|
||||||
background-color: #242424;
|
|
||||||
|
|
||||||
font-synthesis: none;
|
|
||||||
text-rendering: optimizeLegibility;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
font-weight: 500;
|
|
||||||
color: #646cff;
|
|
||||||
text-decoration: inherit;
|
|
||||||
}
|
|
||||||
a:hover {
|
|
||||||
color: #535bf2;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
display: flex;
|
|
||||||
place-items: center;
|
|
||||||
min-width: 320px;
|
|
||||||
min-height: 100vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 3.2em;
|
|
||||||
line-height: 1.1;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
border-radius: 8px;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
padding: 0.6em 1.2em;
|
|
||||||
font-size: 1em;
|
|
||||||
font-weight: 500;
|
|
||||||
font-family: inherit;
|
|
||||||
background-color: #1a1a1a;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: border-color 0.25s;
|
|
||||||
}
|
|
||||||
button:hover {
|
|
||||||
border-color: #646cff;
|
|
||||||
}
|
|
||||||
button:focus,
|
|
||||||
button:focus-visible {
|
|
||||||
outline: 4px auto -webkit-focus-ring-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card {
|
|
||||||
padding: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#app {
|
|
||||||
max-width: 1280px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 2rem;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: light) {
|
|
||||||
:root {
|
|
||||||
color: #213547;
|
|
||||||
background-color: #ffffff;
|
|
||||||
}
|
|
||||||
a:hover {
|
|
||||||
color: #747bff;
|
|
||||||
}
|
|
||||||
button {
|
|
||||||
background-color: #f9f9f9;
|
|
||||||
}
|
|
||||||
}
|
|
163
src/utils/axios/request.ts
Normal file
163
src/utils/axios/request.ts
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
/** @format */
|
||||||
|
|
||||||
|
import axios, { AxiosInstance, AxiosRequestConfig } from "axios";
|
||||||
|
import { message } from "ant-design-vue";
|
||||||
|
import { getStorageFromKey } from "@/utils/localStorage/config.ts";
|
||||||
|
|
||||||
|
class Request {
|
||||||
|
private instance: AxiosInstance | undefined;
|
||||||
|
|
||||||
|
constructor(config: AxiosRequestConfig) {
|
||||||
|
this.instance = axios.create(config);
|
||||||
|
// 全局请求拦截
|
||||||
|
this.instance.interceptors.request.use(
|
||||||
|
(config) => {
|
||||||
|
const token: string | null = getStorageFromKey("token");
|
||||||
|
if (token) {
|
||||||
|
config.headers.Authorization = `${import.meta.env.VITE_APP_TOKEN_KEY} ${token}`;
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
return Promise.reject(error);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// 全局响应拦截
|
||||||
|
this.instance.interceptors.response.use(
|
||||||
|
(response) => {
|
||||||
|
if (response.data instanceof Blob) {
|
||||||
|
return response;
|
||||||
|
} else {
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
const { response } = error;
|
||||||
|
if (response) {
|
||||||
|
this.handleCode(response.status);
|
||||||
|
}
|
||||||
|
if (!window.navigator.onLine) {
|
||||||
|
message.error("网络连接失败");
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleCode(code: number): void {
|
||||||
|
switch (code) {
|
||||||
|
case 400:
|
||||||
|
message
|
||||||
|
.open({
|
||||||
|
content: "请求错误(400)",
|
||||||
|
type: "error",
|
||||||
|
})
|
||||||
|
.then();
|
||||||
|
break;
|
||||||
|
case 401:
|
||||||
|
message
|
||||||
|
.open({
|
||||||
|
content: "未授权,请重新登录(401)",
|
||||||
|
type: "error",
|
||||||
|
})
|
||||||
|
.then();
|
||||||
|
break;
|
||||||
|
case 403:
|
||||||
|
message
|
||||||
|
.open({
|
||||||
|
content: "拒绝访问(403)",
|
||||||
|
type: "error",
|
||||||
|
})
|
||||||
|
.then();
|
||||||
|
break;
|
||||||
|
case 404:
|
||||||
|
message
|
||||||
|
.open({
|
||||||
|
content: "请求出错(404)",
|
||||||
|
type: "error",
|
||||||
|
})
|
||||||
|
.then();
|
||||||
|
break;
|
||||||
|
case 408:
|
||||||
|
message
|
||||||
|
.open({
|
||||||
|
content: "请求超时(408)",
|
||||||
|
type: "error",
|
||||||
|
})
|
||||||
|
.then();
|
||||||
|
break;
|
||||||
|
case 500:
|
||||||
|
message
|
||||||
|
.open({
|
||||||
|
content: "服务器错误(500)",
|
||||||
|
type: "error",
|
||||||
|
})
|
||||||
|
.then();
|
||||||
|
break;
|
||||||
|
case 501:
|
||||||
|
message
|
||||||
|
.open({
|
||||||
|
content: "服务未实现(501)",
|
||||||
|
type: "error",
|
||||||
|
})
|
||||||
|
.then();
|
||||||
|
break;
|
||||||
|
case 502:
|
||||||
|
message
|
||||||
|
.open({
|
||||||
|
content: "网络错误(502)",
|
||||||
|
type: "error",
|
||||||
|
})
|
||||||
|
.then();
|
||||||
|
break;
|
||||||
|
case 503:
|
||||||
|
message
|
||||||
|
.open({
|
||||||
|
content: "服务不可用(503)",
|
||||||
|
type: "error",
|
||||||
|
})
|
||||||
|
.then();
|
||||||
|
break;
|
||||||
|
case 504:
|
||||||
|
message
|
||||||
|
.open({
|
||||||
|
content: "网络超时(504)",
|
||||||
|
type: "error",
|
||||||
|
})
|
||||||
|
.then();
|
||||||
|
break;
|
||||||
|
case 505:
|
||||||
|
message
|
||||||
|
.open({
|
||||||
|
content: "HTTP版本不受支持(505)",
|
||||||
|
type: "error",
|
||||||
|
})
|
||||||
|
.then();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
message
|
||||||
|
.open({
|
||||||
|
content: `连接出错(${code})!`,
|
||||||
|
type: "error",
|
||||||
|
})
|
||||||
|
.then();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
request<T>(config: AxiosRequestConfig<T>): Promise<T> {
|
||||||
|
return new Promise<T>((resolve, reject) => {
|
||||||
|
this.instance
|
||||||
|
?.request<T, T>(config)
|
||||||
|
.then((res) => {
|
||||||
|
resolve(res);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Request;
|
10
src/utils/axios/web.ts
Normal file
10
src/utils/axios/web.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
/** @format */
|
||||||
|
|
||||||
|
import Request from "./request";
|
||||||
|
|
||||||
|
const web: Request = new Request({
|
||||||
|
baseURL: import.meta.env.VITE_APP_BASE_API,
|
||||||
|
timeout: 5000,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default web;
|
91
src/utils/cookie/cookie.ts
Normal file
91
src/utils/cookie/cookie.ts
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
/**
|
||||||
|
* 配置
|
||||||
|
*
|
||||||
|
* @format
|
||||||
|
*/
|
||||||
|
|
||||||
|
interface Options {
|
||||||
|
/** key前缀 */
|
||||||
|
prefix?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 默认配置 */
|
||||||
|
const defaultOptions: Options = {
|
||||||
|
prefix: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
class CookieStorage {
|
||||||
|
private prefix: string;
|
||||||
|
|
||||||
|
constructor(options: Options = defaultOptions) {
|
||||||
|
const { prefix } = options;
|
||||||
|
this.prefix = prefix ?? "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 设置cookie
|
||||||
|
* @param {string} key 键
|
||||||
|
* @param {any} value 值
|
||||||
|
* @param {number} expires 过期时间s毫秒,不传默认2年有效
|
||||||
|
* @Date: 2023-05-17 18:10:34
|
||||||
|
* @Author: mulingyuer
|
||||||
|
*/
|
||||||
|
public setItem(key: string, value: string | number, expires?: number): void {
|
||||||
|
const timestamp = Date.now();
|
||||||
|
if (typeof expires === "number") {
|
||||||
|
expires = timestamp + expires;
|
||||||
|
} else {
|
||||||
|
expires = timestamp + 2 * 365 * 24 * 60 * 60 * 1000;
|
||||||
|
}
|
||||||
|
document.cookie = `${this.prefix}${key}=${value};expires=${new Date(expires).toUTCString()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 获取cookie
|
||||||
|
* @param {string} key 键
|
||||||
|
* @Date: 2023-05-17 18:31:50
|
||||||
|
* @Author: mulingyuer
|
||||||
|
*/
|
||||||
|
public getItem(key: string): string | undefined {
|
||||||
|
const cookies = document.cookie.split("; ");
|
||||||
|
let val: string | undefined = undefined;
|
||||||
|
cookies.find((item) => {
|
||||||
|
const [k, v] = item.split("=");
|
||||||
|
if (k === `${this.prefix}${key}`) {
|
||||||
|
val = v;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 删除指定key的cookie
|
||||||
|
* @param {string} key 键
|
||||||
|
* @Date: 2023-05-17 18:32:56
|
||||||
|
* @Author: mulingyuer
|
||||||
|
*/
|
||||||
|
public removeItem(key: string): void {
|
||||||
|
this.setItem(key, "", -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 清空所有cookie
|
||||||
|
* @Date: 2023-05-17 23:13:04
|
||||||
|
* @Author: mulingyuer
|
||||||
|
*/
|
||||||
|
public clear(): void {
|
||||||
|
const cookies = document.cookie.split("; ");
|
||||||
|
cookies.forEach((item) => {
|
||||||
|
const [k] = item.split("=");
|
||||||
|
this.removeItem(k);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const cookieStorage = new CookieStorage();
|
||||||
|
|
||||||
|
export default cookieStorage;
|
||||||
|
export { CookieStorage };
|
31
src/utils/encrypt/encrypt.ts
Normal file
31
src/utils/encrypt/encrypt.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/** @format */
|
||||||
|
import CryptoJS from "crypto-js";
|
||||||
|
|
||||||
|
const key = CryptoJS.enc.Hex.parse("d86d7bab3d6ac01ad9dc6a897652f2d2");
|
||||||
|
// const iv = CryptoJS.enc.Latin1.parse("d86d7bab3d6ac01ad9dc6a897652f2d2");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
function EncryptData(data: string) {
|
||||||
|
const src = CryptoJS.enc.Utf8.parse(data);
|
||||||
|
const encrypted = CryptoJS.AES.encrypt(src, key, {
|
||||||
|
mode: CryptoJS.mode.ECB,
|
||||||
|
padding: CryptoJS.pad.Pkcs7,
|
||||||
|
});
|
||||||
|
return encrypted.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解密
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
function DecryptData(data: string) {
|
||||||
|
const decrypt = CryptoJS.AES.decrypt(data, key, {
|
||||||
|
mode: CryptoJS.mode.ECB,
|
||||||
|
padding: CryptoJS.pad.Pkcs7,
|
||||||
|
});
|
||||||
|
return JSON.parse(CryptoJS.enc.Utf8.stringify(decrypt).toString());
|
||||||
|
}
|
||||||
|
export { EncryptData, DecryptData };
|
104
src/utils/localStorage/config.ts
Normal file
104
src/utils/localStorage/config.ts
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
/** @format */
|
||||||
|
|
||||||
|
import { encrypt, decrypt } from "./encry";
|
||||||
|
import { globalConfig } from "./interface";
|
||||||
|
|
||||||
|
const config: globalConfig = {
|
||||||
|
type: "localStorage", //存储类型,localStorage | sessionStorage
|
||||||
|
prefix: "schisandra_", //版本号
|
||||||
|
expire: 24 * 60, //过期时间,默认为一天,单位为分钟
|
||||||
|
isEncrypt: true, //支持加密、解密数据处理
|
||||||
|
};
|
||||||
|
|
||||||
|
const setStorage = (key: string, value: any, expire: number = 24 * 60): boolean => {
|
||||||
|
//设定值
|
||||||
|
if (value === "" || value === null || value === undefined) {
|
||||||
|
//空值重置
|
||||||
|
value = null;
|
||||||
|
}
|
||||||
|
if (isNaN(expire) || expire < 0) {
|
||||||
|
//过期时间值合理性判断
|
||||||
|
throw new Error("Expire must be a number");
|
||||||
|
}
|
||||||
|
const data = {
|
||||||
|
value, //存储值
|
||||||
|
time: Date.now(), //存储日期
|
||||||
|
expire: Date.now() + 1000 * 60 * expire, //过期时间
|
||||||
|
};
|
||||||
|
//是否需要加密,判断装载加密数据或原数据
|
||||||
|
window[config.type].setItem(
|
||||||
|
autoAddPreFix(key),
|
||||||
|
config.isEncrypt ? encrypt(JSON.stringify(data)) : JSON.stringify(data),
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getStorageFromKey = (key: string) => {
|
||||||
|
//获取指定值
|
||||||
|
if (config.prefix) {
|
||||||
|
key = autoAddPreFix(key);
|
||||||
|
}
|
||||||
|
if (!window[config.type].getItem(key)) {
|
||||||
|
//不存在判断
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const storageVal = config.isEncrypt
|
||||||
|
? JSON.parse(decrypt(window[config.type].getItem(key) as string))
|
||||||
|
: JSON.parse(window[config.type].getItem(key) as string);
|
||||||
|
const now = Date.now();
|
||||||
|
if (now >= storageVal.expire) {
|
||||||
|
//过期销毁
|
||||||
|
removeStorageFromKey(key);
|
||||||
|
return null;
|
||||||
|
//不过期回值
|
||||||
|
} else {
|
||||||
|
return storageVal.value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const getAllStorage = () => {
|
||||||
|
//获取所有值
|
||||||
|
const storageList: any = {};
|
||||||
|
const keys = Object.keys(window[config.type]);
|
||||||
|
keys.forEach((key) => {
|
||||||
|
const value = getStorageFromKey(autoRemovePreFix(key));
|
||||||
|
if (value !== null) {
|
||||||
|
//如果值没有过期,加入到列表中
|
||||||
|
storageList[autoRemovePreFix(key)] = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return storageList;
|
||||||
|
};
|
||||||
|
const getStorageLength = () => {
|
||||||
|
//获取值列表长度
|
||||||
|
return window[config.type].length;
|
||||||
|
};
|
||||||
|
const removeStorageFromKey = (key: string) => {
|
||||||
|
//删除值
|
||||||
|
if (config.prefix) {
|
||||||
|
key = autoAddPreFix(key);
|
||||||
|
}
|
||||||
|
window[config.type].removeItem(key);
|
||||||
|
};
|
||||||
|
const clearStorage = () => {
|
||||||
|
window[config.type].clear();
|
||||||
|
};
|
||||||
|
const autoAddPreFix = (key: string) => {
|
||||||
|
//添加前缀,保持唯一性
|
||||||
|
const prefix = config.prefix || "";
|
||||||
|
return `${prefix}_${key}`;
|
||||||
|
};
|
||||||
|
const autoRemovePreFix = (key: string) => {
|
||||||
|
//删除前缀,进行增删改查
|
||||||
|
const lineIndex = config.prefix.length + 1;
|
||||||
|
return key.substr(lineIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
setStorage,
|
||||||
|
getStorageFromKey,
|
||||||
|
getAllStorage,
|
||||||
|
getStorageLength,
|
||||||
|
removeStorageFromKey,
|
||||||
|
clearStorage,
|
||||||
|
};
|
39
src/utils/localStorage/encry.ts
Normal file
39
src/utils/localStorage/encry.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/** @format */
|
||||||
|
|
||||||
|
import CryptoJS from "crypto-js";
|
||||||
|
|
||||||
|
const SECRET_KEY = CryptoJS.enc.Utf8.parse("3333e6e143439161"); //十六位十六进制数作为密钥
|
||||||
|
const SECRET_IV = CryptoJS.enc.Utf8.parse("e3bbe7e3ba84431a"); //十六位十六进制数作为密钥偏移量
|
||||||
|
|
||||||
|
const encrypt = (data: object | string): string => {
|
||||||
|
//加密
|
||||||
|
if (typeof data === "object") {
|
||||||
|
try {
|
||||||
|
data = JSON.stringify(data);
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error("encrypt error" + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const dataHex = CryptoJS.enc.Utf8.parse(data);
|
||||||
|
const encrypted = CryptoJS.AES.encrypt(dataHex, SECRET_KEY, {
|
||||||
|
iv: SECRET_IV,
|
||||||
|
mode: CryptoJS.mode.CBC,
|
||||||
|
padding: CryptoJS.pad.Pkcs7,
|
||||||
|
});
|
||||||
|
return encrypted.ciphertext.toString();
|
||||||
|
};
|
||||||
|
|
||||||
|
const decrypt = (data: string) => {
|
||||||
|
//解密
|
||||||
|
const encryptedHexStr = CryptoJS.enc.Hex.parse(data);
|
||||||
|
const str = CryptoJS.enc.Base64.stringify(encryptedHexStr);
|
||||||
|
const decrypt = CryptoJS.AES.decrypt(str, SECRET_KEY, {
|
||||||
|
iv: SECRET_IV,
|
||||||
|
mode: CryptoJS.mode.CBC,
|
||||||
|
padding: CryptoJS.pad.Pkcs7,
|
||||||
|
});
|
||||||
|
const decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
|
||||||
|
return decryptedStr.toString();
|
||||||
|
};
|
||||||
|
|
||||||
|
export {encrypt, decrypt};
|
10
src/utils/localStorage/interface.ts
Normal file
10
src/utils/localStorage/interface.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
/** @format */
|
||||||
|
|
||||||
|
interface globalConfig {
|
||||||
|
type: "localStorage" | "sessionStorage";
|
||||||
|
prefix: string;
|
||||||
|
expire: number;
|
||||||
|
isEncrypt: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type { globalConfig };
|
76
src/utils/localforage/index.ts
Normal file
76
src/utils/localforage/index.ts
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
/** @format */
|
||||||
|
|
||||||
|
import localforage from "localforage";
|
||||||
|
import CryptoJS from "crypto-js";
|
||||||
|
|
||||||
|
const SECRET_KEY = CryptoJS.enc.Utf8.parse("3333e6e143439161"); //十六位十六进制数作为密钥
|
||||||
|
const SECRET_IV = CryptoJS.enc.Utf8.parse("e3bbe7e3ba84431a"); //十六位十六进制数作为密钥偏移量
|
||||||
|
/**
|
||||||
|
* 加密
|
||||||
|
* @param data
|
||||||
|
* @param output
|
||||||
|
*/
|
||||||
|
export const encrypt = (data: string, output?: any) => {
|
||||||
|
const dataHex = CryptoJS.enc.Utf8.parse(data);
|
||||||
|
const encrypted = CryptoJS.AES.encrypt(dataHex, SECRET_KEY, {
|
||||||
|
iv: SECRET_IV,
|
||||||
|
mode: CryptoJS.mode.CBC,
|
||||||
|
padding: CryptoJS.pad.Pkcs7,
|
||||||
|
});
|
||||||
|
return encrypted.ciphertext.toString(output);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解密
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const decrypt = (data: string | null) => {
|
||||||
|
if (data === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const encryptedHex = CryptoJS.enc.Hex.parse(data);
|
||||||
|
const encryptedHexStr = CryptoJS.enc.Base64.stringify(encryptedHex);
|
||||||
|
const decrypted = CryptoJS.AES.decrypt(encryptedHexStr, SECRET_KEY, {
|
||||||
|
iv: SECRET_IV,
|
||||||
|
mode: CryptoJS.mode.CBC,
|
||||||
|
padding: CryptoJS.pad.Pkcs7,
|
||||||
|
});
|
||||||
|
const decryptedStr = decrypted.toString(CryptoJS.enc.Utf8);
|
||||||
|
return decryptedStr.toString();
|
||||||
|
};
|
||||||
|
|
||||||
|
export const handleLocalforage = {
|
||||||
|
config: async (options?: LocalForageOptions) => localforage.config(options || {}),
|
||||||
|
setItem: async (key: string, value: string): Promise<void> => {
|
||||||
|
await localforage.setItem(key, encrypt(value));
|
||||||
|
},
|
||||||
|
getItem: async function getItem<T>(key: string): Promise<T | string | null> {
|
||||||
|
try {
|
||||||
|
const value: any = decrypt(await localforage.getItem(key)) as any;
|
||||||
|
// 如果值是 undefined,返回 null
|
||||||
|
if (value === undefined) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// 如果值是 T 类型,直接返回
|
||||||
|
if (typeof value === "object" && value !== null) {
|
||||||
|
return value as T;
|
||||||
|
}
|
||||||
|
// 如果值是 string 类型,直接返回
|
||||||
|
return value as string;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error retrieving data from localforage:", error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeItem: async (key: string): Promise<void> => {
|
||||||
|
await localforage.removeItem(key);
|
||||||
|
},
|
||||||
|
clear: async () => {
|
||||||
|
return await localforage.clear();
|
||||||
|
},
|
||||||
|
createInstance: async (name: string) => {
|
||||||
|
return localforage.createInstance({
|
||||||
|
name,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
9
src/views/login/LoginPage.vue
Normal file
9
src/views/login/LoginPage.vue
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<template>
|
||||||
|
<AButton> 测试页面</AButton>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
0
src/views/login/index.scss
Normal file
0
src/views/login/index.scss
Normal file
15
src/vite-env.d.ts
vendored
15
src/vite-env.d.ts
vendored
@@ -1 +1,16 @@
|
|||||||
/// <reference types="vite/client" />
|
/// <reference types="vite/client" />
|
||||||
|
declare interface ImportMetaEnv {
|
||||||
|
readonly VITE_APP_BASE_API: string;
|
||||||
|
readonly VITE_APP_TITLE: string;
|
||||||
|
readonly VITE_API_BASE_URL: string;
|
||||||
|
readonly VITE_NODE_ENV: string;
|
||||||
|
readonly VITE_TITLE_NAME: string;
|
||||||
|
readonly VITE_APP_TOKEN_KEY?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ImportMeta {
|
||||||
|
readonly env: ImportMetaEnv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@@ -5,9 +5,12 @@
|
|||||||
"target": "ES2020",
|
"target": "ES2020",
|
||||||
"useDefineForClassFields": true,
|
"useDefineForClassFields": true,
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
"lib": [
|
||||||
|
"ES2020",
|
||||||
|
"DOM",
|
||||||
|
"DOM.Iterable"
|
||||||
|
],
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
|
|
||||||
/* Bundler mode */
|
/* Bundler mode */
|
||||||
"moduleResolution": "bundler",
|
"moduleResolution": "bundler",
|
||||||
"allowImportingTsExtensions": true,
|
"allowImportingTsExtensions": true,
|
||||||
@@ -16,12 +19,27 @@
|
|||||||
"moduleDetection": "force",
|
"moduleDetection": "force",
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
|
|
||||||
/* Linting */
|
/* Linting */
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
"noFallthroughCasesInSwitch": true
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"baseUrl": "./",
|
||||||
|
"types": [
|
||||||
|
"node"
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"@": [
|
||||||
|
"src"
|
||||||
|
],
|
||||||
|
"@/*": [
|
||||||
|
"src/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
|
"include": [
|
||||||
|
"src/**/*.ts",
|
||||||
|
"src/**/*.tsx",
|
||||||
|
"src/**/*.vue"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
@@ -7,7 +7,10 @@
|
|||||||
"moduleResolution": "bundler",
|
"moduleResolution": "bundler",
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"noEmit": true
|
"noEmit": true,
|
||||||
|
|
||||||
},
|
},
|
||||||
"include": ["vite.config.ts"]
|
"include": [
|
||||||
|
"vite.config.ts"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
130
vite.config.ts
130
vite.config.ts
@@ -1,7 +1,129 @@
|
|||||||
import { defineConfig } from 'vite'
|
import {defineConfig, loadEnv} from 'vite'
|
||||||
import vue from '@vitejs/plugin-vue'
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
import * as path from 'path'
|
||||||
|
import viteCompression from "vite-plugin-compression";
|
||||||
|
import {createHtmlPlugin} from "vite-plugin-html";
|
||||||
|
import {nodePolyfills} from "vite-plugin-node-polyfills";
|
||||||
|
import Components from 'unplugin-vue-components/vite';
|
||||||
|
import {AntDesignVueResolver} from 'unplugin-vue-components/resolvers';
|
||||||
|
import AutoImport from 'unplugin-auto-import/vite'
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
export default defineConfig(({mode}: { mode: string }): object => {
|
||||||
export default defineConfig({
|
const env: Record<string, string> = loadEnv(mode, process.cwd())
|
||||||
plugins: [vue()],
|
return {
|
||||||
|
resolve: {
|
||||||
|
//设置别名
|
||||||
|
alias: {
|
||||||
|
'@': path.resolve(__dirname, 'src')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plugins: [vue(),
|
||||||
|
Components({
|
||||||
|
dts: true,
|
||||||
|
dirs: ['src/components', 'src/views'],
|
||||||
|
resolvers: [
|
||||||
|
AntDesignVueResolver({
|
||||||
|
importStyle: "css-in-js",
|
||||||
|
resolveIcons: true
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
AutoImport({
|
||||||
|
//安装两行后你会发现在组件中不用再导入ref,reactive等
|
||||||
|
imports: ['vue', 'vue-router', 'pinia'],
|
||||||
|
dts: 'auto-import.d.ts',
|
||||||
|
//ant-design-vue
|
||||||
|
resolvers: [AntDesignVueResolver()],
|
||||||
|
eslintrc: {
|
||||||
|
enabled: false // 1、改为true用于生成eslint配置。2、生成后改回false,避免重复生成消耗
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
nodePolyfills(),
|
||||||
|
viteCompression({
|
||||||
|
verbose: true, // 是否在控制台中输出压缩结果
|
||||||
|
disable: false,
|
||||||
|
threshold: 10240, // 如果体积大于阈值,将被压缩,单位为b,体积过小时请不要压缩,以免适得其反
|
||||||
|
algorithm: "gzip", // 压缩算法,可选['gzip',' brotliccompress ','deflate ','deflateRaw']
|
||||||
|
ext: ".gz",
|
||||||
|
deleteOriginFile: true, // 源文件压缩后是否删除
|
||||||
|
}),
|
||||||
|
createHtmlPlugin({
|
||||||
|
minify: true,
|
||||||
|
/**
|
||||||
|
* 在这里写entry后,你将不需要在`index.html`内添加 script 标签,原有标签需要删除
|
||||||
|
* @default src/main.ts
|
||||||
|
*/
|
||||||
|
entry: "src/main.ts",
|
||||||
|
/**
|
||||||
|
* 如果你想将 `index.html`存放在指定文件夹,可以修改它,否则不需要配置
|
||||||
|
* @default index.html
|
||||||
|
*/
|
||||||
|
template: "index.html",
|
||||||
|
/**
|
||||||
|
* 需要注入 index.html ejs 模版的数据
|
||||||
|
*/
|
||||||
|
inject: {
|
||||||
|
data: {
|
||||||
|
title: env.VITE_TITLE_NAME,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
css: {
|
||||||
|
preprocessorOptions: {
|
||||||
|
scss: {
|
||||||
|
javascriptEnabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
modules: {
|
||||||
|
// 一般我们可以通过 generateScopedName 属性来对生成的类名进行自定义
|
||||||
|
// 其中,name 表示当前文件名,local 表示类名
|
||||||
|
generateScopedName: "[name]__[local]___[hash:base64:5]",
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
esbuild: {
|
||||||
|
drop: ["console", "debugger"],
|
||||||
|
},
|
||||||
|
build: {
|
||||||
|
outDir: "dist", // 指定输出路径
|
||||||
|
assetsDir: "assets", // 指定生成静态文件目录
|
||||||
|
assetsInlineLimit: "4096", // 小于此阈值的导入或引用资源将内联为 base64 编码
|
||||||
|
cssCodeSplit: true, // 启用 CSS 代码拆分
|
||||||
|
sourcemap: false, // 构建后是否生成 source map 文件
|
||||||
|
minify: "esbuild", // 指定使用哪种混淆器
|
||||||
|
write: true, // 启用将构建后的文件写入磁盘
|
||||||
|
emptyOutDir: true, // 构建时清空该目录
|
||||||
|
brotliSize: true, // 启用 brotli 压缩大小报告
|
||||||
|
chunkSizeWarningLimit: 4000, // chunk 大小警告的限制
|
||||||
|
watch: null, // 设置为 {} 则会启用 rollup 的监听器
|
||||||
|
rollupOptions: { // 自定义底层的 Rollup 打包配置
|
||||||
|
output: {
|
||||||
|
chunkFileNames: 'js/[name]-[hash].js', // 引入文件名的名称
|
||||||
|
entryFileNames: 'js/[name]-[hash].js', // 包的入口文件名称
|
||||||
|
assetFileNames: '[ext]/[name]-[hash].[ext]' // 资源文件像 字体,图片等
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
// 最小化拆分包
|
||||||
|
manualChunks(id: string) {
|
||||||
|
if (id.includes('node_modules')) {
|
||||||
|
return id.toString().split('node_modules/')[1].split('/')[0].toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
proxy: {
|
||||||
|
[env.VITE_APP_BASE_API]: {
|
||||||
|
//后端接口的baseurl
|
||||||
|
target: env.VITE_API_BASE_URL,
|
||||||
|
//是否允许跨域
|
||||||
|
changeOrigin: true,
|
||||||
|
rewrite: (path: string) => path.replace(RegExp(`^${env.VITE_APP_BASE_API}`), ""),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user