Compare commits

..

10 Commits

Author SHA1 Message Date
xiaoxian521
1bafbeaab7 release: update 3.6.4 2022-11-10 12:28:10 +08:00
xiaoxian521
9a802296c7 perf: 优化路由守卫 2022-11-08 18:17:33 +08:00
xiaoxian521
e183ea75a0 feat: 菜单图标 icon 支持使用在线图标 2022-11-08 12:10:54 +08:00
xiaoxian521
969775c7cf perf: 优化代码 2022-11-08 01:25:44 +08:00
xiaoxian521
841c5bd53a release: update 3.6.3 2022-11-01 16:29:32 +08:00
xiaoxian521
761b0e5ec2 feat: 提交非国际化版本代码 2022-10-28 15:32:31 +08:00
xiaoxian521
b811256830 feat: 静态资源分类打包 2022-10-27 15:51:06 +08:00
xiaoxian521
6019739c16 chore: 同步完整版代码 2022-10-27 14:51:32 +08:00
xiaoxian521
0dd1c67280 release: update 3.6.2 2022-10-27 13:18:27 +08:00
xiaoxian521
7d419c3b35 refactor: 使用@/别名替换/@/别名 2022-10-27 13:17:56 +08:00
87 changed files with 379 additions and 1158 deletions

View File

@@ -4,11 +4,5 @@ VITE_PORT = 8848
# 开发环境读取配置文件路径 # 开发环境读取配置文件路径
VITE_PUBLIC_PATH = / VITE_PUBLIC_PATH = /
# 开发环境代理
VITE_PROXY_DOMAIN = /api
# 开发环境路由历史模式 # 开发环境路由历史模式
VITE_ROUTER_HISTORY = "hash" VITE_ROUTER_HISTORY = "hash"
# 开发环境后端地址
VITE_PROXY_DOMAIN_REAL = "http://127.0.0.1:3000"

View File

@@ -4,9 +4,6 @@ VITE_PUBLIC_PATH = /
# 线上环境路由历史模式 # 线上环境路由历史模式
VITE_ROUTER_HISTORY = "hash" VITE_ROUTER_HISTORY = "hash"
# 线上环境后端地址
VITE_PROXY_DOMAIN_REAL = ""
# 是否为打包后的文件提供传统浏览器兼容性支持 支持 true 不支持 false # 是否为打包后的文件提供传统浏览器兼容性支持 支持 true 不支持 false
VITE_LEGACY = false VITE_LEGACY = false

View File

@@ -7,16 +7,13 @@ VITE_PUBLIC_PATH = /
# 线上环境路由历史模式 # 线上环境路由历史模式
VITE_ROUTER_HISTORY = "hash" VITE_ROUTER_HISTORY = "hash"
# 线上环境后端地址
VITE_PROXY_DOMAIN_REAL = ""
# 是否为打包后的文件提供传统浏览器兼容性支持 支持 true 不支持 false # 是否为打包后的文件提供传统浏览器兼容性支持 支持 true 不支持 false
VITE_LEGACY = false VITE_LEGACY = false
# 是否在打包时使用cdn替换本地库 替换 true 不替换 false # 是否在打包时使用cdn替换本地库 替换 true 不替换 false
VITE_CDN = false VITE_CDN = true
# 是否启用gzip压缩或brotli压缩分两种情况删除原始文件和不删除原始文件 # 是否启用gzip压缩或brotli压缩分两种情况删除原始文件和不删除原始文件
# 压缩时不删除原始文件的配置gzip、brotli、both同时开启 gzip 与 brotli 压缩、none不开启压缩默认 # 压缩时不删除原始文件的配置gzip、brotli、both同时开启 gzip 与 brotli 压缩、none不开启压缩默认
# 压缩时删除原始文件的配置gzip-clear、brotli-clear、both-clear同时开启 gzip 与 brotli 压缩、none不开启压缩默认 # 压缩时删除原始文件的配置gzip-clear、brotli-clear、both-clear同时开启 gzip 与 brotli 压缩、none不开启压缩默认
VITE_COMPRESSION = "none" VITE_COMPRESSION = "both-clear"

View File

@@ -7,7 +7,6 @@
"bradlc.vscode-tailwindcss", "bradlc.vscode-tailwindcss",
"dbaeumer.vscode-eslint", "dbaeumer.vscode-eslint",
"esbenp.prettier-vscode", "esbenp.prettier-vscode",
"lokalise.i18n-ally",
"redhat.vscode-yaml", "redhat.vscode-yaml",
"csstools.postcss", "csstools.postcss",
"mikestead.dotenv", "mikestead.dotenv",

View File

@@ -27,13 +27,5 @@
"editor.codeActionsOnSave": { "editor.codeActionsOnSave": {
"source.fixAll.eslint": true "source.fixAll.eslint": true
}, },
"i18n-ally.localesPaths": "locales",
"i18n-ally.keystyle": "nested",
"i18n-ally.sortKeys": true,
"i18n-ally.namespace": true,
"i18n-ally.enabledParsers": ["yaml", "js"],
"i18n-ally.sourceLanguage": "en",
"i18n-ally.displayLanguage": "zh-CN",
"i18n-ally.enabledFrameworks": ["vue"],
"iconify.excludes": ["el"] "iconify.excludes": ["el"]
} }

View File

