first commit
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
[*.{js,jsx,ts,tsx,vue}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = crlf
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
max_line_length = 120
|
||||
@@ -0,0 +1,5 @@
|
||||
# 本地运行端口号
|
||||
VITE_PORT = 8686
|
||||
|
||||
# API接口域名配置
|
||||
API_BASE_URL = https://api.example.com/
|
||||
@@ -0,0 +1,8 @@
|
||||
# 本地环境
|
||||
VITE_USER_NODE_ENV = development
|
||||
|
||||
# 公共基础路径
|
||||
VITE_PUBLIC_PATH = /
|
||||
|
||||
# proxy
|
||||
VITE_PROXY = [["/api","http://localhost:8080"]]
|
||||
@@ -0,0 +1,5 @@
|
||||
# 线上环境
|
||||
VITE_USER_NODE_ENV = production
|
||||
|
||||
# 公共基础路径
|
||||
VITE_PUBLIC_PATH = /
|
||||
@@ -0,0 +1,7 @@
|
||||
node_modules
|
||||
dist
|
||||
public
|
||||
*.md
|
||||
*.txt
|
||||
.vscode
|
||||
index.html
|
||||
@@ -0,0 +1,37 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
es2021: true,
|
||||
node: true
|
||||
},
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:vue/vue3-essential',
|
||||
'plugin:prettier/recommended' // 后续兼容prettier
|
||||
],
|
||||
overrides: [
|
||||
{
|
||||
env: {
|
||||
node: true
|
||||
},
|
||||
files: ['.eslintrc.{js,cjs}'],
|
||||
parserOptions: {
|
||||
sourceType: 'script'
|
||||
}
|
||||
}
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
parser: '@typescript-eslint/parser',
|
||||
sourceType: 'module'
|
||||
},
|
||||
plugins: ['@typescript-eslint', 'vue'],
|
||||
rules: {
|
||||
// Switch语句 https://zh-hans.eslint.org/docs/latest/rules/indent#switchcase
|
||||
indent: ['error', 2, { SwitchCase: 1 }],
|
||||
'linebreak-style': ['error', 'windows'],
|
||||
quotes: ['error', 'single'],
|
||||
semi: ['error', 'never']
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
@@ -0,0 +1,7 @@
|
||||
node_modules
|
||||
dist
|
||||
public
|
||||
*.md
|
||||
*.txt
|
||||
.vscode
|
||||
index.html
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"useTabs": false,
|
||||
"tabWidth": 2,
|
||||
"printWidth": 120,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"bracketSpacing": true,
|
||||
"semi": false,
|
||||
"endOfLine": "crlf"
|
||||
}
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"recommendations": ["Vue.volar"]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
PATH=D:\Software\Python36\Scripts\;D:\Software\Python36;D:\Software\VMware\VMware Workstation\bin\;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Users\Administrator\AppData\Local\Microsoft\WindowsApps;C:\Windows;C:\Windows\System32\OpenSSH\;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\system32;D:\Cache\Android\android-sdk\platform-tools;D:\Software\Git\cmd;D:\Software\JetBrains\IntelliJ IDEA 2023.3.5\bin;D:\Software\JetBrains\PhpStorm 2023.3.2\bin;D:\Software\JetBrains\PyCharm 2023.3.4\bin;c:\Users\Administrator\AppData\Local\Programs\cursor\resources\app\bin;C:\ProgramData\ComposerSetup\bin;D:\Software\Tencent\΢ÐÅweb¿ª·¢Õß¹¤¾ß\dll;C:\Program Files\python;C:\Program Files\python\Scripts;D:\BtSoft\panel\script;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files\NVIDIA Corporation\NVIDIA NvDLISR;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;D:\Software\TortoiseGit\bin;D:\Software\nvm;D:\Software\nvm4w\nodejs;D:\Software\phpstudy_pro\Extensions\php\php7.4.3nts;C:\Program Files\PuTTY\;d:\Software\Trae CN\bin;D:\Software\Python36\;D:\Software\Python39\Scripts\;D:\Software\Python39\;D:\Software\Python310\Scripts\;D:\Software\Python310\;C:\Users\Administrator\AppData\Local\JetBrains\Toolbox\scripts;D:\phpEnv\php\php-8.0;D:\phpEnv\server\mysql\mysql-5.7\bin;D:\phpEnv\tools\Composer;C:\Users\Administrator\AppData\Roaming\Composer\vendor\bin;D:\Software\Microsoft VS Code\bin;C:\Users\Administrator\AppData\Local\Programs\Ollama
|
||||
@@ -0,0 +1,46 @@
|
||||
# Vue 3 + TypeScript + Vite
|
||||
|
||||
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
||||
|
||||
Learn more about the recommended Project Setup and IDE Support in the [Vue Docs TypeScript Guide](https://vuejs.org/guide/typescript/overview.html#project-setup).
|
||||
|
||||
# 目录结构
|
||||
```
|
||||
| .env
|
||||
| .env.development
|
||||
| .env.production
|
||||
| .gitignore
|
||||
| index.html
|
||||
| package-lock.json
|
||||
| package.json
|
||||
| README.md
|
||||
| tree.txt
|
||||
| tsconfig.json
|
||||
| tsconfig.node.json
|
||||
| vite.config.ts
|
||||
|
|
||||
+---.vscode
|
||||
| extensions.json
|
||||
|
|
||||
+---build
|
||||
| index.ts
|
||||
|
|
||||
+---node_modules
|
||||
+---public
|
||||
| vite.svg
|
||||
|
|
||||
+---src
|
||||
| | App.vue
|
||||
| | main.ts
|
||||
| | style.css
|
||||
| | vite-env.d.ts
|
||||
| |
|
||||
| +---assets
|
||||
| | vue.svg
|
||||
| |
|
||||
| \---components
|
||||
| HelloWorld.vue
|
||||
|
|
||||
\---types
|
||||
index.d.ts
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
// 环境变量处理方法
|
||||
export function wrapperEnv(envConf: Recordable): ViteEnv {
|
||||
const ret: Record<string, string | number | boolean> = {};
|
||||
|
||||
for (const envName of Object.keys(envConf)) {
|
||||
let realName = envConf[envName].replace(/\\n/g, "\n");
|
||||
realName = realName === "true" ? true : realName === "false" ? false : realName;
|
||||
if (envName === "VITE_PORT") realName = Number(realName);
|
||||
ret[envName] = realName;
|
||||
if (typeof realName === "string") {
|
||||
process.env[envName] = realName;
|
||||
} else if (typeof realName === "object") {
|
||||
process.env[envName] = JSON.stringify(realName);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
/**
|
||||
* * 扩展setup插件,支持在script标签中使用name属性
|
||||
* usage: <script setup name="MyComp"></script>
|
||||
*/
|
||||
import VueSetupExtend from 'vite-plugin-vue-setup-extend'
|
||||
|
||||
export function createVitePlugins(viteEnv: Record<string, string>, isBuild: boolean): any[] {
|
||||
const plugins = [
|
||||
vue(),
|
||||
VueSetupExtend(),
|
||||
]
|
||||
|
||||
return plugins
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import js from "@eslint/js";
|
||||
import globals from "globals";
|
||||
import tseslint from "typescript-eslint";
|
||||
import pluginVue from "eslint-plugin-vue";
|
||||
import { defineConfig } from "eslint/config";
|
||||
|
||||
|
||||
export default defineConfig([
|
||||
{ files: ["**/*.{js,mjs,cjs,ts,vue}"], plugins: { js }, extends: ["js/recommended"] },
|
||||
{ files: ["**/*.{js,mjs,cjs,ts,vue}"], languageOptions: { globals: {...globals.browser, ...globals.node} } },
|
||||
tseslint.configs.recommended,
|
||||
pluginVue.configs["flat/essential"],
|
||||
{ files: ["**/*.vue"], languageOptions: { parserOptions: { parser: tseslint.parser } } },
|
||||
]);
|
||||
@@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + Vue + TS</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
Generated
+5996
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"name": "vue3project",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vue-tsc -b && vite build",
|
||||
"type-check": "vue-tsc --noEmit",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint --fix --ext .ts,.tsx,.vue,.js,.jsx --max-warnings 0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"@vueuse/core": "^13.1.0",
|
||||
"axios": "^1.8.4",
|
||||
"echarts": "^5.6.0",
|
||||
"element-plus": "^2.9.8",
|
||||
"js-cookie": "^3.0.5",
|
||||
"pinia": "^3.0.2",
|
||||
"pinia-plugin-persistedstate": "^4.2.0",
|
||||
"vue": "^3.5.13",
|
||||
"vue-i18n": "^11.1.3",
|
||||
"vue-router": "^4.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.25.1",
|
||||
"@types/node": "^22.14.1",
|
||||
"@typescript-eslint/eslint-plugin": "^8.31.0",
|
||||
"@typescript-eslint/parser": "^8.31.0",
|
||||
"@vitejs/plugin-vue": "^5.2.2",
|
||||
"@vue/tsconfig": "^0.7.0",
|
||||
"eslint": "^9.25.1",
|
||||
"eslint-config-prettier": "^10.1.2",
|
||||
"eslint-plugin-prettier": "^5.2.6",
|
||||
"eslint-plugin-vue": "^10.0.0",
|
||||
"globals": "^16.0.0",
|
||||
"naive-ui": "^2.41.0",
|
||||
"prettier": "^3.5.3",
|
||||
"sass": "^1.87.0",
|
||||
"sass-embedded": "^1.87.0",
|
||||
"typescript": "~5.7.2",
|
||||
"typescript-eslint": "^8.31.0",
|
||||
"unplugin-vue-components": "^28.5.0",
|
||||
"unplugin-vue-router": "^0.12.0",
|
||||
"vite": "^6.3.1",
|
||||
"vite-plugin-vue-setup-extend": "^0.4.0",
|
||||
"vue-tsc": "^2.2.8"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,4 @@
|
||||
root: pc
|
||||
path: C:\Program Files\nodejs
|
||||
arch: 64
|
||||
proxy: none
|
||||
@@ -0,0 +1,48 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref ,provide} from 'vue'
|
||||
import * as echarts from "echarts";
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
//通过provide提供echarts
|
||||
provide("echarts", echarts);
|
||||
|
||||
const I18n = useI18n()
|
||||
const { locale } = useI18n()
|
||||
// 切换语言更改locale.value的值即可但要跟你index.js中message设置的值一致!
|
||||
|
||||
const translate = (lang) => {
|
||||
locale.value = lang
|
||||
localStorage.setItem('lang', lang)
|
||||
}
|
||||
|
||||
const type = ref('light')
|
||||
const onChange = (e) => {
|
||||
document.documentElement.setAttribute('theme-mode', type.value)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div>
|
||||
<p>{{ $t('welcome') }}</p>
|
||||
</div>
|
||||
<button @click="translate('zh-cn')">切换为中文</button>
|
||||
<button @click="translate('en-us')">切换为英文</button>
|
||||
</div>
|
||||
<div>
|
||||
<el-select style="width: 80px;margin: 10px;" v-model="type" @change="onChange">
|
||||
<el-option label="light" value="light" />
|
||||
<el-option label="dark" value="dark" />
|
||||
<el-option label="red" value="red" />
|
||||
</el-select>
|
||||
</div>
|
||||
<router-link to="/"> 去首页 </router-link> 丨 <router-link to="/login"> 去登录 </router-link> 丨 <router-link to="/demo"> 查看demo </router-link>
|
||||
<router-view />
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
#app {
|
||||
background-color: $primaryColor;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,6 @@
|
||||
import { defRequest } from '../utils/request'
|
||||
|
||||
export const loginApi = (params: Record<string, unknown>) => {
|
||||
// 设置 showLoading,timeout 会覆盖index.ts里的默认值
|
||||
return defRequest.post<Record<string, unknown>>('/login', params, { showLoading: false, timeout: 1000 })
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
:root[theme-mode='light'] {
|
||||
--bg-color: #fff;
|
||||
--text-color: #000
|
||||
}
|
||||
|
||||
:root[theme-mode='dark'] {
|
||||
--bg-color: #2c2c2c;
|
||||
--text-color: #fff
|
||||
}
|
||||
|
||||
:root[theme-mode='red'] {
|
||||
--bg-color: rgb(0, 128, 255);
|
||||
--text-color: red;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
:root {
|
||||
color: var(--text-color);
|
||||
background-color: var(--bg-color);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
$primaryColor: #316c72;
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 496 B |
@@ -0,0 +1,41 @@
|
||||
<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>
|
||||
@@ -0,0 +1,6 @@
|
||||
export default {
|
||||
welcome: 'Welcome',
|
||||
login: 'Login',
|
||||
register: 'Register',
|
||||
// 可以根据实际需求添加更多翻译项
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
import {createI18n} from 'vue-i18n'
|
||||
// 从语言包文件中导入语言包对象
|
||||
import zh from '@language/zh-CN'
|
||||
import en from '@language/en-US'
|
||||
|
||||
const messages = {
|
||||
'zh-cn': zh,
|
||||
'en-us': en
|
||||
}
|
||||
|
||||
const language = (navigator.language || 'en').toLocaleLowerCase() // 这是获取浏览器的语言
|
||||
// 获取浏览器当前使用的语言,并进行处理
|
||||
const i18n = createI18n({
|
||||
legacy: false,
|
||||
locale: localStorage.getItem('lang') || language.split('-')[0] || 'en', // 首先从缓存里拿,没有的话就用浏览器语言,
|
||||
fallbackLocale: 'zh-cn', // 设置备用语言
|
||||
messages,
|
||||
})
|
||||
|
||||
export default i18n
|
||||
@@ -0,0 +1,6 @@
|
||||
export default {
|
||||
welcome: '欢迎',
|
||||
login: '登录',
|
||||
register: '注册',
|
||||
// 可以根据实际需求添加更多翻译项
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
import { createApp } from 'vue'
|
||||
import pinia from '@/store'
|
||||
import './style.css'
|
||||
import '@css/index.scss'
|
||||
import App from './App.vue'
|
||||
import * as echarts from 'echarts'
|
||||
import router from '@/router/index'
|
||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
|
||||
import i18n from './language'
|
||||
import ElementPlus from 'element-plus'
|
||||
import 'element-plus/dist/index.css'
|
||||
|
||||
// 初始化pinia插件
|
||||
pinia.use(piniaPluginPersistedstate)
|
||||
|
||||
// 创建并配置Vue应用
|
||||
const app = createApp(App)
|
||||
.use(router)
|
||||
.use(pinia)
|
||||
.use(i18n)
|
||||
.use(ElementPlus)
|
||||
|
||||
// 全局挂载echarts
|
||||
app.config.globalProperties.$echarts = echarts
|
||||
|
||||
// 挂载应用
|
||||
app.mount('#app')
|
||||
@@ -0,0 +1,58 @@
|
||||
import { Router, createRouter, createWebHistory } from 'vue-router'
|
||||
|
||||
/** 自动导入 src/router/modules 下的静态路由
|
||||
* import.meta.glob使用说明:https://cn.vitejs.dev/guide/features#glob-import
|
||||
*/
|
||||
const modules: Record<string, unknown> = import.meta.glob(['./modules/**/*.ts'], {
|
||||
eager: true
|
||||
})
|
||||
|
||||
/** 初始路由 **/
|
||||
const routes: unknown[] = []
|
||||
|
||||
Object.keys(modules).forEach((key) => {
|
||||
const module = (modules[key] as { default: unknown }).default;
|
||||
if (Array.isArray(module)) {
|
||||
for (const item of module) {
|
||||
routes.push(item)
|
||||
}
|
||||
} else {
|
||||
routes.push(module)
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 创建路由实例
|
||||
* createRouter选项有:https://router.vuejs.org/zh/api/interfaces/RouterOptions.html
|
||||
* hash模式使用createWebHashHistory(): https://router.vuejs.org/zh/api/#Functions-createWebHashHistory
|
||||
*/
|
||||
export const router: Router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes,
|
||||
strict: true,
|
||||
scrollBehavior(_to, from, savedPosition) {
|
||||
return new Promise((resolve) => {
|
||||
if (savedPosition) {
|
||||
return savedPosition
|
||||
} else {
|
||||
if (from.meta.saveSrollTop) {
|
||||
const top: number = document.documentElement.scrollTop || document.body.scrollTop
|
||||
resolve({ left: 0, top })
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 路由守卫
|
||||
* https://router.vuejs.org/zh/guide/advanced/navigation-guards.html
|
||||
*/
|
||||
router.beforeEach((to, _from, next) => {
|
||||
// isAuthenticated 代表你的鉴权
|
||||
const isAuthenticated = true
|
||||
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
|
||||
else next()
|
||||
})
|
||||
|
||||
export default router
|
||||
@@ -0,0 +1,12 @@
|
||||
const routes = [
|
||||
{
|
||||
path: '/',
|
||||
component: () => import('@/views/default/home.vue')
|
||||
},
|
||||
{
|
||||
path: '/login',
|
||||
component: () => import('@/views/default/login.vue') //路由懒加载
|
||||
}
|
||||
]
|
||||
|
||||
export default routes
|
||||
@@ -0,0 +1,7 @@
|
||||
import { createPinia } from 'pinia'
|
||||
import persist from 'pinia-plugin-persistedstate';
|
||||
|
||||
const pinia = createPinia();
|
||||
pinia.use(persist);
|
||||
|
||||
export default pinia
|
||||
@@ -0,0 +1,31 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { UserState } from 'types/store'
|
||||
import { getToken, setToken } from '@/utils/auth'
|
||||
|
||||
// 第一个参数是id,唯一
|
||||
export const useUserStore = defineStore('user', {
|
||||
state: () => {
|
||||
return {
|
||||
token: getToken() || 'YUNZER68205747',
|
||||
userInfo: { name: 'yunzer', phone: '19895983967' }
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
namePic: (state) => state.userInfo.name.substring(0, 1)
|
||||
},
|
||||
actions: {
|
||||
setToken(token: string) {
|
||||
this.token = token
|
||||
},
|
||||
setUserInfo(userInfo: UserState['userInfo']) {
|
||||
this.userInfo = { ...this.userInfo, ...userInfo }
|
||||
}
|
||||
},
|
||||
setToken(token: string) {
|
||||
this.token = token
|
||||
setToken({
|
||||
token,
|
||||
expires: 30
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,19 @@
|
||||
import {defineStore} from 'pinia'
|
||||
import {getToken,setToken} from "@/utils/storage.ts";
|
||||
export const useSettingsStore = defineStore('settings', {
|
||||
id: 'settings', // id必填,且需要唯一
|
||||
state: () => {
|
||||
return {
|
||||
menuCollapse: false,//// 是否水平折叠收起菜单
|
||||
// 布局方式 Classic 经典布局 Streamline 单行布局
|
||||
layoutMode: getToken('layoutMode')?getToken('layoutMode'):'Classic'
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
changeSetting({ key, value }) {
|
||||
//改变全局变量的方法
|
||||
this[key] = value
|
||||
setToken(key, value)
|
||||
},
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,25 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { ref } from 'vue';
|
||||
import type { User } from '@/types/user';
|
||||
|
||||
export const usersStore = defineStore('users', () => {
|
||||
const userInfo = ref<User>({
|
||||
name:'abc',
|
||||
avatar: '123', // 头像
|
||||
mobile: '13221091091', // 手机号
|
||||
account: 'lita', // 用户名
|
||||
id: 1
|
||||
});
|
||||
|
||||
const setUserInfo = (u:User) =>{
|
||||
userInfo.value = u;
|
||||
}
|
||||
|
||||
const clearUserInfo = () =>{
|
||||
// void 是用来创建 undefined,不管它后面跟个啥,得到的都是 undefined;
|
||||
userInfo.value = void 0;
|
||||
// 上面的代码代表 userinfo.value = undefined;
|
||||
}
|
||||
|
||||
return { userInfo ,setUserInfo, clearUserInfo }
|
||||
},{persist: true})
|
||||
@@ -0,0 +1,79 @@
|
||||
:root {
|
||||
font-family: 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import Cookies from 'js-cookie'
|
||||
|
||||
export const TokenKey = 'yunzer-token'
|
||||
|
||||
type ExpiresData = Date | number
|
||||
export interface TokenInfo {
|
||||
token: string
|
||||
expires: ExpiresData
|
||||
}
|
||||
|
||||
export function getToken() {
|
||||
return Cookies.get(TokenKey)
|
||||
}
|
||||
|
||||
export function setToken(data: TokenInfo) {
|
||||
const { token, expires } = data
|
||||
return expires ? Cookies.set(TokenKey, token, { expires: expires }) : Cookies.set(TokenKey, token)
|
||||
}
|
||||
|
||||
export function removeToken() {
|
||||
return Cookies.remove(TokenKey)
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* 创建实例,可以多个,当你需要请求多个不同域名的接口时
|
||||
*/
|
||||
import Request from './request'
|
||||
import { getToken } from '@/utils/auth'
|
||||
|
||||
const defRequest = new Request({
|
||||
// 这里用 Easy Mock 模拟了真实接口
|
||||
baseURL: import.meta.env.VITE_API_BASE_URL,
|
||||
timeout: 5000,
|
||||
showLoading: true,
|
||||
interceptorHooks: {
|
||||
requestInterceptor: (config) => {
|
||||
const token = getToken()
|
||||
if (token) {
|
||||
config.headers.Authorization = token
|
||||
}
|
||||
return config
|
||||
},
|
||||
requestInterceptorCatch: (err) => {
|
||||
return err
|
||||
},
|
||||
responseInterceptor: (res) => {
|
||||
return res.data
|
||||
},
|
||||
responseInterceptorCatch: (err) => {
|
||||
return Promise.reject(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 创建其他示例,然后导出
|
||||
// const otherRequest = new Request({...})
|
||||
|
||||
export { defRequest }
|
||||
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* 封装axios
|
||||
* axios 实例的类型为 AxiosInstance,请求需要传入的参数类型为 AxiosRequestConfig,响应的数据类型为 AxiosResponse,InternalAxiosRequestConfig 继承于 AxiosRequestConfig
|
||||
*/
|
||||
import axios, { AxiosInstance, AxiosRequestConfig, InternalAxiosRequestConfig, AxiosResponse } from 'axios'
|
||||
import { ErrMessage } from './status'
|
||||
|
||||
// 自定义请求返回数据的类型
|
||||
interface Data<T> {
|
||||
data: T
|
||||
code: string
|
||||
success: boolean
|
||||
}
|
||||
|
||||
// 扩展 InternalAxiosRequestConfig,让每个请求都可以控制是否要loading
|
||||
interface RequestInternalAxiosRequestConfig extends InternalAxiosRequestConfig {
|
||||
showLoading?: boolean
|
||||
}
|
||||
|
||||
// 拦截器
|
||||
interface InterceptorHooks {
|
||||
requestInterceptor?: (config: RequestInternalAxiosRequestConfig) => RequestInternalAxiosRequestConfig
|
||||
requestInterceptorCatch?: (error: unknown) => unknown
|
||||
responseInterceptor?: (response: AxiosResponse) => AxiosResponse
|
||||
responseInterceptorCatch?: (error: unknown) => unknown
|
||||
}
|
||||
// 扩展 AxiosRequestConfig,showLoading 给实例默认增加loading,interceptorHooks 拦截
|
||||
interface RequestConfig extends AxiosRequestConfig {
|
||||
showLoading?: boolean
|
||||
interceptorHooks?: InterceptorHooks
|
||||
}
|
||||
|
||||
class Request {
|
||||
config: RequestConfig
|
||||
instance: AxiosInstance
|
||||
loading?: boolean // 用loading指代加载动画状态
|
||||
|
||||
constructor(options: RequestConfig) {
|
||||
this.config = options
|
||||
this.instance = axios.create(options)
|
||||
this.setupInterceptor()
|
||||
}
|
||||
|
||||
// 类型参数的作用,T决定AxiosResponse实例中data的类型
|
||||
request<T>(config: RequestConfig): Promise<T> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.instance
|
||||
.request<Data<T>, Data<T>>(config)
|
||||
.then((res) => {
|
||||
resolve(res.data)
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 封装常用方法
|
||||
// 移除了默认的 any 类型,要求调用者显式指定类型
|
||||
get<T>(url: string, params?: object, _object = {}): Promise<T> {
|
||||
return this.request({ url, params, ..._object, method: 'GET' })
|
||||
}
|
||||
|
||||
post<T>(url: string, params?: object, _object = {}): Promise<T> {
|
||||
return this.request({ url, params, ..._object, method: 'POST' })
|
||||
}
|
||||
|
||||
delete<T>(url: string, params?: object, _object = {}): Promise<T> {
|
||||
return this.request({ url, params, ..._object, method: 'DELETE' })
|
||||
}
|
||||
|
||||
patch<T>(url: string, params?: object, _object = {}): Promise<T> {
|
||||
return this.request({ url, params, ..._object, method: 'PATCH' })
|
||||
}
|
||||
|
||||
put<T>(url: string, params?: object, _object = {}): Promise<T> {
|
||||
return this.request({ url, params, ..._object, method: 'PUT' })
|
||||
}
|
||||
|
||||
// 自定义拦截器 https://axios-http.com/zh/docs/interceptors
|
||||
setupInterceptor(): void {
|
||||
/**
|
||||
* 通用拦截
|
||||
*/
|
||||
this.instance.interceptors.request.use((config: RequestInternalAxiosRequestConfig) => {
|
||||
if (config.showLoading) {
|
||||
// 加载loading动画
|
||||
this.loading = true
|
||||
}
|
||||
return config
|
||||
})
|
||||
// 响应后关闭loading
|
||||
this.instance.interceptors.response.use(
|
||||
(res) => {
|
||||
if (this.loading) this.loading = false
|
||||
return res
|
||||
},
|
||||
(err) => {
|
||||
const { response, message } = err
|
||||
if (this.loading) this.loading = false
|
||||
// 根据不同状态码,返回不同信息
|
||||
const messageStr = response ? ErrMessage(response.status) : message || '请求失败,请重试'
|
||||
window.alert(messageStr)
|
||||
return Promise.reject(err)
|
||||
}
|
||||
)
|
||||
/**
|
||||
* 使用通用实例里的拦截,两个拦截都会生效,返回值以后一个执行的为准
|
||||
*/
|
||||
// 请求拦截
|
||||
this.instance.interceptors.request.use(
|
||||
this.config?.interceptorHooks?.requestInterceptor,
|
||||
this.config?.interceptorHooks?.requestInterceptorCatch
|
||||
)
|
||||
// 响应拦截
|
||||
this.instance.interceptors.response.use(
|
||||
this.config?.interceptorHooks?.responseInterceptor,
|
||||
this.config?.interceptorHooks?.responseInterceptorCatch
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Request
|
||||
@@ -0,0 +1,41 @@
|
||||
export const ErrMessage = (status: number | string): string => {
|
||||
let message: string = ''
|
||||
switch (status) {
|
||||
case 400:
|
||||
message = '请求错误!请您稍后重试'
|
||||
break
|
||||
case 401:
|
||||
message = '未授权!请您重新登录'
|
||||
break
|
||||
case 403:
|
||||
message = '当前账号无访问权限!'
|
||||
break
|
||||
case 404:
|
||||
message = '访问的资源不存在!请您稍后重试'
|
||||
break
|
||||
case 405:
|
||||
message = '请求方式错误!请您稍后重试'
|
||||
break
|
||||
case 408:
|
||||
message = '请求超时!请您稍后重试'
|
||||
break
|
||||
case 500:
|
||||
message = '服务异常!请您稍后重试'
|
||||
break
|
||||
case 501:
|
||||
message = '不支持此请求!请您稍后重试'
|
||||
break
|
||||
case 502:
|
||||
message = '网关错误!请您稍后重试'
|
||||
break
|
||||
case 503:
|
||||
message = '服务不可用!请您稍后重试'
|
||||
break
|
||||
case 504:
|
||||
message = '网关超时!请您稍后重试'
|
||||
break
|
||||
default:
|
||||
message = '请求失败!请您稍后重试'
|
||||
}
|
||||
return message
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref ,provide} from 'vue'
|
||||
import * as echarts from "echarts";
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
//通过provide提供echarts
|
||||
provide("echarts", echarts);
|
||||
|
||||
const I18n = useI18n()
|
||||
const { locale } = useI18n()
|
||||
// 切换语言更改locale.value的值即可但要跟你index.js中message设置的值一致!
|
||||
|
||||
const translate = (lang) => {
|
||||
locale.value = lang
|
||||
localStorage.setItem('lang', lang)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div>
|
||||
<p>{{ $t('welcome') }}</p>
|
||||
</div>
|
||||
<button @click="translate('zh-cn')">切换为中文</button>
|
||||
<button @click="translate('en-us')">切换为英文</button>
|
||||
</div>
|
||||
<router-link to="/"> 去首页 </router-link> 丨 <router-link to="/login"> 去登录 </router-link> 丨 <router-link to="/demo"> 查看demo </router-link>
|
||||
<router-view />
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,55 @@
|
||||
<template>
|
||||
<div class="right-content">
|
||||
<div ref="Chart" style="width: 800px; height: 500px"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, getCurrentInstance, ref } from 'vue'
|
||||
let internalInstance = getCurrentInstance(); //获取当前实例
|
||||
let echarts = internalInstance.appContext.config.globalProperties.$echarts; //获取echarts实例
|
||||
|
||||
|
||||
//通过ref获取html元素
|
||||
const Chart = ref();
|
||||
|
||||
const init = () => {
|
||||
// 渲染echarts的父元素
|
||||
var infoEl = Chart.value;
|
||||
|
||||
// light dark
|
||||
var myChart = echarts.init(infoEl, "light"); //初始化echarts实例
|
||||
|
||||
// 指定图表的配置项和数据 树图
|
||||
var option = {
|
||||
title: {
|
||||
text: 'ECharts 入门示例'
|
||||
},
|
||||
tooltip: {},
|
||||
xAxis: {
|
||||
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
|
||||
},
|
||||
yAxis: {},
|
||||
series: [
|
||||
{
|
||||
name: '销量',
|
||||
type: 'bar',
|
||||
data: [5, 20, 36, 10, 10, 20]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 使用刚指定的配置项和数据显示图表。
|
||||
myChart.setOption(option);
|
||||
window.onresize = function () {
|
||||
myChart.resize()
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
init()
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style scope lang="scss"></style>
|
||||
@@ -0,0 +1,22 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
|
||||
defineOptions({
|
||||
name: 'V-home'
|
||||
})
|
||||
|
||||
const userStore = useUserStore()
|
||||
// 获取state使用computed或者使用storeToRefs,直接使用不具备响应式(拿到的永远是初次的值)
|
||||
const username = computed(() => userStore.userInfo.name)
|
||||
// 获取getter使用storeToRefs,或者直接使用,在模板里 userStore.namePic
|
||||
const { token } = storeToRefs(userStore)
|
||||
const namePic = computed(() => userStore.userInfo.name + '的头像') // 根据store结构,使用userInfo.name生成头像信息
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>Hello: {{ namePic }}, your name is {{ username }}, your token is {{ token }}</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,51 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useUserStore } from '@store/modules/user'
|
||||
import { loginApi } from '@/api/login'
|
||||
|
||||
defineOptions({
|
||||
name: 'V-login'
|
||||
})
|
||||
|
||||
const userStore = useUserStore()
|
||||
const { userInfo, token } = storeToRefs(userStore)
|
||||
let userName = ref(userInfo.value.name)
|
||||
let userToken = ref(token)
|
||||
|
||||
const updateUserName = () => {
|
||||
userStore.setUserInfo({
|
||||
name: userName.value
|
||||
})
|
||||
}
|
||||
const updateUserToken = () => {
|
||||
userStore.setToken(userToken.value)
|
||||
}
|
||||
|
||||
const login = () => {
|
||||
loginApi({
|
||||
name: userName.value
|
||||
})
|
||||
.then((res) => {
|
||||
userName.value = res.name
|
||||
userToken.value = res.token
|
||||
updateUserToken()
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>login page</div>
|
||||
name:
|
||||
<input type="text" v-model="userName" @input="updateUserName" />
|
||||
<br />
|
||||
token:
|
||||
<input type="text" v-model="userToken" />
|
||||
<hr />
|
||||
<button @click="login">login</button>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext", // 将代码编译为最新版本的 JS
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext", // 使用 ES Module 格式打包编译后的文件
|
||||
"lib": ["ESNext", "DOM", "DOM.Iterable"], // 引入 ES 最新特性和 DOM 接口的类型定义
|
||||
"skipLibCheck": true, // 跳过对 .d.ts 文件的类型检查
|
||||
"esModuleInterop": true, // 允许使用 import 引入使用 export = 导出的内容
|
||||
"sourceMap": true, // 用来指定编译时是否生成.map文件
|
||||
"allowJs": false, // 是否允许使用js
|
||||
"baseUrl": ".", // 查询的基础路径
|
||||
"paths": {
|
||||
// 路径映射,配合别名使用
|
||||
"@": ["src"],
|
||||
"@/*": ["src/*"],
|
||||
"@build/*": ["build/*"],
|
||||
"@language/*": ["src/language/*"],
|
||||
"@store/*": ["src/store/modules/*"],
|
||||
"#/*": ["types/*"]
|
||||
},
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "node", // 使用 Node/bundler 的模块解析策略
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true, // 允许引入 JSON 文件
|
||||
"isolatedModules": true, // 要求所有文件都是 ES Module 模块。
|
||||
"noEmit": true, // 不输出文件,即编译后不会生成任何js文件
|
||||
"jsx": "preserve", // 保留原始的 JSX 代码,不进行编译
|
||||
|
||||
/* Linting */
|
||||
"strict": true, // 开启所有严格的类型检查
|
||||
"noUnusedLocals": true, // 报告未使用的局部变量的错误
|
||||
"noUnusedParameters": true, // 报告函数中未使用参数的错误
|
||||
"noFallthroughCasesInSwitch": true // 确保switch语句中的任何非空情况都包含
|
||||
},
|
||||
"include": [
|
||||
// 需要检测的文件
|
||||
"src/**/*.ts",
|
||||
"build/*.ts",
|
||||
"src/**/*.d.ts",
|
||||
"src/**/*.tsx",
|
||||
"src/**/*.vue",
|
||||
"mock/*.ts",
|
||||
"types/*.d.ts",
|
||||
"vite.config.ts"
|
||||
],
|
||||
"exclude": [
|
||||
// 不需要检测的文件
|
||||
"dist",
|
||||
"**/*.js",
|
||||
"node_modules"
|
||||
],
|
||||
"references": [{ "path": "./tsconfig.node.json" }] // 为文件进行不同配置
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true, // 对于引用项目必须设置该属性
|
||||
"skipLibCheck": true, // 跳过对 .d.ts 文件的类型检查
|
||||
"module": "ESNext", // 使用 ES Module 格式打包编译后的文件
|
||||
"moduleResolution": "Node", // 使用 Node/bundler 的模块解析策略
|
||||
"allowSyntheticDefaultImports": true // 允许使用 import 导入使用 export = 导出的默认内容
|
||||
},
|
||||
"include": ["build/*.ts", "types/*.d.ts", "vite.config.ts"]
|
||||
}
|
||||
Vendored
+26
@@ -0,0 +1,26 @@
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
// @ts-nocheck
|
||||
// Generated by unplugin-vue-router. ‼️ DO NOT MODIFY THIS FILE ‼️
|
||||
// It's recommended to commit this file.
|
||||
// Make sure to add this file to your tsconfig.json file as an "includes" or "files" entry.
|
||||
|
||||
declare module 'vue-router/auto-routes' {
|
||||
import type {
|
||||
RouteRecordInfo,
|
||||
ParamValue,
|
||||
ParamValueOneOrMore,
|
||||
ParamValueZeroOrMore,
|
||||
ParamValueZeroOrOne,
|
||||
} from 'vue-router'
|
||||
|
||||
/**
|
||||
* Route name map generated by unplugin-vue-router
|
||||
*/
|
||||
export interface RouteNamedMap {
|
||||
'/default/demo': RouteRecordInfo<'/default/demo', '/default/demo', Record<never, never>, Record<never, never>>,
|
||||
'/default/demo-i18n': RouteRecordInfo<'/default/demo-i18n', '/default/demo-i18n', Record<never, never>, Record<never, never>>,
|
||||
'/default/home': RouteRecordInfo<'/default/home', '/default/home', Record<never, never>, Record<never, never>>,
|
||||
'/default/login': RouteRecordInfo<'/default/login', '/default/login', Record<never, never>, Record<never, never>>,
|
||||
}
|
||||
}
|
||||
Vendored
+22
@@ -0,0 +1,22 @@
|
||||
type TargetContext = "_self" | "_blank";
|
||||
type EmitType = (event: string, ...args: any[]) => void;
|
||||
type AnyFunction<T> = (...args: any[]) => T;
|
||||
type PropType<T> = VuePropType<T>;
|
||||
type Writable<T> = {
|
||||
-readonly [P in keyof T]: T[P];
|
||||
};
|
||||
type Nullable<T> = T | null;
|
||||
type NonNullable<T> = T extends null | undefined ? never : T;
|
||||
type Recordable<T = any> = Record<string, T>;
|
||||
|
||||
interface Fn<T = any, R = T> {
|
||||
(...arg: T[]): R;
|
||||
}
|
||||
interface PromiseFn<T = any, R = T> {
|
||||
(...arg: T[]): Promise<R>;
|
||||
}
|
||||
interface ViteEnv {
|
||||
VITE_USER_NODE_ENV: "development" | "production";
|
||||
VITE_PUBLIC_PATH: string;
|
||||
VITE_PORT: number;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export interface UserState {
|
||||
token: string
|
||||
userInfo: { name?: string; phone?: string }
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
interface User {
|
||||
token: string;
|
||||
avatar: string; // 头像
|
||||
mobile:string; // 手机号
|
||||
account:string; // 用户名
|
||||
id:number; // 用户id
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { defineConfig, loadEnv, ConfigEnv, UserConfig } from "vite";
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
import { resolve } from "path";
|
||||
import { wrapperEnv } from "./build";
|
||||
import VueRouter from 'unplugin-vue-router/vite';
|
||||
|
||||
// 路径查找
|
||||
const pathResolve = (dir: string): string => {
|
||||
return resolve(__dirname, ".", dir);
|
||||
};
|
||||
|
||||
// 设置别名,还可以添加其他路径
|
||||
const alias: Record<string, string> = {
|
||||
"@": pathResolve("src"),
|
||||
"@views": pathResolve("src/views"),
|
||||
"@store": pathResolve("src/store"),
|
||||
"@language": pathResolve("src/language"),
|
||||
"@css": pathResolve("src/assets/css"),
|
||||
};
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
|
||||
const root = process.cwd();
|
||||
const env = loadEnv(mode, root);
|
||||
const viteEnv = wrapperEnv(env);
|
||||
|
||||
return {
|
||||
base: viteEnv.VITE_PUBLIC_PATH,
|
||||
plugins: [
|
||||
VueRouter({
|
||||
routesFolder: 'src/views', // 指定路由文件所在的目录
|
||||
exclude: ['**/components/*.vue'],
|
||||
extensions: ['.vue'], // 指定路由文件的后缀名
|
||||
}),
|
||||
vue(),
|
||||
],
|
||||
resolve: {
|
||||
alias, // 设置别名
|
||||
},
|
||||
css: {
|
||||
preprocessorOptions: {
|
||||
scss: {
|
||||
additionalData: `@import "@css/variables.scss";`, // 引入全局变量
|
||||
},
|
||||
},
|
||||
},
|
||||
server: {
|
||||
host: "0.0.0.0", // 设置服务器主机名
|
||||
port: viteEnv.VITE_PORT, // 设置服务启动端口号
|
||||
https: undefined, // 是否开启 https
|
||||
open: true, // 是否自动打开浏览器
|
||||
cors: true, // 允许跨域
|
||||
// 本地跨域代理 https://cn.vitejs.dev/config/server-options.html#server-proxy
|
||||
proxy: {
|
||||
"^/api": {
|
||||
target: "http://127.0.0.1:8686", // 代理的目标地址
|
||||
changeOrigin: true, // 开发模式,默认的 origin 是真实的 origin:localhost:3000
|
||||
rewrite: (path) => path.replace(/^\/api/, ""), // 把 /api 替换成 target 中的地址
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
Reference in New Issue
Block a user