refactor: 〽️ 更新版本内容;简化项目内容

This commit is contained in:
Bunny 2024-09-01 16:41:05 +08:00
parent 628fd47492
commit 65a956d4e9
24 changed files with 4878 additions and 417 deletions

35
.env
View File

@ -1,5 +1,34 @@
# 平台本地运行端口号
VITE_PORT = 8848
VITE_PORT=8201
# 是否隐藏首页 隐藏 true 不隐藏 false 勿删除VITE_HIDE_HOME只需在.env文件配置
VITE_HIDE_HOME = false
# 预发布环境路由历史模式Hash模式传"hash"、HTML5模式传"h5"、Hash模式带base参数传"hash,base参数"、HTML5模式带base参数传"h5,base参数"
VITE_ROUTER_HISTORY="hash"
# 基础请求路径
VITE_BASE_API=/api
# 跨域代理地址
VITE_APP_URL=http://localhost:8801
# mock地址
VITE_MOCK_BASE_API=/mock
# 网络请求延迟时间
VITE_BASE_API_TIMEOUT=60000
# 失败重试次数
VITE_BASE_API_RETRY=5
# 失败重试时间
VITE_BASE_API_RETRY_DELAY=3000
# 是否在打包时使用cdn替换本地库 替换 true 不替换 false
VITE_CDN=false
# 是否启用gzip压缩或brotli压缩分两种情况删除原始文件和不删除原始文件
# 压缩时不删除原始文件的配置gzip、brotli、both同时开启 gzip 与 brotli 压缩、none不开启压缩默认
# 压缩时删除原始文件的配置gzip-clear、brotli-clear、both-clear同时开启 gzip 与 brotli 压缩、none不开启压缩默认
VITE_COMPRESSION="none"
# 开发环境读取配置文件路径
VITE_PUBLIC_PATH=/

View File

@ -1,8 +1,34 @@
# 平台本地运行端口号
VITE_PORT = 8848
VITE_PORT=8201
# 预发布环境路由历史模式Hash模式传"hash"、HTML5模式传"h5"、Hash模式带base参数传"hash,base参数"、HTML5模式带base参数传"h5,base参数"
VITE_ROUTER_HISTORY="hash"
# 基础请求路径
VITE_BASE_API=/api
# 跨域代理地址
VITE_APP_URL=http://localhost:8801
# mock地址
VITE_MOCK_BASE_API=/mock
# 网络请求延迟时间
VITE_BASE_API_TIMEOUT=60000
# 失败重试次数
VITE_BASE_API_RETRY=5
# 失败重试时间
VITE_BASE_API_RETRY_DELAY=3000
# 是否在打包时使用cdn替换本地库 替换 true 不替换 false
VITE_CDN=false
# 是否启用gzip压缩或brotli压缩分两种情况删除原始文件和不删除原始文件
# 压缩时不删除原始文件的配置gzip、brotli、both同时开启 gzip 与 brotli 压缩、none不开启压缩默认
# 压缩时删除原始文件的配置gzip-clear、brotli-clear、both-clear同时开启 gzip 与 brotli 压缩、none不开启压缩默认
VITE_COMPRESSION="none"
# 开发环境读取配置文件路径
VITE_PUBLIC_PATH = /
# 开发环境路由历史模式Hash模式传"hash"、HTML5模式传"h5"、Hash模式带base参数传"hash,base参数"、HTML5模式带base参数传"h5,base参数"
VITE_ROUTER_HISTORY = "hash"
VITE_PUBLIC_PATH=/

View File

@ -1,13 +1,34 @@
# 线上环境平台打包路径
VITE_PUBLIC_PATH = /
# 平台本地运行端口号
VITE_PORT=8201
# 线上环境路由历史模式Hash模式传"hash"、HTML5模式传"h5"、Hash模式带base参数传"hash,base参数"、HTML5模式带base参数传"h5,base参数"
VITE_ROUTER_HISTORY = "hash"
# 预发布环境路由历史模式Hash模式传"hash"、HTML5模式传"h5"、Hash模式带base参数传"hash,base参数"、HTML5模式带base参数传"h5,base参数"
VITE_ROUTER_HISTORY="hash"
# 基础请求路径
VITE_BASE_API=/api
# 跨域代理地址
VITE_APP_URL=http://localhost:8801
# mock地址
VITE_MOCK_BASE_API=/mock
# 网络请求延迟时间
VITE_BASE_API_TIMEOUT=60000
# 失败重试次数
VITE_BASE_API_RETRY=5
# 失败重试时间
VITE_BASE_API_RETRY_DELAY=3000
# 是否在打包时使用cdn替换本地库 替换 true 不替换 false
VITE_CDN = false
VITE_CDN=false
# 是否启用gzip压缩或brotli压缩分两种情况删除原始文件和不删除原始文件
# 压缩时不删除原始文件的配置gzip、brotli、both同时开启 gzip 与 brotli 压缩、none不开启压缩默认
# 压缩时删除原始文件的配置gzip-clear、brotli-clear、both-clear同时开启 gzip 与 brotli 压缩、none不开启压缩默认
VITE_COMPRESSION = "none"
VITE_COMPRESSION="none"
# 开发环境读取配置文件路径
VITE_PUBLIC_PATH=/

4
.husky/pre-commit Normal file
View File

@ -0,0 +1,4 @@
#!/bin/sh
. "$(dirname -- "$0")/_/husky.sh"
pnpm exec lint-staged

View File

@ -1,20 +0,0 @@
FROM node:20-alpine as build-stage
WORKDIR /app
RUN corepack enable
RUN corepack prepare pnpm@latest --activate
RUN npm config set registry https://registry.npmmirror.com
COPY .npmrc package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
COPY . .
RUN pnpm build
FROM nginx:stable-alpine as production-stage
COPY --from=build-stage /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

View File