@@ -1,4 +1,4 @@
<h1>vue-pure-admin Lite Edition</h1> <h1>vue-pure-admin Lite Editionno i18n version</h1>
[![license](https://img.shields.io/github/license/xiaoxian521/vue-pure-admin.svg)](LICENSE) [![license](https://img.shields.io/github/license/xiaoxian521/vue-pure-admin.svg)](LICENSE)
@@ -6,7 +6,7 @@
## introduce ## introduce
The lite version is based on the shelf extracted from [vue-pure-admin](https://github.com/xiaoxian521/vue-pure-admin), which contains the main functions and is more suitable for actual project development, the packaged size is only `3MB`, and will permanently sync the full version of the code The Lite version is based on the shelf extracted from [vue-pure-admin](https://github.com/xiaoxian521/vue-pure-admin), including the main functions, which is more suitable for actual project development, and the packaged size is lower than ` 3MB`, and will permanently sync the full version of the code. After enabling `brotli` compression and `cdn` to replace the native library mode, the package size is less than `500kb`
## Supporting Video ## Supporting Video
@@ -15,9 +15,8 @@ The lite version is based on the shelf extracted from [vue-pure-admin](https://g
## Docs ## Docs
- [Click me to view the domestic documentation site](http://yiming_chang.gitee.io/pure-admin-doc) - [Click me to view the domestic documentation site](https://yiming_chang.gitee.io/pure-admin-doc)
- [Click me to view foreign document site 1](https://xiaoxian521.github.io/pure-admin-doc) - [Click me to view foreign document site](https://xiaoxian521.github.io/pure-admin-doc)
- [Click me to view foreign document site 2](https://pure-admin-doc.vercel.app)
## Usage ## Usage
@@ -42,7 +41,6 @@ bilibili: https://www.bilibili.com/video/BV1534y1S7HV/
## ⚠️ Attention ## ⚠️ Attention
- The Lite version does not accept any issues and prs. If you have any questions, please go to the full version https://github.com/xiaoxian521/vue-pure-admin/issues/new/choose to mention, thank you! ! ! - The Lite version does not accept any issues and prs. If you have any questions, please go to the full version https://github.com/xiaoxian521/vue-pure-admin/issues/new/choose to mention, thank you! ! !
- Don't use the `delete-i18n` branch code, this branch is just for you to completely delete the internationalized references, it won't sync the code! ! ! [Completely remove the internationalization tutorial](https://www.bilibili.com/video/BV1Ru411B7k3/), please be sure to use the code from the `main` branch! ! !
## License ## License

View File

@@ -1,4 +1,4 @@
<h1>vue-pure-admin精简版</h1> <h1>vue-pure-admin精简版(非国际化版本)</h1>
[![license](https://img.shields.io/github/license/xiaoxian521/vue-pure-admin.svg)](LICENSE) [![license](https://img.shields.io/github/license/xiaoxian521/vue-pure-admin.svg)](LICENSE)
@@ -6,7 +6,7 @@
## 介绍 ## 介绍
精简版是基于 [vue-pure-admin](https://github.com/xiaoxian521/vue-pure-admin) 提炼出的架子,包含主体功能,更适合实际项目开发,打包后的大小 `3MB`,并且会永久同步完整版的代码 精简版是基于 [vue-pure-admin](https://github.com/xiaoxian521/vue-pure-admin) 提炼出的架子,包含主体功能,更适合实际项目开发,打包后的大小低于 `3MB`,并且会永久同步完整版的代码。开启 `brotli` 压缩和 `cdn` 替换本地库模式后,打包大小低于 `500kb`
## 配套视频 ## 配套视频
@@ -15,9 +15,8 @@
## 配套文档 ## 配套文档
- [点我查看国内文档站](http://yiming_chang.gitee.io/pure-admin-doc) - [点我查看国内文档站](https://yiming_chang.gitee.io/pure-admin-doc)
- [点我查看国外文档站 1](https://xiaoxian521.github.io/pure-admin-doc) - [点我查看国外文档站](https://xiaoxian521.github.io/pure-admin-doc)
- [点我查看国外文档站 2](https://pure-admin-doc.vercel.app)
## 维护者 ## 维护者
@@ -54,7 +53,6 @@ pnpm remove 包名
## ⚠️ 注意 ## ⚠️ 注意
- 精简版不接受任何 `issues``pr`,如果有问题请到完整版 [issues](https://github.com/xiaoxian521/vue-pure-admin/issues/new/choose) 去提,谢谢!!! - 精简版不接受任何 `issues``pr`,如果有问题请到完整版 [issues](https://github.com/xiaoxian521/vue-pure-admin/issues/new/choose) 去提,谢谢!!!
- 不要使用 `delete-i18n` 分支代码,这个分支只是给你们完全删除国际化的参考,不会同步代码的!!! [完全删除国际化教程](https://www.bilibili.com/video/BV1Ru411B7k3/) ,请务必使用 `main` 分支的代码!!!
## 许可证 ## 许可证

View File

@@ -20,11 +20,6 @@ export const cdn = importToCDN({
var: "VueRouter", var: "VueRouter",
path: "vue-router.global.min.js" path: "vue-router.global.min.js"
}, },
{
name: "vue-i18n",
var: "VueI18n",
path: "vue-i18n.runtime.global.prod.min.js"
},
// 项目中没有直接安装vue-demi但是pinia用到了所以需要在引入pinia前引入vue-demihttps://github.com/vuejs/pinia/blob/v2/packages/pinia/package.json#L77 // 项目中没有直接安装vue-demi但是pinia用到了所以需要在引入pinia前引入vue-demihttps://github.com/vuejs/pinia/blob/v2/packages/pinia/package.json#L77
{ {
name: "vue-demi", name: "vue-demi",

View File

@@ -4,8 +4,6 @@ const warpperEnv = (envConf: Recordable): ViteEnv => {
const ret: ViteEnv = { const ret: ViteEnv = {
VITE_PORT: 8848, VITE_PORT: 8848,
VITE_PUBLIC_PATH: "", VITE_PUBLIC_PATH: "",
VITE_PROXY_DOMAIN: "",
VITE_PROXY_DOMAIN_REAL: "",
VITE_ROUTER_HISTORY: "", VITE_ROUTER_HISTORY: "",
VITE_LEGACY: false, VITE_LEGACY: false,
VITE_CDN: false, VITE_CDN: false,
@@ -30,14 +28,9 @@ const warpperEnv = (envConf: Recordable): ViteEnv => {
return ret; return ret;
}; };
/** 跨域代理重写 */
const regExps = (value: string, reg: string): string => {
return value.replace(new RegExp(`^${reg}`, "g"), "");
};
/** 环境变量 */ /** 环境变量 */
const loadEnv = (): ViteEnv => { const loadEnv = (): ViteEnv => {
return import.meta.env; return import.meta.env;
}; };
export { warpperEnv, regExps, loadEnv }; export { warpperEnv, loadEnv };

View File

@@ -1,5 +1,4 @@
import { cdn } from "./cdn"; import { cdn } from "./cdn";
import { resolve } from "path";
import vue from "@vitejs/plugin-vue"; import vue from "@vitejs/plugin-vue";
import { viteBuildInfo } from "./info"; import { viteBuildInfo } from "./info";
import svgLoader from "vite-svg-loader"; import svgLoader from "vite-svg-loader";
@@ -7,13 +6,12 @@ import legacy from "@vitejs/plugin-legacy";
import vueJsx from "@vitejs/plugin-vue-jsx"; import vueJsx from "@vitejs/plugin-vue-jsx";
import { viteMockServe } from "vite-plugin-mock"; import { viteMockServe } from "vite-plugin-mock";
import { configCompressPlugin } from "./compress"; import { configCompressPlugin } from "./compress";
import VueI18n from "@intlify/vite-plugin-vue-i18n";
// import ElementPlus from "unplugin-element-plus/vite"; // import ElementPlus from "unplugin-element-plus/vite";
import { visualizer } from "rollup-plugin-visualizer"; import { visualizer } from "rollup-plugin-visualizer";
import removeConsole from "vite-plugin-remove-console"; import removeConsole from "vite-plugin-remove-console";
import themePreprocessorPlugin from "@pureadmin/theme"; import themePreprocessorPlugin from "@pureadmin/theme";
import { genScssMultipleScopeVars } from "/@/layout/theme";
import DefineOptions from "unplugin-vue-define-options/vite"; import DefineOptions from "unplugin-vue-define-options/vite";
import { genScssMultipleScopeVars } from "../src/layout/theme";
export function getPluginsList( export function getPluginsList(
command: string, command: string,
@@ -25,12 +23,6 @@ export function getPluginsList(
const lifecycle = process.env.npm_lifecycle_event; const lifecycle = process.env.npm_lifecycle_event;
return [ return [
vue(), vue(),
// https://github.com/intlify/bundle-tools/tree/main/packages/vite-plugin-vue-i18n
VueI18n({
runtimeOnly: true,
compositionOnly: true,
include: [resolve("locales/**")]
}),
// jsx、tsx语法支持 // jsx、tsx语法支持
vueJsx(), vueJsx(),
VITE_CDN ? cdn : null, VITE_CDN ? cdn : null,

View File

@@ -1,43 +0,0 @@
buttons:
hsLoginOut: LoginOut
hsfullscreen: FullScreen
hsexitfullscreen: ExitFullscreen
hsrefreshRoute: RefreshRoute
hslogin: Login
hsadd: Add
hsmark: Mark/Cancel
hssave: Save
hssearch: Search
hsexpendAll: Expand All
hscollapseAll: Collapse All
hssystemSet: Open ProjectConfig
hsdelete: Delete
hsreload: Reload
hscloseCurrentTab: Close CurrentTab
hscloseLeftTabs: Close LeftTabs
hscloseRightTabs: Close RightTabs
hscloseOtherTabs: Close OtherTabs
hscloseAllTabs: Close AllTabs
hswholeFullScreen: Whole FullScreen
hswholeExitFullScreen: Whole ExitFullScreen
hscontentFullScreen: Content FullScreen
hscontentExitFullScreen: Content ExitFullScreen
menus:
hshome: Home
hslogin: Login
hsabnormal: Abnormal Page
hsfourZeroFour: "404"
hsfourZeroOne: "403"
hsFive: "500"
permission: Permission Manage
permissionPage: Page Permission
permissionButton: Button Permission
status:
hsLoad: Loading...
login:
username: Username
password: Password
login: Login
usernameReg: Please enter username
passwordReg: Please enter password
passwordRuleReg: The password format should be any combination of 8-18 digits

View File

@@ -1,43 +0,0 @@
buttons:
hsLoginOut: 退出系统
hsfullscreen: 全屏
hsexitfullscreen: 退出全屏
hsrefreshRoute: 刷新路由
hslogin: 登录
hsadd: 新增
hsmark: 标记/取消
hssave: 保存
hssearch: 搜索
hsexpendAll: 全部展开
hscollapseAll: 全部折叠
hssystemSet: 打开项目配置
hsdelete: 删除
hsreload: 重新加载
hscloseCurrentTab: 关闭当前标签页
hscloseLeftTabs: 关闭左侧标签页
hscloseRightTabs: 关闭右侧标签页
hscloseOtherTabs: 关闭其他标签页
hscloseAllTabs: 关闭全部标签页
hswholeFullScreen: 整体页面全屏
hswholeExitFullScreen: 整体页面退出全屏
hscontentFullScreen: 内容区全屏
hscontentExitFullScreen: 内容区退出全屏
menus:
hshome: 首页
hslogin: 登录
hsabnormal: 异常页面
hsfourZeroFour: "404"
hsfourZeroOne: "403"
hsFive: "500"
permission: 权限管理
permissionPage: 页面权限
permissionButton: 按钮权限
status:
hsLoad: 加载中...
login:
username: 账号
password: 密码
login: 登录
usernameReg: 请输入账号
passwordReg: 请输入密码
passwordRuleReg: 密码格式应为8-18位数字、字母、符号的任意两种组合

View File

@@ -10,7 +10,7 @@ import { MockMethod } from "vite-plugin-mock";
const permissionRouter = { const permissionRouter = {
path: "/permission", path: "/permission",
meta: { meta: {
title: "menus.permission", title: "权限管理",
icon: "lollipop", icon: "lollipop",
rank: 10 rank: 10
}, },
@@ -19,15 +19,15 @@ const permissionRouter = {
path: "/permission/page/index", path: "/permission/page/index",
name: "PermissionPage", name: "PermissionPage",
meta: { meta: {
roles: ["admin", "common"], title: "页面权限",
title: "menus.permissionPage" roles: ["admin", "common"]
} }
}, },
{ {
path: "/permission/button/index", path: "/permission/button/index",
name: "PermissionButton", name: "PermissionButton",
meta: { meta: {
title: "menus.permissionButton", title: "按钮权限",
roles: ["admin", "common"], roles: ["admin", "common"],
auths: ["btn_add", "btn_edit", "btn_delete"] auths: ["btn_add", "btn_edit", "btn_delete"]
} }

View File

@@ -10,8 +10,8 @@ export default [
return { return {
success: true, success: true,
data: { data: {
accessToken: "eyJhbGciOiJIUzUxMiJ9.admin", accessToken: "eyJhbGciOiJIUzUxMiJ9.newAdmin",
refreshToken: "eyJhbGciOiJIUzUxMiJ9.adminRefresh", refreshToken: "eyJhbGciOiJIUzUxMiJ9.newAdminRefresh",
// `expires`选择这种日期格式是为了方便调试,后端直接设置时间戳或许更方便(每次都应该递增)。如果后端返回的是时间戳格式,前端开发请来到这个目录`src/utils/auth.ts`,把第`38`行的代码换成expires = data.expires即可。 // `expires`选择这种日期格式是为了方便调试,后端直接设置时间戳或许更方便(每次都应该递增)。如果后端返回的是时间戳格式,前端开发请来到这个目录`src/utils/auth.ts`,把第`38`行的代码换成expires = data.expires即可。
expires: "2023/10/30 23:59:59" expires: "2023/10/30 23:59:59"
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "pure-admin-thin", "name": "pure-admin-thin",
"version": "3.6.1", "version": "3.6.3",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "NODE_OPTIONS=--max-old-space-size=4096 vite", "dev": "NODE_OPTIONS=--max-old-space-size=4096 vite",
@@ -12,7 +12,7 @@
"preview:build": "pnpm build && vite preview", "preview:build": "pnpm build && vite preview",
"typecheck": "tsc --noEmit && vue-tsc --noEmit --skipLibCheck", "typecheck": "tsc --noEmit && vue-tsc --noEmit --skipLibCheck",
"cloc": "NODE_OPTIONS=--max-old-space-size=4096 cloc . --exclude-dir=node_modules --exclude-lang=YAML", "cloc": "NODE_OPTIONS=--max-old-space-size=4096 cloc . --exclude-dir=node_modules --exclude-lang=YAML",
"clean:cache": "rm -rf node_modules && rm -rf .eslintcache && pnpm install", "clean:cache": "rm -rf node_modules && rm -rf .eslintcache && npm cache clean --force && pnpm install",
"lint:eslint": "eslint --cache --max-warnings 0 \"{src,mock,build}/**/*.{vue,js,ts,tsx}\" --fix", "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,less,scss,vue,html,md}\"", "lint:prettier": "prettier --write \"src/**/*.{js,ts,json,tsx,css,less,scss,vue,html,md}\"",
"lint:stylelint": "stylelint --cache --fix \"**/*.{vue,css,scss,postcss,less}\" --cache --cache-location node_modules/.cache/stylelint/", "lint:stylelint": "stylelint --cache --fix \"**/*.{vue,css,scss,postcss,less}\" --cache --cache-location node_modules/.cache/stylelint/",
@@ -55,7 +55,6 @@
"resize-observer-polyfill": "^1.5.1", "resize-observer-polyfill": "^1.5.1",
"responsive-storage": "^2.1.0", "responsive-storage": "^2.1.0",
"vue": "^3.2.40", "vue": "^3.2.40",
"vue-i18n": "^9.2.2",
"vue-router": "^4.1.6", "vue-router": "^4.1.6",
"vue-types": "^4.2.1", "vue-types": "^4.2.1",
"vxe-table": "^4.3.2", "vxe-table": "^4.3.2",
@@ -67,7 +66,6 @@
"@iconify-icons/ep": "^1.2.7", "@iconify-icons/ep": "^1.2.7",
"@iconify-icons/ri": "^1.2.3", "@iconify-icons/ri": "^1.2.3",
"@iconify/vue": "^3.2.1", "@iconify/vue": "^3.2.1",
"@intlify/vite-plugin-vue-i18n": "^6.0.3",
"@pureadmin/theme": "^2.4.0", "@pureadmin/theme": "^2.4.0",
"@types/element-resize-detector": "1.1.3", "@types/element-resize-detector": "1.1.3",
"@types/js-cookie": "^3.0.1", "@types/js-cookie": "^3.0.1",
@@ -85,9 +83,9 @@
"@vue/eslint-config-prettier": "^7.0.0", "@vue/eslint-config-prettier": "^7.0.0",
"@vue/eslint-config-typescript": "^10.0.0", "@vue/eslint-config-typescript": "^10.0.0",
"@vue/runtime-core": "^3.2.40", "@vue/runtime-core": "^3.2.40",
"autoprefixer": "^10.4.12", "autoprefixer": "^10.4.13",
"cloc": "^2.10.0", "cloc": "^2.10.0",
"cssnano": "^5.1.13", "cssnano": "^5.1.14",
"eslint": "^8.8.0", "eslint": "^8.8.0",
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^8.4.1", "eslint-plugin-vue": "^8.4.1",
@@ -95,14 +93,14 @@
"husky": "^7.0.4", "husky": "^7.0.4",
"lint-staged": "11.1.2", "lint-staged": "11.1.2",
"picocolors": "^1.0.0", "picocolors": "^1.0.0",
"postcss": "^8.4.17", "postcss": "^8.4.18",
"postcss-html": "^1.5.0", "postcss-html": "^1.5.0",
"postcss-import": "^15.0.0", "postcss-import": "^15.0.0",
"postcss-scss": "^4.0.5", "postcss-scss": "^4.0.5",
"prettier": "^2.5.1", "prettier": "^2.5.1",
"pretty-quick": "3.1.1", "pretty-quick": "3.1.1",
"rimraf": "3.0.2", "rimraf": "3.0.2",
"rollup-plugin-visualizer": "^5.8.2", "rollup-plugin-visualizer": "^5.8.3",
"sass": "^1.53.0", "sass": "^1.53.0",
"sass-loader": "^13.0.2", "sass-loader": "^13.0.2",
"stylelint": "^14.3.0", "stylelint": "^14.3.0",
@@ -111,15 +109,15 @@
"stylelint-config-recommended": "^6.0.0", "stylelint-config-recommended": "^6.0.0",
"stylelint-config-standard": "^24.0.0", "stylelint-config-standard": "^24.0.0",
"stylelint-order": "^5.0.0", "stylelint-order": "^5.0.0",
"tailwindcss": "^3.2.1", "tailwindcss": "^3.2.3",
"terser": "^5.15.0", "terser": "^5.15.1",
"typescript": "^4.7.4", "typescript": "^4.7.4",
"unplugin-vue-define-options": "0.7.3", "unplugin-vue-define-options": "0.7.3",
"vite": "^3.1.8", "vite": "^3.1.8",
"vite-plugin-cdn-import": "^0.3.5", "vite-plugin-cdn-import": "^0.3.5",
"vite-plugin-compression": "^0.5.1", "vite-plugin-compression": "^0.5.1",
"vite-plugin-mock": "^2.9.6", "vite-plugin-mock": "^2.9.6",
"vite-plugin-remove-console": "^1.1.0", "vite-plugin-remove-console": "^1.2.0",
"vite-svg-loader": "^3.6.0", "vite-svg-loader": "^3.6.0",
"vue-eslint-parser": "^8.2.0", "vue-eslint-parser": "^8.2.0",
"vue-tsc": "^0.40.13" "vue-tsc": "^0.40.13"

309
pnpm-lock.yaml generated
View File

@@ -7,7 +7,6 @@ specifiers:
"@iconify-icons/ep": ^1.2.7 "@iconify-icons/ep": ^1.2.7
"@iconify-icons/ri": ^1.2.3 "@iconify-icons/ri": ^1.2.3
"@iconify/vue": ^3.2.1 "@iconify/vue": ^3.2.1
"@intlify/vite-plugin-vue-i18n": ^6.0.3
"@pureadmin/components": ^1.1.0 "@pureadmin/components": ^1.1.0
"@pureadmin/descriptions": ^1.1.0 "@pureadmin/descriptions": ^1.1.0
"@pureadmin/table": ^1.2.0 "@pureadmin/table": ^1.2.0
@@ -33,10 +32,10 @@ specifiers:
"@vueuse/motion": ^2.0.0-beta.12 "@vueuse/motion": ^2.0.0-beta.12
"@vueuse/shared": ^9.4.0 "@vueuse/shared": ^9.4.0
animate.css: ^4.1.1 animate.css: ^4.1.1
autoprefixer: ^10.4.12 autoprefixer: ^10.4.13
axios: ^1.1.3 axios: ^1.1.3
cloc: ^2.10.0 cloc: ^2.10.0
cssnano: ^5.1.13 cssnano: ^5.1.14
dayjs: ^1.11.4 dayjs: ^1.11.4
echarts: ^5.3.3 echarts: ^5.3.3
element-plus: ^2.2.16 element-plus: ^2.2.16
@@ -57,7 +56,7 @@ specifiers:
path: ^0.12.7 path: ^0.12.7
picocolors: ^1.0.0 picocolors: ^1.0.0
pinia: ^2.0.21 pinia: ^2.0.21
postcss: ^8.4.17 postcss: ^8.4.18
postcss-html: ^1.5.0 postcss-html: ^1.5.0
postcss-import: ^15.0.0 postcss-import: ^15.0.0
postcss-scss: ^4.0.5 postcss-scss: ^4.0.5
@@ -67,7 +66,7 @@ specifiers:
resize-observer-polyfill: ^1.5.1 resize-observer-polyfill: ^1.5.1
responsive-storage: ^2.1.0 responsive-storage: ^2.1.0
rimraf: 3.0.2 rimraf: 3.0.2
rollup-plugin-visualizer: ^5.8.2 rollup-plugin-visualizer: ^5.8.3
sass: ^1.53.0 sass: ^1.53.0
sass-loader: ^13.0.2 sass-loader: ^13.0.2
stylelint: ^14.3.0 stylelint: ^14.3.0
@@ -76,19 +75,18 @@ specifiers:
stylelint-config-recommended: ^6.0.0 stylelint-config-recommended: ^6.0.0
stylelint-config-standard: ^24.0.0 stylelint-config-standard: ^24.0.0
stylelint-order: ^5.0.0 stylelint-order: ^5.0.0
tailwindcss: ^3.2.1 tailwindcss: ^3.2.3
terser: ^5.15.0 terser: ^5.15.1
typescript: ^4.7.4 typescript: ^4.7.4
unplugin-vue-define-options: 0.7.3 unplugin-vue-define-options: 0.7.3
vite: ^3.1.8 vite: ^3.1.8
vite-plugin-cdn-import: ^0.3.5 vite-plugin-cdn-import: ^0.3.5
vite-plugin-compression: ^0.5.1 vite-plugin-compression: ^0.5.1
vite-plugin-mock: ^2.9.6 vite-plugin-mock: ^2.9.6
vite-plugin-remove-console: ^1.1.0 vite-plugin-remove-console: ^1.2.0
vite-svg-loader: ^3.6.0 vite-svg-loader: ^3.6.0
vue: ^3.2.40 vue: ^3.2.40
vue-eslint-parser: ^8.2.0 vue-eslint-parser: ^8.2.0
vue-i18n: ^9.2.2
vue-router: ^4.1.6 vue-router: ^4.1.6
vue-tsc: ^0.40.13 vue-tsc: ^0.40.13
vue-types: ^4.2.1 vue-types: ^4.2.1
@@ -123,7 +121,6 @@ dependencies:
resize-observer-polyfill: 1.5.1 resize-observer-polyfill: 1.5.1
responsive-storage: 2.1.0 responsive-storage: 2.1.0
vue: 3.2.41 vue: 3.2.41
vue-i18n: 9.2.2_vue@3.2.41
vue-router: 4.1.6_vue@3.2.41 vue-router: 4.1.6_vue@3.2.41
vue-types: 4.2.1_vue@3.2.41 vue-types: 4.2.1_vue@3.2.41
vxe-table: 4.3.5_vue@3.2.41+xe-utils@3.5.7 vxe-table: 4.3.5_vue@3.2.41+xe-utils@3.5.7
@@ -135,7 +132,6 @@ devDependencies:
"@iconify-icons/ep": 1.2.9 "@iconify-icons/ep": 1.2.9
"@iconify-icons/ri": 1.2.3 "@iconify-icons/ri": 1.2.3
"@iconify/vue": 3.2.1_vue@3.2.41 "@iconify/vue": 3.2.1_vue@3.2.41
"@intlify/vite-plugin-vue-i18n": 6.0.3_vite@3.1.8+vue-i18n@9.2.2
"@pureadmin/theme": 2.4.0 "@pureadmin/theme": 2.4.0
"@types/element-resize-detector": 1.1.3 "@types/element-resize-detector": 1.1.3
"@types/js-cookie": 3.0.2 "@types/js-cookie": 3.0.2
@@ -153,9 +149,9 @@ devDependencies:
"@vue/eslint-config-prettier": 7.0.0_eslint@8.25.0+prettier@2.7.1 "@vue/eslint-config-prettier": 7.0.0_eslint@8.25.0+prettier@2.7.1
"@vue/eslint-config-typescript": 10.0.0_07d3deb2283d82fbf0376bf257049d49 "@vue/eslint-config-typescript": 10.0.0_07d3deb2283d82fbf0376bf257049d49
"@vue/runtime-core": 3.2.41 "@vue/runtime-core": 3.2.41
autoprefixer: 10.4.12_postcss@8.4.18 autoprefixer: 10.4.13_postcss@8.4.18
cloc: 2.10.0 cloc: 2.10.0
cssnano: 5.1.13_postcss@8.4.18 cssnano: 5.1.14_postcss@8.4.18
eslint: 8.25.0 eslint: 8.25.0
eslint-plugin-prettier: 4.2.1_eslint@8.25.0+prettier@2.7.1 eslint-plugin-prettier: 4.2.1_eslint@8.25.0+prettier@2.7.1
eslint-plugin-vue: 8.7.1_eslint@8.25.0 eslint-plugin-vue: 8.7.1_eslint@8.25.0
@@ -179,7 +175,7 @@ devDependencies:
stylelint-config-recommended: 6.0.0_stylelint@14.14.0 stylelint-config-recommended: 6.0.0_stylelint@14.14.0
stylelint-config-standard: 24.0.0_stylelint@14.14.0 stylelint-config-standard: 24.0.0_stylelint@14.14.0
stylelint-order: 5.0.0_stylelint@14.14.0 stylelint-order: 5.0.0_stylelint@14.14.0
tailwindcss: 3.2.1 tailwindcss: 3.2.3
terser: 5.15.1 terser: 5.15.1
typescript: 4.8.4 typescript: 4.8.4
unplugin-vue-define-options: 0.7.3_vite@3.1.8+vue@3.2.41 unplugin-vue-define-options: 0.7.3_vite@3.1.8+vue@3.2.41
@@ -187,7 +183,7 @@ devDependencies:
vite-plugin-cdn-import: 0.3.5 vite-plugin-cdn-import: 0.3.5
vite-plugin-compression: 0.5.1_vite@3.1.8 vite-plugin-compression: 0.5.1_vite@3.1.8
vite-plugin-mock: 2.9.6_mockjs@1.1.0+vite@3.1.8 vite-plugin-mock: 2.9.6_mockjs@1.1.0+vite@3.1.8
vite-plugin-remove-console: 1.1.0 vite-plugin-remove-console: 1.2.0
vite-svg-loader: 3.6.0 vite-svg-loader: 3.6.0
vue-eslint-parser: 8.3.0_eslint@8.25.0 vue-eslint-parser: 8.3.0_eslint@8.25.0
vue-tsc: 0.40.13_typescript@4.8.4 vue-tsc: 0.40.13_typescript@4.8.4
@@ -988,131 +984,6 @@ packages:
vue: 3.2.41 vue: 3.2.41
dev: true dev: true
/@intlify/bundle-utils/3.2.1_vue-i18n@9.2.2:
resolution:
{
integrity: sha512-rf4cLBOnbqmpXVcCdcYHilZpMt1m82syh3WLBJlZvGxN2KkH9HeHVH4+bnibF/SDXCHNh6lM6wTpS/qw+PkcMg==
}
engines: { node: ">= 12" }
peerDependencies:
petite-vue-i18n: "*"
vue-i18n: "*"
peerDependenciesMeta:
petite-vue-i18n:
optional: true
vue-i18n:
optional: true
dependencies:
"@intlify/message-compiler": 9.3.0-beta.6
"@intlify/shared": 9.3.0-beta.6
jsonc-eslint-parser: 1.4.1
source-map: 0.6.1
vue-i18n: 9.2.2_vue@3.2.41
yaml-eslint-parser: 0.3.2
dev: true
/@intlify/core-base/9.2.2:
resolution:
{
integrity: sha512-JjUpQtNfn+joMbrXvpR4hTF8iJQ2sEFzzK3KIESOx+f+uwIjgw20igOyaIdhfsVVBCds8ZM64MoeNSx+PHQMkA==
}
engines: { node: ">= 14" }
dependencies:
"@intlify/devtools-if": 9.2.2
"@intlify/message-compiler": 9.2.2
"@intlify/shared": 9.2.2
"@intlify/vue-devtools": 9.2.2
dev: false
/@intlify/devtools-if/9.2.2:
resolution:
{
integrity: sha512-4ttr/FNO29w+kBbU7HZ/U0Lzuh2cRDhP8UlWOtV9ERcjHzuyXVZmjyleESK6eVP60tGC9QtQW9yZE+JeRhDHkg==
}
engines: { node: ">= 14" }
dependencies:
"@intlify/shared": 9.2.2
dev: false
/@intlify/message-compiler/9.2.2:
resolution:
{
integrity: sha512-IUrQW7byAKN2fMBe8z6sK6riG1pue95e5jfokn8hA5Q3Bqy4MBJ5lJAofUsawQJYHeoPJ7svMDyBaVJ4d0GTtA==
}
engines: { node: ">= 14" }
dependencies:
"@intlify/shared": 9.2.2
source-map: 0.6.1
dev: false
/@intlify/message-compiler/9.3.0-beta.6:
resolution:
{
integrity: sha512-3PJqRJoqvFHExA9DCkf7fZYKbvYne1tYQ0fptJAhUOZsELarh8wr4aPLKWCkQSRuutdrtZ/n5CcPgJgUmVthDw==
}
engines: { node: ">= 14" }
dependencies:
"@intlify/shared": 9.3.0-beta.6
source-map: 0.6.1
dev: true
/@intlify/shared/9.2.2:
resolution:
{
integrity: sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q==
}
engines: { node: ">= 14" }
dev: false
/@intlify/shared/9.3.0-beta.6:
resolution:
{
integrity: sha512-ITA1R4tvJYwZXT5x6QCSwxcwQ4dU52zrzVm/EUbgsp8oWzYS1xexBrxyNM80PSQudYvL2rvcZJKQ7yBh7b0LkQ==
}
engines: { node: ">= 14" }
dev: true
/@intlify/vite-plugin-vue-i18n/6.0.3_vite@3.1.8+vue-i18n@9.2.2:
resolution:
{
integrity: sha512-6SgNzPAOCR90wvt368lKzi7f/5ZEWJn22UCGvhFsP3XvKqlF3cVzojahgQ6o+LTdCkExeM6wPgd+haFf28E9VQ==
}
engines: { node: ">= 14.6" }
peerDependencies:
petite-vue-i18n: "*"
vite: ^2.9.0 || ^3.0.0
vue-i18n: "*"
peerDependenciesMeta:
petite-vue-i18n:
optional: true
vite:
optional: true
vue-i18n:
optional: true
dependencies:
"@intlify/bundle-utils": 3.2.1_vue-i18n@9.2.2
"@intlify/shared": 9.3.0-beta.6
"@rollup/pluginutils": 4.2.1
debug: 4.3.4
fast-glob: 3.2.12
source-map: 0.6.1
vite: 3.1.8_sass@1.55.0+terser@5.15.1
vue-i18n: 9.2.2_vue@3.2.41
transitivePeerDependencies:
- supports-color
dev: true
/@intlify/vue-devtools/9.2.2:
resolution:
{
integrity: sha512-+dUyqyCHWHb/UcvY1MlIpO87munedm3Gn6E9WWYdWrMuYLcoIoOEVDWSS8xSwtlPU+kA+MEQTP6Q1iI/ocusJg==
}
engines: { node: ">= 14" }
dependencies:
"@intlify/core-base": 9.2.2
"@intlify/shared": 9.2.2
dev: false
/@jridgewell/gen-mapping/0.1.1: /@jridgewell/gen-mapping/0.1.1:
resolution: resolution:
{ {
@@ -2041,7 +1912,7 @@ packages:
dependencies: dependencies:
cac: 6.7.14 cac: 6.7.14
color: 4.2.3 color: 4.2.3
cssnano: 5.1.13_postcss@8.4.18 cssnano: 5.1.14_postcss@8.4.18
cssnano-preset-lite: 2.1.3_postcss@8.4.18 cssnano-preset-lite: 2.1.3_postcss@8.4.18
fs-extra: 10.1.0 fs-extra: 10.1.0
postcss: 8.4.18 postcss: 8.4.18
@@ -2060,17 +1931,6 @@ packages:
through: 2.3.8 through: 2.3.8
dev: true dev: true
/acorn-jsx/5.3.2_acorn@7.4.1:
resolution:
{
integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
}
peerDependencies:
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
dependencies:
acorn: 7.4.1
dev: true
/acorn-jsx/5.3.2_acorn@8.8.0: /acorn-jsx/5.3.2_acorn@8.8.0:
resolution: resolution:
{ {
@@ -2300,10 +2160,10 @@ packages:
} }
dev: false dev: false
/autoprefixer/10.4.12_postcss@8.4.18: /autoprefixer/10.4.13_postcss@8.4.18:
resolution: resolution:
{ {
integrity: sha512-WrCGV9/b97Pa+jtwf5UGaRjgQIg7OK3D06GnoYoZNcG1Xb8Gt3EfuKjlhh9i/VtT16g6PYjZ69jdJ2g8FxSC4Q== integrity: sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==
} }
engines: { node: ^10 || ^12 || >=14 } engines: { node: ^10 || ^12 || >=14 }
hasBin: true hasBin: true
@@ -2311,7 +2171,7 @@ packages:
postcss: ^8.1.0 postcss: ^8.1.0
dependencies: dependencies:
browserslist: 4.21.4 browserslist: 4.21.4
caniuse-lite: 1.0.30001422 caniuse-lite: 1.0.30001431
fraction.js: 4.2.0 fraction.js: 4.2.0
normalize-range: 0.1.2 normalize-range: 0.1.2
picocolors: 1.0.0 picocolors: 1.0.0
@@ -2393,7 +2253,7 @@ packages:
engines: { node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7 } engines: { node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7 }
hasBin: true hasBin: true
dependencies: dependencies:
caniuse-lite: 1.0.30001422 caniuse-lite: 1.0.30001431
electron-to-chromium: 1.4.284 electron-to-chromium: 1.4.284
node-releases: 2.0.6 node-releases: 2.0.6
update-browserslist-db: 1.0.10_browserslist@4.21.4 update-browserslist-db: 1.0.10_browserslist@4.21.4
@@ -2483,15 +2343,15 @@ packages:
} }
dependencies: dependencies:
browserslist: 4.21.4 browserslist: 4.21.4
caniuse-lite: 1.0.30001422 caniuse-lite: 1.0.30001431
lodash.memoize: 4.1.2 lodash.memoize: 4.1.2
lodash.uniq: 4.5.0 lodash.uniq: 4.5.0
dev: true dev: true
/caniuse-lite/1.0.30001422: /caniuse-lite/1.0.30001431:
resolution: resolution:
{ {
integrity: sha512-hSesn02u1QacQHhaxl/kNMZwqVG35Sz/8DgvmgedxSH8z9UUpcDYSPYgsj3x5dQNRcNp6BwpSfQfVzYUTm+fog== integrity: sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==
} }
dev: true dev: true
@@ -2874,10 +2734,10 @@ packages:
hasBin: true hasBin: true
dev: true dev: true
/cssnano-preset-default/5.2.12_postcss@8.4.18: /cssnano-preset-default/5.2.13_postcss@8.4.18:
resolution: resolution:
{ {
integrity: sha512-OyCBTZi+PXgylz9HAA5kHyoYhfGcYdwFmyaJzWnzxuGRtnMw/kR6ilW9XzlzlRAtB6PLT/r+prYgkef7hngFew== integrity: sha512-PX7sQ4Pb+UtOWuz8A1d+Rbi+WimBIxJTRyBdgGp1J75VU0r/HFQeLnMYgHiCAp6AR4rqrc7Y4R+1Rjk3KJz6DQ==
} }
engines: { node: ^10 || ^12 || >=14.0 } engines: { node: ^10 || ^12 || >=14.0 }
peerDependencies: peerDependencies:
@@ -2888,16 +2748,16 @@ packages:
postcss: 8.4.18 postcss: 8.4.18
postcss-calc: 8.2.4_postcss@8.4.18 postcss-calc: 8.2.4_postcss@8.4.18
postcss-colormin: 5.3.0_postcss@8.4.18 postcss-colormin: 5.3.0_postcss@8.4.18
postcss-convert-values: 5.1.2_postcss@8.4.18 postcss-convert-values: 5.1.3_postcss@8.4.18
postcss-discard-comments: 5.1.2_postcss@8.4.18 postcss-discard-comments: 5.1.2_postcss@8.4.18
postcss-discard-duplicates: 5.1.0_postcss@8.4.18 postcss-discard-duplicates: 5.1.0_postcss@8.4.18
postcss-discard-empty: 5.1.1_postcss@8.4.18 postcss-discard-empty: 5.1.1_postcss@8.4.18
postcss-discard-overridden: 5.1.0_postcss@8.4.18 postcss-discard-overridden: 5.1.0_postcss@8.4.18
postcss-merge-longhand: 5.1.6_postcss@8.4.18 postcss-merge-longhand: 5.1.7_postcss@8.4.18
postcss-merge-rules: 5.1.2_postcss@8.4.18 postcss-merge-rules: 5.1.3_postcss@8.4.18
postcss-minify-font-values: 5.1.0_postcss@8.4.18 postcss-minify-font-values: 5.1.0_postcss@8.4.18
postcss-minify-gradients: 5.1.1_postcss@8.4.18 postcss-minify-gradients: 5.1.1_postcss@8.4.18
postcss-minify-params: 5.1.3_postcss@8.4.18 postcss-minify-params: 5.1.4_postcss@8.4.18
postcss-minify-selectors: 5.2.1_postcss@8.4.18 postcss-minify-selectors: 5.2.1_postcss@8.4.18
postcss-normalize-charset: 5.1.0_postcss@8.4.18 postcss-normalize-charset: 5.1.0_postcss@8.4.18
postcss-normalize-display-values: 5.1.0_postcss@8.4.18 postcss-normalize-display-values: 5.1.0_postcss@8.4.18
@@ -2905,11 +2765,11 @@ packages:
postcss-normalize-repeat-style: 5.1.1_postcss@8.4.18 postcss-normalize-repeat-style: 5.1.1_postcss@8.4.18
postcss-normalize-string: 5.1.0_postcss@8.4.18 postcss-normalize-string: 5.1.0_postcss@8.4.18
postcss-normalize-timing-functions: 5.1.0_postcss@8.4.18 postcss-normalize-timing-functions: 5.1.0_postcss@8.4.18
postcss-normalize-unicode: 5.1.0_postcss@8.4.18 postcss-normalize-unicode: 5.1.1_postcss@8.4.18
postcss-normalize-url: 5.1.0_postcss@8.4.18 postcss-normalize-url: 5.1.0_postcss@8.4.18
postcss-normalize-whitespace: 5.1.1_postcss@8.4.18 postcss-normalize-whitespace: 5.1.1_postcss@8.4.18
postcss-ordered-values: 5.1.3_postcss@8.4.18 postcss-ordered-values: 5.1.3_postcss@8.4.18
postcss-reduce-initial: 5.1.0_postcss@8.4.18 postcss-reduce-initial: 5.1.1_postcss@8.4.18
postcss-reduce-transforms: 5.1.0_postcss@8.4.18 postcss-reduce-transforms: 5.1.0_postcss@8.4.18
postcss-svgo: 5.1.0_postcss@8.4.18 postcss-svgo: 5.1.0_postcss@8.4.18
postcss-unique-selectors: 5.1.1_postcss@8.4.18 postcss-unique-selectors: 5.1.1_postcss@8.4.18
@@ -2943,16 +2803,16 @@ packages:
postcss: 8.4.18 postcss: 8.4.18
dev: true dev: true
/cssnano/5.1.13_postcss@8.4.18: /cssnano/5.1.14_postcss@8.4.18:
resolution: resolution:
{ {
integrity: sha512-S2SL2ekdEz6w6a2epXn4CmMKU4K3KpcyXLKfAYc9UQQqJRkD/2eLUG0vJ3Db/9OvO5GuAdgXw3pFbR6abqghDQ== integrity: sha512-Oou7ihiTocbKqi0J1bB+TRJIQX5RMR3JghA8hcWSw9mjBLQ5Y3RWqEDoYG3sRNlAbCIXpqMoZGbq5KDR3vdzgw==
} }
engines: { node: ^10 || ^12 || >=14.0 } engines: { node: ^10 || ^12 || >=14.0 }
peerDependencies: peerDependencies:
postcss: ^8.2.15 postcss: ^8.2.15
dependencies: dependencies:
cssnano-preset-default: 5.2.12_postcss@8.4.18 cssnano-preset-default: 5.2.13_postcss@8.4.18
lilconfig: 2.0.6 lilconfig: 2.0.6
postcss: 8.4.18 postcss: 8.4.18
yaml: 1.10.2 yaml: 1.10.2
@@ -3736,16 +3596,6 @@ packages:
estraverse: 5.3.0 estraverse: 5.3.0
dev: true dev: true
/eslint-utils/2.1.0:
resolution:
{
integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==
}
engines: { node: ">=6" }
dependencies:
eslint-visitor-keys: 1.3.0
dev: true
/eslint-utils/3.0.0_eslint@8.25.0: /eslint-utils/3.0.0_eslint@8.25.0:
resolution: resolution:
{ {
@@ -3759,14 +3609,6 @@ packages:
eslint-visitor-keys: 2.1.0 eslint-visitor-keys: 2.1.0
dev: true dev: true
/eslint-visitor-keys/1.3.0:
resolution:
{
integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==
}
engines: { node: ">=4" }
dev: true
/eslint-visitor-keys/2.1.0: /eslint-visitor-keys/2.1.0:
resolution: resolution:
{ {
@@ -3833,18 +3675,6 @@ packages:
- supports-color - supports-color
dev: true dev: true
/espree/6.2.1:
resolution:
{
integrity: sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==
}
engines: { node: ">=6.0.0" }
dependencies:
acorn: 7.4.1
acorn-jsx: 5.3.2_acorn@7.4.1
eslint-visitor-keys: 1.3.0
dev: true
/espree/9.4.0: /espree/9.4.0:
resolution: resolution:
{ {
@@ -4819,20 +4649,6 @@ packages:
hasBin: true hasBin: true
dev: true dev: true
/jsonc-eslint-parser/1.4.1:
resolution:
{
integrity: sha512-hXBrvsR1rdjmB2kQmUjf1rEIa+TqHBGMge8pwi++C+Si1ad7EjZrJcpgwym+QGK/pqTx+K7keFAtLlVNdLRJOg==
}
engines: { node: ">=8.10.0" }
dependencies:
acorn: 7.4.1
eslint-utils: 2.1.0
eslint-visitor-keys: 1.3.0
espree: 6.2.1
semver: 6.3.0
dev: true
/jsonfile/6.1.0: /jsonfile/6.1.0:
resolution: resolution:
{ {
@@ -5730,10 +5546,10 @@ packages:
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
dev: true dev: true
/postcss-convert-values/5.1.2_postcss@8.4.18: /postcss-convert-values/5.1.3_postcss@8.4.18:
resolution: resolution:
{ {
integrity: sha512-c6Hzc4GAv95B7suy4udszX9Zy4ETyMCgFPUDtWjdFTKH1SE9eFY/jEpHSwTH1QPuwxHpWslhckUQWbNRM4ho5g== integrity: sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==
} }
engines: { node: ^10 || ^12 || >=14.0 } engines: { node: ^10 || ^12 || >=14.0 }
peerDependencies: peerDependencies:
@@ -5875,10 +5691,10 @@ packages:
} }
dev: true dev: true
/postcss-merge-longhand/5.1.6_postcss@8.4.18: /postcss-merge-longhand/5.1.7_postcss@8.4.18:
resolution: resolution:
{ {
integrity: sha512-6C/UGF/3T5OE2CEbOuX7iNO63dnvqhGZeUnKkDeifebY0XqkkvrctYSZurpNE902LDf2yKwwPFgotnfSoPhQiw== integrity: sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==
} }
engines: { node: ^10 || ^12 || >=14.0 } engines: { node: ^10 || ^12 || >=14.0 }
peerDependencies: peerDependencies:
@@ -5886,13 +5702,13 @@ packages:
dependencies: dependencies:
postcss: 8.4.18 postcss: 8.4.18
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
stylehacks: 5.1.0_postcss@8.4.18 stylehacks: 5.1.1_postcss@8.4.18
dev: true dev: true
/postcss-merge-rules/5.1.2_postcss@8.4.18: /postcss-merge-rules/5.1.3_postcss@8.4.18:
resolution: resolution:
{ {
integrity: sha512-zKMUlnw+zYCWoPN6yhPjtcEdlJaMUZ0WyVcxTAmw3lkkN/NDMRkOkiuctQEoWAOvH7twaxUUdvBWl0d4+hifRQ== integrity: sha512-LbLd7uFC00vpOuMvyZop8+vvhnfRGpp2S+IMQKeuOZZapPRY4SMq5ErjQeHbHsjCUgJkRNrlU+LmxsKIqPKQlA==
} }
engines: { node: ^10 || ^12 || >=14.0 } engines: { node: ^10 || ^12 || >=14.0 }
peerDependencies: peerDependencies:
@@ -5933,10 +5749,10 @@ packages:
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
dev: true dev: true
/postcss-minify-params/5.1.3_postcss@8.4.18: /postcss-minify-params/5.1.4_postcss@8.4.18:
resolution: resolution:
{ {
integrity: sha512-bkzpWcjykkqIujNL+EVEPOlLYi/eZ050oImVtHU7b4lFS82jPnsCb44gvC6pxaNt38Els3jWYDHTjHKf0koTgg== integrity: sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==
} }
engines: { node: ^10 || ^12 || >=14.0 } engines: { node: ^10 || ^12 || >=14.0 }
peerDependencies: peerDependencies:
@@ -6051,10 +5867,10 @@ packages:
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
dev: true dev: true
/postcss-normalize-unicode/5.1.0_postcss@8.4.18: /postcss-normalize-unicode/5.1.1_postcss@8.4.18:
resolution: resolution:
{ {
integrity: sha512-J6M3MizAAZ2dOdSjy2caayJLQT8E8K9XjLce8AUQMwOrCvjCHv24aLC/Lps1R1ylOfol5VIDMaM/Lo9NGlk1SQ== integrity: sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==
} }
engines: { node: ^10 || ^12 || >=14.0 } engines: { node: ^10 || ^12 || >=14.0 }
peerDependencies: peerDependencies:
@@ -6106,10 +5922,10 @@ packages:
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
dev: true dev: true
/postcss-reduce-initial/5.1.0_postcss@8.4.18: /postcss-reduce-initial/5.1.1_postcss@8.4.18:
resolution: resolution:
{ {
integrity: sha512-5OgTUviz0aeH6MtBjHfbr57tml13PuedK/Ecg8szzd4XRMbYxH4572JFG067z+FqBIf6Zp/d+0581glkvvWMFw== integrity: sha512-//jeDqWcHPuXGZLoolFrUXBDyuEGbr9S2rMo19bkTIjBQ4PqkaO+oI8wua5BOUxpfi97i3PCoInsiFIEBfkm9w==
} }
engines: { node: ^10 || ^12 || >=14.0 } engines: { node: ^10 || ^12 || >=14.0 }
peerDependencies: peerDependencies:
@@ -6970,10 +6786,10 @@ packages:
tslib: 2.4.0 tslib: 2.4.0
dev: false dev: false
/stylehacks/5.1.0_postcss@8.4.18: /stylehacks/5.1.1_postcss@8.4.18:
resolution: resolution:
{ {
integrity: sha512-SzLmvHQTrIWfSgljkQCw2++C9+Ne91d/6Sp92I8c5uHTcy/PgeHamwITIbBW9wnFTY/3ZfSXR9HIL6Ikqmcu6Q== integrity: sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==
} }
engines: { node: ^10 || ^12 || >=14.0 } engines: { node: ^10 || ^12 || >=14.0 }
peerDependencies: peerDependencies:
@@ -7181,10 +6997,10 @@ packages:
strip-ansi: 6.0.1 strip-ansi: 6.0.1
dev: true dev: true
/tailwindcss/3.2.1: /tailwindcss/3.2.3:
resolution: resolution:
{ {
integrity: sha512-Uw+GVSxp5CM48krnjHObqoOwlCt5Qo6nw1jlCRwfGy68dSYb/LwS9ZFidYGRiM+w6rMawkZiu1mEMAsHYAfoLg== integrity: sha512-Xt9D4PK4zuuQCEB8bwK9JUCKmTgUwyac/6b0/42Vqhgl6YJkep+Wf5wq+5uXYfmrupdAD0YY2NY1hyZp1HjRrg==
} }
engines: { node: ">=12.13.0" } engines: { node: ">=12.13.0" }
hasBin: true hasBin: true
@@ -7582,10 +7398,10 @@ packages:
- supports-color - supports-color
dev: true dev: true
/vite-plugin-remove-console/1.1.0: /vite-plugin-remove-console/1.2.0:
resolution: resolution:
{ {
integrity: sha512-FZ0gLEsRqgHPCl+blHpT3h004+InKrGddmBXTfs7Cj/xWY7FdHpL9Zc9kgjxh8zIzjZ/MblsPDDEqg5BVHIXDA== integrity: sha512-1fm50pJswSeTJZZ6wBPp9Q0xUhdMqo5+drd39XRVrJ/9LmSvZ90JXf1P7P68aCTNJSf6C1KTAo7sq0PctYZURg==
} }
dev: true dev: true
@@ -7670,22 +7486,6 @@ packages:
- supports-color - supports-color
dev: true dev: true
/vue-i18n/9.2.2_vue@3.2.41:
resolution:
{
integrity: sha512-yswpwtj89rTBhegUAv9Mu37LNznyu3NpyLQmozF3i1hYOhwpG8RjcjIFIIfnu+2MDZJGSZPXaKWvnQA71Yv9TQ==
}
engines: { node: ">= 14" }
peerDependencies:
vue: ^3.0.0
dependencies:
"@intlify/core-base": 9.2.2
"@intlify/shared": 9.2.2
"@intlify/vue-devtools": 9.2.2
"@vue/devtools-api": 6.4.5
vue: 3.2.41
dev: false
/vue-router/4.1.6_vue@3.2.41: /vue-router/4.1.6_vue@3.2.41:
resolution: resolution:
{ {
@@ -7867,17 +7667,6 @@ packages:
} }
dev: true dev: true
/yaml-eslint-parser/0.3.2:
resolution:
{
integrity: sha512-32kYO6kJUuZzqte82t4M/gB6/+11WAuHiEnK7FreMo20xsCKPeFH5tDBU7iWxR7zeJpNnMXfJyXwne48D0hGrg==
}
dependencies:
eslint-visitor-keys: 1.3.0
lodash: 4.17.21
yaml: 1.10.2
dev: true
/yaml/1.10.2: /yaml/1.10.2:
resolution: resolution:
{ {

View File

@@ -1,11 +1,10 @@
{ {
"Version": "3.6.1", "Version": "3.6.3",
"Title": "PureAdmin", "Title": "PureAdmin",
"FixedHeader": true, "FixedHeader": true,
"HiddenSideBar": false, "HiddenSideBar": false,
"MultiTagsCache": false, "MultiTagsCache": false,
"KeepAlive": true, "KeepAlive": true,
"Locale": "zh",
"Layout": "vertical", "Layout": "vertical",
"Theme": "default", "Theme": "default",
"DarkMode": false, "DarkMode": false,

View File

@@ -8,7 +8,6 @@
import { defineComponent } from "vue"; import { defineComponent } from "vue";
import { ElConfigProvider } from "element-plus"; import { ElConfigProvider } from "element-plus";
import zhCn from "element-plus/lib/locale/lang/zh-cn"; import zhCn from "element-plus/lib/locale/lang/zh-cn";
import en from "element-plus/lib/locale/lang/en";
export default defineComponent({ export default defineComponent({
name: "app", name: "app",
components: { components: {
@@ -16,7 +15,7 @@ export default defineComponent({
}, },
computed: { computed: {
currentLocale() { currentLocale() {
return this.$storage.locale?.locale === "zh" ? zhCn : en; return zhCn;
} }
} }
}); });

View File

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

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="globalization" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 512 512"><path d="M478.33 433.6l-90-218a22 22 0 0 0-40.67 0l-90 218a22 22 0 1 0 40.67 16.79L316.66 406h102.67l18.33 44.39A22 22 0 0 0 458 464a22 22 0 0 0 20.32-30.4zM334.83 362L368 281.65L401.17 362z" fill="currentColor"></path><path d="M267.84 342.92a22 22 0 0 0-4.89-30.7c-.2-.15-15-11.13-36.49-34.73c39.65-53.68 62.11-114.75 71.27-143.49H330a22 22 0 0 0 0-44H214V70a22 22 0 0 0-44 0v20H54a22 22 0 0 0 0 44h197.25c-9.52 26.95-27.05 69.5-53.79 108.36c-31.41-41.68-43.08-68.65-43.17-68.87a22 22 0 0 0-40.58 17c.58 1.38 14.55 34.23 52.86 83.93c.92 1.19 1.83 2.35 2.74 3.51c-39.24 44.35-77.74 71.86-93.85 80.74a22 22 0 1 0 21.07 38.63c2.16-1.18 48.6-26.89 101.63-85.59c22.52 24.08 38 35.44 38.93 36.1a22 22 0 0 0 30.75-4.9z" fill="currentColor"></path></svg>

Before

Width:  |  Height:  |  Size: 965 B

View File

Before

Width:  |  Height:  |  Size: 477 B

After

Width:  |  Height:  |  Size: 477 B

View File

@@ -1,5 +1,5 @@
import { defineComponent, Fragment } from "vue"; import { defineComponent, Fragment } from "vue";
import { hasAuth } from "/@/router/utils"; import { hasAuth } from "@/router/utils";
export default defineComponent({ export default defineComponent({
name: "Auth", name: "Auth",

View File

@@ -2,7 +2,7 @@ import iconifyIconOffline from "./src/iconifyIconOffline";
import iconifyIconOnline from "./src/iconifyIconOnline"; import iconifyIconOnline from "./src/iconifyIconOnline";
import fontIcon from "./src/iconfont"; import fontIcon from "./src/iconfont";
/** 离线图标组件 */ /** 本地图标组件 */
const IconifyIconOffline = iconifyIconOffline; const IconifyIconOffline = iconifyIconOffline;
/** 在线图标组件 */ /** 在线图标组件 */
const IconifyIconOnline = iconifyIconOnline; const IconifyIconOnline = iconifyIconOnline;

View File

@@ -3,7 +3,8 @@ import { h, defineComponent, Component } from "vue";
import { IconifyIconOnline, IconifyIconOffline, FontIcon } from "../index"; import { IconifyIconOnline, IconifyIconOffline, FontIcon } from "../index";
/** /**
* 支持fontawesome4、5+、iconfont、remixicon、element-plus的icons、自定义svg * 支持 `iconfont`、自定义 `svg` 以及 `iconify` 中所有的图标
* @see 点击查看文档图标篇 {@link https://yiming_chang.gitee.io/pure-admin-doc/pages/icon/}
* @param icon 必传 图标 * @param icon 必传 图标
* @param attrs 可选 iconType 属性 * @param attrs 可选 iconType 属性
* @returns Component * @returns Component
@@ -34,11 +35,12 @@ export function useRenderIcon(icon: any, attrs?: iconType): Component {
// svg // svg
return icon; return icon;
} else { } else {
// 通过是否存在 : 符号来判断是在线还是本地图标,存在即是在线图标,反之
return defineComponent({ return defineComponent({
name: "Icon", name: "Icon",
render() { render() {
const IconifyIcon = const IconifyIcon =
attrs && attrs["online"] ? IconifyIconOnline : IconifyIconOffline; icon && icon.includes(":") ? IconifyIconOnline : IconifyIconOffline;
return h(IconifyIcon, { return h(IconifyIcon, {
icon: icon, icon: icon,
...attrs ...attrs

View File

@@ -59,7 +59,7 @@ addIcon("close-all-tags", CloseAllTags);
addIcon("fullscreen", Fullscreen); addIcon("fullscreen", Fullscreen);
addIcon("exit-fullscreen", ExitFullscreen); addIcon("exit-fullscreen", ExitFullscreen);
// Iconify Icon在Vue里离线使用用于内网环境https://docs.iconify.design/icon-components/vue/offline.html // Iconify Icon在Vue里本地使用用于内网环境https://docs.iconify.design/icon-components/vue/offline.html
export default defineComponent({ export default defineComponent({
name: "IconifyIconOffline", name: "IconifyIconOffline",
components: { IconifyIcon }, components: { IconifyIcon },

View File

@@ -11,7 +11,6 @@ export interface iconType {
horizontalAlign?: boolean; horizontalAlign?: boolean;
verticalAlign?: boolean; verticalAlign?: boolean;
align?: string; align?: string;
online?: boolean;
onLoad?: Function; onLoad?: Function;
includes?: Function; includes?: Function;

View File

@@ -1,4 +1,4 @@
import { hasAuth } from "/@/router/utils"; import { hasAuth } from "@/router/utils";
import { Directive, type DirectiveBinding } from "vue"; import { Directive, type DirectiveBinding } from "vue";
export const auth: Directive = { export const auth: Directive = {

View File

@@ -1,7 +1,7 @@
import { Directive, type DirectiveBinding, type VNode } from "vue"; import { Directive, type DirectiveBinding, type VNode } from "vue";
import elementResizeDetectorMaker from "element-resize-detector"; import elementResizeDetectorMaker from "element-resize-detector";
import type { Erd } from "element-resize-detector"; import type { Erd } from "element-resize-detector";
import { emitter } from "/@/utils/mitt"; import { emitter } from "@/utils/mitt";
const erd: Erd = elementResizeDetectorMaker({ const erd: Erd = elementResizeDetectorMaker({
strategy: "scroll" strategy: "scroll"

View File

@@ -1,8 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { useGlobal } from "@pureadmin/utils"; import { useGlobal } from "@pureadmin/utils";
import backTop from "/@/assets/svg/back_top.svg?component"; import backTop from "@/assets/svg/back_top.svg?component";
import { h, computed, Transition, defineComponent } from "vue"; import { h, computed, Transition, defineComponent } from "vue";
import { usePermissionStoreHook } from "/@/store/modules/permission"; import { usePermissionStoreHook } from "@/store/modules/permission";
const props = defineProps({ const props = defineProps({
fixedHeader: Boolean fixedHeader: Boolean

View File

@@ -2,12 +2,9 @@
import Search from "./search/index.vue"; import Search from "./search/index.vue";
import Notice from "./notice/index.vue"; import Notice from "./notice/index.vue";
import mixNav from "./sidebar/mixNav.vue"; import mixNav from "./sidebar/mixNav.vue";
import avatars from "/@/assets/avatars.jpg"; import { useNav } from "@/layout/hooks/useNav";
import { useNav } from "/@/layout/hooks/useNav";
import Breadcrumb from "./sidebar/breadCrumb.vue"; import Breadcrumb from "./sidebar/breadCrumb.vue";
import topCollapse from "./sidebar/topCollapse.vue"; import topCollapse from "./sidebar/topCollapse.vue";
import { useTranslationLang } from "../hooks/useTranslationLang";
import globalization from "/@/assets/svg/globalization.svg?component";
const { const {
layout, layout,
@@ -17,12 +14,8 @@ const {
pureApp, pureApp,
username, username,
avatarsStyle, avatarsStyle,
toggleSideBar, toggleSideBar
getDropdownItemStyle,
getDropdownItemClass
} = useNav(); } = useNav();
const { t, locale, translationCh, translationEn } = useTranslationLang();
</script> </script>
<template> <template>
@@ -48,42 +41,13 @@ const { t, locale, translationCh, translationEn } = useTranslationLang();
<Search /> <Search />
<!-- 通知 --> <!-- 通知 -->
<Notice id="header-notice" /> <Notice id="header-notice" />
<!-- 国际化 -->
<el-dropdown id="header-translation" trigger="click">
<globalization
class="navbar-bg-hover w-[40px] h-[48px] p-[11px] cursor-pointer outline-none"
/>
<template #dropdown>
<el-dropdown-menu class="translation">
<el-dropdown-item
:style="getDropdownItemStyle(locale, 'zh')"
:class="['dark:!text-white', getDropdownItemClass(locale, 'zh')]"
@click="translationCh"
>
<IconifyIconOffline
class="check-zh"
v-show="locale === 'zh'"
icon="check"
/>
简体中文
</el-dropdown-item>
<el-dropdown-item
:style="getDropdownItemStyle(locale, 'en')"
:class="['dark:!text-white', getDropdownItemClass(locale, 'en')]"
@click="translationEn"
>
<span class="check-en" v-show="locale === 'en'">
<IconifyIconOffline icon="check" />
</span>
English
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<!-- 退出登录 --> <!-- 退出登录 -->
<el-dropdown trigger="click"> <el-dropdown trigger="click">
<span class="el-dropdown-link navbar-bg-hover"> <span class="el-dropdown-link navbar-bg-hover select-none">
<img v-if="avatars" :src="avatars" :style="avatarsStyle" /> <img
src="https://avatars.githubusercontent.com/u/44761321?v=4"
:style="avatarsStyle"
/>
<p v-if="username" class="dark:text-white">{{ username }}</p> <p v-if="username" class="dark:text-white">{{ username }}</p>
</span> </span>
<template #dropdown> <template #dropdown>
@@ -93,14 +57,14 @@ const { t, locale, translationCh, translationEn } = useTranslationLang();
icon="logout-circle-r-line" icon="logout-circle-r-line"
style="margin: 5px" style="margin: 5px"
/> />
{{ t("buttons.hsLoginOut") }} 退出系统
</el-dropdown-item> </el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
</el-dropdown> </el-dropdown>
<span <span
class="set-icon navbar-bg-hover" class="set-icon navbar-bg-hover"
:title="t('buttons.hssystemSet')" title="打开项目配置"
@click="onPanel" @click="onPanel"
> >
<IconifyIconOffline icon="setting" /> <IconifyIconOffline icon="setting" />
@@ -157,22 +121,6 @@ const { t, locale, translationCh, translationEn } = useTranslationLang();
} }
} }
.translation {
::v-deep(.el-dropdown-menu__item) {
padding: 5px 40px;
}
.check-zh {
position: absolute;
left: 20px;
}
.check-en {
position: absolute;
left: 20px;
}
}
.logout { .logout {
max-width: 120px; max-width: 120px;

View File

@@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from "vue"; import { ref } from "vue";
import { onClickOutside } from "@vueuse/core"; import { onClickOutside } from "@vueuse/core";
import { emitter } from "/@/utils/mitt"; import { emitter } from "@/utils/mitt";
let show = ref<Boolean>(false); let show = ref<Boolean>(false);
const target = ref(null); const target = ref(null);

View File

@@ -1,8 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { useI18n } from "vue-i18n";
import { useFullscreen } from "@vueuse/core"; import { useFullscreen } from "@vueuse/core";
const { t } = useI18n();
const { isFullscreen, toggle } = useFullscreen(); const { isFullscreen, toggle } = useFullscreen();
</script> </script>
@@ -12,9 +10,7 @@ const { isFullscreen, toggle } = useFullscreen();
@click="toggle" @click="toggle"
> >
<FontIcon <FontIcon
:title=" :title="isFullscreen ? '退出全屏' : '全屏'"
isFullscreen ? t('buttons.hsexitfullscreen') : t('buttons.hsfullscreen')
"
:icon="isFullscreen ? 'team-iconexit-fullscreen' : 'team-iconfullscreen'" :icon="isFullscreen ? 'team-iconexit-fullscreen' : 'team-iconfullscreen'"
/> />
</div> </div>

View File

@@ -17,8 +17,8 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import enterOutlined from "/@/assets/svg/enter_outlined.svg?component"; import enterOutlined from "@/assets/svg/enter_outlined.svg?component";
import mdiKeyboardEsc from "/@/assets/svg/mdi_keyboard_esc.svg?component"; import mdiKeyboardEsc from "@/assets/svg/keyboard_esc.svg?component";
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.search-footer { .search-footer {

View File

@@ -3,12 +3,11 @@ import { useRouter } from "vue-router";
import { cloneDeep } from "lodash-unified"; import { cloneDeep } from "lodash-unified";
import SearchResult from "./SearchResult.vue"; import SearchResult from "./SearchResult.vue";
import SearchFooter from "./SearchFooter.vue"; import SearchFooter from "./SearchFooter.vue";
import { useNav } from "/@/layout/hooks/useNav"; import { useNav } from "@/layout/hooks/useNav";
import { transformI18n } from "/@/plugins/i18n";
import { deleteChildren } from "@pureadmin/utils"; import { deleteChildren } from "@pureadmin/utils";
import { useDebounceFn, onKeyStroke } from "@vueuse/core"; import { useDebounceFn, onKeyStroke } from "@vueuse/core";
import { ref, watch, computed, nextTick, shallowRef } from "vue"; import { ref, watch, computed, nextTick, shallowRef } from "vue";
import { usePermissionStoreHook } from "/@/store/modules/permission"; import { usePermissionStoreHook } from "@/store/modules/permission";
interface Props { interface Props {
/** 弹窗显隐 */ /** 弹窗显隐 */
@@ -71,7 +70,7 @@ function search() {
resultOptions.value = flatMenusData.filter( resultOptions.value = flatMenusData.filter(
menu => menu =>
keyword.value && keyword.value &&
transformI18n(menu.meta?.title) menu.meta?.title
.toLocaleLowerCase() .toLocaleLowerCase()
.includes(keyword.value.toLocaleLowerCase().trim()) .includes(keyword.value.toLocaleLowerCase().trim())
); );

View File

@@ -1,11 +1,8 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed } from "vue"; import { computed } from "vue";
import { useI18n } from "vue-i18n"; import { useEpThemeStoreHook } from "@/store/modules/epTheme";
import { useEpThemeStoreHook } from "/@/store/modules/epTheme"; import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import { useRenderIcon } from "/@/components/ReIcon/src/hooks"; import enterOutlined from "@/assets/svg/enter_outlined.svg?component";
import enterOutlined from "/@/assets/svg/enter_outlined.svg?component";
const { t } = useI18n();
interface optionsItem { interface optionsItem {
path: string; path: string;
@@ -68,7 +65,7 @@ function handleTo() {
@mouseenter="handleMouse(item)" @mouseenter="handleMouse(item)"
> >
<component :is="useRenderIcon(item.meta?.icon ?? 'bookmark-2-line')" /> <component :is="useRenderIcon(item.meta?.icon ?? 'bookmark-2-line')" />
<span class="result-item-title">{{ t(item.meta?.title) }}</span> <span class="result-item-title">{{ item.meta?.title }}</span>
<enterOutlined /> <enterOutlined />
</div> </div>
</template> </template>

View File

@@ -8,18 +8,18 @@ import {
nextTick, nextTick,
useCssModule useCssModule
} from "vue"; } from "vue";
import { getConfig } from "/@/config"; import { getConfig } from "@/config";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import panel from "../panel/index.vue"; import panel from "../panel/index.vue";
import { emitter } from "/@/utils/mitt"; import { emitter } from "@/utils/mitt";
import { resetRouter } from "/@/router"; import { resetRouter } from "@/router";
import { templateRef } from "@vueuse/core"; import { templateRef } from "@vueuse/core";
import { removeToken } from "/@/utils/auth"; import { removeToken } from "@/utils/auth";
import { routerArrays } from "/@/layout/types"; import { routerArrays } from "@/layout/types";
import { useNav } from "/@/layout/hooks/useNav"; import { useNav } from "@/layout/hooks/useNav";
import { useAppStoreHook } from "/@/store/modules/app"; import { useAppStoreHook } from "@/store/modules/app";
import { useMultiTagsStoreHook } from "/@/store/modules/multiTags"; import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
import { useDataThemeChange } from "/@/layout/hooks/useDataThemeChange"; import { useDataThemeChange } from "@/layout/hooks/useDataThemeChange";
import { import {
useDark, useDark,
debounce, debounce,
@@ -29,8 +29,8 @@ import {
} from "@pureadmin/utils"; } from "@pureadmin/utils";
import { toggleTheme } from "@pureadmin/theme/dist/browser-utils"; import { toggleTheme } from "@pureadmin/theme/dist/browser-utils";
import dayIcon from "/@/assets/svg/day.svg?component"; import dayIcon from "@/assets/svg/day.svg?component";
import darkIcon from "/@/assets/svg/dark.svg?component"; import darkIcon from "@/assets/svg/dark.svg?component";
const router = useRouter(); const router = useRouter();
const { device } = useNav(); const { device } = useNav();

View File

@@ -1,9 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { isEqual } from "lodash-unified"; import { isEqual } from "lodash-unified";
import { transformI18n } from "/@/plugins/i18n";
import { ref, watch, onMounted, toRaw } from "vue"; import { ref, watch, onMounted, toRaw } from "vue";
import { getParentPaths, findRouteByPath } from "/@/router/utils"; import { getParentPaths, findRouteByPath } from "@/router/utils";
import { useMultiTagsStoreHook } from "/@/store/modules/multiTags"; import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
import { useRoute, useRouter, RouteLocationMatched } from "vue-router"; import { useRoute, useRouter, RouteLocationMatched } from "vue-router";
const route = useRoute(); const route = useRoute();
@@ -53,7 +52,7 @@ const getBreadcrumb = (): void => {
{ {
path: "/welcome", path: "/welcome",
parentPath: "/", parentPath: "/",
meta: { title: "menus.hshome" } meta: { title: "首页" }
} as unknown as RouteLocationMatched } as unknown as RouteLocationMatched
].concat(matched); ].concat(matched);
} }
@@ -100,7 +99,7 @@ watch(
<transition-group appear name="breadcrumb"> <transition-group appear name="breadcrumb">
<el-breadcrumb-item v-for="item in levelList" :key="item.path"> <el-breadcrumb-item v-for="item in levelList" :key="item.path">
<a @click.prevent="handleLink(item)"> <a @click.prevent="handleLink(item)">
{{ transformI18n(item.meta.title) }} {{ item.meta.title }}
</a> </a>
</el-breadcrumb-item> </el-breadcrumb-item>
</transition-group> </transition-group>

View File

@@ -3,17 +3,13 @@ import Search from "../search/index.vue";
import Notice from "../notice/index.vue"; import Notice from "../notice/index.vue";
import { ref, watch, nextTick } from "vue"; import { ref, watch, nextTick } from "vue";
import SidebarItem from "./sidebarItem.vue"; import SidebarItem from "./sidebarItem.vue";
import avatars from "/@/assets/avatars.jpg"; import { useNav } from "@/layout/hooks/useNav";
import { useNav } from "/@/layout/hooks/useNav"; import { usePermissionStoreHook } from "@/store/modules/permission";
import { useTranslationLang } from "../../hooks/useTranslationLang";
import { usePermissionStoreHook } from "/@/store/modules/permission";
import globalization from "/@/assets/svg/globalization.svg?component";
const menuRef = ref(); const menuRef = ref();
const { t, route, locale, translationCh, translationEn } =
useTranslationLang(menuRef);
const { const {
route,
title, title,
routers, routers,
logout, logout,
@@ -21,9 +17,7 @@ const {
onPanel, onPanel,
menuSelect, menuSelect,
username, username,
avatarsStyle, avatarsStyle
getDropdownItemStyle,
getDropdownItemClass
} = useNav(); } = useNav();
nextTick(() => { nextTick(() => {
@@ -64,40 +58,13 @@ watch(
<Search /> <Search />
<!-- 通知 --> <!-- 通知 -->
<Notice id="header-notice" /> <Notice id="header-notice" />
<!-- 国际化 -->
<el-dropdown id="header-translation" trigger="click">
<globalization
class="navbar-bg-hover w-[40px] h-[48px] p-[11px] cursor-pointer outline-none"
/>
<template #dropdown>
<el-dropdown-menu class="translation">
<el-dropdown-item
:style="getDropdownItemStyle(locale, 'zh')"
:class="['dark:!text-white', getDropdownItemClass(locale, 'zh')]"
@click="translationCh"
>
<span class="check-zh" v-show="locale === 'zh'">
<IconifyIconOffline icon="check" />
</span>
简体中文
</el-dropdown-item>
<el-dropdown-item
:style="getDropdownItemStyle(locale, 'en')"
:class="['dark:!text-white', getDropdownItemClass(locale, 'en')]"
@click="translationEn"
>
<span class="check-en" v-show="locale === 'en'">
<IconifyIconOffline icon="check" />
</span>
English
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<!-- 退出登录 --> <!-- 退出登录 -->
<el-dropdown trigger="click"> <el-dropdown trigger="click">
<span class="el-dropdown-link navbar-bg-hover"> <span class="el-dropdown-link navbar-bg-hover">
<img v-if="avatars" :src="avatars" :style="avatarsStyle" /> <img
src="https://avatars.githubusercontent.com/u/44761321?v=4"
:style="avatarsStyle"
/>
<p v-if="username" class="dark:text-white">{{ username }}</p> <p v-if="username" class="dark:text-white">{{ username }}</p>
</span> </span>
<template #dropdown> <template #dropdown>
@@ -107,14 +74,14 @@ watch(
icon="logout-circle-r-line" icon="logout-circle-r-line"
style="margin: 5px" style="margin: 5px"
/> />
{{ t("buttons.hsLoginOut") }} 退出系统
</el-dropdown-item> </el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
</el-dropdown> </el-dropdown>
<span <span
class="set-icon navbar-bg-hover" class="set-icon navbar-bg-hover"
:title="t('buttons.hssystemSet')" title="打开项目配置"
@click="onPanel" @click="onPanel"
> >
<IconifyIconOffline icon="setting" /> <IconifyIconOffline icon="setting" />
@@ -124,22 +91,6 @@ watch(
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
.translation {
::v-deep(.el-dropdown-menu__item) {
padding: 5px 40px;
}
.check-zh {
position: absolute;
left: 20px;
}
.check-en {
position: absolute;
left: 20px;
}
}
.logout { .logout {
max-width: 120px; max-width: 120px;

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { useNav } from "/@/layout/hooks/useNav"; import { useNav } from "@/layout/hooks/useNav";
const props = defineProps({ const props = defineProps({
collapse: Boolean collapse: Boolean
@@ -9,7 +9,7 @@ const { title } = useNav();
</script> </script>
<template> <template>
<div class="sidebar-logo-container" :class="{ collapse: props.collapse }"> <div class="sidebar-logo-container" :class="{ collapses: props.collapse }">
<transition name="sidebarLogoFade"> <transition name="sidebarLogoFade">
<router-link <router-link
v-if="props.collapse" v-if="props.collapse"
@@ -65,7 +65,7 @@ const { title } = useNav();
} }
} }
.collapse { .collapses {
.sidebar-logo { .sidebar-logo {
margin-right: 0; margin-right: 0;
} }

View File

@@ -1,22 +1,17 @@
<script setup lang="ts"> <script setup lang="ts">
import Search from "../search/index.vue"; import Search from "../search/index.vue";
import Notice from "../notice/index.vue"; import Notice from "../notice/index.vue";
import avatars from "/@/assets/avatars.jpg"; import { useNav } from "@/layout/hooks/useNav";
import { useNav } from "/@/layout/hooks/useNav";
import { transformI18n } from "/@/plugins/i18n";
import { ref, toRaw, watch, onMounted, nextTick } from "vue"; import { ref, toRaw, watch, onMounted, nextTick } from "vue";
import { useRenderIcon } from "/@/components/ReIcon/src/hooks"; import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import { getParentPaths, findRouteByPath } from "/@/router/utils"; import { getParentPaths, findRouteByPath } from "@/router/utils";
import { useTranslationLang } from "../../hooks/useTranslationLang"; import { usePermissionStoreHook } from "@/store/modules/permission";
import { usePermissionStoreHook } from "/@/store/modules/permission";
import globalization from "/@/assets/svg/globalization.svg?component";
const menuRef = ref(); const menuRef = ref();
let defaultActive = ref(null); let defaultActive = ref(null);
const { t, route, locale, translationCh, translationEn } =
useTranslationLang(menuRef);
const { const {
route,
device, device,
routers, routers,
logout, logout,
@@ -24,9 +19,7 @@ const {
menuSelect, menuSelect,
resolvePath, resolvePath,
username, username,
avatarsStyle, avatarsStyle
getDropdownItemStyle,
getDropdownItemClass
} = useNav(); } = useNav();
function getDefaultActive(routePath) { function getDefaultActive(routePath) {
@@ -79,7 +72,7 @@ watch(
:is="useRenderIcon(route.meta && toRaw(route.meta.icon))" :is="useRenderIcon(route.meta && toRaw(route.meta.icon))"
/> />
</div> </div>
<span class="select-none">{{ transformI18n(route.meta.title) }}</span> <span class="select-none">{{ route.meta.title }}</span>
<FontIcon <FontIcon
v-if="route.meta.extraIcon" v-if="route.meta.extraIcon"
width="30px" width="30px"
@@ -96,40 +89,13 @@ watch(
<Search /> <Search />
<!-- 通知 --> <!-- 通知 -->
<Notice id="header-notice" /> <Notice id="header-notice" />
<!-- 国际化 -->
<el-dropdown id="header-translation" trigger="click">
<globalization
class="navbar-bg-hover w-[40px] h-[48px] p-[11px] cursor-pointer outline-none"
/>
<template #dropdown>
<el-dropdown-menu class="translation">
<el-dropdown-item
:style="getDropdownItemStyle(locale, 'zh')"
:class="['dark:!text-white', getDropdownItemClass(locale, 'zh')]"
@click="translationCh"
>
<span class="check-zh" v-show="locale === 'zh'">
<IconifyIconOffline icon="check" />
</span>
简体中文
</el-dropdown-item>
<el-dropdown-item
:style="getDropdownItemStyle(locale, 'en')"
:class="['dark:!text-white', getDropdownItemClass(locale, 'en')]"
@click="translationEn"
>
<span class="check-en" v-show="locale === 'en'">
<IconifyIconOffline icon="check" />
</span>
English
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<!-- 退出登录 --> <!-- 退出登录 -->
<el-dropdown trigger="click"> <el-dropdown trigger="click">
<span class="el-dropdown-link navbar-bg-hover"> <span class="el-dropdown-link navbar-bg-hover select-none">
<img v-if="avatars" :src="avatars" :style="avatarsStyle" /> <img
src="https://avatars.githubusercontent.com/u/44761321?v=4"
:style="avatarsStyle"
/>
<p v-if="username" class="dark:text-white">{{ username }}</p> <p v-if="username" class="dark:text-white">{{ username }}</p>
</span> </span>
<template #dropdown> <template #dropdown>
@@ -139,14 +105,14 @@ watch(
icon="logout-circle-r-line" icon="logout-circle-r-line"
style="margin: 5px" style="margin: 5px"
/> />
{{ t("buttons.hsLoginOut") }} 退出系统
</el-dropdown-item> </el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
</el-dropdown> </el-dropdown>
<span <span
class="set-icon navbar-bg-hover" class="set-icon navbar-bg-hover"
:title="t('buttons.hssystemSet')" title="打开项目配置"
@click="onPanel" @click="onPanel"
> >
<IconifyIconOffline icon="setting" /> <IconifyIconOffline icon="setting" />
@@ -156,22 +122,6 @@ watch(
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
.translation {
::v-deep(.el-dropdown-menu__item) {
padding: 5px 40px;
}
.check-zh {
position: absolute;
left: 20px;
}
.check-en {
position: absolute;
left: 20px;
}
}
.logout { .logout {
max-width: 120px; max-width: 120px;

View File

@@ -1,9 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import path from "path"; import path from "path";
import { childrenType } from "../../types"; import { childrenType } from "../../types";
import { useNav } from "/@/layout/hooks/useNav"; import { useNav } from "@/layout/hooks/useNav";
import { transformI18n } from "/@/plugins/i18n"; import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
import { ref, toRaw, PropType, nextTick, computed, CSSProperties } from "vue"; import { ref, toRaw, PropType, nextTick, computed, CSSProperties } from "vue";
const { layout, isCollapse } = useNav(); const { layout, isCollapse } = useNav();
@@ -164,7 +163,7 @@ function resolvePath(routePath) {
:style="getDivStyle" :style="getDivStyle"
> >
<span :style="getMenuTextStyle"> <span :style="getMenuTextStyle">
{{ transformI18n(onlyOneChild.meta.title) }} {{ onlyOneChild.meta.title }}
</span> </span>
</div> </div>
<div <div
@@ -174,13 +173,13 @@ function resolvePath(routePath) {
:style="getDivStyle" :style="getDivStyle"
> >
<span :style="getMenuTextStyle"> <span :style="getMenuTextStyle">
{{ transformI18n(onlyOneChild.meta.title) }} {{ onlyOneChild.meta.title }}
</span> </span>
</div> </div>
<template #title> <template #title>
<div :style="getDivStyle"> <div :style="getDivStyle">
<span v-if="layout === 'horizontal'"> <span v-if="layout === 'horizontal'">
{{ transformI18n(onlyOneChild.meta.title) }} {{ onlyOneChild.meta.title }}
</span> </span>
<el-tooltip <el-tooltip
v-else v-else
@@ -189,14 +188,14 @@ function resolvePath(routePath) {
:disabled="!onlyOneChild.showTooltip" :disabled="!onlyOneChild.showTooltip"
> >
<template #content> <template #content>
{{ transformI18n(onlyOneChild.meta.title) }} {{ onlyOneChild.meta.title }}
</template> </template>
<span <span
ref="menuTextRef" ref="menuTextRef"
:style="getMenuTextStyle" :style="getMenuTextStyle"
@mouseover="hoverMenu(onlyOneChild)" @mouseover="hoverMenu(onlyOneChild)"
> >
{{ transformI18n(onlyOneChild.meta.title) }} {{ onlyOneChild.meta.title }}
</span> </span>
</el-tooltip> </el-tooltip>
<FontIcon <FontIcon
@@ -220,7 +219,7 @@ function resolvePath(routePath) {
/> />
</div> </div>
<span v-if="layout === 'horizontal'"> <span v-if="layout === 'horizontal'">
{{ transformI18n(props.item.meta.title) }} {{ props.item.meta.title }}
</span> </span>
<el-tooltip <el-tooltip
v-else v-else
@@ -229,7 +228,7 @@ function resolvePath(routePath) {
:disabled="!isCollapse || !props.item.showTooltip" :disabled="!isCollapse || !props.item.showTooltip"
> >
<template #content> <template #content>
{{ transformI18n(props.item.meta.title) }} {{ props.item.meta.title }}
</template> </template>
<div <div
ref="menuTextRef" ref="menuTextRef"
@@ -237,7 +236,7 @@ function resolvePath(routePath) {
@mouseover="hoverMenu(props.item)" @mouseover="hoverMenu(props.item)"
> >
<span :style="getSpanStyle"> <span :style="getSpanStyle">
{{ transformI18n(props.item.meta.title) }} {{ props.item.meta.title }}
</span> </span>
</div> </div>
</el-tooltip> </el-tooltip>

View File

@@ -1,15 +1,15 @@
<script setup lang="ts"> <script setup lang="ts">
import Logo from "./logo.vue"; import Logo from "./logo.vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { emitter } from "/@/utils/mitt"; import { emitter } from "@/utils/mitt";
import SidebarItem from "./sidebarItem.vue"; import SidebarItem from "./sidebarItem.vue";
import leftCollapse from "./leftCollapse.vue"; import leftCollapse from "./leftCollapse.vue";
import type { StorageConfigs } from "/#/index"; import type { StorageConfigs } from "/#/index";
import { useNav } from "/@/layout/hooks/useNav"; import { useNav } from "@/layout/hooks/useNav";
import { storageLocal } from "@pureadmin/utils"; import { storageLocal } from "@pureadmin/utils";
import { ref, computed, watch, onBeforeMount } from "vue"; import { ref, computed, watch, onBeforeMount } from "vue";
import { findRouteByPath, getParentPaths } from "/@/router/utils"; import { findRouteByPath, getParentPaths } from "@/router/utils";
import { usePermissionStoreHook } from "/@/store/modules/permission"; import { usePermissionStoreHook } from "@/store/modules/permission";
const route = useRoute(); const route = useRoute();
const showLogo = ref( const showLogo = ref(

View File

@@ -1,14 +1,13 @@
<script setup lang="ts"> <script setup lang="ts">
import { $t } from "/@/plugins/i18n"; import { emitter } from "@/utils/mitt";
import { emitter } from "/@/utils/mitt";
import { RouteConfigs } from "../../types"; import { RouteConfigs } from "../../types";
import { useTags } from "../../hooks/useTag"; import { useTags } from "../../hooks/useTag";
import { routerArrays } from "/@/layout/types"; import { routerArrays } from "@/layout/types";
import { isEqual, isEmpty } from "lodash-unified"; import { isEqual, isEmpty } from "lodash-unified";
import { useSettingStoreHook } from "/@/store/modules/settings"; import { useSettingStoreHook } from "@/store/modules/settings";
import { ref, watch, unref, nextTick, onBeforeMount } from "vue"; import { ref, watch, unref, nextTick, onBeforeMount } from "vue";
import { handleAliveRoute, delAliveRoutes } from "/@/router/utils"; import { handleAliveRoute, delAliveRoutes } from "@/router/utils";
import { useMultiTagsStoreHook } from "/@/store/modules/multiTags"; import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
import { useResizeObserver, useDebounceFn, useFullscreen } from "@vueuse/core"; import { useResizeObserver, useDebounceFn, useFullscreen } from "@vueuse/core";
const { const {
@@ -35,7 +34,6 @@ const {
onMounted, onMounted,
onMouseenter, onMouseenter,
onMouseleave, onMouseleave,
transformI18n,
onContentFullScreen onContentFullScreen
} = useTags(); } = useTags();
@@ -285,10 +283,10 @@ function onClickDrop(key, item, selectRoute?: RouteConfigs) {
setTimeout(() => { setTimeout(() => {
if (isFullscreen.value) { if (isFullscreen.value) {
tagsViews[6].icon = "exit-fullscreen"; tagsViews[6].icon = "exit-fullscreen";
tagsViews[6].text = $t("buttons.hswholeExitFullScreen"); tagsViews[6].text = "整体页面退出全屏";
} else { } else {
tagsViews[6].icon = "fullscreen"; tagsViews[6].icon = "fullscreen";
tagsViews[6].text = $t("buttons.hswholeFullScreen"); tagsViews[6].text = "整体页面全屏";
} }
}, 100); }, 100);
break; break;
@@ -298,10 +296,10 @@ function onClickDrop(key, item, selectRoute?: RouteConfigs) {
setTimeout(() => { setTimeout(() => {
if (pureSetting.hiddenSideBar) { if (pureSetting.hiddenSideBar) {
tagsViews[7].icon = "exit-fullscreen"; tagsViews[7].icon = "exit-fullscreen";
tagsViews[7].text = $t("buttons.hscontentExitFullScreen"); tagsViews[7].text = "内容区退出全屏";
} else { } else {
tagsViews[7].icon = "fullscreen"; tagsViews[7].icon = "fullscreen";
tagsViews[7].text = $t("buttons.hscontentFullScreen"); tagsViews[7].text = "内容区全屏";
} }
}, 100); }, 100);
break; break;
@@ -499,7 +497,7 @@ onMounted(() => {
<IconifyIconOffline icon="arrow-left-s-line" @click="handleScroll(200)" /> <IconifyIconOffline icon="arrow-left-s-line" @click="handleScroll(200)" />
</span> </span>
<div ref="scrollbarDom" class="scroll-container"> <div ref="scrollbarDom" class="scroll-container">
<div class="tab" ref="tabDom" :style="getTabStyle"> <div class="tab select-none" ref="tabDom" :style="getTabStyle">
<div <div
:ref="'dynamic' + index" :ref="'dynamic' + index"
v-for="(item, index) in multiTags" v-for="(item, index) in multiTags"
@@ -520,7 +518,7 @@ onMounted(() => {
:to="item.path" :to="item.path"
class="dark:!text-text_color_primary dark:hover:!text-primary" class="dark:!text-text_color_primary dark:hover:!text-primary"
> >
{{ transformI18n(item.meta.title) }} {{ item.meta.title }}
</router-link> </router-link>
<span <span
v-if=" v-if="
@@ -561,7 +559,7 @@ onMounted(() => {
> >
<li v-if="item.show" @click="selectTag(key, item)"> <li v-if="item.show" @click="selectTag(key, item)">
<IconifyIconOffline :icon="item.icon" /> <IconifyIconOffline :icon="item.icon" />
{{ transformI18n(item.text) }} {{ item.text }}
</li> </li>
</div> </div>
</ul> </ul>
@@ -585,7 +583,7 @@ onMounted(() => {
:disabled="item.disabled" :disabled="item.disabled"
> >
<IconifyIconOffline :icon="item.icon" /> <IconifyIconOffline :icon="item.icon" />
{{ transformI18n(item.text) }} {{ item.text }}
</el-dropdown-item> </el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>

View File

@@ -1,5 +1,4 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useI18n } from "vue-i18n";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { ref, unref, onMounted, nextTick } from "vue"; import { ref, unref, onMounted, nextTick } from "vue";
@@ -7,7 +6,6 @@ defineOptions({
name: "FrameView" name: "FrameView"
}); });
const { t } = useI18n();
const loading = ref(true); const loading = ref(true);
const currentRoute = useRoute(); const currentRoute = useRoute();
const frameSrc = ref<string>(""); const frameSrc = ref<string>("");
@@ -45,11 +43,7 @@ onMounted(() => {
</script> </script>
<template> <template>
<div <div class="frame" v-loading="loading" element-loading-text="加载中...">
class="frame"
v-loading="loading"
:element-loading-text="t('status.hsLoad')"
>
<iframe :src="frameSrc" class="frame-iframe" ref="frameRef" /> <iframe :src="frameSrc" class="frame-iframe" ref="frameRef" />
</div> </div>
</template> </template>

View File

@@ -1,11 +1,11 @@
import { ref } from "vue"; import { ref } from "vue";
import { getConfig } from "/@/config"; import { getConfig } from "@/config";
import { find } from "lodash-unified"; import { find } from "lodash-unified";
import { useLayout } from "./useLayout"; import { useLayout } from "./useLayout";
import { themeColorsType } from "../types"; import { themeColorsType } from "../types";
import { TinyColor } from "@ctrl/tinycolor"; import { TinyColor } from "@ctrl/tinycolor";
import { useGlobal } from "@pureadmin/utils"; import { useGlobal } from "@pureadmin/utils";
import { useEpThemeStoreHook } from "/@/store/modules/epTheme"; import { useEpThemeStoreHook } from "@/store/modules/epTheme";
import { import {
darken, darken,
lighten, lighten,
@@ -69,7 +69,7 @@ export function useDataThemeChange() {
return new TinyColor(color).shade(10).toString(); return new TinyColor(color).shade(10).toString();
}; };
/** 设置ep主题色 */ /** 设置 `element-plus` 主题色 */
const setEpThemeColor = (color: string) => { const setEpThemeColor = (color: string) => {
useEpThemeStoreHook().setEpThemeColor(color); useEpThemeStoreHook().setEpThemeColor(color);
body.style.setProperty("--el-color-primary-active", shadeBgColor(color)); body.style.setProperty("--el-color-primary-active", shadeBgColor(color));

View File

@@ -1,8 +1,7 @@
import { computed } from "vue"; import { computed } from "vue";
import { useI18n } from "vue-i18n";
import { routerArrays } from "../types"; import { routerArrays } from "../types";
import { useGlobal } from "@pureadmin/utils"; import { useGlobal } from "@pureadmin/utils";
import { useMultiTagsStore } from "/@/store/modules/multiTags"; import { useMultiTagsStore } from "@/store/modules/multiTags";
export function useLayout() { export function useLayout() {
const { $storage, $config } = useGlobal<GlobalPropertiesApi>(); const { $storage, $config } = useGlobal<GlobalPropertiesApi>();
@@ -15,11 +14,6 @@ export function useLayout() {
) { ) {
$storage.tags = routerArrays; $storage.tags = routerArrays;
} }
/** 国际化 */
if (!$storage.locale) {
$storage.locale = { locale: $config?.Locale ?? "zh" };
useI18n().locale.value = $config?.Locale ?? "zh";
}
/** 导航 */ /** 导航 */
if (!$storage.layout) { if (!$storage.layout) {
$storage.layout = { $storage.layout = {

View File

@@ -1,18 +1,17 @@
import { computed } from "vue"; import { computed } from "vue";
import { getConfig } from "/@/config"; import { getConfig } from "@/config";
import { useRouter } from "vue-router"; import { emitter } from "@/utils/mitt";
import { emitter } from "/@/utils/mitt";
import { routeMetaType } from "../types"; import { routeMetaType } from "../types";
import { useGlobal } from "@pureadmin/utils"; import { useGlobal } from "@pureadmin/utils";
import { transformI18n } from "/@/plugins/i18n"; import { useRouter, useRoute } from "vue-router";
import { router, remainingPaths } from "/@/router"; import { router, remainingPaths } from "@/router";
import { useAppStoreHook } from "/@/store/modules/app"; import { useAppStoreHook } from "@/store/modules/app";
import { useUserStoreHook } from "/@/store/modules/user"; import { useUserStoreHook } from "@/store/modules/user";
import { useEpThemeStoreHook } from "/@/store/modules/epTheme";
const errorInfo = "当前路由配置不正确,请检查配置"; const errorInfo = "当前路由配置不正确,请检查配置";
export function useNav() { export function useNav() {
const route = useRoute();
const pureApp = useAppStoreHook(); const pureApp = useAppStoreHook();
const routers = useRouter().options.routes; const routers = useRouter().options.routes;
@@ -21,22 +20,6 @@ export function useNav() {
return useUserStoreHook()?.username; return useUserStoreHook()?.username;
}); });
/** 设置国际化选中后的样式 */
const getDropdownItemStyle = computed(() => {
return (locale, t) => {
return {
background: locale === t ? useEpThemeStoreHook().epThemeColor : "",
color: locale === t ? "#f4f4f5" : "#000"
};
};
});
const getDropdownItemClass = computed(() => {
return (locale, t) => {
return locale === t ? "" : "dark:hover:!text-primary";
};
});
const avatarsStyle = computed(() => { const avatarsStyle = computed(() => {
return username.value ? { marginRight: "10px" } : ""; return username.value ? { marginRight: "10px" } : "";
}); });
@@ -61,8 +44,8 @@ export function useNav() {
/** 动态title */ /** 动态title */
function changeTitle(meta: routeMetaType) { function changeTitle(meta: routeMetaType) {
const Title = getConfig().Title; const Title = getConfig().Title;
if (Title) document.title = `${transformI18n(meta.title)} | ${Title}`; if (Title) document.title = `${meta.title} | ${Title}`;
else document.title = transformI18n(meta.title); else document.title = meta.title;
} }
/** 退出登录 */ /** 退出登录 */
@@ -132,6 +115,7 @@ export function useNav() {
} }
return { return {
route,
title, title,
device, device,
layout, layout,
@@ -148,8 +132,6 @@ export function useNav() {
isCollapse, isCollapse,
pureApp, pureApp,
username, username,
avatarsStyle, avatarsStyle
getDropdownItemStyle,
getDropdownItemClass
}; };
} }

View File

@@ -13,9 +13,8 @@ import { isEqual } from "lodash-unified";
import type { StorageConfigs } from "/#/index"; import type { StorageConfigs } from "/#/index";
import { useEventListener } from "@vueuse/core"; import { useEventListener } from "@vueuse/core";
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from "vue-router";
import { transformI18n, $t } from "/@/plugins/i18n"; import { useSettingStoreHook } from "@/store/modules/settings";
import { useSettingStoreHook } from "/@/store/modules/settings"; import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
import { useMultiTagsStoreHook } from "/@/store/modules/multiTags";
import { storageLocal, toggleClass, hasClass } from "@pureadmin/utils"; import { storageLocal, toggleClass, hasClass } from "@pureadmin/utils";
export function useTags() { export function useTags() {
@@ -49,56 +48,56 @@ export function useTags() {
const tagsViews = reactive<Array<tagsViewsType>>([ const tagsViews = reactive<Array<tagsViewsType>>([
{ {
icon: "refresh-right", icon: "refresh-right",
text: $t("buttons.hsreload"), text: "重新加载",
divided: false, divided: false,
disabled: false, disabled: false,
show: true show: true
}, },
{ {
icon: "close", icon: "close",
text: $t("buttons.hscloseCurrentTab"), text: "关闭当前标签页",
divided: false, divided: false,
disabled: multiTags.value.length > 1 ? false : true, disabled: multiTags.value.length > 1 ? false : true,
show: true show: true
}, },
{ {
icon: "close-left-tags", icon: "close-left-tags",
text: $t("buttons.hscloseLeftTabs"), text: "关闭左侧标签页",
divided: true, divided: true,
disabled: multiTags.value.length > 1 ? false : true, disabled: multiTags.value.length > 1 ? false : true,
show: true show: true
}, },
{ {
icon: "close-right-tags", icon: "close-right-tags",
text: $t("buttons.hscloseRightTabs"), text: "关闭右侧标签页",
divided: false, divided: false,
disabled: multiTags.value.length > 1 ? false : true, disabled: multiTags.value.length > 1 ? false : true,
show: true show: true
}, },
{ {
icon: "close-other-tags", icon: "close-other-tags",
text: $t("buttons.hscloseOtherTabs"), text: "关闭其他标签页",
divided: true, divided: true,
disabled: multiTags.value.length > 2 ? false : true, disabled: multiTags.value.length > 2 ? false : true,
show: true show: true
}, },
{ {
icon: "close-all-tags", icon: "close-all-tags",
text: $t("buttons.hscloseAllTabs"), text: "关闭全部标签页",
divided: false, divided: false,
disabled: multiTags.value.length > 1 ? false : true, disabled: multiTags.value.length > 1 ? false : true,
show: true show: true
}, },
{ {
icon: "fullscreen", icon: "fullscreen",
text: $t("buttons.hswholeFullScreen"), text: "整体页面全屏",
divided: true, divided: true,
disabled: false, disabled: false,
show: true show: true
}, },
{ {
icon: "fullscreen", icon: "fullscreen",
text: $t("buttons.hscontentFullScreen"), text: "内容区全屏",
divided: false, divided: false,
disabled: false, disabled: false,
show: true show: true
@@ -224,12 +223,10 @@ export function useTags() {
currentSelect, currentSelect,
scheduleIsActive, scheduleIsActive,
getContextMenuStyle, getContextMenuStyle,
$t,
closeMenu, closeMenu,
onMounted, onMounted,
onMouseenter, onMouseenter,
onMouseleave, onMouseleave,
transformI18n,
onContentFullScreen onContentFullScreen
}; };
} }

View File

@@ -1,37 +0,0 @@
import { useNav } from "./useNav";
import { useI18n } from "vue-i18n";
import { useRoute } from "vue-router";
import { watch, type Ref } from "vue";
export function useTranslationLang(ref?: Ref) {
const { $storage, changeTitle, handleResize } = useNav();
const { locale, t } = useI18n();
const route = useRoute();
function translationCh() {
$storage.locale = { locale: "zh" };
locale.value = "zh";
ref && handleResize(ref.value);
}
function translationEn() {
$storage.locale = { locale: "en" };
locale.value = "en";
ref && handleResize(ref.value);
}
watch(
() => locale.value,
() => {
changeTitle(route.meta);
}
);
return {
t,
route,
locale,
translationCh,
translationEn
};
}

View File

@@ -1,9 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { setType } from "./types"; import { setType } from "./types";
import { emitter } from "/@/utils/mitt"; import { emitter } from "@/utils/mitt";
import { useLayout } from "./hooks/useLayout"; import { useLayout } from "./hooks/useLayout";
import { useAppStoreHook } from "/@/store/modules/app"; import { useAppStoreHook } from "@/store/modules/app";
import { useSettingStoreHook } from "/@/store/modules/settings"; import { useSettingStoreHook } from "@/store/modules/settings";
import { deviceDetection, useDark, useGlobal } from "@pureadmin/utils"; import { deviceDetection, useDark, useGlobal } from "@pureadmin/utils";
import { h, reactive, computed, onMounted, defineComponent } from "vue"; import { h, reactive, computed, onMounted, defineComponent } from "vue";
@@ -13,7 +13,7 @@ import appMain from "./components/appMain.vue";
import setting from "./components/setting/index.vue"; import setting from "./components/setting/index.vue";
import Vertical from "./components/sidebar/vertical.vue"; import Vertical from "./components/sidebar/vertical.vue";
import Horizontal from "./components/sidebar/horizontal.vue"; import Horizontal from "./components/sidebar/horizontal.vue";
import backTop from "/@/assets/svg/back_top.svg?component"; import backTop from "@/assets/svg/back_top.svg?component";
const { isDark } = useDark(); const { isDark } = useDark();
const { layout } = useLayout(); const { layout } = useLayout();

View File

@@ -20,7 +20,6 @@ const themeColors = {
menuHover: "#4091f7", menuHover: "#4091f7",
subMenuBg: "#0f0303", subMenuBg: "#0f0303",
subMenuActiveBg: "#4091f7", subMenuActiveBg: "#4091f7",
navTextColor: "#fff",
menuText: "rgb(254 254 254 / 65%)", menuText: "rgb(254 254 254 / 65%)",
sidebarLogo: "#002140", sidebarLogo: "#002140",
menuTitleHover: "#fff", menuTitleHover: "#fff",
@@ -33,7 +32,6 @@ const themeColors = {
menuHover: "#e0ebf6", menuHover: "#e0ebf6",
subMenuBg: "#fff", subMenuBg: "#fff",
subMenuActiveBg: "#e0ebf6", subMenuActiveBg: "#e0ebf6",
navTextColor: "#7a80b4",
menuText: "#7a80b4", menuText: "#7a80b4",
sidebarLogo: "#fff", sidebarLogo: "#fff",
menuTitleHover: "#000", menuTitleHover: "#000",
@@ -46,7 +44,6 @@ const themeColors = {
menuHover: "#e13c39", menuHover: "#e13c39",
subMenuBg: "#000", subMenuBg: "#000",
subMenuActiveBg: "#e13c39", subMenuActiveBg: "#e13c39",
navTextColor: "#red",
menuText: "rgb(254 254 254 / 65.1%)", menuText: "rgb(254 254 254 / 65.1%)",
sidebarLogo: "#42090c", sidebarLogo: "#42090c",
menuTitleHover: "#fff", menuTitleHover: "#fff",
@@ -59,7 +56,6 @@ const themeColors = {
menuHover: "#e85f33", menuHover: "#e85f33",
subMenuBg: "#0f0603", subMenuBg: "#0f0603",
subMenuActiveBg: "#e85f33", subMenuActiveBg: "#e85f33",
navTextColor: "#fff",
menuText: "rgb(254 254 254 / 65%)", menuText: "rgb(254 254 254 / 65%)",
sidebarLogo: "#441708", sidebarLogo: "#441708",
menuTitleHover: "#fff", menuTitleHover: "#fff",
@@ -72,7 +68,6 @@ const themeColors = {
menuHover: "#f6da4d", menuHover: "#f6da4d",
subMenuBg: "#0f0603", subMenuBg: "#0f0603",
subMenuActiveBg: "#f6da4d", subMenuActiveBg: "#f6da4d",
navTextColor: "#fff",
menuText: "rgb(254 254 254 / 65%)", menuText: "rgb(254 254 254 / 65%)",
sidebarLogo: "#443b05", sidebarLogo: "#443b05",
menuTitleHover: "#fff", menuTitleHover: "#fff",
@@ -85,7 +80,6 @@ const themeColors = {
menuHover: "#59bfc1", menuHover: "#59bfc1",
subMenuBg: "#000", subMenuBg: "#000",
subMenuActiveBg: "#59bfc1", subMenuActiveBg: "#59bfc1",
navTextColor: "#7a80b4",
menuText: "#7a80b4", menuText: "#7a80b4",
sidebarLogo: "#053434", sidebarLogo: "#053434",
menuTitleHover: "#fff", menuTitleHover: "#fff",
@@ -98,7 +92,6 @@ const themeColors = {
menuHover: "#60ac80", menuHover: "#60ac80",
subMenuBg: "#000", subMenuBg: "#000",
subMenuActiveBg: "#60ac80", subMenuActiveBg: "#60ac80",
navTextColor: "#7a80b4",
menuText: "#7a80b4", menuText: "#7a80b4",
sidebarLogo: "#112f21", sidebarLogo: "#112f21",
menuTitleHover: "#fff", menuTitleHover: "#fff",
@@ -111,7 +104,6 @@ const themeColors = {
menuHover: "#d84493", menuHover: "#d84493",
subMenuBg: "#000", subMenuBg: "#000",
subMenuActiveBg: "#d84493", subMenuActiveBg: "#d84493",
navTextColor: "#7a80b4",
menuText: "#7a80b4", menuText: "#7a80b4",
sidebarLogo: "#3f0d29", sidebarLogo: "#3f0d29",
menuTitleHover: "#fff", menuTitleHover: "#fff",
@@ -124,7 +116,6 @@ const themeColors = {
menuHover: "#693ac9", menuHover: "#693ac9",
subMenuBg: "#000", subMenuBg: "#000",
subMenuActiveBg: "#693ac9", subMenuActiveBg: "#693ac9",
navTextColor: "#7a80b4",
menuText: "#7a80b4", menuText: "#7a80b4",
sidebarLogo: "#1f0c38", sidebarLogo: "#1f0c38",
menuTitleHover: "#fff", menuTitleHover: "#fff",
@@ -147,7 +138,6 @@ export const genScssMultipleScopeVars = (): MultipleScopeVarsItem[] => {
$menuHover: ${themeColors[key].menuHover} !default; $menuHover: ${themeColors[key].menuHover} !default;
$subMenuBg: ${themeColors[key].subMenuBg} !default; $subMenuBg: ${themeColors[key].subMenuBg} !default;
$subMenuActiveBg: ${themeColors[key].subMenuActiveBg} !default; $subMenuActiveBg: ${themeColors[key].subMenuActiveBg} !default;
$navTextColor: ${themeColors[key].navTextColor} !default;
$menuText: ${themeColors[key].menuText} !default; $menuText: ${themeColors[key].menuText} !default;
$sidebarLogo: ${themeColors[key].sidebarLogo} !default; $sidebarLogo: ${themeColors[key].sidebarLogo} !default;
$menuTitleHover: ${themeColors[key].menuTitleHover} !default; $menuTitleHover: ${themeColors[key].menuTitleHover} !default;

View File

@@ -3,7 +3,7 @@ export const routerArrays: Array<RouteConfigs> = [
path: "/welcome", path: "/welcome",
parentPath: "/", parentPath: "/",
meta: { meta: {
title: "menus.hshome", title: "首页",
icon: "home-filled" icon: "home-filled"
} }
} }

View File

@@ -1,14 +1,13 @@
import App from "./App.vue"; import App from "./App.vue";
import router from "./router"; import router from "./router";
import { setupStore } from "/@/store"; import { setupStore } from "@/store";
import ElementPlus from "element-plus"; import ElementPlus from "element-plus";
import { getServerConfig } from "./config"; import { getServerConfig } from "./config";
import { createApp, Directive } from "vue"; import { createApp, Directive } from "vue";
import { useI18n } from "../src/plugins/i18n";
import { MotionPlugin } from "@vueuse/motion"; import { MotionPlugin } from "@vueuse/motion";
// import { useEcharts } from "/@/plugins/echarts"; // import { useEcharts } from "@/plugins/echarts";
// import { useTable } from "../src/plugins/vxe-table"; // import { useTable } from "@/plugins/vxe-table";
import { injectResponsiveStorage } from "/@/utils/responsive"; import { injectResponsiveStorage } from "@/utils/responsive";
// import Table from "@pureadmin/table"; // import Table from "@pureadmin/table";
// import PureDescriptions from "@pureadmin/descriptions"; // import PureDescriptions from "@pureadmin/descriptions";
@@ -29,7 +28,7 @@ import "./assets/iconfont/iconfont.css";
const app = createApp(App); const app = createApp(App);
// 自定义指令 // 自定义指令
import * as directives from "/@/directives"; import * as directives from "@/directives";
Object.keys(directives).forEach(key => { Object.keys(directives).forEach(key => {
app.directive(key, (directives as { [key: string]: Directive })[key]); app.directive(key, (directives as { [key: string]: Directive })[key]);
}); });
@@ -45,7 +44,7 @@ app.component("IconifyIconOnline", IconifyIconOnline);
app.component("FontIcon", FontIcon); app.component("FontIcon", FontIcon);
// 全局注册按钮级别权限组件 // 全局注册按钮级别权限组件
import { Auth } from "/@/components/ReAuth"; import { Auth } from "@/components/ReAuth";
app.component("Auth", Auth); app.component("Auth", Auth);
getServerConfig(app).then(async config => { getServerConfig(app).then(async config => {
@@ -53,7 +52,7 @@ getServerConfig(app).then(async config => {
await router.isReady(); await router.isReady();
injectResponsiveStorage(app, config); injectResponsiveStorage(app, config);
setupStore(app); setupStore(app);
app.use(MotionPlugin).use(useI18n).use(ElementPlus); app.use(MotionPlugin).use(ElementPlus);
// .use(useEcharts); // .use(useEcharts);
// .use(Table); // .use(Table);
// .use(PureDescriptions); // .use(PureDescriptions);

View File

@@ -1,74 +0,0 @@
// 多组件库的国际化和本地项目国际化兼容
import { App, WritableComputedRef } from "vue";
import type { StorageConfigs } from "/#/index";
import { storageLocal } from "@pureadmin/utils";
import { type I18n, createI18n } from "vue-i18n";
// element-plus国际化
import enLocale from "element-plus/lib/locale/lang/en";
import zhLocale from "element-plus/lib/locale/lang/zh-cn";
function siphonI18n(prefix = "zh-CN") {
return Object.fromEntries(
Object.entries(
import.meta.glob("../../locales/*.y(a)?ml", { eager: true })
).map(([key, value]: any) => {
const matched = key.match(/([A-Za-z0-9-_]+)\./i)[1];
return [matched, value.default];
})
)[prefix];
}
export const localesConfigs = {
zh: {
...siphonI18n("zh-CN"),
...zhLocale
},
en: {
...siphonI18n("en"),
...enLocale
}
};
/**
* 国际化转换工具函数自动读取根目录locales文件夹下文件进行国际化匹配
* @param message message
* @returns 转化后的message
*/
export function transformI18n(message: any = "") {
if (!message) {
return "";
}
// 处理存储动态路由的title,格式 {zh:"",en:""}
if (typeof message === "object") {
const locale: string | WritableComputedRef<string> | any =
i18n.global.locale;
return message[locale?.value];
}
const key = message.match(/(\S*)\./)?.[1];
if (key && Object.keys(siphonI18n("zh-CN")).includes(key)) {
return i18n.global.t.call(i18n.global.locale, message);
} else if (!key && Object.keys(siphonI18n("zh-CN")).includes(message)) {
// 兼容非嵌套形式的国际化写法
return i18n.global.t.call(i18n.global.locale, message);
} else {
return message;
}
}
/** 此函数只是配合i18n Ally插件来进行国际化智能提示并无实际意义只对提示起作用如果不需要国际化可删除 */
export const $t = (key: string) => key;
export const i18n: I18n = createI18n({
legacy: false,
locale:
storageLocal.getItem<StorageConfigs>("responsive-locale")?.locale ?? "zh",
fallbackLocale: "en",
messages: localesConfigs
});
export function useI18n(app: App) {
app.use(i18n);
}

View File

@@ -1,11 +1,7 @@
import "xe-utils"; import "xe-utils";
import "./index.scss"; import "./index.scss";
import XEUtils from "xe-utils"; import { App } from "vue";
import { App, unref } from "vue";
import { i18n } from "/@/plugins/i18n";
import "font-awesome/css/font-awesome.min.css"; import "font-awesome/css/font-awesome.min.css";
import zh from "vxe-table/lib/locale/lang/zh-CN";
import en from "vxe-table/lib/locale/lang/en-US";
import { import {
// 核心 // 核心
@@ -60,18 +56,6 @@ VXETable.setup({
}, },
input: { input: {
clearable: true clearable: true
},
i18n: (key, args) => {
return unref(i18n.global.locale) === "zh"
? XEUtils.toFormatString(XEUtils.get(zh, key), args)
: XEUtils.toFormatString(XEUtils.get(en, key), args);
},
translate(key) {
const NAMESPACED = ["el.", "buttons."];
if (key && NAMESPACED.findIndex(v => key.includes(v)) !== -1) {
return i18n.global.t.call(i18n.global.locale, key);
}
return key;
} }
}); });

View File

@@ -1,11 +1,10 @@
import { getConfig } from "/@/config"; import { getConfig } from "@/config";
import { toRouteType } from "./types"; import { toRouteType } from "./types";
import NProgress from "/@/utils/progress"; import NProgress from "@/utils/progress";
import { findIndex } from "lodash-unified"; import { findIndex } from "lodash-unified";
import { transformI18n } from "/@/plugins/i18n"; import { sessionKey, type DataInfo } from "@/utils/auth";
import { sessionKey, type DataInfo } from "/@/utils/auth"; import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
import { useMultiTagsStoreHook } from "/@/store/modules/multiTags"; import { usePermissionStoreHook } from "@/store/modules/permission";
import { usePermissionStoreHook } from "/@/store/modules/permission";
import { import {
Router, Router,
createRouter, createRouter,
@@ -104,11 +103,14 @@ router.beforeEach((to: toRouteType, _from, next) => {
to.matched.some(item => { to.matched.some(item => {
if (!item.meta.title) return ""; if (!item.meta.title) return "";
const Title = getConfig().Title; const Title = getConfig().Title;
if (Title) if (Title) document.title = `${item.meta.title} | ${Title}`;
document.title = `${transformI18n(item.meta.title)} | ${Title}`; else document.title = item.meta.title as string;
else document.title = transformI18n(item.meta.title);
}); });
} }
/** 如果已经登录并存在登录信息后不能跳转到路由白名单,而是继续保持在当前页面 */
function toCorrectRoute() {
whiteList.includes(to.fullPath) ? next(_from.fullPath) : next();
}
if (userInfo) { if (userInfo) {
// 无权限跳转403页面 // 无权限跳转403页面
if (to.meta?.roles && !isOneOfArray(to.meta?.roles, userInfo?.roles)) { if (to.meta?.roles && !isOneOfArray(to.meta?.roles, userInfo?.roles)) {
@@ -120,7 +122,7 @@ router.beforeEach((to: toRouteType, _from, next) => {
openLink(to?.name as string); openLink(to?.name as string);
NProgress.done(); NProgress.done();
} else { } else {
next(); toCorrectRoute();
} }
} else { } else {
// 刷新 // 刷新
@@ -150,7 +152,7 @@ router.beforeEach((to: toRouteType, _from, next) => {
} }
router.push(to.fullPath); router.push(to.fullPath);
}); });
next(); toCorrectRoute();
} }
} else { } else {
if (to.path !== "/login") { if (to.path !== "/login") {

View File

@@ -1,4 +1,3 @@
import { $t } from "/@/plugins/i18n";
import type { RouteConfigsTable } from "/#/index"; import type { RouteConfigsTable } from "/#/index";
const errorRouter: RouteConfigsTable = { const errorRouter: RouteConfigsTable = {
@@ -6,32 +5,32 @@ const errorRouter: RouteConfigsTable = {
redirect: "/error/403", redirect: "/error/403",
meta: { meta: {
icon: "information-line", icon: "information-line",
title: $t("menus.hsabnormal"), title: "异常页面",
rank: 9 rank: 9
}, },
children: [ children: [
{ {
path: "/error/403", path: "/error/403",
name: "403", name: "403",
component: () => import("/@/views/error/403.vue"), component: () => import("@/views/error/403.vue"),
meta: { meta: {
title: $t("menus.hsfourZeroOne") title: "403"
} }
}, },
{ {
path: "/error/404", path: "/error/404",
name: "404", name: "404",
component: () => import("/@/views/error/404.vue"), component: () => import("@/views/error/404.vue"),
meta: { meta: {
title: $t("menus.hsfourZeroFour") title: "404"
} }
}, },
{ {
path: "/error/500", path: "/error/500",
name: "500", name: "500",
component: () => import("/@/views/error/500.vue"), component: () => import("@/views/error/500.vue"),
meta: { meta: {
title: $t("menus.hsFive") title: "500"
} }
} }
] ]

View File

@@ -1,6 +1,5 @@
import { $t } from "/@/plugins/i18n";
import type { RouteConfigsTable } from "/#/index"; import type { RouteConfigsTable } from "/#/index";
const Layout = () => import("/@/layout/index.vue"); const Layout = () => import("@/layout/index.vue");
const homeRouter: RouteConfigsTable = { const homeRouter: RouteConfigsTable = {
path: "/", path: "/",
@@ -9,16 +8,16 @@ const homeRouter: RouteConfigsTable = {
redirect: "/welcome", redirect: "/welcome",
meta: { meta: {
icon: "home-filled", icon: "home-filled",
title: $t("menus.hshome"), title: "首页",
rank: 0 rank: 0
}, },
children: [ children: [
{ {
path: "/welcome", path: "/welcome",
name: "Welcome", name: "Welcome",
component: () => import("/@/views/welcome/index.vue"), component: () => import("@/views/welcome/index.vue"),
meta: { meta: {
title: $t("menus.hshome") title: "首页"
} }
} }
] ]

View File

@@ -1,14 +1,13 @@
import { $t } from "/@/plugins/i18n";
import type { RouteConfigsTable } from "/#/index"; import type { RouteConfigsTable } from "/#/index";
const Layout = () => import("/@/layout/index.vue"); const Layout = () => import("@/layout/index.vue");
const remainingRouter: Array<RouteConfigsTable> = [ const remainingRouter: Array<RouteConfigsTable> = [
{ {
path: "/login", path: "/login",
name: "Login", name: "Login",
component: () => import("/@/views/login/index.vue"), component: () => import("@/views/login/index.vue"),
meta: { meta: {
title: $t("menus.hslogin"), title: "登录",
showLink: false, showLink: false,
rank: 101 rank: 101
} }
@@ -18,7 +17,7 @@ const remainingRouter: Array<RouteConfigsTable> = [
component: Layout, component: Layout,
meta: { meta: {
icon: "home-filled", icon: "home-filled",
title: $t("menus.hshome"), title: "首页",
showLink: false, showLink: false,
rank: 104 rank: 104
}, },
@@ -26,7 +25,7 @@ const remainingRouter: Array<RouteConfigsTable> = [
{ {
path: "/redirect/:path(.*)", path: "/redirect/:path(.*)",
name: "Redirect", name: "Redirect",
component: () => import("/@/layout/redirect.vue") component: () => import("@/layout/redirect.vue")
} }
] ]
} }

View File

@@ -10,7 +10,7 @@ import { router } from "./index";
import { isProxy, toRaw } from "vue"; import { isProxy, toRaw } from "vue";
import { loadEnv } from "../../build"; import { loadEnv } from "../../build";
import { useTimeoutFn } from "@vueuse/core"; import { useTimeoutFn } from "@vueuse/core";
import { RouteConfigs } from "/@/layout/types"; import { RouteConfigs } from "@/layout/types";
import { import {
isString, isString,
storageSession, storageSession,
@@ -18,14 +18,14 @@ import {
isIncludeAllChildren isIncludeAllChildren
} from "@pureadmin/utils"; } from "@pureadmin/utils";
import { cloneDeep, intersection } from "lodash-unified"; import { cloneDeep, intersection } from "lodash-unified";
import { sessionKey, type DataInfo } from "/@/utils/auth"; import { sessionKey, type DataInfo } from "@/utils/auth";
import { usePermissionStoreHook } from "/@/store/modules/permission"; import { usePermissionStoreHook } from "@/store/modules/permission";
const IFrame = () => import("/@/layout/frameView.vue"); const IFrame = () => import("@/layout/frameView.vue");
// https://cn.vitejs.dev/guide/features.html#glob-import // https://cn.vitejs.dev/guide/features.html#glob-import
const modulesRoutes = import.meta.glob("/src/views/**/*.{vue,tsx}"); const modulesRoutes = import.meta.glob("/src/views/**/*.{vue,tsx}");
// 动态路由 // 动态路由
import { getAsyncRoutes } from "/@/api/routes"; import { getAsyncRoutes } from "@/api/routes";
/** 按照路由中meta下的rank等级升序来排序路由 */ /** 按照路由中meta下的rank等级升序来排序路由 */
function ascending(arr: any[]) { function ascending(arr: any[]) {

View File

@@ -1,7 +1,7 @@
import { store } from "/@/store"; import { store } from "@/store";
import { appType } from "./types"; import { appType } from "./types";
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { getConfig } from "/@/config"; import { getConfig } from "@/config";
import type { StorageConfigs } from "/#/index"; import type { StorageConfigs } from "/#/index";
import { deviceDetection, storageLocal } from "@pureadmin/utils"; import { deviceDetection, storageLocal } from "@pureadmin/utils";

View File

@@ -1,6 +1,6 @@
import { store } from "/@/store"; import { store } from "@/store";
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { getConfig } from "/@/config"; import { getConfig } from "@/config";
import type { StorageConfigs } from "/#/index"; import type { StorageConfigs } from "/#/index";
import { storageLocal } from "@pureadmin/utils"; import { storageLocal } from "@pureadmin/utils";

View File

@@ -1,8 +1,8 @@
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { store } from "/@/store"; import { store } from "@/store";
import { isEqual } from "lodash-unified"; import { isEqual } from "lodash-unified";
import type { StorageConfigs } from "/#/index"; import type { StorageConfigs } from "/#/index";
import { routerArrays } from "/@/layout/types"; import { routerArrays } from "@/layout/types";
import { multiType, positionType } from "./types"; import { multiType, positionType } from "./types";
import { isUrl, storageLocal } from "@pureadmin/utils"; import { isUrl, storageLocal } from "@pureadmin/utils";

View File

@@ -1,8 +1,8 @@
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { store } from "/@/store"; import { store } from "@/store";
import { cacheType } from "./types"; import { cacheType } from "./types";
import { constantMenus } from "/@/router"; import { constantMenus } from "@/router";
import { ascending, filterTree, filterNoPermissionTree } from "/@/router/utils"; import { ascending, filterTree, filterNoPermissionTree } from "@/router/utils";
export const usePermissionStore = defineStore({ export const usePermissionStore = defineStore({
id: "pure-permission", id: "pure-permission",

View File

@@ -1,7 +1,7 @@
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { store } from "/@/store"; import { store } from "@/store";
import { setType } from "./types"; import { setType } from "./types";
import { getConfig } from "/@/config"; import { getConfig } from "@/config";
export const useSettingStore = defineStore({ export const useSettingStore = defineStore({
id: "pure-setting", id: "pure-setting",

View File

@@ -1,22 +1,18 @@
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { store } from "/@/store"; import { store } from "@/store";
import { userType } from "./types"; import { userType } from "./types";
import { routerArrays } from "/@/layout/types"; import { routerArrays } from "@/layout/types";
import { router, resetRouter } from "/@/router"; import { router, resetRouter } from "@/router";
import { storageSession } from "@pureadmin/utils"; import { storageSession } from "@pureadmin/utils";
import { getLogin, refreshTokenApi } from "/@/api/user"; import { getLogin, refreshTokenApi } from "@/api/user";
import { UserResult, RefreshTokenResult } from "/@/api/user"; import { UserResult, RefreshTokenResult } from "@/api/user";
import { useMultiTagsStoreHook } from "/@/store/modules/multiTags"; import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
import { import { type DataInfo, setToken, removeToken, sessionKey } from "@/utils/auth";
type DataInfo,
setToken,
removeToken,
sessionKey
} from "/@/utils/auth";
export const useUserStore = defineStore({ export const useUserStore = defineStore({
id: "pure-user", id: "pure-user",
state: (): userType => ({ state: (): userType => ({
// 用户名
username: username:
storageSession.getItem<DataInfo<number>>(sessionKey)?.username ?? "", storageSession.getItem<DataInfo<number>>(sessionKey)?.username ?? "",
// 页面级别权限 // 页面级别权限

View File

@@ -68,10 +68,6 @@
} }
} }
.el-popper.is-light {
border: none !important;
}
.sidebar-container { .sidebar-container {
/* 展开动画 */ /* 展开动画 */
transition: width var(--pure-transition-duration); transition: width var(--pure-transition-duration);
@@ -233,11 +229,7 @@
.search-container, .search-container,
/* 告警 */ /* 告警 */
.dropdown-badge, .dropdown-badge,
/* 全屏 */ /* 用户名 */
.screen-full,
/* 国际化 */
.globalization,
/* 登录名 */
.el-dropdown-link, .el-dropdown-link,
/* 设置 */ /* 设置 */
.set-icon { .set-icon {
@@ -251,15 +243,6 @@
color: $subMenuActiveText; color: $subMenuActiveText;
} }
.globalization {
width: 40px;
height: 48px;
padding: 11px;
outline: none;
cursor: pointer;
color: $subMenuActiveText;
}
.el-dropdown-link { .el-dropdown-link {
height: 48px; height: 48px;
padding: 10px; padding: 10px;
@@ -587,11 +570,7 @@ body[layout="vertical"] {
.search-container, .search-container,
/* 告警 */ /* 告警 */
.dropdown-badge, .dropdown-badge,
/* 全屏 */ /* 用户名 */
.screen-full,
/* 国际化 */
.globalization,
/* 登录名 */
.el-dropdown-link, .el-dropdown-link,
/* 设置 */ /* 设置 */
.set-icon { .set-icon {

View File

@@ -1,5 +0,0 @@
### 注意
- [文档](https://pure-admin-utils-docs.vercel.app/)
- [npm](https://www.npmjs.com/package/@pureadmin/utils)
- vue-pure-admin 从 3.3.0 版本之后(不包括 3.3.0 版本),大部分工具和 hooks 都集成到了[@pureadmin/utils](https://pure-admin-utils-docs.vercel.app/)

View File

@@ -1,6 +1,6 @@
import Cookies from "js-cookie"; import Cookies from "js-cookie";
import { storageSession } from "@pureadmin/utils"; import { storageSession } from "@pureadmin/utils";
import { useUserStoreHook } from "/@/store/modules/user"; import { useUserStoreHook } from "@/store/modules/user";
export interface DataInfo<T> { export interface DataInfo<T> {
/** token */ /** token */
@@ -70,3 +70,8 @@ export function removeToken() {
Cookies.remove(TokenKey); Cookies.remove(TokenKey);
sessionStorage.removeItem(sessionKey); sessionStorage.removeItem(sessionKey);
} }
/** 格式化tokenjwt格式 */
export const formatToken = (token: string): string => {
return "Bearer " + token;
};

View File

@@ -1,25 +0,0 @@
## 用法
### Get 请求
```
import { http } from "/@/utils/http";
// params传参
http.request('get', '/xxx', { params: param });
// url拼接传参
http.request('get', '/xxx?message=' + msg);
```
### Post 请求
```
import { http } from "/@/utils/http";
// params传参
http.request('post', '/xxx', { params: param });
// data传参
http.request('post', '/xxx', { data: param });
```

View File

@@ -11,21 +11,12 @@ import {
} from "./types.d"; } from "./types.d";
import { stringify } from "qs"; import { stringify } from "qs";
import NProgress from "../progress"; import NProgress from "../progress";
// import { loadEnv } from "@build/index"; import { getToken, formatToken } from "@/utils/auth";
import { getToken } from "/@/utils/auth"; import { useUserStoreHook } from "@/store/modules/user";
import { useUserStoreHook } from "/@/store/modules/user";
// 加载环境变量 VITE_PROXY_DOMAIN开发环境 VITE_PROXY_DOMAIN_REAL打包后的线上环境
// const { VITE_PROXY_DOMAIN, VITE_PROXY_DOMAIN_REAL } = loadEnv();
// 相关配置请参考www.axios-js.com/zh-cn/docs/#axios-request-config-1 // 相关配置请参考www.axios-js.com/zh-cn/docs/#axios-request-config-1
const defaultConfig: AxiosRequestConfig = { const defaultConfig: AxiosRequestConfig = {
// baseURL: // 请求超时时间
// process.env.NODE_ENV === "production"
// ? VITE_PROXY_DOMAIN_REAL
// : VITE_PROXY_DOMAIN,
// 当前使用mock模拟请求将baseURL制空如果你的环境用到了http请求请删除下面的baseURL启用上面的baseURL并将第14行、19行代码注释取消
baseURL: "",
timeout: 10000, timeout: 10000,
headers: { headers: {
Accept: "application/json, text/plain, */*", Accept: "application/json, text/plain, */*",
@@ -43,27 +34,43 @@ class PureHttp {
this.httpInterceptorsRequest(); this.httpInterceptorsRequest();
this.httpInterceptorsResponse(); this.httpInterceptorsResponse();
} }
/** token过期后暂存待执行的请求 */
private static requests = [];
/** 防止重复刷新token */
private static isRefreshing = false;
/** 初始化配置对象 */ /** 初始化配置对象 */
private static initConfig: PureHttpRequestConfig = {}; private static initConfig: PureHttpRequestConfig = {};
/** 保存当前Axios实例对象 */ /** 保存当前Axios实例对象 */
private static axiosInstance: AxiosInstance = Axios.create(defaultConfig); private static axiosInstance: AxiosInstance = Axios.create(defaultConfig);
/** 重连原始请求 */
private static retryOriginalRequest(config: PureHttpRequestConfig) {
return new Promise(resolve => {
PureHttp.requests.push((token: string) => {
config.headers["Authorization"] = formatToken(token);
resolve(config);
});
});
}
/** 请求拦截 */ /** 请求拦截 */
private httpInterceptorsRequest(): void { private httpInterceptorsRequest(): void {
PureHttp.axiosInstance.interceptors.request.use( PureHttp.axiosInstance.interceptors.request.use(
async (config: PureHttpRequestConfig) => { async (config: PureHttpRequestConfig) => {
const $config = config;
// 开启进度条动画 // 开启进度条动画
NProgress.start(); NProgress.start();
// 优先判断post/get等方法是否传入回掉否则执行初始化设置等回掉 // 优先判断post/get等方法是否传入回掉否则执行初始化设置等回掉
if (typeof config.beforeRequestCallback === "function") { if (typeof config.beforeRequestCallback === "function") {
config.beforeRequestCallback($config); config.beforeRequestCallback(config);
return $config; return config;
} }
if (PureHttp.initConfig.beforeRequestCallback) { if (PureHttp.initConfig.beforeRequestCallback) {
PureHttp.initConfig.beforeRequestCallback($config); PureHttp.initConfig.beforeRequestCallback(config);
return $config; return config;
} }
/** 请求白名单放置一些不需要token的接口通过设置请求白名单防止token过期后再请求造成的死循环问题 */ /** 请求白名单放置一些不需要token的接口通过设置请求白名单防止token过期后再请求造成的死循环问题 */
const whiteList = ["/refreshToken", "/login"]; const whiteList = ["/refreshToken", "/login"];
@@ -75,21 +82,30 @@ class PureHttp {
const now = new Date().getTime(); const now = new Date().getTime();
const expired = parseInt(data.expires) - now <= 0; const expired = parseInt(data.expires) - now <= 0;
if (expired) { if (expired) {
// token过期刷新 if (!PureHttp.isRefreshing) {
useUserStoreHook() PureHttp.isRefreshing = true;
.handRefreshToken({ refreshToken: data.refreshToken }) // token过期刷新
.then(res => { useUserStoreHook()
config.headers["Authorization"] = .handRefreshToken({ refreshToken: data.refreshToken })
"Bearer " + res.data.accessToken; .then(res => {
resolve($config); 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 { } else {
config.headers["Authorization"] = config.headers["Authorization"] = formatToken(
"Bearer " + data.accessToken; data.accessToken
resolve($config); );
resolve(config);
} }
} else { } else {
resolve($config); resolve(config);
} }
}); });
}, },

View File

@@ -1,17 +1,13 @@
// 响应式storage // 响应式storage
import { App } from "vue"; import { App } from "vue";
import Storage from "responsive-storage"; import Storage from "responsive-storage";
import { routerArrays } from "/@/layout/types"; import { routerArrays } from "@/layout/types";
const nameSpace = "responsive-"; const nameSpace = "responsive-";
export const injectResponsiveStorage = (app: App, config: ServerConfigs) => { export const injectResponsiveStorage = (app: App, config: ServerConfigs) => {
const configObj = Object.assign( const configObj = Object.assign(
{ {
// 国际化 默认中文zh
locale: Storage.getData("locale", nameSpace) ?? {
locale: config.Locale ?? "zh"
},
// layout模式以及主题 // layout模式以及主题
layout: Storage.getData("layout", nameSpace) ?? { layout: Storage.getData("layout", nameSpace) ?? {
layout: config.Layout ?? "vertical", layout: config.Layout ?? "vertical",

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import noAccess from "/@/assets/status/403.svg?component"; import noAccess from "@/assets/status/403.svg?component";
defineOptions({ defineOptions({
name: "403" name: "403"

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import noExist from "/@/assets/status/404.svg?component"; import noExist from "@/assets/status/404.svg?component";
defineOptions({ defineOptions({
name: "404" name: "404"

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import noServer from "/@/assets/status/500.svg?component"; import noServer from "@/assets/status/500.svg?component";
defineOptions({ defineOptions({
name: "500" name: "500"

View File

@@ -1,24 +1,20 @@
<script setup lang="ts"> <script setup lang="ts">
import { useI18n } from "vue-i18n";
import Motion from "./utils/motion"; import Motion from "./utils/motion";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { loginRules } from "./utils/rule"; import { loginRules } from "./utils/rule";
import { initRouter } from "/@/router/utils"; import { initRouter } from "@/router/utils";
import { useNav } from "/@/layout/hooks/useNav"; import { useNav } from "@/layout/hooks/useNav";
import { message } from "@pureadmin/components"; import { message } from "@pureadmin/components";
import type { FormInstance } from "element-plus"; import type { FormInstance } from "element-plus";
import { $t, transformI18n } from "/@/plugins/i18n"; import { useLayout } from "@/layout/hooks/useLayout";
import { useLayout } from "/@/layout/hooks/useLayout"; import { useUserStoreHook } from "@/store/modules/user";
import { useUserStoreHook } from "/@/store/modules/user";
import { bg, avatar, illustration } from "./utils/static"; import { bg, avatar, illustration } from "./utils/static";
import { useRenderIcon } from "/@/components/ReIcon/src/hooks"; import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import { ref, reactive, toRaw, onMounted, onBeforeUnmount } from "vue"; import { ref, reactive, toRaw, onMounted, onBeforeUnmount } from "vue";
import { useTranslationLang } from "/@/layout/hooks/useTranslationLang"; import { useDataThemeChange } from "@/layout/hooks/useDataThemeChange";
import { useDataThemeChange } from "/@/layout/hooks/useDataThemeChange";
import dayIcon from "/@/assets/svg/day.svg?component"; import dayIcon from "@/assets/svg/day.svg?component";
import darkIcon from "/@/assets/svg/dark.svg?component"; import darkIcon from "@/assets/svg/dark.svg?component";
import globalization from "/@/assets/svg/globalization.svg?component";
defineOptions({ defineOptions({
name: "Login" name: "Login"
@@ -30,11 +26,9 @@ const ruleFormRef = ref<FormInstance>();
const { initStorage } = useLayout(); const { initStorage } = useLayout();
initStorage(); initStorage();
const { t } = useI18n();
const { dataTheme, dataThemeChange } = useDataThemeChange(); const { dataTheme, dataThemeChange } = useDataThemeChange();
dataThemeChange(); dataThemeChange();
const { title, getDropdownItemStyle, getDropdownItemClass } = useNav(); const { title } = useNav();
const { locale, translationCh, translationEn } = useTranslationLang();
const ruleForm = reactive({ const ruleForm = reactive({
username: "admin", username: "admin",
@@ -47,7 +41,7 @@ const onLogin = async (formEl: FormInstance | undefined) => {
await formEl.validate((valid, fields) => { await formEl.validate((valid, fields) => {
if (valid) { if (valid) {
useUserStoreHook() useUserStoreHook()
.loginByUsername({ username: ruleForm.username }) .loginByUsername({ username: ruleForm.username, password: "admin123" })
.then(res => { .then(res => {
if (res.success) { if (res.success) {
// 获取后端路由 // 获取后端路由
@@ -92,38 +86,6 @@ onBeforeUnmount(() => {
:inactive-icon="darkIcon" :inactive-icon="darkIcon"
@change="dataThemeChange" @change="dataThemeChange"
/> />
<!-- 国际化 -->
<el-dropdown trigger="click">
<globalization
class="hover:text-primary hover:!bg-[transparent] w-[20px] h-[20px] ml-1.5 cursor-pointer outline-none duration-300"
/>
<template #dropdown>
<el-dropdown-menu class="translation">
<el-dropdown-item
:style="getDropdownItemStyle(locale, 'zh')"
:class="['dark:!text-white', getDropdownItemClass(locale, 'zh')]"
@click="translationCh"
>
<IconifyIconOffline
class="check-zh"
v-show="locale === 'zh'"
icon="check"
/>
简体中文
</el-dropdown-item>
<el-dropdown-item
:style="getDropdownItemStyle(locale, 'en')"
:class="['dark:!text-white', getDropdownItemClass(locale, 'en')]"
@click="translationEn"
>
<span class="check-en" v-show="locale === 'en'">
<IconifyIconOffline icon="check" />
</span>
English
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div> </div>
<div class="login-container"> <div class="login-container">
<div class="img"> <div class="img">
@@ -147,7 +109,7 @@ onBeforeUnmount(() => {
:rules="[ :rules="[
{ {
required: true, required: true,
message: transformI18n($t('login.usernameReg')), message: '请输入账号',
trigger: 'blur' trigger: 'blur'
} }
]" ]"
@@ -156,7 +118,7 @@ onBeforeUnmount(() => {
<el-input <el-input
clearable clearable
v-model="ruleForm.username" v-model="ruleForm.username"
:placeholder="t('login.username')" placeholder="账号"
:prefix-icon="useRenderIcon('user')" :prefix-icon="useRenderIcon('user')"
/> />
</el-form-item> </el-form-item>
@@ -168,7 +130,7 @@ onBeforeUnmount(() => {
clearable clearable
show-password show-password
v-model="ruleForm.password" v-model="ruleForm.password"
:placeholder="t('login.password')" placeholder="密码"
:prefix-icon="useRenderIcon('lock')" :prefix-icon="useRenderIcon('lock')"
/> />
</el-form-item> </el-form-item>
@@ -182,7 +144,7 @@ onBeforeUnmount(() => {
:loading="loading" :loading="loading"
@click="onLogin(ruleFormRef)" @click="onLogin(ruleFormRef)"
> >
{{ t("login.login") }} 登录
</el-button> </el-button>
</Motion> </Motion>
</el-form> </el-form>
@@ -193,27 +155,11 @@ onBeforeUnmount(() => {
</template> </template>
<style scoped> <style scoped>
@import url("/@/style/login.css"); @import url("@/style/login.css");
</style> </style>
<style lang="scss" scoped> <style lang="scss" scoped>
:deep(.el-input-group__append, .el-input-group__prepend) { :deep(.el-input-group__append, .el-input-group__prepend) {
padding: 0; padding: 0;
} }
.translation {
::v-deep(.el-dropdown-menu__item) {
padding: 5px 40px;
}
.check-zh {
position: absolute;
left: 20px;
}
.check-en {
position: absolute;
left: 20px;
}
}
</style> </style>

View File

@@ -1,6 +1,5 @@
import { reactive } from "vue"; import { reactive } from "vue";
import type { FormRules } from "element-plus"; import type { FormRules } from "element-plus";
import { $t, transformI18n } from "/@/plugins/i18n";
/** 密码正则密码格式应为8-18位数字、字母、符号的任意两种组合 */ /** 密码正则密码格式应为8-18位数字、字母、符号的任意两种组合 */
export const REGEXP_PWD = export const REGEXP_PWD =
@@ -12,9 +11,11 @@ const loginRules = reactive(<FormRules>{
{ {
validator: (rule, value, callback) => { validator: (rule, value, callback) => {
if (value === "") { if (value === "") {
callback(new Error(transformI18n($t("login.passwordReg")))); callback(new Error("请输入密码"));
} else if (!REGEXP_PWD.test(value)) { } else if (!REGEXP_PWD.test(value)) {
callback(new Error(transformI18n($t("login.passwordRuleReg")))); callback(
new Error("密码格式应为8-18位数字、字母、符号的任意两种组合")
);
} else { } else {
callback(); callback();
} }

View File

@@ -1,5 +1,5 @@
import bg from "/@/assets/login/bg.png"; import bg from "@/assets/login/bg.png";
import avatar from "/@/assets/login/avatar.svg?component"; import avatar from "@/assets/login/avatar.svg?component";
import illustration from "/@/assets/login/illustration.svg?component"; import illustration from "@/assets/login/illustration.svg?component";
export { bg, avatar, illustration }; export { bg, avatar, illustration };

View File

@@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { type CSSProperties, computed } from "vue"; import { type CSSProperties, computed } from "vue";
import { hasAuth, getAuths } from "/@/router/utils"; import { hasAuth, getAuths } from "@/router/utils";
defineOptions({ defineOptions({
name: "PermissionButton" name: "PermissionButton"

View File

@@ -1,8 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { initRouter } from "/@/router/utils"; import { initRouter } from "@/router/utils";
import { type CSSProperties, ref, computed } from "vue"; import { type CSSProperties, ref, computed } from "vue";
import { useUserStoreHook } from "/@/store/modules/user"; import { useUserStoreHook } from "@/store/modules/user";
import { usePermissionStoreHook } from "/@/store/modules/permission"; import { usePermissionStoreHook } from "@/store/modules/permission";
defineOptions({ defineOptions({
name: "PermissionPage" name: "PermissionPage"
@@ -30,7 +30,7 @@ const options = [
function onChange() { function onChange() {
useUserStoreHook() useUserStoreHook()
.loginByUsername({ username: username.value }) .loginByUsername({ username: username.value, password: "admin123" })
.then(res => { .then(res => {
if (res.success) { if (res.success) {
usePermissionStoreHook().clearAllCachePage(); usePermissionStoreHook().clearAllCachePage();

View File

@@ -5,5 +5,5 @@ defineOptions({
</script> </script>
<template> <template>
<h1>Pure-Admin-Thin</h1> <h1>Pure-Admin-Thin非国际化版本</h1>
</template> </template>

View File

@@ -20,7 +20,7 @@
"lib": ["dom", "esnext"], "lib": ["dom", "esnext"],
"incremental": true, "incremental": true,
"paths": { "paths": {
"/@/*": ["src/*"], "@/*": ["src/*"],
"@build/*": ["build/*"], "@build/*": ["build/*"],
"/#/*": ["types/*"] "/#/*": ["types/*"]
}, },

3
types/global.d.ts vendored
View File

@@ -86,8 +86,6 @@ declare global {
declare interface ViteEnv { declare interface ViteEnv {
VITE_PORT: number; VITE_PORT: number;
VITE_PUBLIC_PATH: string; VITE_PUBLIC_PATH: string;
VITE_PROXY_DOMAIN: string;
VITE_PROXY_DOMAIN_REAL: string;
VITE_ROUTER_HISTORY: string; VITE_ROUTER_HISTORY: string;
VITE_LEGACY: boolean; VITE_LEGACY: boolean;
VITE_CDN: boolean; VITE_CDN: boolean;
@@ -101,7 +99,6 @@ declare global {
HiddenSideBar?: boolean; HiddenSideBar?: boolean;
MultiTagsCache?: boolean; MultiTagsCache?: boolean;
KeepAlive?: boolean; KeepAlive?: boolean;
Locale?: string;
Layout?: string; Layout?: string;
Theme?: string; Theme?: string;
DarkMode?: boolean; DarkMode?: boolean;

View File

@@ -1,3 +1,4 @@
import { type FunctionalComponent } from "vue";
import { type RouteComponent } from "vue-router"; import { type RouteComponent } from "vue-router";
export interface StorageConfigs { export interface StorageConfigs {
@@ -7,7 +8,6 @@ export interface StorageConfigs {
hiddenSideBar?: boolean; hiddenSideBar?: boolean;
multiTagsCache?: boolean; multiTagsCache?: boolean;
keepAlive?: boolean; keepAlive?: boolean;
locale?: string;
layout?: string; layout?: string;
theme?: string; theme?: string;
darkMode?: boolean; darkMode?: boolean;
@@ -30,9 +30,6 @@ export interface StorageConfigs {
} }
export interface ResponsiveStorage { export interface ResponsiveStorage {
locale: {
locale?: string;
};
layout: { layout: {
layout?: string; layout?: string;
theme?: string; theme?: string;
@@ -64,7 +61,7 @@ export interface RouteChildrenConfigsTable {
/** 菜单名称(兼容国际化、非国际化,如何用国际化的写法就必须在根目录的`locales`文件夹下对应添加) `必填` */ /** 菜单名称(兼容国际化、非国际化,如何用国际化的写法就必须在根目录的`locales`文件夹下对应添加) `必填` */
title: string; title: string;
/** 菜单图标 `可选` */ /** 菜单图标 `可选` */
icon?: string; icon?: string | FunctionalComponent;
/** 菜单名称右侧的额外图标,支持`fontawesome`、`iconfont`、`element-plus-icon` `可选` */ /** 菜单名称右侧的额外图标,支持`fontawesome`、`iconfont`、`element-plus-icon` `可选` */
extraIcon?: { extraIcon?: {
svg?: boolean; svg?: boolean;
@@ -122,7 +119,7 @@ export interface RouteConfigsTable {
/** 菜单名称(兼容国际化、非国际化,如何用国际化的写法就必须在根目录的`locales`文件夹下对应添加)`必填` */ /** 菜单名称(兼容国际化、非国际化,如何用国际化的写法就必须在根目录的`locales`文件夹下对应添加)`必填` */
title: string; title: string;
/** 菜单图标 `可选` */ /** 菜单图标 `可选` */
icon?: string; icon?: string | FunctionalComponent;
/** 是否在菜单中显示(默认`true``可选` */ /** 是否在菜单中显示(默认`true``可选` */
showLink?: boolean; showLink?: boolean;
/** 菜单升序排序,值越高排的越后(只针对顶级路由)`可选` */ /** 菜单升序排序,值越高排的越后(只针对顶级路由)`可选` */

View File

@@ -1,7 +1,7 @@
import dayjs from "dayjs"; import dayjs from "dayjs";
import { resolve } from "path"; import { resolve } from "path";
import pkg from "./package.json"; import pkg from "./package.json";
import { warpperEnv, regExps } from "./build"; import { warpperEnv } from "./build";
import { getPluginsList } from "./build/plugins"; import { getPluginsList } from "./build/plugins";
import { UserConfigExport, ConfigEnv, loadEnv } from "vite"; import { UserConfigExport, ConfigEnv, loadEnv } from "vite";
@@ -15,7 +15,7 @@ const pathResolve = (dir: string): string => {
/** 设置别名 */ /** 设置别名 */
const alias: Record<string, string> = { const alias: Record<string, string> = {
"/@": pathResolve("src"), "@": pathResolve("src"),
"@build": pathResolve("build") "@build": pathResolve("build")
}; };
@@ -31,9 +31,7 @@ export default ({ command, mode }: ConfigEnv): UserConfigExport => {
VITE_PORT, VITE_PORT,
VITE_LEGACY, VITE_LEGACY,
VITE_COMPRESSION, VITE_COMPRESSION,
VITE_PUBLIC_PATH, VITE_PUBLIC_PATH
VITE_PROXY_DOMAIN,
VITE_PROXY_DOMAIN_REAL
} = warpperEnv(loadEnv(mode, root)); } = warpperEnv(loadEnv(mode, root));
return { return {
base: VITE_PUBLIC_PATH, base: VITE_PUBLIC_PATH,
@@ -48,28 +46,29 @@ export default ({ command, mode }: ConfigEnv): UserConfigExport => {
// 端口号 // 端口号
port: VITE_PORT, port: VITE_PORT,
host: "0.0.0.0", host: "0.0.0.0",
// 本地跨域代理 // 本地跨域代理 https://cn.vitejs.dev/config/server-options.html#server-proxy
proxy: proxy: {}
VITE_PROXY_DOMAIN_REAL.length > 0
? {
[VITE_PROXY_DOMAIN]: {
target: VITE_PROXY_DOMAIN_REAL,
// ws: true,
changeOrigin: true,
rewrite: (path: string) => regExps(path, VITE_PROXY_DOMAIN)
}
}
: null
}, },
plugins: getPluginsList(command, VITE_LEGACY, VITE_CDN, VITE_COMPRESSION), plugins: getPluginsList(command, VITE_LEGACY, VITE_CDN, VITE_COMPRESSION),
optimizeDeps: { optimizeDeps: {
include: ["pinia", "vue-i18n", "lodash-es", "@vueuse/core", "dayjs"], include: ["pinia", "lodash-es", "@vueuse/core", "dayjs"],
exclude: ["@pureadmin/theme/dist/browser-utils"] exclude: ["@pureadmin/theme/dist/browser-utils"]
}, },
build: { build: {
sourcemap: false, sourcemap: false,
// 消除打包大小超过500kb警告 // 消除打包大小超过500kb警告
chunkSizeWarningLimit: 4000 chunkSizeWarningLimit: 4000,
rollupOptions: {
input: {
index: pathResolve("index.html")
},
// 静态资源分类打包
output: {
chunkFileNames: "static/js/[name]-[hash].js",
entryFileNames: "static/js/[name]-[hash].js",
assetFileNames: "static/[ext]/[name]-[hash].[ext]"
}
}
}, },
define: { define: {
__INTLIFY_PROD_DEVTOOLS__: false, __INTLIFY_PROD_DEVTOOLS__: false,