@ -1,51 +0,0 @@
<h1>vue-pure-admin精简版国际化版本</h1>
[![license](https://img.shields.io/github/license/pure-admin/vue-pure-admin.svg)](LICENSE)
**中文** | [English](./README.en-US.md)
## 介绍
精简版是基于 [vue-pure-admin](https://github.com/pure-admin/vue-pure-admin) 提炼出的架子,包含主体功能,更适合实际项目开发,打包后的大小在全局引入 [element-plus](https://element-plus.org) 的情况下仍然低于 `2.3MB`,并且会永久同步完整版的代码。开启 `brotli` 压缩和 `cdn` 替换本地库模式后,打包大小低于 `350kb`
## 版本选择
当前是国际化版本,如果您需要非国际化版本 [请点击](https://github.com/pure-admin/pure-admin-thin)
## `js` 版本
[点我查看 js 版本](https://pure-admin.github.io/pure-admin-doc/pages/js/)
## `max` 版本
[点我查看 max 版本](https://github.com/pure-admin/vue-pure-admin-max)
## 配套视频
[点我查看 UI 设计](https://www.bilibili.com/video/BV17g411T7rq)
[点我查看快速开发教程](https://www.bilibili.com/video/BV1kg411v7QT)
## 配套保姆级文档
[点我查看 vue-pure-admin 文档](https://pure-admin.github.io/pure-admin-doc)
[点我查看 @pureadmin/utils 文档](https://pure-admin-utils.netlify.app)
## 优质服务、软件外包、赞助支持
[点我查看详情](https://pure-admin.github.io/pure-admin-doc/pages/service/)
## 预览
[查看预览](https://pure-admin-thin.netlify.app/#/login)
## 维护者
[xiaoxian521](https://github.com/xiaoxian521)
## ⚠️ 注意
精简版不接受任何 `issues``pr`,如果有问题请到完整版 [issues](https://github.com/pure-admin/vue-pure-admin/issues/new/choose) 去提,谢谢!
## 许可证
[MIT © 2020-present, pure-admin](./LICENSE)

52
build/buildEnv.ts Normal file
View File

@ -0,0 +1,52 @@
import { pathResolve } from "./utils";
import type { BuildOptions } from "vite";
export const buildEnvironment = () => {
const environment: BuildOptions = {
target: "es2015",
assetsInlineLimit: 20000,
// 构建输出的目录,默认值为"dist"
outDir: "dist",
// 用于指定使用的代码压缩工具。在这里minify 被设置为 'terser',表示使用 Terser 进行代码压缩。默认值terser
// esbuild 打包更快,但是不能去除 console.logterser打包慢但能去除 console.log
minify: "terser",
// 用于配置 Terser 的选项
terserOptions: {
// 用于配置压缩选项
compress: {
drop_console: true, // 是否删除代码中的 console 语句, 默认值false
drop_debugger: true // 是否删除代码中的 debugger 语句, 默认值false
}
},
// 禁用 gzip 压缩大小报告,可略微减少打包时间
reportCompressedSize: false,
// 用于指定是否生成源映射文件。源映射文件可以帮助调试和定位源代码中的错误。当设置为false时构建过程不会生成源映射文件
sourcemap: false,
// 用于配置 CommonJS 模块的选项
commonjsOptions: {
// 用于指定是否忽略 CommonJS 模块中的 try-catch 语句。当设置为false时构建过程会保留 CommonJS 模块中的 try-catch 语句
ignoreTryCatch: false
},
// 规定触发警告的 chunk 大小, 当某个代码分块的大小超过该限制时Vite 会发出警告
chunkSizeWarningLimit: 2000,
rollupOptions: {
input: {
index: pathResolve("../index.html", import.meta.url)
},
// 静态资源分类打包
output: {
chunkFileNames: "static/js/[name]-[hash].js",
entryFileNames: "static/js/[name]-[hash].js",
assetFileNames: "static/[ext]/[name]-[hash].[ext]",
manualChunks: id => {
// 如果是包含在包中则打包成 vendor
if (id.includes("node_modules")) {
return "vendor";
}
}
}
}
};
return environment;
};

31
build/server.ts Normal file
View File

@ -0,0 +1,31 @@
import { loadEnv, type ServerOptions } from "vite";
import { root, wrapperEnv } from "./utils";
export const serverOptions = (mode: string) => {
const { VITE_PORT, VITE_APP_URL } = wrapperEnv(loadEnv(mode, root));
const options: ServerOptions = {
port: VITE_PORT, // ? 端口号
host: "0.0.0.0",
open: true,
cors: true,
proxy: {
"/api": {
target: VITE_APP_URL,
changeOrigin: true,
rewrite: (path: string) => path.replace(/^\/api/, "/api")
},
"/mock": {
target: VITE_APP_URL,
changeOrigin: true,
rewrite: (path: string) => path.replace(/^\/mock/, "/mock")
}
},
// 预热文件以提前转换和缓存结果,降低启动期间的初始页面加载时长并防止转换瀑布
warmup: {
clientFiles: ["./index.html", "./src/{views,components}/*"]
}
};
return options;
};

View File

@ -2,13 +2,13 @@ import dayjs from "dayjs";
import { readdir, stat } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, resolve } from "node:path";
import { sum, formatBytes } from "@pureadmin/utils";
import { formatBytes, sum } from "@pureadmin/utils";
import {
name,
version,
engines,
dependencies,
devDependencies
devDependencies,
engines,
name,
version
} from "../package.json";
/** 启动`node`进程时所在工作目录的绝对路径 */
@ -54,6 +54,7 @@ const wrapperEnv = (envConf: Recordable): ViteEnv => {
VITE_PORT: 8848,
VITE_PUBLIC_PATH: "",
VITE_ROUTER_HISTORY: "",
VITE_APP_URL: "",
VITE_CDN: false,
VITE_HIDE_HOME: "false",
VITE_COMPRESSION: "none"

View File

@ -2,7 +2,7 @@
/** @type {import("cz-git").UserConfig} */
export default {
ignores: [commit => commit.includes("init")],
ignores: [commit => commit === "init"],
extends: ["@commitlint/config-conventional"],
rules: {
// @see: https://commitlint.js.org/#/reference-rules
@ -17,11 +17,12 @@ export default {
"always",
[
"init",
"optimize",
"feat",
"page",
"media",
"completepage",
"fix",
"fixbug",
"media",
"docs",
"style",
"refactor",
@ -34,7 +35,8 @@ export default {
"wip",
"workflow",
"types",
"release"
"release",
"optimize"
]
]
},
@ -54,8 +56,11 @@ export default {
types: [
{ value: "init", name: "初始化: ⏳ 初始化项目", emoji: "⏳" },
{ value: "optimize", name: "优化代码: ♻️ 优化项目代码", emoji: "♻️" },
{ value: "feat", name: "特性: 🚀 新增功能", emoji: "🚀" },
{ value: "feat", name: "新增: 🚀 新增功能", emoji: "🚀" },
{ value: "media", name: "媒体: 🎁 新增媒体资源", emoji: "🎁" },
{ value: "page", name: "页面: 📄 新增页面", emoji: "📄" },
{ value: "completepage", name: "完成页面: 🍻 完成页面", emoji: "🍻" },
{ value: "fixbug", name: "bug: 🐛 修改bug", emoji: "🐛" },
{ value: "fix", name: "修复: 🧩 修复缺陷", emoji: "🧩" },
{ value: "docs", name: "文档: 📚 文档变更", emoji: "📚" },
{
@ -63,11 +68,10 @@ export default {
name: "格式: 🎨 代码格式(不影响功能,例如空格、分号等格式修正)",
emoji: "🎨"
},
{ value: "fixbug", name: "bug: 🐛 修改bug", emoji: "🐛" },
{
value: "refactor",
name: "重构: 代码重构(不包括 bug 修复、功能新增)",
emoji: ""
name: "重构: 代码重构(不包括 bug 修复、功能新增)",
emoji: ""
},
{ value: "perf", name: "性能: ⚡️ 性能优化", emoji: "⚡️" },
{
@ -76,17 +80,13 @@ export default {
emoji: "✅"
},
{
value: "build",
value: "chore",
name: "构建: 📦️ 构建流程、外部依赖变更(如升级 npm 包、修改 webpack 配置等)",
emoji: "📦️"
},
{ value: "ci", name: "集成: 🎡 修改 CI 配置、脚本", emoji: "🎡" },
{ value: "revert", name: "回退: ⏪️ 回滚 commit", emoji: "⏪️" },
{
value: "chore",
name: "其他: 🔨 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)",
emoji: "🔨"
}
{ value: "build", name: "打包: 🔨 项目打包发布", emoji: "🔨" }
],
useEmoji: true,
themeColorCode: "",

View File

@ -1,3 +1,8 @@
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
listen [::]:80;
@ -9,14 +14,25 @@ server {
try_files $uri /index.html;
}
# 后端跨域请求
# 后端跨域请求
location ~/api/ {
proxy_pass http://192.168.3.98:1001;
proxy_pass http://192.168.3.98:8200;
}
# mock 跨域
location ~/mock/ {
proxy_pass http://192.168.3.98:1001;
# 配置WebSocket
location ~/ws/ {
# WebSocket 代理配置
proxy_pass http://192.168.3.98:8200; # WebSocket 服务器地址和端口
proxy_http_version 1.1; # 使用 HTTP 1.1 版本
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 600s; # 保持连接的超时时间,根据需要调整
proxy_redirect off; # 关闭重定向
}
# mock 跨域
location ~/mock/ {
proxy_pass http://192.168.3.98:8200;
}
error_page 404 404.html;

View File

@ -1,8 +1,10 @@
export default {
'*.{js,jsx,ts,tsx}': ['eslint --fix', 'prettier --write'],
'{!(package)*.json,*.code-snippets,.!(browserslist)*rc}': ['prettier --write--parser json'],
'package.json': ['prettier --write'],
'*.vue': ['eslint --fix', 'prettier --write', 'stylelint --fix'],
'*.{scss,less,styl,html}': ['stylelint --fix', 'prettier --write'],
'*.md': ['prettier --write'],
"*.{js,jsx,ts,tsx}": ["eslint --fix", "prettier --write"],
"{!(package)*.json,*.code-snippets,.!(browserslist)*rc}": [
"prettier --write--parser json"
],
"package.json": ["prettier --write"],
"*.vue": ["eslint --fix", "prettier --write", "stylelint --fix"],
"*.{scss,less,styl,html}": ["stylelint --fix", "prettier --write"],
"*.md": ["prettier --write"]
};

View File

@ -55,9 +55,10 @@ const permissionRouter = {
]
};
// 获取系统路由
export default defineFakeRoute([
{
url: "/get-async-routes",
url: "/mock/get-async-routes",
method: "get",
response: () => {
return {

View File

@ -3,7 +3,7 @@ import { defineFakeRoute } from "vite-plugin-fake-server/client";
export default defineFakeRoute([
{
url: "/login",
url: "/mock/login",
method: "post",
response: ({ body }) => {
if (body.username === "admin") {

View File

@ -3,7 +3,7 @@ import { defineFakeRoute } from "vite-plugin-fake-server/client";
// 模拟刷新token接口
export default defineFakeRoute([
{
url: "/refresh-token",
url: "/mock/refresh-token",
method: "post",
response: ({ body }) => {
if (body.refreshToken) {

View File

@ -1,27 +1,8 @@
{
"name": "pure-admin-thin",
"version": "5.8.0",
"name": "bunny-admin-element",
"version": "1.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "NODE_OPTIONS=--max-old-space-size=4096 vite",
"serve": "pnpm dev",
"build": "rimraf dist && NODE_OPTIONS=--max-old-space-size=8192 vite build",
"build:staging": "rimraf dist && vite build --mode staging",
"report": "rimraf dist && vite build",
"preview": "vite preview",
"preview:build": "pnpm build && vite preview",
"typecheck": "tsc --noEmit && vue-tsc --noEmit --skipLibCheck",
"svgo": "svgo -f . -r",
"clean:cache": "rimraf .eslintcache && rimraf pnpm-lock.yaml && rimraf node_modules && pnpm store prune && pnpm install",
"lint:eslint": "eslint --fix --ext .js,.ts,.vue ./src",
"lint:prettier": "prettier --write --loglevel warn \"src/**/*.{js,ts,json,tsx,css,less,scss,vue,html,md}\"",
"lint:stylelint": "stylelint --cache --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
"lint:lint-staged": "lint-staged",
"prepare": "husky install",
"release": "standard-version",
"commit": "git status && git add -A && git-cz"
},
"keywords": [
"bunny-admin-element",
"bunny-cli",
@ -45,115 +26,169 @@
"author": {
"name": "Bunny0212",
"email": "1319900154@qq.com",
"url": "https://github.com/BunnyMaster"
"url": "https://github.com/xiaoxian521"
},
"scripts": {
"dev": "NODE_OPTIONS=--max-old-space-size=4096 vite",
"serve": "pnpm vite",
"start": "vite",
"build": "rimraf dist && NODE_OPTIONS=--max-old-space-size=8192 vite build && generate-version-file",
"build:staging": "rimraf dist && vite build --mode staging",
"report": "rimraf dist && vite build",
"preview": "vite preview",
"preview:build": "pnpm build && vite preview",
"typecheck": "tsc --noEmit && vue-tsc --noEmit --skipLibCheck",
"svgo": "svgo -f . -r",
"clean:cache": "rimraf .eslintcache && rimraf pnpm-lock.yaml && rimraf node_modules && pnpm store prune && pnpm install",
"lint:eslint": "eslint --cache --max-warnings 0 \"{src,mock,build}/**/*.{vue,js,ts,tsx}\" --fix",
"lint:prettier": "prettier --write \"src/**/*.{js,ts,json,tsx,css,scss,vue,html,md}\"",
"lint:stylelint": "stylelint --cache --fix \"**/*.{html,vue,css,scss}\" --cache-location node_modules/.cache/stylelint/",
"lint": "pnpm lint:eslint && pnpm lint:prettier && pnpm lint:stylelint",
"prepare": "husky install",
"preinstall": "npx only-allow pnpm",
"commit": "git pull && git add -A && git-cz && git push"
},
"dependencies": {
"@amap/amap-jsapi-loader": "^1.0.1",
"@howdyjs/mouse-menu": "^2.1.3",
"@infectoone/vue-ganttastic": "^2.3.2",
"@logicflow/core": "^1.2.27",
"@logicflow/extension": "^1.2.27",
"@pureadmin/descriptions": "^1.2.1",
"@pureadmin/table": "^3.2.0",
"@pureadmin/utils": "^2.4.8",
"@vueuse/core": "^10.11.1",
"@vueuse/motion": "^2.2.3",
"@pureadmin/table": "^3.1.2",
"@pureadmin/utils": "^2.4.7",
"@vue-flow/background": "^1.3.0",
"@vue-flow/core": "^1.33.6",
"@vueuse/core": "^10.9.0",
"@vueuse/motion": "^2.1.0",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^5.1.12",
"@zxcvbn-ts/core": "^3.0.4",
"animate.css": "^4.1.1",
"axios": "^1.7.4",
"dayjs": "^1.11.12",
"axios": "^1.6.8",
"china-area-data": "^5.0.1",
"cropperjs": "^1.6.2",
"dayjs": "^1.11.11",
"echarts": "^5.5.0",
"element-plus": "^2.8.0",
"git-cz": "^4.9.0",
"el-table-infinite-scroll": "^3.0.3",
"element-plus": "2.7.1",
"intro.js": "^7.2.0",
"js-cookie": "^3.0.5",
"jsbarcode": "^3.11.6",
"localforage": "^1.10.0",
"mint-filter": "^4.0.3",
"mitt": "^3.0.1",
"mqtt": "4.3.7",
"nprogress": "^0.2.0",
"path": "^0.12.7",
"pinia": "^2.2.2",
"pinyin-pro": "^3.24.2",
"qs": "^6.13.0",
"pinia": "^2.1.7",
"pinia-plugin-persistedstate": "^3.2.1",
"pinyin-pro": "^3.20.4",
"plus-pro-components": "^0.1.1",
"qrcode": "^1.5.3",
"qs": "^6.12.1",
"responsive-storage": "^2.2.0",
"sortablejs": "^1.15.2",
"vue": "^3.4.38",
"vue-i18n": "^9.14.0",
"vue-router": "^4.4.3",
"vue-tippy": "^6.4.4",
"vue-types": "^5.1.3"
"swiper": "^11.1.1",
"terser": "^5.31.0",
"typeit": "^8.8.3",
"v-contextmenu": "^3.2.0",
"v3-infinite-loading": "^1.3.1",
"version-rocket": "^1.7.1",
"vite-plugin-vue-inspector": "^5.1.3",
"vue": "^3.4.27",
"vue-i18n": "^9.13.1",
"vue-json-pretty": "^2.4.0",
"vue-pdf-embed": "^2.0.3",
"vue-router": "^4.3.2",
"vue-tippy": "^6.4.1",
"vue-types": "^5.1.2",
"vue-virtual-scroller": "2.0.0-beta.8",
"vue-waterfall-plugin-next": "^2.4.3",
"vue3-danmaku": "^1.6.0",
"vue3-puzzle-vcode": "^1.1.7",
"vuedraggable": "^4.1.0",
"vxe-table": "^4.6.9",
"wavesurfer.js": "^7.7.13",
"xgplayer": "^3.0.17",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@commitlint/cli": "^19.3.0",
"@commitlint/config-conventional": "^19.2.2",
"@commitlint/types": "^19.0.3",
"commitizen": "^4.2.4",
"commitlint": "^17.0.1",
"@eslint/js": "^9.9.0",
"@eslint/js": "^9.2.0",
"@faker-js/faker": "^8.4.1",
"@iconify-icons/ep": "^1.2.12",
"@iconify-icons/ri": "^1.2.10",
"@iconify/vue": "^4.1.2",
"@intlify/unplugin-vue-i18n": "^4.0.0",
"@pureadmin/theme": "^3.2.0",
"@types/dagre": "^0.7.52",
"@types/gradient-string": "^1.1.6",
"@types/intro.js": "^5.1.5",
"@types/js-cookie": "^3.0.6",
"@types/node": "^20.16.1",
"@types/node": "^20.12.11",
"@types/nprogress": "^0.2.3",
"@types/qrcode": "^1.5.5",
"@types/qs": "^6.9.15",
"@types/sortablejs": "^1.15.8",
"@typescript-eslint/eslint-plugin": "^7.18.0",
"@typescript-eslint/parser": "^7.18.0",
"@vitejs/plugin-vue": "^5.1.2",
"@vitejs/plugin-vue-jsx": "^4.0.1",
"autoprefixer": "^10.4.20",
"@typescript-eslint/eslint-plugin": "^7.8.0",
"@typescript-eslint/parser": "^7.8.0",
"@vitejs/plugin-vue": "^5.0.4",
"@vitejs/plugin-vue-jsx": "^3.1.0",
"autoprefixer": "^10.4.19",
"boxen": "^7.1.1",
"cssnano": "^7.0.5",
"commitizen": "^4.2.4",
"commitlint": "^17.0.1",
"cssnano": "^7.0.1",
"cz-git": "^1.3.2",
"eslint": "^9.9.0",
"dagre": "^0.8.5",
"eslint": "^9.2.0",
"eslint-config-prettier": "^9.1.0",
"eslint-define-config": "^2.1.0",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-vue": "^9.27.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-vue": "^9.25.0",
"gradient-string": "^2.0.2",
"husky": "^9.1.5",
"lint-staged": "^15.2.9",
"postcss": "^8.4.41",
"husky": "^8.0.1",
"lint-staged": "^15.2.2",
"postcss": "^8.4.38",
"postcss-html": "^1.7.0",
"postcss-import": "^16.1.0",
"postcss-scss": "^4.0.9",
"prettier": "^3.3.3",
"rimraf": "^5.0.10",
"prettier": "^3.2.5",
"rimraf": "^5.0.5",
"rollup-plugin-visualizer": "^5.12.0",
"sass": "^1.77.8",
"stylelint": "^16.8.2",
"sass": "^1.77.0",
"stylelint": "^16.5.0",
"stylelint-config-recess-order": "^5.0.1",
"stylelint-config-recommended-vue": "^1.5.0",
"stylelint-config-standard-scss": "^13.1.0",
"stylelint-prettier": "^5.0.2",
"svgo": "^3.3.2",
"tailwindcss": "^3.4.10",
"typescript": "^5.5.4",
"vite": "^5.4.1",
"vite-plugin-cdn-import": "^1.0.1",
"stylelint-prettier": "^5.0.0",
"svgo": "^3.3.0",
"tailwindcss": "^3.4.3",
"typescript": "^5.4.5",
"vite": "^5.2.11",
"vite-plugin-cdn-import": "^0.3.5",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-fake-server": "^2.1.1",
"vite-plugin-remove-console": "^2.2.0",
"vite-plugin-router-warn": "^1.0.0",
"vite-plugin-vue-inspector": "^5.1.3",
"vite-svg-loader": "^5.1.0",
"vue-eslint-parser": "^9.4.3",
"vue-eslint-parser": "^9.4.2",
"vue-tsc": "^1.8.27"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0",
"pnpm": ">=9"
"pnpm": ">=8.6.10"
},
"pnpm": {
"allowedDeprecatedVersions": {
"are-we-there-yet": "*",
"sourcemap-codec": "*",
"domexception": "*",
"w3c-hr-time": "*",
"inflight": "*",
"npmlog": "*",
"rimraf": "*",
"stable": "*",
"gauge": "*",
"abab": "*",
"glob": "*"
"abab": "*"
},
"peerDependencyRules": {
"allowedVersions": {

File diff suppressed because it is too large Load Diff

740
public/html/button.html Normal file
View File

@ -0,0 +1,740 @@
<!doctype html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
</head>
<body>
<div class="btns">
<div class="btn java">JAVA攻城狮</div>
<div class="btn golang">Golang工程师!</div>
<div class="btn js"><span>js攻城狮</span></div>
<div class="btn nodd-ruby ruby">
<div class="anim"></div>
<span>Ruby攻城狮</span>
</div>
<div class="btn vb">
<span>VB攻城狮</span>
<div class="dot"></div>
</div>
<div class="btn python python-1">python攻城狮</div>
<div class="btn python python-2">python攻城狮</div>
<div class="btn python python-3">python攻城狮</div>
<div class="btn python python-4">python攻城狮</div>
<div class="btn python python-5">python攻城狮</div>
<div class="btn php php-1">php攻城狮</div>
<div class="btn php php-2">php攻城狮</div>
<div class="btn php php-3">php攻城狮</div>
<div class="btn php php-4">php攻城狮</div>
<div class="btn php php-5">php攻城狮</div>
<div class="btn kotlin kotlin-3">kotlin攻城狮</div>
<div class="btn kotlin kotlin-1">kotlin攻城狮</div>
<div class="btn kotlin kotlin-4">kotlin攻城狮</div>
<div class="btn kotlin kotlin-2">kotlin攻城狮</div>
<div class="btn kotlin kotlin-5">kotlin攻城狮</div>
<div class="btn c">C语言攻城狮</div>
</div>
</body>
<style>
.text-info {
position: absolute;
top: calc(50vh - 245px);
text-align: center;
font-size: 12px;
color: #999;
width: 100%;
margin-left: -5px;
}
.btn {
vertical-align: top;
margin: 15px;
display: inline-block;
text-align: center;
width: 122px;
height: 44px;
line-height: 44px;
border-radius: 4px;
color: #fff;
cursor: pointer;
}
.java {
color: #eb9e05;
height: 42px;
line-height: 42px;
width: 120px;
border: 1px solid #eb9e05;
opacity: 1;
transition: all 0.6s;
}
.java:hover {
background: #eb9e05;
color: #fff;
}
.java:active {
opacity: 0.7;
}
.c {
height: 44px;
line-height: 44px;
background: #55acee;
transition: all 0.5s;
box-shadow: 0px 5px 0px 0px #3486d5;
}
.c:hover {
background-color: #6fc6ff;
}
.c:active {
transform: translate(0px, 4px);
box-shadow: 0px 1px 0px 0px #3486d5;
}
@keyframes sheen {
0% {
transform: skewY(-45deg) translateX(0);
}
100% {
transform: skewY(-45deg) translateX(12.5em);
}
}
.golang {
vertical-align: top;
height: 42px;
line-height: 42px;
width: 120px;
color: #2194e0;
border: 1px solid #2194e0;
transition: all 0.2s ease-in-out;
position: relative;
opacity: 1;
overflow: hidden;
}
.golang:before {
content: "";
background-color: rgba(255, 255, 255, 0.5);
height: 100%;
width: 3em;
display: block;
position: absolute;
top: 0;
left: -4.5em;
transform: skewX(-45deg) translateX(0);
transition: none;
}
.golang:hover {
background-color: #2194e0;
color: #fff;
}
.golang:hover:before {
transform: skewX(-45deg) translateX(260px);
transition: all 0.5s ease-in-out;
}
.golang:active {
opacity: 0.8;
}
.js {
width: 160px;
height: 42px;
line-height: 42px;
background: #0d6;
width: 120px;
border: 1px solid #0d6;
overflow: hidden;
transition: all 0.5s;
opacity: 1;
}
.js:hover,
.js:active {
text-decoration: none;
color: #0c5;
border-color: #0c5;
background: #fff;
}
.js:active {
opacity: 0.8;
}
.js span {
display: inline-block;
position: relative;
padding-right: 0;
transition: padding-right 0.5s;
}
.js span:after {
content: " ";
position: absolute;
top: 0;
right: -18px;
opacity: 0;
width: 10px;
height: 10px;
margin-top: -10px;
background: rgba(0, 0, 0, 0);
border: 2px solid #fff;
border-top: none;
border-right: none;
transition:
opacity 0.5s,
top 0.5s,
right 0.5s;
transform: rotate(-140deg);
}
.js:hover span,
.js:active span {
padding-right: 30px;
}
.js:hover span:after,
.js:active span:after {
transition:
opacity 0.5s,
top 0.5s,
right 0.5s;
opacity: 1;
border-color: #0c5;
right: 0;
top: calc(50% + 2.5px);
transform: rotate(-140deg);
}
.nodd-ruby {
background: #c147e6;
position: relative;
overflow: hidden;
z-index: 0;
cursor: pointer;
opacity: 1;
transition: all 0.3s;
}
input[type="checkbox"].toggle {
position: absolute;
width: 100%;
height: 100%;
margin: 0;
left: 0;
top: 0;
cursor: pointer;
}
input[type="checkbox"].toggle:focus {
outline: 0;
}
.anim {
transform: translate(-50%, -50%);
position: absolute;
top: 50%;
left: 50%;
z-index: -1;
}
.anim:before {
position: relative;
content: "";
display: block;
margin-top: 100%;
}
.anim:after {
content: "";
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
border-radius: 50%;
}
.node .toggle:checked + .anim {
animation: 0.75s anim-in;
}
.node .toggle:checked + .anim:after {
animation: anim-in-pseudo 0.75s;
}
.node .toggle:not(:checked) + .anim {
animation: anim-out 0.75s;
}
.node .toggle:not(:checked) + .anim:after {
animation: anim-out-pseudo 0.75s;
}
.node {
background: #ed3f14;
}
.node:hover {
opacity: 0.8;
}
.ruby:active {
opacity: 0.8;
}
.ruby:hover > .anim {
animation: anim-out 0.75s;
}
.ruby:hover > .anim:after {
animation: anim-out-pseudo 0.75s;
}
@keyframes anim-in {
0% {
width: 0%;
}
100% {
width: 100%;
}
}
@keyframes anim-in-pseudo {
0% {
background: rgba(0, 0, 0, 0.3);
}
100% {
background: transparent;
}
}
@keyframes anim-out {
0% {
width: 0%;
}
100% {
width: 100%;
}
}
@keyframes anim-out-pseudo {
0% {
background: rgba(0, 0, 0, 0.35);
}
100% {
background: transparent;
}
}
.python {
transition: 0.5s;
background-size: 200% auto;
}
.python:hover {
background-position: right center;
}
.python-1 {
background-image: linear-gradient(
to right,
#f6d365 0%,
#fda085 51%,
#f6d365 100%
);
}
.python-2 {
background-image: linear-gradient(
to right,
#fbc2eb 0%,
#a6c1ee 51%,
#fbc2eb 100%
);
}
.python-3 {
background-image: linear-gradient(
to right,
#84fab0 0%,
#8fd3f4 51%,
#84fab0 100%
);
}
.python-4 {
background-image: linear-gradient(
to right,
#a1c4fd 0%,
#c2e9fb 51%,
#a1c4fd 100%
);
}
.python-5 {
background-image: linear-gradient(
to right,
#ffecd2 0%,
#fcb69f 51%,
#ffecd2 100%
);
}
.php,
.php::after {
transition: all 0.5s;
}
.php {
border: 1px solid #c147e6;
color: #c147e6;
width: 120px;
height: 42px;
line-height: 42px;
position: relative;
z-index: 1;
text-transform: uppercase;
}
.php:hover {
color: #fff;
}
.php::before,
.php::after {
background: #c147e6;
content: "";
position: absolute;
z-index: -2;
border-radius: 3px;
}
.php-1::after {
height: 0;
left: 0;
top: 0;
width: 100%;
}
.php-1:hover:after {
height: 100%;
}
.php-2::after {
height: 100%;
left: 0;
top: 0;
width: 0;
}
.php-2:hover:after {
width: 100%;
}
.php-3::after {
height: 0;
left: 50%;
top: 50%;
width: 0;
}
.php-3:hover:after {
height: 100%;
left: 0;
top: 0;
width: 100%;
}
.php-4::before {
height: 100%;
left: 0;
top: 0;
width: 100%;
}
.php-4::after {
background: #fff;
height: 100%;
left: 0;
top: 0;
width: 100%;
}
.php-4:hover:after {
height: 0;
left: 50%;
top: 50%;
width: 0;
}
.php-5 {
overflow: hidden;
}
.php-5::after {
height: 100%;
left: -35%;
top: 0;
transform: skew(50deg);
transition-duration: 0.6s;
transform-origin: top left;
width: 0;
}
.php-5:hover:after {
height: 100%;
width: 135%;
}
.kotlin {
background: none;
border: 1px solid;
width: 120px;
height: 42px;
line-height: 42px;
letter-spacing: inherit;
text-transform: inherit;
transition: color 1s;
}
.kotlin-1 {
color: #9c89f7;
}
.kotlin-1:hover {
animation: halftone 1s forwards;
background:
radial-gradient(circle, #9c89f7 0.2em, transparent 0.25em) 0 0/1.25em
1.25em,
radial-gradient(circle, #9c89f7 0.2em, transparent 0.25em) 6.25em 6.25em/1.25em
1.25em;
color: #e4f789;
}
@keyframes halftone {
100% {
background-size:
2.375em 2.375em,
0.1em 0.1em;
}
}
.kotlin-2 {
color: #82f6d8;
}
.kotlin-2:hover {
animation: stripes-move 0.75s infinite linear;
background: repeating-linear-gradient(
45deg,
#82f6d8 0,
#82f6d8 0.25em,
transparent 0.25em,
transparent 0.5em
);
color: #f682a0;
}
@keyframes stripes-move {
100% {
background-position: 5em 0px;
}
}
.kotlin-3 {
color: #d3f169;
}
.kotlin-3:hover {
animation: sawtooth 0.35s infinite linear;
background:
linear-gradient(45deg, #d3f169 0.5em, transparent 0.5em) 0 0/1em 1em,
linear-gradient(-45deg, #d3f169 0.5em, transparent 0.5em) 0 0/1em 1em;
color: #8769f1;
}
@keyframes sawtooth {
100% {
background-position: 1em 0;
}
}
.kotlin-4 {
color: #eea163;
}
.kotlin-4:hover {
animation: zigzag 1s linear infinite;
background:
linear-gradient(
135deg,
rgba(238, 161, 99, 0.25) 0.25em,
transparent 0.25em
) -0.5em 0,
linear-gradient(
225deg,
rgba(238, 161, 99, 0.25) 0.25em,
transparent 0.25em
) -0.5em 0,
linear-gradient(
315deg,
rgba(238, 161, 99, 0.25) 0.25em,
transparent 0.25em
)
0 0,
linear-gradient(
45deg,
rgba(238, 161, 99, 0.25) 0.25em,
transparent 0.25em
)
0 0;
background-size: 0.75em 0.75em;
color: #63b0ee;
}
@keyframes zigzag {
100% {
background-position:
1em 0,
1em 0,
-0.75em 0,
-0.75em 0;
}
}
.kotlin-5 {
color: #f9879b;
}
.kotlin-5:hover {
animation: pulse 1s ease-in infinite;
background:
radial-gradient(circle, rgba(249, 135, 155, 0.25) 43%, transparent 50%)
0 0/1em 1em,
radial-gradient(circle, rgba(249, 135, 155, 0.25) 43%, transparent 50%)
0.5em 0.5em/2em 2em;
color: #0bdcb7;
}
@keyframes pulse {
50% {
background-position:
0.66em 0.66em,
-0.33em -0.33em;
}
100% {
background-size:
2em 2em,
1em 1em;
background-position:
-1.5em -1.5em,
-1em -1em;
}
}
.vb:before,
.vb:after {
box-sizing: border-box;
}
.vb {
position: relative;
width: 120px;
color: #fa5555;
height: 40px;
line-height: 42px;
border: 2px solid #fa5555;
border-radius: 14px;
text-transform: uppercase;
}
.dot {
content: "";
position: absolute;
top: 0;
width: 32px;
height: 100%;
border-radius: 50%;
transition: all 300ms ease;
display: none;
}
.dot:after {
content: "";
position: absolute;
top: -6px;
height: 5px;
width: 5px;
background: #fa5555;
border-radius: 50%;
border: 4px solid #fa5555;
box-shadow:
0 0 0.7em #fff,
0 0 2em #fa5555;
}
.vb:hover .dot,
.vb:focus .dot {
animation: atom 2s infinite linear;
display: block;
}
/*calc(122px - 36px) 按钮宽度 - dot宽度 - 边框宽度*/
@keyframes atom {
0% {
transform: translateX(0) rotate(0);
}
30% {
transform: translateX(calc(122px - 36px)) rotate(0);
}
50% {
transform: translateX(calc(122px - 36px)) rotate(180deg);
}
80% {
transform: translateX(0) rotate(180deg);
}
100% {
transform: translateX(0) rotate(360deg);
}
}
.btn-down {
position: absolute;
top: calc(50vh - 280px);
text-align: center;
border-radius: 4px;
cursor: pointer;
left: calc(50vw - 87px);
width: 122px;
line-height: 44px;
color: #fff;
background: #2194e0;
opacity: 1;
}
.btn-down:active {
opacity: 0.8;
}
</style>
</html>

View File

@ -1,4 +1,4 @@
import { http } from "@/utils/http";
import { http } from "@/utils/http/mockRequest";
type Result = {
success: boolean;

View File

@ -1,4 +1,4 @@
import { http } from "@/utils/http";
import { http } from "@/utils/http/mockRequest";
export type UserResult = {
success: boolean;

View File

@ -5,19 +5,26 @@ import Axios, {
} from "axios";
import type {
PureHttpError,
RequestMethods,
PureHttpRequestConfig,
PureHttpResponse,
PureHttpRequestConfig
RequestMethods
} from "./types.d";
import { stringify } from "qs";
import NProgress from "../progress";
import { getToken, formatToken } from "@/utils/auth";
import { formatToken, getToken } from "@/utils/auth";
import { useUserStoreHook } from "@/store/modules/user";
// 相关配置请参考www.axios-js.com/zh-cn/docs/#axios-request-config-1
const defaultConfig: AxiosRequestConfig = {
// 请求超时时间
timeout: 10000,
// 默认请求地址
baseURL: import.meta.env.VITE_BASE_API,
// 设置超时时间
timeout: import.meta.env.VITE_BASE_API_TIMEOUT,
// @ts-expect-error
retry: import.meta.env.VITE_BASE_API_RETRY, //设置全局重试请求次数(最多重试几次请求)
retryDelay: import.meta.env.VITE_BASE_API_RETRY_DELAY, //设置全局请求间隔
// 跨域允许携带凭证
// withCredentials: true,
headers: {
Accept: "application/json, text/plain, */*",
"Content-Type": "application/json",
@ -30,23 +37,20 @@ const defaultConfig: AxiosRequestConfig = {
};
class PureHttp {
/** `token`过期后,暂存待执行的请求 */
private static requests = [];
/** 防止重复刷新`token` */
private static isRefreshing = false;
/** 初始化配置对象 */
private static initConfig: PureHttpRequestConfig = {};
/** 保存当前`Axios`实例对象 */
private static axiosInstance: AxiosInstance = Axios.create(defaultConfig);
constructor() {
this.httpInterceptorsRequest();
this.httpInterceptorsResponse();
}
/** `token`过期后,暂存待执行的请求 */
private static requests = [];
/** 防止重复刷新`token` */
private static isRefreshing = false;
/** 初始化配置对象 */
private static initConfig: PureHttpRequestConfig = {};
/** 保存当前`Axios`实例对象 */
private static axiosInstance: AxiosInstance = Axios.create(defaultConfig);
/** 重连原始请求 */
private static retryOriginalRequest(config: PureHttpRequestConfig) {
return new Promise(resolve => {
@ -57,6 +61,51 @@ class PureHttp {
});
}
/** 通用请求工具函数 */
public request<T>(
method: RequestMethods,
url: string,
param?: AxiosRequestConfig,
axiosConfig?: PureHttpRequestConfig
): Promise<T> {
const config = {
method,
url,
...param,
...axiosConfig
} as PureHttpRequestConfig;
// 单独处理自定义请求/响应回调
return new Promise((resolve, reject) => {
PureHttp.axiosInstance
.request(config)
.then((response: undefined) => {
resolve(response);
})
.catch(error => {
reject(error);
});
});
}
/** 单独抽离的`post`工具函数 */
public post<T, P>(
url: string,
params?: AxiosRequestConfig<P>,
config?: PureHttpRequestConfig
): Promise<T> {
return this.request<T>("post", url, params, config);
}
/** 单独抽离的`get`工具函数 */
public get<T, P>(
url: string,
params?: AxiosRequestConfig<P>,
config?: PureHttpRequestConfig
): Promise<T> {
return this.request<T>("get", url, params, config);
}
/** 请求拦截 */
private httpInterceptorsRequest(): void {
PureHttp.axiosInstance.interceptors.request.use(
@ -144,51 +193,6 @@ class PureHttp {
}
);
}
/** 通用请求工具函数 */
public request<T>(
method: RequestMethods,
url: string,
param?: AxiosRequestConfig,
axiosConfig?: PureHttpRequestConfig
): Promise<T> {
const config = {
method,
url,
...param,
...axiosConfig
} as PureHttpRequestConfig;
// 单独处理自定义请求/响应回调
return new Promise((resolve, reject) => {
PureHttp.axiosInstance
.request(config)
.then((response: undefined) => {
resolve(response);
})
.catch(error => {
reject(error);
});
});
}
/** 单独抽离的`post`工具函数 */
public post<T, P>(
url: string,
params?: AxiosRequestConfig<P>,
config?: PureHttpRequestConfig
): Promise<T> {
return this.request<T>("post", url, params, config);
}
/** 单独抽离的`get`工具函数 */
public get<T, P>(
url: string,
params?: AxiosRequestConfig<P>,
config?: PureHttpRequestConfig
): Promise<T> {
return this.request<T>("get", url, params, config);
}
}
export const http = new PureHttp();

View File

@ -0,0 +1,191 @@
import Axios, {
type AxiosInstance,
type AxiosRequestConfig,
type CustomParamsSerializer
} from "axios";
import type {
PureHttpError,
PureHttpRequestConfig,
PureHttpResponse,
RequestMethods
} from "./types.d";
import { stringify } from "qs";
import NProgress from "../progress";
import { formatToken, getToken } from "@/utils/auth";
import { useUserStoreHook } from "@/store/modules/user";
// 相关配置请参考www.axios-js.com/zh-cn/docs/#axios-request-config-1
const defaultConfig: AxiosRequestConfig = {
timeout: import.meta.env.VITE_BASE_API_TIMEOUT,
baseURL: import.meta.env.VITE_MOCK_BASE_API || "/mock",
headers: {
Accept: "application/json, text/plain, */*",
"Content-Type": "application/json",
"X-Requested-With": "XMLHttpRequest"
},
// 数组格式参数序列化https://github.com/axios/axios/issues/5142
paramsSerializer: {
serialize: stringify as unknown as CustomParamsSerializer
}
};
class PureHttp {
/** `token`过期后,暂存待执行的请求 */
private static requests = [];
/** 防止重复刷新`token` */
private static isRefreshing = false;
/** 初始化配置对象 */
private static initConfig: PureHttpRequestConfig = {};
/** 保存当前`Axios`实例对象 */
private static axiosInstance: AxiosInstance = Axios.create(defaultConfig);
constructor() {
this.httpInterceptorsRequest();
this.httpInterceptorsResponse();
}
/** 重连原始请求 */
private static retryOriginalRequest(config: PureHttpRequestConfig) {
return new Promise(resolve => {
PureHttp.requests.push((token: string) => {
config.headers["Authorization"] = formatToken(token);
resolve(config);
});
});
}
/** 通用请求工具函数 */
public request<T>(
method: RequestMethods,
url: string,
param?: AxiosRequestConfig,
axiosConfig?: PureHttpRequestConfig
): Promise<T> {
const config = {
method,
url,
...param,
...axiosConfig
} as PureHttpRequestConfig;
// 单独处理自定义请求/响应回调
return new Promise((resolve, reject) => {
PureHttp.axiosInstance
.request(config)
.then((response: undefined) => {
resolve(response);
})
.catch(error => {
reject(error);
});
});
}
/** 单独抽离的`post`工具函数 */
public post<T, P>(
url: string,
params?: AxiosRequestConfig<P>,
config?: PureHttpRequestConfig
): Promise<T> {
return this.request<T>("post", url, params, config);
}
/** 单独抽离的`get`工具函数 */
public get<T, P>(
url: string,
params?: AxiosRequestConfig<P>,
config?: PureHttpRequestConfig
): Promise<T> {
return this.request<T>("get", url, params, config);
}
/** 请求拦截 */
private httpInterceptorsRequest(): void {
PureHttp.axiosInstance.interceptors.request.use(
async (config: PureHttpRequestConfig): Promise<any> => {
// 开启进度条动画
NProgress.start();
// 优先判断post/get等方法是否传入回调否则执行初始化设置等回调
if (typeof config.beforeRequestCallback === "function") {
config.beforeRequestCallback(config);
return config;
}
if (PureHttp.initConfig.beforeRequestCallback) {
PureHttp.initConfig.beforeRequestCallback(config);
return config;
}
/** 请求白名单,放置一些不需要`token`的接口(通过设置请求白名单,防止`token`过期后再请求造成的死循环问题) */
const whiteList = ["/refresh-token", "/login"];
return whiteList.some(url => config.url.endsWith(url))
? config
: new Promise(resolve => {
const data = getToken();
if (data) {
const now = new Date().getTime();
const expired = parseInt(data.expires) - now <= 0;
if (expired) {
if (!PureHttp.isRefreshing) {
PureHttp.isRefreshing = true;
// token过期刷新
useUserStoreHook()
.handRefreshToken({ refreshToken: data.refreshToken })
.then(res => {
const token = res.data.accessToken;
config.headers["Authorization"] = formatToken(token);
PureHttp.requests.forEach(cb => cb(token));
PureHttp.requests = [];
})
.finally(() => {
PureHttp.isRefreshing = false;
});
}
resolve(PureHttp.retryOriginalRequest(config));
} else {
config.headers["Authorization"] = formatToken(
data.accessToken
);
resolve(config);
}
} else {
resolve(config);
}
});
},
error => {
return Promise.reject(error);
}
);
}
/** 响应拦截 */
private httpInterceptorsResponse(): void {
const instance = PureHttp.axiosInstance;
instance.interceptors.response.use(
(response: PureHttpResponse) => {
const $config = response.config;
// 关闭进度条动画
NProgress.done();
// 优先判断post/get等方法是否传入回调否则执行初始化设置等回调
if (typeof $config.beforeResponseCallback === "function") {
$config.beforeResponseCallback(response);
return response.data;
}
if (PureHttp.initConfig.beforeResponseCallback) {
PureHttp.initConfig.beforeResponseCallback(response);
return response.data;
}
return response.data;
},
(error: PureHttpError) => {
const $error = error;
$error.isCancelRequest = Axios.isCancel($error);
// 关闭进度条动画
NProgress.done();
// 所有的响应异常 区分来源为取消请求/非取消请求
return Promise.reject($error);
}
);
}
}
export const http = new PureHttp();

1
types/global.d.ts vendored
View File

@ -65,6 +65,7 @@ declare global {
*/
interface ViteEnv {
VITE_PORT: number;
VITE_APP_URL: string;
VITE_PUBLIC_PATH: string;
VITE_ROUTER_HISTORY: string;
VITE_CDN: boolean;

View File

@ -1,13 +1,9 @@
import { getPluginsList } from "./build/plugins";
import { exclude, include } from "./build/optimize";
import { type ConfigEnv, loadEnv, type UserConfigExport } from "vite";
import {
__APP_INFO__,
alias,
pathResolve,
root,
wrapperEnv
} from "./build/utils";
import { __APP_INFO__, alias, root, wrapperEnv } from "./build/utils";
import { serverOptions } from "./build/server";
import { buildEnvironment } from "./build/buildEnv";
export default ({ mode }: ConfigEnv): UserConfigExport => {
const { VITE_CDN, VITE_PORT, VITE_COMPRESSION, VITE_PUBLIC_PATH } =
@ -15,45 +11,19 @@ export default ({ mode }: ConfigEnv): UserConfigExport => {
return {
base: VITE_PUBLIC_PATH,
root,
resolve: {
alias
},
resolve: { alias },
// 服务端渲染
server: {
// 端口号
port: VITE_PORT,
host: "0.0.0.0",
// 本地跨域代理 https://cn.vitejs.dev/config/server-options.html#server-proxy
proxy: {},
// 预热文件以提前转换和缓存结果,降低启动期间的初始页面加载时长并防止转换瀑布
warmup: {
clientFiles: ["./index.html", "./src/{views,components}/*"]
}
},
server: serverOptions(mode),
plugins: getPluginsList(VITE_CDN, VITE_COMPRESSION, VITE_PORT),
// https://cn.vitejs.dev/config/dep-optimization-options.html#dep-optimization-options
optimizeDeps: {
include,
exclude
},
build: {
// https://cn.vitejs.dev/guide/build.html#browser-compatibility
target: "es2015",
sourcemap: false,
// 消除打包大小超过500kb警告
chunkSizeWarningLimit: 4000,
rollupOptions: {
input: {
index: pathResolve("./index.html", import.meta.url)
},
// 静态资源分类打包
output: {
chunkFileNames: "static/js/[name]-[hash].js",
entryFileNames: "static/js/[name]-[hash].js",
assetFileNames: "static/[ext]/[name]-[hash].[ext]"
}
}
optimizeDeps: { include, exclude },
esbuild: {
pure: ["console.log", "debugger"],
jsxFactory: "h",
jsxFragment: "Fragment",
jsxInject: "import { h } from 'vue';"
},
build: buildEnvironment(),
define: {
__INTLIFY_PROD_DEVTOOLS__: false,
__APP_INFO__: JSON.stringify(__APP_INFO__)