Compare commits
No commits in common. "9caa00855197d04c6defcc7da0a4c07a40a78967" and "607b73a7b3f323c17af92757cee1928fdd47dea2" have entirely different histories.
9caa008551
...
607b73a7b3
11
.env.base
11
.env.base
|
@ -1,5 +1,5 @@
|
||||||
# 环境
|
# 环境
|
||||||
VITE_NODE_ENV=development
|
NODE_ENV=development
|
||||||
|
|
||||||
# 接口前缀
|
# 接口前缀
|
||||||
VITE_API_BASE_PATH=
|
VITE_API_BASE_PATH=
|
||||||
|
@ -9,12 +9,3 @@ VITE_BASE_PATH=/
|
||||||
|
|
||||||
# 标题
|
# 标题
|
||||||
VITE_APP_TITLE=ElementAdmin
|
VITE_APP_TITLE=ElementAdmin
|
||||||
|
|
||||||
# 是否全量引入element-plus样式
|
|
||||||
VITE_USE_ALL_ELEMENT_PLUS_STYLE=true
|
|
||||||
|
|
||||||
# 是否开启mock
|
|
||||||
VITE_USE_MOCK=true
|
|
||||||
|
|
||||||
# 是否使用在线图标
|
|
||||||
VITE_USE_ONLINE_ICON=true
|
|
17
.env.dev
17
.env.dev
|
@ -1,5 +1,5 @@
|
||||||
# 环境
|
# 环境
|
||||||
VITE_NODE_ENV=production
|
NODE_ENV=production
|
||||||
|
|
||||||
# 接口前缀
|
# 接口前缀
|
||||||
VITE_API_BASE_PATH=
|
VITE_API_BASE_PATH=
|
||||||
|
@ -21,18 +21,3 @@ VITE_OUT_DIR=dist-dev
|
||||||
|
|
||||||
# 标题
|
# 标题
|
||||||
VITE_APP_TITLE=ElementAdmin
|
VITE_APP_TITLE=ElementAdmin
|
||||||
|
|
||||||
# 是否包分析
|
|
||||||
VITE_USE_BUNDLE_ANALYZER=false
|
|
||||||
|
|
||||||
# 是否全量引入element-plus样式
|
|
||||||
VITE_USE_ALL_ELEMENT_PLUS_STYLE=false
|
|
||||||
|
|
||||||
# 是否开启mock
|
|
||||||
VITE_USE_MOCK=true
|
|
||||||
|
|
||||||
# 是否切割css
|
|
||||||
VITE_USE_CSS_SPLIT=true
|
|
||||||
|
|
||||||
# 是否使用在线图标
|
|
||||||
VITE_USE_ONLINE_ICON=true
|
|
17
.env.gitee
17
.env.gitee
|
@ -1,5 +1,5 @@
|
||||||
# 环境
|
# 环境
|
||||||
VITE_NODE_ENV=production
|
NODE_ENV=production
|
||||||
|
|
||||||
# 接口前缀
|
# 接口前缀
|
||||||
VITE_API_BASE_PATH=
|
VITE_API_BASE_PATH=
|
||||||
|
@ -21,18 +21,3 @@ VITE_OUT_DIR=dist-pro
|
||||||
|
|
||||||
# 标题
|
# 标题
|
||||||
VITE_APP_TITLE=ElementAdmin
|
VITE_APP_TITLE=ElementAdmin
|
||||||
|
|
||||||
# 是否包分析
|
|
||||||
VITE_USE_BUNDLE_ANALYZER=false
|
|
||||||
|
|
||||||
# 是否全量引入element-plus样式
|
|
||||||
VITE_USE_ALL_ELEMENT_PLUS_STYLE=false
|
|
||||||
|
|
||||||
# 是否开启mock
|
|
||||||
VITE_USE_MOCK=true
|
|
||||||
|
|
||||||
# 是否切割css
|
|
||||||
VITE_USE_CSS_SPLIT=true
|
|
||||||
|
|
||||||
# 是否使用在线图标
|
|
||||||
VITE_USE_ONLINE_ICON=true
|
|
17
.env.pro
17
.env.pro
|
@ -1,5 +1,5 @@
|
||||||
# 环境
|
# 环境
|
||||||
VITE_NODE_ENV=production
|
NODE_ENV=production
|
||||||
|
|
||||||
# 接口前缀
|
# 接口前缀
|
||||||
VITE_API_BASE_PATH=
|
VITE_API_BASE_PATH=
|
||||||
|
@ -21,18 +21,3 @@ VITE_OUT_DIR=dist-pro
|
||||||
|
|
||||||
# 标题
|
# 标题
|
||||||
VITE_APP_TITLE=ElementAdmin
|
VITE_APP_TITLE=ElementAdmin
|
||||||
|
|
||||||
# 是否包分析
|
|
||||||
VITE_USE_BUNDLE_ANALYZER=true
|
|
||||||
|
|
||||||
# 是否全量引入element-plus样式
|
|
||||||
VITE_USE_ALL_ELEMENT_PLUS_STYLE=false
|
|
||||||
|
|
||||||
# 是否开启mock
|
|
||||||
VITE_USE_MOCK=true
|
|
||||||
|
|
||||||
# 是否切割css
|
|
||||||
VITE_USE_CSS_SPLIT=true
|
|
||||||
|
|
||||||
# 是否使用在线图标
|
|
||||||
VITE_USE_ONLINE_ICON=true
|
|
19
.env.test
19
.env.test
|
@ -1,8 +1,8 @@
|
||||||
# 环境
|
# 环境
|
||||||
VITE_NODE_ENV=production
|
NODE_ENV=production
|
||||||
|
|
||||||
# 接口前缀
|
# 接口前缀
|
||||||
VITE_API_BASE_PATH=
|
VITE_API_BASE_PATH=test
|
||||||
|
|
||||||
# 打包路径
|
# 打包路径
|
||||||
VITE_BASE_PATH=/dist-test/
|
VITE_BASE_PATH=/dist-test/
|
||||||
|
@ -21,18 +21,3 @@ VITE_OUT_DIR=dist-test
|
||||||
|
|
||||||
# 标题
|
# 标题
|
||||||
VITE_APP_TITLE=ElementAdmin
|
VITE_APP_TITLE=ElementAdmin
|
||||||
|
|
||||||
# 是否包分析
|
|
||||||
VITE_USE_BUNDLE_ANALYZER=false
|
|
||||||
|
|
||||||
# 是否全量引入element-plus样式
|
|
||||||
VITE_USE_ALL_ELEMENT_PLUS_STYLE=false
|
|
||||||
|
|
||||||
# 是否开启mock
|
|
||||||
VITE_USE_MOCK=true
|
|
||||||
|
|
||||||
# 是否切割css
|
|
||||||
VITE_USE_CSS_SPLIT=false
|
|
||||||
|
|
||||||
# 是否使用在线图标
|
|
||||||
VITE_USE_ONLINE_ICON=true
|
|
|
@ -6,4 +6,3 @@ dist-ssr
|
||||||
/dist*
|
/dist*
|
||||||
*-lock.*
|
*-lock.*
|
||||||
pnpm-debug
|
pnpm-debug
|
||||||
stats.html
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"typescript.tsdk": "node_modules/typescript/lib",
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
"prettier.enable": false,
|
"prettier.enable": false,
|
||||||
"editor.codeActionsOnSave": {
|
"editor.codeActionsOnSave": {
|
||||||
"source.fixAll.eslint": "explicit"
|
"source.fixAll.eslint": true
|
||||||
},
|
},
|
||||||
"[vue]": {
|
"[vue]": {
|
||||||
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
|
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
|
||||||
|
|
91
package.json
91
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "vue-element-plus-admin",
|
"name": "vue-element-plus-admin",
|
||||||
"version": "2.5.6",
|
"version": "2.0.0",
|
||||||
"description": "一套基于vue3、element-plus、typesScript、vite4的后台集成方案。",
|
"description": "一套基于vue3、element-plus、typesScript、vite4的后台集成方案。",
|
||||||
"author": "Archer <502431556@qq.com>",
|
"author": "Archer <502431556@qq.com>",
|
||||||
"private": false,
|
"private": false,
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
"build:pro": "pnpm vite build --mode pro",
|
"build:pro": "pnpm vite build --mode pro",
|
||||||
"build:gitee": "pnpm vite build --mode gitee",
|
"build:gitee": "pnpm vite build --mode gitee",
|
||||||
"build:dev": "pnpm vite build --mode dev",
|
"build:dev": "pnpm vite build --mode dev",
|
||||||
"build:test": "pnpm vite build --mode test",
|
"build:test": "pnpm run ts:check && vite build --mode test",
|
||||||
"serve:pro": "pnpm vite preview --mode pro",
|
"serve:pro": "pnpm vite preview --mode pro",
|
||||||
"serve:dev": "pnpm vite preview --mode dev",
|
"serve:dev": "pnpm vite preview --mode dev",
|
||||||
"serve:test": "pnpm vite preview --mode test",
|
"serve:test": "pnpm vite preview --mode test",
|
||||||
|
@ -26,95 +26,94 @@
|
||||||
"p": "plop"
|
"p": "plop"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@faker-js/faker": "^8.4.0",
|
"@faker-js/faker": "^8.3.1",
|
||||||
"@iconify/iconify": "^3.1.1",
|
"@iconify/iconify": "^3.1.1",
|
||||||
"@iconify/vue": "^4.1.1",
|
"@iconify/vue": "^4.1.1",
|
||||||
"@vueuse/core": "^10.7.2",
|
"@vueuse/core": "^10.7.0",
|
||||||
"@wangeditor/editor": "^5.1.23",
|
"@wangeditor/editor": "^5.1.23",
|
||||||
"@wangeditor/editor-for-vue": "^5.1.10",
|
"@wangeditor/editor-for-vue": "^5.1.10",
|
||||||
"@zxcvbn-ts/core": "^3.0.4",
|
"@zxcvbn-ts/core": "^3.0.4",
|
||||||
"animate.css": "^4.1.1",
|
"animate.css": "^4.1.1",
|
||||||
"axios": "^1.6.7",
|
"axios": "^1.6.2",
|
||||||
"cropperjs": "^1.6.1",
|
"cropperjs": "^1.6.1",
|
||||||
"dayjs": "^1.11.10",
|
"dayjs": "^1.11.10",
|
||||||
"driver.js": "^1.3.1",
|
"driver.js": "^1.3.1",
|
||||||
"echarts": "^5.4.3",
|
"echarts": "^5.4.3",
|
||||||
"echarts-wordcloud": "^2.1.0",
|
"echarts-wordcloud": "^2.1.0",
|
||||||
"element-plus": "2.5.5",
|
"element-plus": "^2.4.3",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"mitt": "^3.0.1",
|
"mitt": "^3.0.1",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
"pinia-plugin-persistedstate": "^3.2.1",
|
"pinia-plugin-persistedstate": "^3.2.0",
|
||||||
"qrcode": "^1.5.3",
|
"qrcode": "^1.5.3",
|
||||||
"qs": "^6.11.2",
|
"qs": "^6.11.2",
|
||||||
"url": "^0.11.3",
|
"url": "^0.11.3",
|
||||||
"vue": "3.4.15",
|
"vue": "3.3.10",
|
||||||
"vue-draggable-plus": "^0.3.5",
|
"vue-i18n": "9.8.0",
|
||||||
"vue-i18n": "9.9.1",
|
"vue-json-pretty": "^2.2.4",
|
||||||
"vue-json-pretty": "^2.3.0",
|
|
||||||
"vue-router": "^4.2.5",
|
"vue-router": "^4.2.5",
|
||||||
"vue-types": "^5.1.1",
|
"vue-types": "^5.1.1",
|
||||||
"xgplayer": "^3.0.12"
|
"xgplayer": "^3.0.10"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^18.6.0",
|
"@commitlint/cli": "^18.4.3",
|
||||||
"@commitlint/config-conventional": "^18.6.0",
|
"@commitlint/config-conventional": "^18.4.3",
|
||||||
"@iconify/json": "^2.2.180",
|
"@iconify/json": "^2.2.153",
|
||||||
"@intlify/unplugin-vue-i18n": "^2.0.0",
|
"@intlify/unplugin-vue-i18n": "^1.5.0",
|
||||||
|
"@purge-icons/generated": "^0.10.0",
|
||||||
"@types/fs-extra": "^11.0.4",
|
"@types/fs-extra": "^11.0.4",
|
||||||
"@types/inquirer": "^9.0.7",
|
"@types/inquirer": "^9.0.7",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/node": "^20.11.16",
|
"@types/node": "^20.10.3",
|
||||||
"@types/nprogress": "^0.2.3",
|
"@types/nprogress": "^0.2.3",
|
||||||
"@types/qrcode": "^1.5.5",
|
"@types/qrcode": "^1.5.5",
|
||||||
"@types/qs": "^6.9.11",
|
"@types/qs": "^6.9.10",
|
||||||
"@types/sortablejs": "^1.15.7",
|
"@types/sortablejs": "^1.15.7",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
"@typescript-eslint/eslint-plugin": "^6.13.2",
|
||||||
"@typescript-eslint/parser": "^6.21.0",
|
"@typescript-eslint/parser": "^6.13.2",
|
||||||
"@unocss/transformer-variant-group": "^0.58.5",
|
"@unocss/transformer-variant-group": "^0.58.0",
|
||||||
"@vitejs/plugin-legacy": "^5.3.0",
|
"@vitejs/plugin-legacy": "^5.2.0",
|
||||||
"@vitejs/plugin-vue": "^5.0.3",
|
"@vitejs/plugin-vue": "^4.5.1",
|
||||||
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
||||||
"autoprefixer": "^10.4.17",
|
"autoprefixer": "^10.4.16",
|
||||||
"chalk": "^5.3.0",
|
"chalk": "^5.3.0",
|
||||||
"consola": "^3.2.3",
|
"consola": "^3.2.3",
|
||||||
"eslint": "^8.56.0",
|
"eslint": "^8.55.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-define-config": "^2.1.0",
|
"eslint-define-config": "^2.0.0",
|
||||||
"eslint-plugin-prettier": "^5.1.3",
|
"eslint-plugin-prettier": "^5.0.1",
|
||||||
"eslint-plugin-vue": "^9.21.1",
|
"eslint-plugin-vue": "^9.19.2",
|
||||||
"esno": "^4.0.0",
|
"esno": "^4.0.0",
|
||||||
"fs-extra": "^11.2.0",
|
"fs-extra": "^11.2.0",
|
||||||
"husky": "^9.0.10",
|
"husky": "^8.0.3",
|
||||||
"inquirer": "^9.2.14",
|
"inquirer": "^9.2.12",
|
||||||
"less": "^4.2.0",
|
"less": "^4.2.0",
|
||||||
"lint-staged": "^15.2.2",
|
"lint-staged": "^15.2.0",
|
||||||
"plop": "^4.0.1",
|
"plop": "^4.0.0",
|
||||||
"postcss": "^8.4.34",
|
"postcss": "^8.4.32",
|
||||||
"postcss-html": "^1.6.0",
|
"postcss-html": "^1.5.0",
|
||||||
"postcss-less": "^6.0.0",
|
"postcss-less": "^6.0.0",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.1.0",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^5.0.5",
|
||||||
"rollup": "^4.9.6",
|
"rollup": "^4.6.1",
|
||||||
"rollup-plugin-visualizer": "^5.12.0",
|
"stylelint": "^15.11.0",
|
||||||
"stylelint": "^16.2.1",
|
|
||||||
"stylelint-config-html": "^1.1.0",
|
"stylelint-config-html": "^1.1.0",
|
||||||
"stylelint-config-recommended": "^14.0.0",
|
"stylelint-config-recommended": "^13.0.0",
|
||||||
"stylelint-config-standard": "^36.0.0",
|
"stylelint-config-standard": "^34.0.0",
|
||||||
"stylelint-order": "^6.0.4",
|
"stylelint-order": "^6.0.3",
|
||||||
"terser": "^5.27.0",
|
"terser": "^5.25.0",
|
||||||
"typescript": "5.3.3",
|
"typescript": "5.3.3",
|
||||||
"unocss": "^0.58.5",
|
"unocss": "^0.58.0",
|
||||||
"vite": "5.0.12",
|
"vite": "5.0.6",
|
||||||
"vite-plugin-ejs": "^1.7.0",
|
"vite-plugin-ejs": "^1.7.0",
|
||||||
"vite-plugin-eslint": "^1.8.1",
|
"vite-plugin-eslint": "^1.8.1",
|
||||||
"vite-plugin-mock": "2.9.6",
|
"vite-plugin-mock": "^2.9.6",
|
||||||
"vite-plugin-progress": "^0.0.7",
|
"vite-plugin-progress": "^0.0.7",
|
||||||
"vite-plugin-purge-icons": "^0.10.0",
|
"vite-plugin-purge-icons": "^0.10.0",
|
||||||
"vite-plugin-style-import": "2.0.0",
|
"vite-plugin-style-import": "2.0.0",
|
||||||
"vite-plugin-svg-icons": "^2.0.1",
|
"vite-plugin-svg-icons": "^2.0.1",
|
||||||
"vue-tsc": "^1.8.27"
|
"vue-tsc": "^1.8.25"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@8.1.0",
|
"packageManager": "pnpm@8.1.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
16
src/App.vue
16
src/App.vue
|
@ -2,7 +2,9 @@
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { useAppStore } from '@/store/modules/app'
|
import { useAppStore } from '@/store/modules/app'
|
||||||
import { ConfigGlobal } from '@/components/ConfigGlobal'
|
import { ConfigGlobal } from '@/components/ConfigGlobal'
|
||||||
|
import { isDark } from '@/utils/is'
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
import { useDesign } from '@/hooks/web/useDesign'
|
||||||
|
import { useStorage } from '@/hooks/web/useStorage'
|
||||||
|
|
||||||
const { getPrefixCls } = useDesign()
|
const { getPrefixCls } = useDesign()
|
||||||
|
|
||||||
|
@ -14,7 +16,19 @@ const currentSize = computed(() => appStore.getCurrentSize)
|
||||||
|
|
||||||
const greyMode = computed(() => appStore.getGreyMode)
|
const greyMode = computed(() => appStore.getGreyMode)
|
||||||
|
|
||||||
appStore.initTheme()
|
const { getStorage } = useStorage()
|
||||||
|
|
||||||
|
// 根据浏览器当前主题设置系统主题色
|
||||||
|
const setDefaultTheme = () => {
|
||||||
|
if (getStorage('isDark') !== null) {
|
||||||
|
appStore.setIsDark(getStorage('isDark'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const isDarkTheme = isDark()
|
||||||
|
appStore.setIsDark(isDarkTheme)
|
||||||
|
}
|
||||||
|
|
||||||
|
setDefaultTheme()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import { AxiosResponse, InternalAxiosRequestConfig } from './types'
|
import { AxiosResponse, InternalAxiosRequestConfig } from './types'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import qs from 'qs'
|
import qs from 'qs'
|
||||||
import { SUCCESS_CODE, TRANSFORM_REQUEST_DATA } from '@/constants'
|
import { SUCCESS_CODE } from '@/constants'
|
||||||
import { useUserStoreWithOut } from '@/store/modules/user'
|
import { useUserStoreWithOut } from '@/store/modules/user'
|
||||||
import { objToFormData } from '@/utils'
|
|
||||||
|
|
||||||
const defaultRequestInterceptors = (config: InternalAxiosRequestConfig) => {
|
const defaultRequestInterceptors = (config: InternalAxiosRequestConfig) => {
|
||||||
if (
|
if (
|
||||||
|
@ -11,12 +10,6 @@ const defaultRequestInterceptors = (config: InternalAxiosRequestConfig) => {
|
||||||
config.headers['Content-Type'] === 'application/x-www-form-urlencoded'
|
config.headers['Content-Type'] === 'application/x-www-form-urlencoded'
|
||||||
) {
|
) {
|
||||||
config.data = qs.stringify(config.data)
|
config.data = qs.stringify(config.data)
|
||||||
} else if (
|
|
||||||
TRANSFORM_REQUEST_DATA &&
|
|
||||||
config.method === 'post' &&
|
|
||||||
config.headers['Content-Type'] === 'multipart/form-data'
|
|
||||||
) {
|
|
||||||
config.data = objToFormData(config.data)
|
|
||||||
}
|
}
|
||||||
if (config.method === 'get' && config.params) {
|
if (config.method === 'get' && config.params) {
|
||||||
let url = config.url as string
|
let url = config.url as string
|
||||||
|
|
|
@ -15,7 +15,7 @@ const title = computed(() => appStore.getTitle)
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
:class="prefixCls"
|
:class="prefixCls"
|
||||||
class="shrink-0 text-center text-[var(--el-text-color-placeholder)] bg-[var(--app-content-bg-color)] h-[var(--app-footer-height)] leading-[var(--app-footer-height)] dark:bg-[var(--el-bg-color)]"
|
class="text-center text-[var(--el-text-color-placeholder)] bg-[var(--app-content-bg-color)] h-[var(--app-footer-height)] leading-[var(--app-footer-height)] dark:bg-[var(--el-bg-color)]"
|
||||||
>
|
>
|
||||||
Copyright ©2021-present {{ title }}
|
Copyright ©2021-present {{ title }}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -230,7 +230,7 @@ export default defineComponent({
|
||||||
const { schema = [], isCol } = unref(getProps)
|
const { schema = [], isCol } = unref(getProps)
|
||||||
|
|
||||||
return schema
|
return schema
|
||||||
.filter((v) => !v.remove && !v.hidden)
|
.filter((v) => !v.remove)
|
||||||
.map((item) => {
|
.map((item) => {
|
||||||
// 如果是 Divider 组件,需要自己占用一行
|
// 如果是 Divider 组件,需要自己占用一行
|
||||||
const isDivider = item.component === 'Divider'
|
const isDivider = item.component === 'Divider'
|
||||||
|
@ -406,15 +406,7 @@ export default defineComponent({
|
||||||
margin-left: 0 !important;
|
margin-left: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.@{elNamespace}-form--inline {
|
.@{elNamespace}-form--inline .@{elNamespace}-input {
|
||||||
:deep(.el-form-item__content) {
|
width: 245px;
|
||||||
& > :first-child {
|
|
||||||
min-width: 229.5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.@{elNamespace}-input-number {
|
|
||||||
// 229.5px是兼容el-input-number的最小宽度,
|
|
||||||
min-width: 229.5px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -25,11 +25,6 @@ const symbolId = computed(() => {
|
||||||
return unref(isLocal) ? `#icon-${props.icon.split('svg-icon:')[1]}` : props.icon
|
return unref(isLocal) ? `#icon-${props.icon.split('svg-icon:')[1]}` : props.icon
|
||||||
})
|
})
|
||||||
|
|
||||||
// 是否使用在线图标
|
|
||||||
const isUseOnline = computed(() => {
|
|
||||||
return import.meta.env.VITE_USE_ONLINE_ICON === 'true'
|
|
||||||
})
|
|
||||||
|
|
||||||
const getIconifyStyle = computed(() => {
|
const getIconifyStyle = computed(() => {
|
||||||
const { color, size } = props
|
const { color, size } = props
|
||||||
return {
|
return {
|
||||||
|
@ -45,10 +40,7 @@ const getIconifyStyle = computed(() => {
|
||||||
<use :xlink:href="symbolId" />
|
<use :xlink:href="symbolId" />
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
<template v-else>
|
<Icon v-else :icon="icon" :style="getIconifyStyle" />
|
||||||
<Icon v-if="isUseOnline" :icon="icon" :style="getIconifyStyle" />
|
|
||||||
<div v-else :class="`${icon} iconify`" :style="getIconifyStyle"></div>
|
|
||||||
</template>
|
|
||||||
</ElIcon>
|
</ElIcon>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -57,18 +49,11 @@ const getIconifyStyle = computed(() => {
|
||||||
|
|
||||||
.@{prefix-cls},
|
.@{prefix-cls},
|
||||||
.iconify {
|
.iconify {
|
||||||
:deep(svg) {
|
&:hover {
|
||||||
&:hover {
|
:deep(svg) {
|
||||||
// stylelint-disable-next-line
|
// stylelint-disable-next-line
|
||||||
color: v-bind(hoverColor) !important;
|
color: v-bind(hoverColor) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.iconify {
|
|
||||||
&:hover {
|
|
||||||
// stylelint-disable-next-line
|
|
||||||
color: v-bind(hoverColor) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -89,16 +89,11 @@ export default defineComponent({
|
||||||
backgroundColor="var(--left-menu-bg-color)"
|
backgroundColor="var(--left-menu-bg-color)"
|
||||||
textColor="var(--left-menu-text-color)"
|
textColor="var(--left-menu-text-color)"
|
||||||
activeTextColor="var(--left-menu-text-active-color)"
|
activeTextColor="var(--left-menu-text-active-color)"
|
||||||
popperClass={
|
|
||||||
unref(menuMode) === 'vertical'
|
|
||||||
? `${prefixCls}-popper--vertical`
|
|
||||||
: `${prefixCls}-popper--horizontal`
|
|
||||||
}
|
|
||||||
onSelect={menuSelect}
|
onSelect={menuSelect}
|
||||||
>
|
>
|
||||||
{{
|
{{
|
||||||
default: () => {
|
default: () => {
|
||||||
const { renderMenuItem } = useRenderMenuItem()
|
const { renderMenuItem } = useRenderMenuItem(unref(menuMode))
|
||||||
return renderMenuItem(unref(routers))
|
return renderMenuItem(unref(routers))
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
@ -128,10 +123,30 @@ export default defineComponent({
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
@prefix-cls: ~'@{namespace}-menu';
|
@prefix-cls: ~'@{namespace}-menu';
|
||||||
|
|
||||||
|
// .is-active--after {
|
||||||
|
// position: absolute;
|
||||||
|
// top: 0;
|
||||||
|
// right: 0;
|
||||||
|
// width: 4px;
|
||||||
|
// height: 100%;
|
||||||
|
// background-color: var(--el-color-primary);
|
||||||
|
// content: '';
|
||||||
|
// }
|
||||||
|
|
||||||
.@{prefix-cls} {
|
.@{prefix-cls} {
|
||||||
position: relative;
|
position: relative;
|
||||||
transition: width var(--transition-time-02);
|
transition: width var(--transition-time-02);
|
||||||
|
|
||||||
|
// &:after {
|
||||||
|
// position: absolute;
|
||||||
|
// top: 0;
|
||||||
|
// right: 0;
|
||||||
|
// height: 100%;
|
||||||
|
// width: 1px;
|
||||||
|
// background-color: var(--el-border-color);
|
||||||
|
// content: '';
|
||||||
|
// }
|
||||||
|
|
||||||
:deep(.@{elNamespace}-menu) {
|
:deep(.@{elNamespace}-menu) {
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
border-right: none;
|
border-right: none;
|
||||||
|
@ -140,6 +155,7 @@ export default defineComponent({
|
||||||
.is-active {
|
.is-active {
|
||||||
& > .@{elNamespace}-sub-menu__title {
|
& > .@{elNamespace}-sub-menu__title {
|
||||||
color: var(--left-menu-text-active-color) !important;
|
color: var(--left-menu-text-active-color) !important;
|
||||||
|
// background-color: var(--left-menu-bg-color) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,6 +180,10 @@ export default defineComponent({
|
||||||
|
|
||||||
.@{elNamespace}-menu-item.is-active {
|
.@{elNamespace}-menu-item.is-active {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
// &:after {
|
||||||
|
// .is-active--after;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置子菜单的背景颜色
|
// 设置子菜单的背景颜色
|
||||||
|
@ -183,11 +203,16 @@ export default defineComponent({
|
||||||
& > .is-active > .@{elNamespace}-sub-menu__title {
|
& > .is-active > .@{elNamespace}-sub-menu__title {
|
||||||
position: relative;
|
position: relative;
|
||||||
background-color: var(--left-menu-collapse-bg-active-color) !important;
|
background-color: var(--left-menu-collapse-bg-active-color) !important;
|
||||||
|
|
||||||
|
// &:after {
|
||||||
|
// .is-active--after;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 折叠动画的时候,就需要把文字给隐藏掉
|
// 折叠动画的时候,就需要把文字给隐藏掉
|
||||||
:deep(.horizontal-collapse-transition) {
|
:deep(.horizontal-collapse-transition) {
|
||||||
|
// transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out !important;
|
||||||
.@{prefix-cls}__title {
|
.@{prefix-cls}__title {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
@ -229,12 +254,23 @@ export default defineComponent({
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
@prefix-cls: ~'@{namespace}-menu-popper';
|
@prefix-cls: ~'@{namespace}-menu-popper';
|
||||||
|
|
||||||
|
// .is-active--after {
|
||||||
|
// position: absolute;
|
||||||
|
// top: 0;
|
||||||
|
// right: 0;
|
||||||
|
// width: 4px;
|
||||||
|
// height: 100%;
|
||||||
|
// background-color: var(--el-color-primary);
|
||||||
|
// content: '';
|
||||||
|
// }
|
||||||
|
|
||||||
.@{prefix-cls}--vertical,
|
.@{prefix-cls}--vertical,
|
||||||
.@{prefix-cls}--horizontal {
|
.@{prefix-cls}--horizontal {
|
||||||
// 设置选中时子标题的颜色
|
// 设置选中时子标题的颜色
|
||||||
.is-active {
|
.is-active {
|
||||||
& > .el-sub-menu__title {
|
& > .el-sub-menu__title {
|
||||||
color: var(--left-menu-text-active-color) !important;
|
color: var(--left-menu-text-active-color) !important;
|
||||||
|
// background-color: var(--left-menu-bg-color) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,6 +291,10 @@ export default defineComponent({
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--left-menu-bg-active-color) !important;
|
background-color: var(--left-menu-bg-active-color) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// &:after {
|
||||||
|
// .is-active--after;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -2,49 +2,57 @@ import { ElSubMenu, ElMenuItem } from 'element-plus'
|
||||||
import { hasOneShowingChild } from '../helper'
|
import { hasOneShowingChild } from '../helper'
|
||||||
import { isUrl } from '@/utils/is'
|
import { isUrl } from '@/utils/is'
|
||||||
import { useRenderMenuTitle } from './useRenderMenuTitle'
|
import { useRenderMenuTitle } from './useRenderMenuTitle'
|
||||||
|
import { useDesign } from '@/hooks/web/useDesign'
|
||||||
import { pathResolve } from '@/utils/routerHelper'
|
import { pathResolve } from '@/utils/routerHelper'
|
||||||
|
|
||||||
const { renderMenuTitle } = useRenderMenuTitle()
|
const { renderMenuTitle } = useRenderMenuTitle()
|
||||||
|
|
||||||
export const useRenderMenuItem = () =>
|
export const useRenderMenuItem = (
|
||||||
// allRouters: AppRouteRecordRaw[] = [],
|
// allRouters: AppRouteRecordRaw[] = [],
|
||||||
{
|
menuMode: 'vertical' | 'horizontal'
|
||||||
const renderMenuItem = (routers: AppRouteRecordRaw[], parentPath = '/') => {
|
) => {
|
||||||
return routers
|
const renderMenuItem = (routers: AppRouteRecordRaw[], parentPath = '/') => {
|
||||||
.filter((v) => !v.meta?.hidden)
|
return routers
|
||||||
.map((v) => {
|
.filter((v) => !v.meta?.hidden)
|
||||||
const meta = v.meta ?? {}
|
.map((v) => {
|
||||||
const { oneShowingChild, onlyOneChild } = hasOneShowingChild(v.children, v)
|
const meta = v.meta ?? {}
|
||||||
const fullPath = isUrl(v.path) ? v.path : pathResolve(parentPath, v.path) // getAllParentPath<AppRouteRecordRaw>(allRouters, v.path).join('/')
|
const { oneShowingChild, onlyOneChild } = hasOneShowingChild(v.children, v)
|
||||||
|
const fullPath = isUrl(v.path) ? v.path : pathResolve(parentPath, v.path) // getAllParentPath<AppRouteRecordRaw>(allRouters, v.path).join('/')
|
||||||
|
|
||||||
if (
|
if (
|
||||||
oneShowingChild &&
|
oneShowingChild &&
|
||||||
(!onlyOneChild?.children || onlyOneChild?.noShowingChildren) &&
|
(!onlyOneChild?.children || onlyOneChild?.noShowingChildren) &&
|
||||||
!meta?.alwaysShow
|
!meta?.alwaysShow
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
<ElMenuItem
|
<ElMenuItem index={onlyOneChild ? pathResolve(fullPath, onlyOneChild.path) : fullPath}>
|
||||||
index={onlyOneChild ? pathResolve(fullPath, onlyOneChild.path) : fullPath}
|
{{
|
||||||
>
|
default: () => renderMenuTitle(onlyOneChild ? onlyOneChild?.meta : meta)
|
||||||
{{
|
}}
|
||||||
default: () => renderMenuTitle(onlyOneChild ? onlyOneChild?.meta : meta)
|
</ElMenuItem>
|
||||||
}}
|
)
|
||||||
</ElMenuItem>
|
} else {
|
||||||
)
|
const { getPrefixCls } = useDesign()
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<ElSubMenu index={fullPath}>
|
|
||||||
{{
|
|
||||||
title: () => renderMenuTitle(meta),
|
|
||||||
default: () => renderMenuItem(v.children!, fullPath)
|
|
||||||
}}
|
|
||||||
</ElSubMenu>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
const preFixCls = getPrefixCls('menu-popper')
|
||||||
renderMenuItem
|
return (
|
||||||
}
|
<ElSubMenu
|
||||||
|
index={fullPath}
|
||||||
|
popperClass={
|
||||||
|
menuMode === 'vertical' ? `${preFixCls}--vertical` : `${preFixCls}--horizontal`
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
title: () => renderMenuTitle(meta),
|
||||||
|
default: () => renderMenuItem(v.children!, fullPath)
|
||||||
|
}}
|
||||||
|
</ElSubMenu>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
renderMenuItem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,14 +10,10 @@ export const useRenderMenuTitle = () => {
|
||||||
return icon ? (
|
return icon ? (
|
||||||
<>
|
<>
|
||||||
<Icon icon={meta.icon}></Icon>
|
<Icon icon={meta.icon}></Icon>
|
||||||
<span class="v-menu__title overflow-hidden overflow-ellipsis whitespace-nowrap">
|
<span class="v-menu__title">{t(title as string)}</span>
|
||||||
{t(title as string)}
|
|
||||||
</span>
|
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<span class="v-menu__title overflow-hidden overflow-ellipsis whitespace-nowrap">
|
<span class="v-menu__title">{t(title as string)}</span>
|
||||||
{t(title as string)}
|
|
||||||
</span>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import type { RouteMeta } from 'vue-router'
|
||||||
import { ref, unref } from 'vue'
|
import { ref, unref } from 'vue'
|
||||||
import { findPath } from '@/utils/tree'
|
import { findPath } from '@/utils/tree'
|
||||||
|
|
||||||
|
@ -20,7 +21,7 @@ export const hasOneShowingChild = (
|
||||||
const onlyOneChild = ref<OnlyOneChildType>()
|
const onlyOneChild = ref<OnlyOneChildType>()
|
||||||
|
|
||||||
const showingChildren = children.filter((v) => {
|
const showingChildren = children.filter((v) => {
|
||||||
const meta = v.meta ?? {}
|
const meta = (v.meta ?? {}) as RouteMeta
|
||||||
if (meta.hidden) {
|
if (meta.hidden) {
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ElDrawer, ElDivider, ElMessage } from 'element-plus'
|
import { ElDrawer, ElDivider, ElMessage } from 'element-plus'
|
||||||
import { ref, unref } from 'vue'
|
import { ref, unref, computed, watch } from 'vue'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { ThemeSwitch } from '@/components/ThemeSwitch'
|
import { ThemeSwitch } from '@/components/ThemeSwitch'
|
||||||
|
import { colorIsDark, lighten, hexToRGB } from '@/utils/color'
|
||||||
import { useCssVar } from '@vueuse/core'
|
import { useCssVar } from '@vueuse/core'
|
||||||
import { useAppStore } from '@/store/modules/app'
|
import { useAppStore } from '@/store/modules/app'
|
||||||
import { trim, setCssVar, getCssVar } from '@/utils'
|
import { trim, setCssVar } from '@/utils'
|
||||||
import ColorRadioPicker from './components/ColorRadioPicker.vue'
|
import ColorRadioPicker from './components/ColorRadioPicker.vue'
|
||||||
import InterfaceDisplay from './components/InterfaceDisplay.vue'
|
import InterfaceDisplay from './components/InterfaceDisplay.vue'
|
||||||
import LayoutRadioPicker from './components/LayoutRadioPicker.vue'
|
import LayoutRadioPicker from './components/LayoutRadioPicker.vue'
|
||||||
|
@ -23,6 +24,8 @@ const appStore = useAppStore()
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
const layout = computed(() => appStore.getLayout)
|
||||||
|
|
||||||
const drawer = ref(false)
|
const drawer = ref(false)
|
||||||
|
|
||||||
// 主题色相关
|
// 主题色相关
|
||||||
|
@ -39,28 +42,70 @@ const setSystemTheme = (color: string) => {
|
||||||
const headerTheme = ref(appStore.getTheme.topHeaderBgColor || '')
|
const headerTheme = ref(appStore.getTheme.topHeaderBgColor || '')
|
||||||
|
|
||||||
const setHeaderTheme = (color: string) => {
|
const setHeaderTheme = (color: string) => {
|
||||||
appStore.setHeaderTheme(color)
|
const isDarkColor = colorIsDark(color)
|
||||||
|
const textColor = isDarkColor ? '#fff' : 'inherit'
|
||||||
|
const textHoverColor = isDarkColor ? lighten(color!, 6) : '#f6f6f6'
|
||||||
|
const topToolBorderColor = isDarkColor ? color : '#eee'
|
||||||
|
setCssVar('--top-header-bg-color', color)
|
||||||
|
setCssVar('--top-header-text-color', textColor)
|
||||||
|
setCssVar('--top-header-hover-color', textHoverColor)
|
||||||
|
appStore.setTheme({
|
||||||
|
topHeaderBgColor: color,
|
||||||
|
topHeaderTextColor: textColor,
|
||||||
|
topHeaderHoverColor: textHoverColor,
|
||||||
|
topToolBorderColor
|
||||||
|
})
|
||||||
|
if (unref(layout) === 'top') {
|
||||||
|
setMenuTheme(color)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 菜单主题相关
|
// 菜单主题相关
|
||||||
const menuTheme = ref(appStore.getTheme.leftMenuBgColor || '')
|
const menuTheme = ref(appStore.getTheme.leftMenuBgColor || '')
|
||||||
|
|
||||||
const setMenuTheme = (color: string) => {
|
const setMenuTheme = (color: string) => {
|
||||||
appStore.setMenuTheme(color)
|
const primaryColor = useCssVar('--el-color-primary', document.documentElement)
|
||||||
|
const isDarkColor = colorIsDark(color)
|
||||||
|
const theme: Recordable = {
|
||||||
|
// 左侧菜单边框颜色
|
||||||
|
leftMenuBorderColor: isDarkColor ? 'inherit' : '#eee',
|
||||||
|
// 左侧菜单背景颜色
|
||||||
|
leftMenuBgColor: color,
|
||||||
|
// 左侧菜单浅色背景颜色
|
||||||
|
leftMenuBgLightColor: isDarkColor ? lighten(color!, 6) : color,
|
||||||
|
// 左侧菜单选中背景颜色
|
||||||
|
leftMenuBgActiveColor: isDarkColor
|
||||||
|
? 'var(--el-color-primary)'
|
||||||
|
: hexToRGB(unref(primaryColor), 0.1),
|
||||||
|
// 左侧菜单收起选中背景颜色
|
||||||
|
leftMenuCollapseBgActiveColor: isDarkColor
|
||||||
|
? 'var(--el-color-primary)'
|
||||||
|
: hexToRGB(unref(primaryColor), 0.1),
|
||||||
|
// 左侧菜单字体颜色
|
||||||
|
leftMenuTextColor: isDarkColor ? '#bfcbd9' : '#333',
|
||||||
|
// 左侧菜单选中字体颜色
|
||||||
|
leftMenuTextActiveColor: isDarkColor ? '#fff' : 'var(--el-color-primary)',
|
||||||
|
// logo字体颜色
|
||||||
|
logoTitleTextColor: isDarkColor ? '#fff' : 'inherit',
|
||||||
|
// logo边框颜色
|
||||||
|
logoBorderColor: isDarkColor ? color : '#eee'
|
||||||
|
}
|
||||||
|
appStore.setTheme(theme)
|
||||||
|
appStore.setCssVarTheme()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 监听layout变化,重置一些主题色
|
// 监听layout变化,重置一些主题色
|
||||||
// watch(
|
watch(
|
||||||
// () => layout.value,
|
() => layout.value,
|
||||||
// (n) => {
|
(n) => {
|
||||||
// if (n === 'top' && !appStore.getIsDark) {
|
if (n === 'top' && !appStore.getIsDark) {
|
||||||
// headerTheme.value = '#fff'
|
headerTheme.value = '#fff'
|
||||||
// setHeaderTheme('#fff')
|
setHeaderTheme('#fff')
|
||||||
// } else {
|
} else {
|
||||||
// setMenuTheme(unref(menuTheme))
|
setMenuTheme(unref(menuTheme))
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// )
|
)
|
||||||
|
|
||||||
// 拷贝
|
// 拷贝
|
||||||
const copyConfig = async () => {
|
const copyConfig = async () => {
|
||||||
|
@ -147,12 +192,6 @@ const clear = () => {
|
||||||
storageClear()
|
storageClear()
|
||||||
window.location.reload()
|
window.location.reload()
|
||||||
}
|
}
|
||||||
|
|
||||||
const themeChange = () => {
|
|
||||||
const color = getCssVar('--el-bg-color')
|
|
||||||
setMenuTheme(color)
|
|
||||||
setHeaderTheme(color)
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -172,7 +211,7 @@ const themeChange = () => {
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<!-- 主题 -->
|
<!-- 主题 -->
|
||||||
<ElDivider>{{ t('setting.theme') }}</ElDivider>
|
<ElDivider>{{ t('setting.theme') }}</ElDivider>
|
||||||
<ThemeSwitch @change="themeChange" />
|
<ThemeSwitch />
|
||||||
|
|
||||||
<!-- 布局 -->
|
<!-- 布局 -->
|
||||||
<ElDivider>{{ t('setting.layout') }}</ElDivider>
|
<ElDivider>{{ t('setting.layout') }}</ElDivider>
|
||||||
|
@ -213,21 +252,23 @@ const themeChange = () => {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 菜单主题 -->
|
<!-- 菜单主题 -->
|
||||||
<ElDivider>{{ t('setting.menuTheme') }}</ElDivider>
|
<template v-if="layout !== 'top'">
|
||||||
<ColorRadioPicker
|
<ElDivider>{{ t('setting.menuTheme') }}</ElDivider>
|
||||||
v-model="menuTheme"
|
<ColorRadioPicker
|
||||||
:schema="[
|
v-model="menuTheme"
|
||||||
'#fff',
|
:schema="[
|
||||||
'#001529',
|
'#fff',
|
||||||
'#212121',
|
'#001529',
|
||||||
'#273352',
|
'#212121',
|
||||||
'#191b24',
|
'#273352',
|
||||||
'#383f45',
|
'#191b24',
|
||||||
'#001628',
|
'#383f45',
|
||||||
'#344058'
|
'#001628',
|
||||||
]"
|
'#344058'
|
||||||
@change="setMenuTheme"
|
]"
|
||||||
/>
|
@change="setMenuTheme"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 界面显示 -->
|
<!-- 界面显示 -->
|
||||||
|
|
|
@ -85,9 +85,6 @@ export default defineComponent({
|
||||||
} else {
|
} else {
|
||||||
showTitle.value = !collapse
|
showTitle.value = !collapse
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
immediate: true
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -200,12 +197,11 @@ export default defineComponent({
|
||||||
</div>
|
</div>
|
||||||
<Menu
|
<Menu
|
||||||
class={[
|
class={[
|
||||||
'!absolute top-0 z-3000',
|
'!absolute top-0',
|
||||||
{
|
{
|
||||||
'!left-[var(--tab-menu-min-width)]': unref(collapse),
|
'!left-[var(--tab-menu-min-width)]': unref(collapse),
|
||||||
'!left-[var(--tab-menu-max-width)]': !unref(collapse),
|
'!left-[var(--tab-menu-max-width)]': !unref(collapse),
|
||||||
'!w-[var(--left-menu-max-width)] border-r-1 border-r-solid border-[var(--el-border-color)]':
|
'!w-[calc(var(--left-menu-max-width)+1px)]': unref(showMenu) || unref(fixedMenu),
|
||||||
unref(showMenu) || unref(fixedMenu),
|
|
||||||
'!w-0': !unref(showMenu) && !unref(fixedMenu)
|
'!w-0': !unref(showMenu) && !unref(fixedMenu)
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import { set, get } from 'lodash-es'
|
||||||
import { CSSProperties } from 'vue'
|
import { CSSProperties } from 'vue'
|
||||||
import { getSlot } from '@/utils/tsxHelper'
|
import { getSlot } from '@/utils/tsxHelper'
|
||||||
import TableActions from './components/TableActions.vue'
|
import TableActions from './components/TableActions.vue'
|
||||||
|
import { isImgPath } from '@/utils/is'
|
||||||
import { createVideoViewer } from '@/components/VideoPlayer'
|
import { createVideoViewer } from '@/components/VideoPlayer'
|
||||||
import { Icon } from '@/components/Icon'
|
import { Icon } from '@/components/Icon'
|
||||||
import { BaseButton } from '@/components/Button'
|
import { BaseButton } from '@/components/Button'
|
||||||
|
@ -58,13 +59,8 @@ export default defineComponent({
|
||||||
type: Array as PropType<Recordable[]>,
|
type: Array as PropType<Recordable[]>,
|
||||||
default: () => []
|
default: () => []
|
||||||
},
|
},
|
||||||
// 图片自动预览字段数组
|
// 是否自动预览
|
||||||
imagePreview: {
|
preview: {
|
||||||
type: Array as PropType<string[]>,
|
|
||||||
default: () => []
|
|
||||||
},
|
|
||||||
// 视频自动预览字段数组
|
|
||||||
videoPreview: {
|
|
||||||
type: Array as PropType<string[]>,
|
type: Array as PropType<string[]>,
|
||||||
default: () => []
|
default: () => []
|
||||||
},
|
},
|
||||||
|
@ -279,10 +275,6 @@ export default defineComponent({
|
||||||
setProps({ size })
|
setProps({ size })
|
||||||
}
|
}
|
||||||
|
|
||||||
const confirmSetColumn = (columns: TableColumn[]) => {
|
|
||||||
setProps({ columns })
|
|
||||||
}
|
|
||||||
|
|
||||||
expose({
|
expose({
|
||||||
setProps,
|
setProps,
|
||||||
setColumn,
|
setColumn,
|
||||||
|
@ -339,13 +331,11 @@ export default defineComponent({
|
||||||
const bindValue: Recordable = { ...attrs, ...unref(getProps) }
|
const bindValue: Recordable = { ...attrs, ...unref(getProps) }
|
||||||
delete bindValue.columns
|
delete bindValue.columns
|
||||||
delete bindValue.data
|
delete bindValue.data
|
||||||
delete bindValue.align
|
|
||||||
return bindValue
|
return bindValue
|
||||||
})
|
})
|
||||||
|
|
||||||
const renderTreeTableColumn = (columnsChildren: TableColumn[]) => {
|
const renderTreeTableColumn = (columnsChildren: TableColumn[]) => {
|
||||||
const { align, headerAlign, showOverflowTooltip, imagePreview, videoPreview } =
|
const { align, headerAlign, showOverflowTooltip, preview } = unref(getProps)
|
||||||
unref(getProps)
|
|
||||||
return columnsChildren.map((v) => {
|
return columnsChildren.map((v) => {
|
||||||
if (v.hidden) return null
|
if (v.hidden) return null
|
||||||
const props = { ...v } as any
|
const props = { ...v } as any
|
||||||
|
@ -356,10 +346,10 @@ export default defineComponent({
|
||||||
const slots = {
|
const slots = {
|
||||||
default: (...args: any[]) => {
|
default: (...args: any[]) => {
|
||||||
const data = args[0]
|
const data = args[0]
|
||||||
let isPreview = false
|
let isImageUrl = false
|
||||||
isPreview =
|
if (preview.length) {
|
||||||
imagePreview.some((item) => (item as string) === v.field) ||
|
isImageUrl = preview.some((item) => (item as string) === v.field)
|
||||||
videoPreview.some((item) => (item as string) === v.field)
|
}
|
||||||
|
|
||||||
return children && children.length
|
return children && children.length
|
||||||
? renderTreeTableColumn(children)
|
? renderTreeTableColumn(children)
|
||||||
|
@ -367,8 +357,8 @@ export default defineComponent({
|
||||||
? props.slots.default(...args)
|
? props.slots.default(...args)
|
||||||
: v?.formatter
|
: v?.formatter
|
||||||
? v?.formatter?.(data.row, data.column, get(data.row, v.field), data.$index)
|
? v?.formatter?.(data.row, data.column, get(data.row, v.field), data.$index)
|
||||||
: isPreview
|
: isImageUrl
|
||||||
? renderPreview(get(data.row, v.field), v.field)
|
? renderPreview(get(data.row, v.field))
|
||||||
: get(data.row, v.field)
|
: get(data.row, v.field)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -390,11 +380,10 @@ export default defineComponent({
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderPreview = (url: string, field: string) => {
|
const renderPreview = (url: string) => {
|
||||||
const { imagePreview, videoPreview } = unref(getProps)
|
|
||||||
return (
|
return (
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
{imagePreview.includes(field) ? (
|
{isImgPath(url) ? (
|
||||||
<ElImage
|
<ElImage
|
||||||
src={url}
|
src={url}
|
||||||
fit="cover"
|
fit="cover"
|
||||||
|
@ -403,7 +392,7 @@ export default defineComponent({
|
||||||
preview-src-list={[url]}
|
preview-src-list={[url]}
|
||||||
preview-teleported
|
preview-teleported
|
||||||
/>
|
/>
|
||||||
) : videoPreview.includes(field) ? (
|
) : (
|
||||||
<BaseButton
|
<BaseButton
|
||||||
type="primary"
|
type="primary"
|
||||||
icon={<Icon icon="ep:video-play" />}
|
icon={<Icon icon="ep:video-play" />}
|
||||||
|
@ -415,7 +404,7 @@ export default defineComponent({
|
||||||
>
|
>
|
||||||
预览
|
预览
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
) : null}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -430,8 +419,7 @@ export default defineComponent({
|
||||||
headerAlign,
|
headerAlign,
|
||||||
showOverflowTooltip,
|
showOverflowTooltip,
|
||||||
reserveSelection,
|
reserveSelection,
|
||||||
imagePreview,
|
preview
|
||||||
videoPreview
|
|
||||||
} = unref(getProps)
|
} = unref(getProps)
|
||||||
|
|
||||||
return (columnsChildren || columns).map((v) => {
|
return (columnsChildren || columns).map((v) => {
|
||||||
|
@ -446,7 +434,6 @@ export default defineComponent({
|
||||||
align={v.align || align}
|
align={v.align || align}
|
||||||
headerAlign={v.headerAlign || headerAlign}
|
headerAlign={v.headerAlign || headerAlign}
|
||||||
label={v.label}
|
label={v.label}
|
||||||
fixed={v.fixed}
|
|
||||||
width="65px"
|
width="65px"
|
||||||
></ElTableColumn>
|
></ElTableColumn>
|
||||||
)
|
)
|
||||||
|
@ -471,10 +458,10 @@ export default defineComponent({
|
||||||
default: (...args: any[]) => {
|
default: (...args: any[]) => {
|
||||||
const data = args[0]
|
const data = args[0]
|
||||||
|
|
||||||
let isPreview = false
|
let isImageUrl = false
|
||||||
isPreview =
|
if (preview.length) {
|
||||||
imagePreview.some((item) => (item as string) === v.field) ||
|
isImageUrl = preview.some((item) => (item as string) === v.field)
|
||||||
videoPreview.some((item) => (item as string) === v.field)
|
}
|
||||||
|
|
||||||
return children && children.length
|
return children && children.length
|
||||||
? renderTreeTableColumn(children)
|
? renderTreeTableColumn(children)
|
||||||
|
@ -482,8 +469,8 @@ export default defineComponent({
|
||||||
? props.slots.default(...args)
|
? props.slots.default(...args)
|
||||||
: v?.formatter
|
: v?.formatter
|
||||||
? v?.formatter?.(data.row, data.column, get(data.row, v.field), data.$index)
|
? v?.formatter?.(data.row, data.column, get(data.row, v.field), data.$index)
|
||||||
: isPreview
|
: isImageUrl
|
||||||
? renderPreview(get(data.row, v.field), v.field)
|
? renderPreview(get(data.row, v.field))
|
||||||
: get(data.row, v.field)
|
: get(data.row, v.field)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -556,12 +543,11 @@ export default defineComponent({
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{unref(getProps).showAction && !unref(getProps).customContent ? (
|
{unref(getProps).showAction ? (
|
||||||
<TableActions
|
<TableActions
|
||||||
columns={unref(getProps).columns}
|
columns={unref(getProps).columns}
|
||||||
onChangSize={changSize}
|
onChangSize={changSize}
|
||||||
onRefresh={refresh}
|
onRefresh={refresh}
|
||||||
onConfirm={confirmSetColumn}
|
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<ElTable ref={elTableRef} data={unref(getProps).data} {...unref(getBindValue)}>
|
<ElTable ref={elTableRef} data={unref(getProps).data} {...unref(getBindValue)}>
|
||||||
|
|
|
@ -1,166 +0,0 @@
|
||||||
<script setup lang="ts">
|
|
||||||
import {
|
|
||||||
ElDrawer,
|
|
||||||
ElCheckbox,
|
|
||||||
ElCheckboxGroup,
|
|
||||||
ElText,
|
|
||||||
ElRadioButton,
|
|
||||||
ElRadioGroup
|
|
||||||
} from 'element-plus'
|
|
||||||
import { TableColumn } from '../types'
|
|
||||||
import { PropType, ref, watch, unref } from 'vue'
|
|
||||||
import { cloneDeep } from 'lodash-es'
|
|
||||||
import { DEFAULT_FILTER_COLUMN } from '@/constants'
|
|
||||||
import { VueDraggable } from 'vue-draggable-plus'
|
|
||||||
|
|
||||||
const modelValue = defineModel<boolean>()
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
columns: {
|
|
||||||
type: Array as PropType<TableColumn[]>,
|
|
||||||
default: () => []
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const emit = defineEmits(['confirm'])
|
|
||||||
|
|
||||||
const oldColumns = ref<TableColumn[]>()
|
|
||||||
|
|
||||||
const settingColumns = ref<TableColumn[]>()
|
|
||||||
|
|
||||||
// 存储不要的列
|
|
||||||
const hiddenColumns = ref<TableColumn[]>([])
|
|
||||||
|
|
||||||
const defaultCheckColumns = ref<string[]>([])
|
|
||||||
const checkColumns = ref<string[]>([])
|
|
||||||
|
|
||||||
const checkAll = ref(false)
|
|
||||||
const isIndeterminate = ref(true)
|
|
||||||
const handleCheckAllChange = (val: boolean) => {
|
|
||||||
checkColumns.value = val ? unref(defaultCheckColumns) : []
|
|
||||||
isIndeterminate.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleCheckedColumnsChange = (value: string[]) => {
|
|
||||||
const checkedCount = value.length
|
|
||||||
checkAll.value = checkedCount === unref(defaultCheckColumns)?.length
|
|
||||||
isIndeterminate.value = checkedCount > 0 && checkedCount < unref(defaultCheckColumns)?.length
|
|
||||||
}
|
|
||||||
|
|
||||||
const confirm = () => {
|
|
||||||
const newColumns = cloneDeep(unref(settingColumns))?.map((item) => {
|
|
||||||
const fixed = unref(settingColumns)?.find((col) => col.field === item.field)?.fixed
|
|
||||||
item.hidden = !!!unref(checkColumns)?.includes(item.field)
|
|
||||||
item.fixed = fixed ? fixed : undefined
|
|
||||||
return item
|
|
||||||
})
|
|
||||||
emit('confirm', [...unref(hiddenColumns), ...(newColumns || [])])
|
|
||||||
modelValue.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
const restore = () => {
|
|
||||||
initColumns([...unref(hiddenColumns), ...(unref(oldColumns) || [])], true)
|
|
||||||
}
|
|
||||||
|
|
||||||
const initColumns = (columns: TableColumn[], isReStore = false) => {
|
|
||||||
const newColumns = columns?.filter((item) => {
|
|
||||||
if (!isReStore) {
|
|
||||||
item.fixed = item.fixed !== void 0 ? item.fixed : undefined
|
|
||||||
}
|
|
||||||
return (item.type && !DEFAULT_FILTER_COLUMN.includes(item.type)) || !item.type
|
|
||||||
})
|
|
||||||
if (!unref(oldColumns)?.length) {
|
|
||||||
oldColumns.value = cloneDeep(newColumns)
|
|
||||||
}
|
|
||||||
settingColumns.value = cloneDeep(newColumns)
|
|
||||||
|
|
||||||
hiddenColumns.value = cloneDeep(
|
|
||||||
columns?.filter((item) => item.type && DEFAULT_FILTER_COLUMN.includes(item.type))
|
|
||||||
)
|
|
||||||
|
|
||||||
defaultCheckColumns.value = unref(settingColumns)?.map((item) => item.field) || []
|
|
||||||
checkColumns.value =
|
|
||||||
unref(settingColumns)
|
|
||||||
?.filter((item) => !item.hidden)
|
|
||||||
?.map((item) => item.field) || []
|
|
||||||
|
|
||||||
if (unref(checkColumns)?.length === unref(defaultCheckColumns)?.length) {
|
|
||||||
checkAll.value = true
|
|
||||||
isIndeterminate.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.columns,
|
|
||||||
(columns) => {
|
|
||||||
initColumns(columns)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
immediate: true,
|
|
||||||
deep: true
|
|
||||||
}
|
|
||||||
)
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<ElDrawer v-model="modelValue" title="列设置" size="350px">
|
|
||||||
<div>
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<ElCheckbox
|
|
||||||
v-model="checkAll"
|
|
||||||
:indeterminate="isIndeterminate"
|
|
||||||
@change="handleCheckAllChange"
|
|
||||||
/>
|
|
||||||
<ElText class="ml-8px!">{{ checkColumns.length }} / {{ settingColumns?.length }}</ElText>
|
|
||||||
</div>
|
|
||||||
<ElText>固定 / 排序</ElText>
|
|
||||||
</div>
|
|
||||||
<div v-if="settingColumns?.length">
|
|
||||||
<VueDraggable
|
|
||||||
v-model="settingColumns"
|
|
||||||
target=".el-checkbox-group"
|
|
||||||
handle=".handle"
|
|
||||||
:animation="150"
|
|
||||||
>
|
|
||||||
<ElCheckboxGroup
|
|
||||||
ref="draggableWrap"
|
|
||||||
v-model="checkColumns"
|
|
||||||
@change="handleCheckedColumnsChange"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-for="item in settingColumns"
|
|
||||||
:key="item.field"
|
|
||||||
class="flex items-center justify-between mt-12px"
|
|
||||||
>
|
|
||||||
<ElCheckbox :label="item.field">
|
|
||||||
{{ item.label }}
|
|
||||||
</ElCheckbox>
|
|
||||||
<div class="flex items-center">
|
|
||||||
<ElRadioGroup size="small" v-model="item.fixed">
|
|
||||||
<ElRadioButton label="left">
|
|
||||||
<Icon icon="ep:arrow-left" />
|
|
||||||
</ElRadioButton>
|
|
||||||
<ElRadioButton :label="undefined">
|
|
||||||
<Icon icon="ep:close" />
|
|
||||||
</ElRadioButton>
|
|
||||||
<ElRadioButton label="right">
|
|
||||||
<Icon icon="ep:arrow-right" />
|
|
||||||
</ElRadioButton>
|
|
||||||
</ElRadioGroup>
|
|
||||||
|
|
||||||
<div class="ml-12px cursor-move handle"><Icon icon="ep:rank" /></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ElCheckboxGroup>
|
|
||||||
</VueDraggable>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<template #footer>
|
|
||||||
<div>
|
|
||||||
<BaseButton @click="restore">还原</BaseButton>
|
|
||||||
<BaseButton type="primary" @click="confirm">确定</BaseButton>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</ElDrawer>
|
|
||||||
</template>
|
|
|
@ -1,30 +1,36 @@
|
||||||
<script lang="tsx">
|
<script lang="tsx">
|
||||||
import { defineComponent, unref, computed, PropType, ref } from 'vue'
|
import { defineComponent, unref, computed, PropType, watch } from 'vue'
|
||||||
import { ElDropdown, ElDropdownMenu, ElDropdownItem, ComponentSize } from 'element-plus'
|
import {
|
||||||
|
ElTooltip,
|
||||||
|
ElDropdown,
|
||||||
|
ElDropdownMenu,
|
||||||
|
ElDropdownItem,
|
||||||
|
ComponentSize
|
||||||
|
// ElPopover,
|
||||||
|
// ElTree
|
||||||
|
} from 'element-plus'
|
||||||
import { Icon } from '@/components/Icon'
|
import { Icon } from '@/components/Icon'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { useAppStore } from '@/store/modules/app'
|
import { useAppStore } from '@/store/modules/app'
|
||||||
import { TableColumn } from '../types'
|
import { TableColumn } from '../types'
|
||||||
import ColumnSetting from './ColumnSetting.vue'
|
import { cloneDeep } from 'lodash-es'
|
||||||
|
// import { eachTree } from '@/utils/tree'
|
||||||
|
|
||||||
|
const appStore = useAppStore()
|
||||||
|
const sizeMap = computed(() => appStore.sizeMap)
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'TableActions',
|
name: 'TableActions',
|
||||||
components: {
|
|
||||||
ColumnSetting
|
|
||||||
},
|
|
||||||
props: {
|
props: {
|
||||||
columns: {
|
columns: {
|
||||||
type: Array as PropType<TableColumn[]>,
|
type: Array as PropType<TableColumn[]>,
|
||||||
default: () => []
|
default: () => []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['refresh', 'changSize', 'confirm'],
|
emits: ['refresh', 'changSize'],
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
const appStore = useAppStore()
|
|
||||||
const { t } = useI18n()
|
|
||||||
const sizeMap = computed(() => appStore.sizeMap)
|
|
||||||
const showSetting = ref(false)
|
|
||||||
|
|
||||||
const refresh = () => {
|
const refresh = () => {
|
||||||
emit('refresh')
|
emit('refresh')
|
||||||
}
|
}
|
||||||
|
@ -33,71 +39,111 @@ export default defineComponent({
|
||||||
emit('changSize', size)
|
emit('changSize', size)
|
||||||
}
|
}
|
||||||
|
|
||||||
const confirm = (columns: TableColumn[]) => {
|
const columns = computed(() => {
|
||||||
emit('confirm', columns)
|
return cloneDeep(props.columns).filter((v) => {
|
||||||
}
|
// 去掉type为selection的列和expand的列
|
||||||
|
if (v.type !== 'selection' && v.type !== 'expand') {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
const showColumnSetting = () => {
|
watch(
|
||||||
showSetting.value = true
|
() => columns.value,
|
||||||
}
|
(newColumns) => {
|
||||||
|
console.log('columns change:', newColumns)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
return () => (
|
return () => (
|
||||||
<>
|
<>
|
||||||
<div class="text-right h-28px flex items-center justify-end">
|
<div class="text-right h-28px flex items-center justify-end">
|
||||||
<div title="刷新" class="w-30px h-20px flex items-center justify-end" onClick={refresh}>
|
<ElTooltip content={t('common.refresh')} placement="top">
|
||||||
<Icon
|
<span onClick={refresh}>
|
||||||
icon="ant-design:sync-outlined"
|
<Icon
|
||||||
class="cursor-pointer"
|
icon="ant-design:sync-outlined"
|
||||||
hover-color="var(--el-color-primary)"
|
class="cursor-pointer"
|
||||||
/>
|
hover-color="var(--el-color-primary)"
|
||||||
</div>
|
/>
|
||||||
|
</span>
|
||||||
|
</ElTooltip>
|
||||||
|
|
||||||
<ElDropdown trigger="click" onCommand={changSize}>
|
<ElTooltip content={t('common.size')} placement="top">
|
||||||
|
<ElDropdown trigger="click" onCommand={changSize}>
|
||||||
|
{{
|
||||||
|
default: () => {
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
<Icon
|
||||||
|
icon="ant-design:column-height-outlined"
|
||||||
|
class="cursor-pointer mr-8px ml-8px"
|
||||||
|
hover-color="var(--el-color-primary)"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
dropdown: () => {
|
||||||
|
return (
|
||||||
|
<ElDropdownMenu>
|
||||||
|
{{
|
||||||
|
default: () => {
|
||||||
|
return unref(sizeMap).map((v) => {
|
||||||
|
return (
|
||||||
|
<ElDropdownItem key={v} command={v}>
|
||||||
|
{t(`size.${v}`)}
|
||||||
|
</ElDropdownItem>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
</ElDropdownMenu>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
</ElDropdown>
|
||||||
|
</ElTooltip>
|
||||||
|
|
||||||
|
{/* <ElTooltip content={t('common.columnSetting')} placement="top"> */}
|
||||||
|
{/* <ElPopover trigger="click" placement="left">
|
||||||
{{
|
{{
|
||||||
default: () => {
|
default: () => {
|
||||||
return (
|
return (
|
||||||
<div title="尺寸" class="w-30px h-20px flex items-center justify-end">
|
<div>
|
||||||
<Icon
|
<ElTree
|
||||||
icon="ant-design:column-height-outlined"
|
data={unref(columns)}
|
||||||
class="cursor-pointer"
|
show-checkbox
|
||||||
hover-color="var(--el-color-primary)"
|
default-checked-keys={unref(defaultCheckeds)}
|
||||||
|
draggable
|
||||||
|
node-key="field"
|
||||||
|
allow-drop={(_draggingNode: any, _dropNode: any, type: string) => {
|
||||||
|
if (type === 'inner') {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onNode-drag-end={onNodeDragEnd}
|
||||||
|
onCheck-change={onCheckChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
dropdown: () => {
|
reference: () => {
|
||||||
return (
|
return (
|
||||||
<ElDropdownMenu>
|
<Icon
|
||||||
{{
|
icon="ant-design:setting-outlined"
|
||||||
default: () => {
|
class="cursor-pointer"
|
||||||
return unref(sizeMap).map((v) => {
|
hoverColor="var(--el-color-primary)"
|
||||||
return (
|
/>
|
||||||
<ElDropdownItem key={v} command={v}>
|
|
||||||
{t(`size.${v}`)}
|
|
||||||
</ElDropdownItem>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
</ElDropdownMenu>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
</ElDropdown>
|
</ElPopover> */}
|
||||||
|
{/* </ElTooltip> */}
|
||||||
<div
|
|
||||||
title="列设置"
|
|
||||||
class="w-30px h-20px flex items-center justify-end"
|
|
||||||
onClick={showColumnSetting}
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
icon="ant-design:setting-outlined"
|
|
||||||
class="cursor-pointer"
|
|
||||||
hover-color="var(--el-color-primary)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<ColumnSetting v-model={showSetting.value} columns={props.columns} onConfirm={confirm} />
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,6 @@ import { useDesign } from '@/hooks/web/useDesign'
|
||||||
import { useTemplateRefsList } from '@vueuse/core'
|
import { useTemplateRefsList } from '@vueuse/core'
|
||||||
import { ElScrollbar } from 'element-plus'
|
import { ElScrollbar } from 'element-plus'
|
||||||
import { useScrollTo } from '@/hooks/event/useScrollTo'
|
import { useScrollTo } from '@/hooks/event/useScrollTo'
|
||||||
import { useTagsView } from '@/hooks/web/useTagsView'
|
|
||||||
import { cloneDeep } from 'lodash-es'
|
|
||||||
|
|
||||||
const { getPrefixCls } = useDesign()
|
const { getPrefixCls } = useDesign()
|
||||||
|
|
||||||
|
@ -21,9 +19,7 @@ const prefixCls = getPrefixCls('tags-view')
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
const { currentRoute, push } = useRouter()
|
const { currentRoute, push, replace } = useRouter()
|
||||||
|
|
||||||
const { closeAll, closeLeft, closeRight, closeOther, closeCurrent, refreshPage } = useTagsView()
|
|
||||||
|
|
||||||
const permissionStore = usePermissionStore()
|
const permissionStore = usePermissionStore()
|
||||||
|
|
||||||
|
@ -35,10 +31,6 @@ const visitedViews = computed(() => tagsViewStore.getVisitedViews)
|
||||||
|
|
||||||
const affixTagArr = ref<RouteLocationNormalizedLoaded[]>([])
|
const affixTagArr = ref<RouteLocationNormalizedLoaded[]>([])
|
||||||
|
|
||||||
const selectedTag = computed(() => tagsViewStore.getSelectedTag)
|
|
||||||
|
|
||||||
const setSelectTag = tagsViewStore.setSelectedTag
|
|
||||||
|
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
|
|
||||||
const tagsViewIcon = computed(() => appStore.getTagsViewIcon)
|
const tagsViewIcon = computed(() => appStore.getTagsViewIcon)
|
||||||
|
@ -51,30 +43,66 @@ const initTags = () => {
|
||||||
for (const tag of unref(affixTagArr)) {
|
for (const tag of unref(affixTagArr)) {
|
||||||
// Must have tag name
|
// Must have tag name
|
||||||
if (tag.name) {
|
if (tag.name) {
|
||||||
tagsViewStore.addVisitedView(cloneDeep(tag))
|
tagsViewStore.addVisitedView(tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const selectedTag = ref<RouteLocationNormalizedLoaded>()
|
||||||
|
|
||||||
// 新增tag
|
// 新增tag
|
||||||
const addTags = () => {
|
const addTags = () => {
|
||||||
const { name } = unref(currentRoute)
|
const { name } = unref(currentRoute)
|
||||||
if (name) {
|
if (name) {
|
||||||
setSelectTag(unref(currentRoute))
|
selectedTag.value = unref(currentRoute)
|
||||||
tagsViewStore.addView(unref(currentRoute))
|
tagsViewStore.addView(unref(currentRoute))
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 关闭选中的tag
|
// 关闭选中的tag
|
||||||
const closeSelectedTag = (view: RouteLocationNormalizedLoaded) => {
|
const closeSelectedTag = (view: RouteLocationNormalizedLoaded) => {
|
||||||
closeCurrent(view, () => {
|
if (view?.meta?.affix) return
|
||||||
if (isActive(view)) {
|
tagsViewStore.delView(view)
|
||||||
toLastView()
|
if (isActive(view)) {
|
||||||
}
|
toLastView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭全部
|
||||||
|
const closeAllTags = () => {
|
||||||
|
tagsViewStore.delAllViews()
|
||||||
|
toLastView()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭其它
|
||||||
|
const closeOthersTags = () => {
|
||||||
|
tagsViewStore.delOthersViews(unref(selectedTag) as RouteLocationNormalizedLoaded)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重新加载
|
||||||
|
const refreshSelectedTag = async (view?: RouteLocationNormalizedLoaded) => {
|
||||||
|
if (!view) return
|
||||||
|
tagsViewStore.delCachedView()
|
||||||
|
const { path, query } = view
|
||||||
|
await nextTick()
|
||||||
|
replace({
|
||||||
|
path: '/redirect' + path,
|
||||||
|
query: query
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 去最后一个
|
// 关闭左侧
|
||||||
|
const closeLeftTags = () => {
|
||||||
|
tagsViewStore.delLeftViews(unref(selectedTag) as RouteLocationNormalizedLoaded)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭右侧
|
||||||
|
const closeRightTags = () => {
|
||||||
|
tagsViewStore.delRightViews(unref(selectedTag) as RouteLocationNormalizedLoaded)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 跳转到最后一个
|
||||||
const toLastView = () => {
|
const toLastView = () => {
|
||||||
const visitedViews = tagsViewStore.getVisitedViews
|
const visitedViews = tagsViewStore.getVisitedViews
|
||||||
const latestView = visitedViews.slice(-1)[0]
|
const latestView = visitedViews.slice(-1)[0]
|
||||||
|
@ -93,33 +121,6 @@ const toLastView = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 关闭全部
|
|
||||||
const closeAllTags = () => {
|
|
||||||
closeAll(() => {
|
|
||||||
toLastView()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 关闭其它
|
|
||||||
const closeOthersTags = () => {
|
|
||||||
closeOther()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重新加载
|
|
||||||
const refreshSelectedTag = async (view?: RouteLocationNormalizedLoaded) => {
|
|
||||||
refreshPage(view)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 关闭左侧
|
|
||||||
const closeLeftTags = () => {
|
|
||||||
closeLeft()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 关闭右侧
|
|
||||||
const closeRightTags = () => {
|
|
||||||
closeRight()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 滚动到选中的tag
|
// 滚动到选中的tag
|
||||||
const moveToCurrentTag = async () => {
|
const moveToCurrentTag = async () => {
|
||||||
await nextTick()
|
await nextTick()
|
||||||
|
@ -210,14 +211,13 @@ const isActive = (route: RouteLocationNormalizedLoaded): boolean => {
|
||||||
// 所有右键菜单组件的元素
|
// 所有右键菜单组件的元素
|
||||||
const itemRefs = useTemplateRefsList<ComponentRef<typeof ContextMenu & ContextMenuExpose>>()
|
const itemRefs = useTemplateRefsList<ComponentRef<typeof ContextMenu & ContextMenuExpose>>()
|
||||||
|
|
||||||
// 右键菜单状态改变的时候
|
// 右键菜单装填改变的时候
|
||||||
const visibleChange = (visible: boolean, tagItem: RouteLocationNormalizedLoaded) => {
|
const visibleChange = (visible: boolean, tagItem: RouteLocationNormalizedLoaded) => {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
for (const v of unref(itemRefs)) {
|
for (const v of unref(itemRefs)) {
|
||||||
const elDropdownMenuRef = v.elDropdownMenuRef
|
const elDropdownMenuRef = v.elDropdownMenuRef
|
||||||
if (tagItem.fullPath !== v.tagItem.fullPath) {
|
if (tagItem.fullPath !== v.tagItem.fullPath) {
|
||||||
elDropdownMenuRef?.handleClose()
|
elDropdownMenuRef?.handleClose()
|
||||||
setSelectTag(tagItem)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,6 @@ import { useDesign } from '@/hooks/web/useDesign'
|
||||||
|
|
||||||
const { getPrefixCls } = useDesign()
|
const { getPrefixCls } = useDesign()
|
||||||
|
|
||||||
const emit = defineEmits(['change'])
|
|
||||||
|
|
||||||
const prefixCls = getPrefixCls('theme-switch')
|
const prefixCls = getPrefixCls('theme-switch')
|
||||||
|
|
||||||
const Sun = useIcon({ icon: 'emojione-monotone:sun', color: '#fde047' })
|
const Sun = useIcon({ icon: 'emojione-monotone:sun', color: '#fde047' })
|
||||||
|
@ -25,7 +23,6 @@ const blackColor = 'var(--el-color-black)'
|
||||||
|
|
||||||
const themeChange = (val: boolean) => {
|
const themeChange = (val: boolean) => {
|
||||||
appStore.setIsDark(val)
|
appStore.setIsDark(val)
|
||||||
emit('change', val)
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ export const SUCCESS_CODE = 0
|
||||||
/**
|
/**
|
||||||
* 请求contentType
|
* 请求contentType
|
||||||
*/
|
*/
|
||||||
export const CONTENT_TYPE: AxiosContentType = 'application/json'
|
export const CONTENT_TYPE = 'application/json'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 请求超时时间
|
* 请求超时时间
|
||||||
|
@ -22,13 +22,3 @@ export const NO_REDIRECT_WHITE_LIST = ['/login']
|
||||||
* 不重置路由白名单
|
* 不重置路由白名单
|
||||||
*/
|
*/
|
||||||
export const NO_RESET_WHITE_LIST = ['Redirect', 'Login', 'NoFind', 'Root']
|
export const NO_RESET_WHITE_LIST = ['Redirect', 'Login', 'NoFind', 'Root']
|
||||||
|
|
||||||
/**
|
|
||||||
* 表格默认过滤列设置字段
|
|
||||||
*/
|
|
||||||
export const DEFAULT_FILTER_COLUMN = ['expand', 'selection']
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否根据headers->content-type自动转换数据格式
|
|
||||||
*/
|
|
||||||
export const TRANSFORM_REQUEST_DATA = true
|
|
||||||
|
|
|
@ -78,14 +78,20 @@ const filterSearchSchema = (crudSchema: CrudSchema[]): FormSchema[] => {
|
||||||
|
|
||||||
for (let i = 0; i < length; i++) {
|
for (let i = 0; i < length; i++) {
|
||||||
const schemaItem = crudSchema[i]
|
const schemaItem = crudSchema[i]
|
||||||
const searchSchemaItem = {
|
// 判断是否隐藏
|
||||||
component: schemaItem?.search?.component || 'Input',
|
if (!schemaItem?.search?.hidden) {
|
||||||
...schemaItem.search,
|
const searchSchemaItem = {
|
||||||
field: schemaItem.field,
|
component: schemaItem?.search?.component || 'Input',
|
||||||
label: schemaItem.label
|
...schemaItem.search,
|
||||||
}
|
field: schemaItem.field,
|
||||||
|
label: schemaItem.label
|
||||||
|
}
|
||||||
|
|
||||||
searchSchema.push(searchSchemaItem)
|
// 删除不必要的字段
|
||||||
|
delete searchSchemaItem.hidden
|
||||||
|
|
||||||
|
searchSchema.push(searchSchemaItem)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return searchSchema
|
return searchSchema
|
||||||
|
@ -121,14 +127,19 @@ const filterFormSchema = (crudSchema: CrudSchema[]): FormSchema[] => {
|
||||||
for (let i = 0; i < length; i++) {
|
for (let i = 0; i < length; i++) {
|
||||||
const formItem = crudSchema[i]
|
const formItem = crudSchema[i]
|
||||||
// 判断是否隐藏
|
// 判断是否隐藏
|
||||||
const formSchemaItem = {
|
if (!formItem?.form?.hidden) {
|
||||||
component: formItem?.form?.component || 'Input',
|
const formSchemaItem = {
|
||||||
...formItem.form,
|
component: formItem?.form?.component || 'Input',
|
||||||
field: formItem.field,
|
...formItem.form,
|
||||||
label: formItem.label
|
field: formItem.field,
|
||||||
}
|
label: formItem.label
|
||||||
|
}
|
||||||
|
|
||||||
formSchema.push(formSchemaItem)
|
// 删除不必要的字段
|
||||||
|
delete formSchemaItem.hidden
|
||||||
|
|
||||||
|
formSchema.push(formSchemaItem)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return formSchema
|
return formSchema
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { useAppStoreWithOut } from '@/store/modules/app'
|
import { useAppStoreWithOut } from '@/store/modules/app'
|
||||||
|
|
||||||
|
const appStore = useAppStoreWithOut()
|
||||||
|
|
||||||
export const usePageLoading = () => {
|
export const usePageLoading = () => {
|
||||||
const loadStart = () => {
|
const loadStart = () => {
|
||||||
const appStore = useAppStoreWithOut()
|
|
||||||
appStore.setPageLoading(true)
|
appStore.setPageLoading(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadDone = () => {
|
const loadDone = () => {
|
||||||
const appStore = useAppStoreWithOut()
|
|
||||||
appStore.setPageLoading(false)
|
appStore.setPageLoading(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
import { useTagsViewStoreWithOut } from '@/store/modules/tagsView'
|
|
||||||
import { RouteLocationNormalizedLoaded, useRouter } from 'vue-router'
|
|
||||||
import { computed, nextTick, unref } from 'vue'
|
|
||||||
|
|
||||||
export const useTagsView = () => {
|
|
||||||
const tagsViewStore = useTagsViewStoreWithOut()
|
|
||||||
|
|
||||||
const { replace, currentRoute } = useRouter()
|
|
||||||
|
|
||||||
const selectedTag = computed(() => tagsViewStore.getSelectedTag)
|
|
||||||
|
|
||||||
const closeAll = (callback?: Fn) => {
|
|
||||||
tagsViewStore.delAllViews()
|
|
||||||
callback?.()
|
|
||||||
}
|
|
||||||
|
|
||||||
const closeLeft = (callback?: Fn) => {
|
|
||||||
tagsViewStore.delLeftViews(unref(selectedTag) as RouteLocationNormalizedLoaded)
|
|
||||||
callback?.()
|
|
||||||
}
|
|
||||||
|
|
||||||
const closeRight = (callback?: Fn) => {
|
|
||||||
tagsViewStore.delRightViews(unref(selectedTag) as RouteLocationNormalizedLoaded)
|
|
||||||
callback?.()
|
|
||||||
}
|
|
||||||
|
|
||||||
const closeOther = (callback?: Fn) => {
|
|
||||||
tagsViewStore.delOthersViews(unref(selectedTag) as RouteLocationNormalizedLoaded)
|
|
||||||
callback?.()
|
|
||||||
}
|
|
||||||
|
|
||||||
const closeCurrent = (view?: RouteLocationNormalizedLoaded, callback?: Fn) => {
|
|
||||||
if (view?.meta?.affix) return
|
|
||||||
tagsViewStore.delView(view || unref(currentRoute))
|
|
||||||
|
|
||||||
callback?.()
|
|
||||||
}
|
|
||||||
|
|
||||||
const refreshPage = async (view?: RouteLocationNormalizedLoaded, callback?: Fn) => {
|
|
||||||
tagsViewStore.delCachedView()
|
|
||||||
const { path, query } = view || unref(currentRoute)
|
|
||||||
await nextTick()
|
|
||||||
replace({
|
|
||||||
path: '/redirect' + path,
|
|
||||||
query: query
|
|
||||||
})
|
|
||||||
callback?.()
|
|
||||||
}
|
|
||||||
|
|
||||||
const setTitle = (title: string, path?: string) => {
|
|
||||||
tagsViewStore.setTitle(title, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
closeAll,
|
|
||||||
closeLeft,
|
|
||||||
closeRight,
|
|
||||||
closeOther,
|
|
||||||
closeCurrent,
|
|
||||||
refreshPage,
|
|
||||||
setTitle
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,10 +3,10 @@ import { isString } from '@/utils/is'
|
||||||
import { useAppStoreWithOut } from '@/store/modules/app'
|
import { useAppStoreWithOut } from '@/store/modules/app'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
|
|
||||||
|
const appStore = useAppStoreWithOut()
|
||||||
|
|
||||||
export const useTitle = (newTitle?: string) => {
|
export const useTitle = (newTitle?: string) => {
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const appStore = useAppStoreWithOut()
|
|
||||||
|
|
||||||
const title = ref(
|
const title = ref(
|
||||||
newTitle ? `${appStore.getTitle} - ${t(newTitle as string)}` : appStore.getTitle
|
newTitle ? `${appStore.getTitle} - ${t(newTitle as string)}` : appStore.getTitle
|
||||||
)
|
)
|
||||||
|
|
|
@ -71,14 +71,8 @@ export default defineComponent({
|
||||||
|
|
||||||
.@{prefix-cls} {
|
.@{prefix-cls} {
|
||||||
background-color: var(--app-content-bg-color);
|
background-color: var(--app-content-bg-color);
|
||||||
.@{prefix-cls}-content-scrollbar {
|
:deep(.@{elNamespace}-scrollbar__view) {
|
||||||
& > :deep(.el-scrollbar__wrap) {
|
height: 100% !important;
|
||||||
& > .@{elNamespace}-scrollbar__view {
|
|
||||||
display: flex;
|
|
||||||
height: 100% !important;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -6,6 +6,10 @@ import { computed } from 'vue'
|
||||||
|
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
|
|
||||||
|
const layout = computed(() => appStore.getLayout)
|
||||||
|
|
||||||
|
const fixedHeader = computed(() => appStore.getFixedHeader)
|
||||||
|
|
||||||
const footer = computed(() => appStore.getFooter)
|
const footer = computed(() => appStore.getFooter)
|
||||||
|
|
||||||
const tagsViewStore = useTagsViewStore()
|
const tagsViewStore = useTagsViewStore()
|
||||||
|
@ -13,12 +17,39 @@ const tagsViewStore = useTagsViewStore()
|
||||||
const getCaches = computed((): string[] => {
|
const getCaches = computed((): string[] => {
|
||||||
return tagsViewStore.getCachedViews
|
return tagsViewStore.getCachedViews
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const tagsView = computed(() => appStore.getTagsView)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section
|
<section
|
||||||
:class="[
|
:class="[
|
||||||
'flex-1 p-[var(--app-content-padding)] w-[calc(100%-var(--app-content-padding)-var(--app-content-padding))] bg-[var(--app-content-bg-color)] dark:bg-[var(--el-bg-color)]'
|
'p-[var(--app-content-padding)] w-[calc(100%-var(--app-content-padding)-var(--app-content-padding))] bg-[var(--app-content-bg-color)] dark:bg-[var(--el-bg-color)]',
|
||||||
|
{
|
||||||
|
'!min-h-[calc(100%-var(--app-content-padding)-var(--app-content-padding)-var(--app-footer-height))]':
|
||||||
|
(fixedHeader &&
|
||||||
|
(layout === 'classic' || layout === 'topLeft' || layout === 'top') &&
|
||||||
|
footer) ||
|
||||||
|
(!tagsView && layout === 'top' && footer),
|
||||||
|
|
||||||
|
'!min-h-[calc(100%-var(--app-content-padding)-var(--app-content-padding)-var(--app-footer-height)-var(--tags-view-height))]':
|
||||||
|
tagsView && layout === 'top' && footer,
|
||||||
|
|
||||||
|
'!min-h-[calc(100%-var(--tags-view-height)-var(--app-content-padding)-var(--app-content-padding)-var(--top-tool-height)-var(--app-footer-height))]':
|
||||||
|
!fixedHeader && layout === 'classic' && footer,
|
||||||
|
|
||||||
|
'!min-h-[calc(100%-var(--tags-view-height)-var(--app-content-padding)-var(--app-content-padding)-var(--app-footer-height))]':
|
||||||
|
!fixedHeader && layout === 'topLeft' && footer,
|
||||||
|
|
||||||
|
// '!min-h-[calc(100%-var(--app-content-padding)-var(--app-content-padding)-var(--app-footer-height)-var(--tags-view-height)-var(--top-tool-height))]':
|
||||||
|
// !fixedHeader && layout === 'top' && footer,
|
||||||
|
|
||||||
|
'!min-h-[calc(100%-var(--top-tool-height)-var(--app-content-padding)-var(--app-content-padding))]':
|
||||||
|
fixedHeader && layout === 'cutMenu' && footer,
|
||||||
|
|
||||||
|
'!min-h-[calc(100%-var(--top-tool-height)-var(--app-content-padding)-var(--app-content-padding)-var(--tags-view-height))]':
|
||||||
|
!fixedHeader && layout === 'cutMenu' && footer
|
||||||
|
}
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
<router-view>
|
<router-view>
|
||||||
|
|
|
@ -41,7 +41,8 @@ export default defineComponent({
|
||||||
id={`${variables.namespace}-tool-header`}
|
id={`${variables.namespace}-tool-header`}
|
||||||
class={[
|
class={[
|
||||||
prefixCls,
|
prefixCls,
|
||||||
'h-[var(--top-tool-height)] relative px-[var(--top-tool-p-x)] flex items-center justify-between'
|
'h-[var(--top-tool-height)] relative px-[var(--top-tool-p-x)] flex items-center justify-between',
|
||||||
|
'dark:bg-[var(--el-bg-color)]'
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
{layout.value !== 'top' ? (
|
{layout.value !== 'top' ? (
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
import 'vue/jsx'
|
// 引入windi css
|
||||||
|
|
||||||
// 引入unocss
|
|
||||||
import '@/plugins/unocss'
|
import '@/plugins/unocss'
|
||||||
|
|
||||||
// 导入全局的svg图标
|
// 导入全局的svg图标
|
||||||
|
|
|
@ -12,13 +12,7 @@ export const setupElementPlus = (app: App<Element>) => {
|
||||||
app.use(plugin)
|
app.use(plugin)
|
||||||
})
|
})
|
||||||
|
|
||||||
// 为了开发环境启动更快,一次性引入所有样式
|
|
||||||
if (import.meta.env.VITE_USE_ALL_ELEMENT_PLUS_STYLE === 'true') {
|
|
||||||
import('element-plus/dist/index.css')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
components.forEach((component) => {
|
components.forEach((component) => {
|
||||||
app.component(component.name!, component)
|
app.component(component.name, component)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
import 'virtual:svg-icons-register'
|
import 'virtual:svg-icons-register'
|
||||||
|
|
||||||
|
import '@purge-icons/generated'
|
||||||
|
|
|
@ -2,10 +2,6 @@ import { defineStore } from 'pinia'
|
||||||
import { store } from '../index'
|
import { store } from '../index'
|
||||||
import { setCssVar, humpToUnderline } from '@/utils'
|
import { setCssVar, humpToUnderline } from '@/utils'
|
||||||
import { ElMessage, ComponentSize } from 'element-plus'
|
import { ElMessage, ComponentSize } from 'element-plus'
|
||||||
import { colorIsDark, hexToRGB, lighten, mix } from '@/utils/color'
|
|
||||||
import { unref } from 'vue'
|
|
||||||
import { useCssVar } from '@vueuse/core'
|
|
||||||
import { useDark } from '@vueuse/core'
|
|
||||||
|
|
||||||
interface AppState {
|
interface AppState {
|
||||||
breadcrumb: boolean
|
breadcrumb: boolean
|
||||||
|
@ -243,7 +239,6 @@ export const useAppStore = defineStore('app', {
|
||||||
document.documentElement.classList.add('light')
|
document.documentElement.classList.add('light')
|
||||||
document.documentElement.classList.remove('dark')
|
document.documentElement.classList.remove('dark')
|
||||||
}
|
}
|
||||||
this.setPrimaryLight()
|
|
||||||
},
|
},
|
||||||
setCurrentSize(currentSize: ComponentSize) {
|
setCurrentSize(currentSize: ComponentSize) {
|
||||||
this.currentSize = currentSize
|
this.currentSize = currentSize
|
||||||
|
@ -258,76 +253,9 @@ export const useAppStore = defineStore('app', {
|
||||||
for (const key in this.theme) {
|
for (const key in this.theme) {
|
||||||
setCssVar(`--${humpToUnderline(key)}`, this.theme[key])
|
setCssVar(`--${humpToUnderline(key)}`, this.theme[key])
|
||||||
}
|
}
|
||||||
this.setPrimaryLight()
|
|
||||||
},
|
},
|
||||||
setFooter(footer: boolean) {
|
setFooter(footer: boolean) {
|
||||||
this.footer = footer
|
this.footer = footer
|
||||||
},
|
|
||||||
setPrimaryLight() {
|
|
||||||
if (this.theme.elColorPrimary) {
|
|
||||||
const elColorPrimary = this.theme.elColorPrimary
|
|
||||||
const color = this.isDark ? '#000000' : '#ffffff'
|
|
||||||
const lightList = [3, 5, 7, 8, 9]
|
|
||||||
lightList.forEach((v) => {
|
|
||||||
setCssVar(`--el-color-primary-light-${v}`, mix(color, elColorPrimary, v / 10))
|
|
||||||
})
|
|
||||||
setCssVar(`--el-color-primary-dark-2`, mix(color, elColorPrimary, 0.2))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setMenuTheme(color: string) {
|
|
||||||
const primaryColor = useCssVar('--el-color-primary', document.documentElement)
|
|
||||||
const isDarkColor = colorIsDark(color)
|
|
||||||
const theme: Recordable = {
|
|
||||||
// 左侧菜单边框颜色
|
|
||||||
leftMenuBorderColor: isDarkColor ? 'inherit' : '#eee',
|
|
||||||
// 左侧菜单背景颜色
|
|
||||||
leftMenuBgColor: color,
|
|
||||||
// 左侧菜单浅色背景颜色
|
|
||||||
leftMenuBgLightColor: isDarkColor ? lighten(color!, 6) : color,
|
|
||||||
// 左侧菜单选中背景颜色
|
|
||||||
leftMenuBgActiveColor: isDarkColor
|
|
||||||
? 'var(--el-color-primary)'
|
|
||||||
: hexToRGB(unref(primaryColor), 0.1),
|
|
||||||
// 左侧菜单收起选中背景颜色
|
|
||||||
leftMenuCollapseBgActiveColor: isDarkColor
|
|
||||||
? 'var(--el-color-primary)'
|
|
||||||
: hexToRGB(unref(primaryColor), 0.1),
|
|
||||||
// 左侧菜单字体颜色
|
|
||||||
leftMenuTextColor: isDarkColor ? '#bfcbd9' : '#333',
|
|
||||||
// 左侧菜单选中字体颜色
|
|
||||||
leftMenuTextActiveColor: isDarkColor ? '#fff' : 'var(--el-color-primary)',
|
|
||||||
// logo字体颜色
|
|
||||||
logoTitleTextColor: isDarkColor ? '#fff' : 'inherit',
|
|
||||||
// logo边框颜色
|
|
||||||
logoBorderColor: isDarkColor ? color : '#eee'
|
|
||||||
}
|
|
||||||
this.setTheme(theme)
|
|
||||||
this.setCssVarTheme()
|
|
||||||
},
|
|
||||||
setHeaderTheme(color: string) {
|
|
||||||
const isDarkColor = colorIsDark(color)
|
|
||||||
const textColor = isDarkColor ? '#fff' : 'inherit'
|
|
||||||
const textHoverColor = isDarkColor ? lighten(color!, 6) : '#f6f6f6'
|
|
||||||
const topToolBorderColor = isDarkColor ? color : '#eee'
|
|
||||||
setCssVar('--top-header-bg-color', color)
|
|
||||||
setCssVar('--top-header-text-color', textColor)
|
|
||||||
setCssVar('--top-header-hover-color', textHoverColor)
|
|
||||||
this.setTheme({
|
|
||||||
topHeaderBgColor: color,
|
|
||||||
topHeaderTextColor: textColor,
|
|
||||||
topHeaderHoverColor: textHoverColor,
|
|
||||||
topToolBorderColor
|
|
||||||
})
|
|
||||||
if (this.getLayout === 'top') {
|
|
||||||
this.setMenuTheme(color)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
initTheme() {
|
|
||||||
const isDark = useDark({
|
|
||||||
valueDark: 'dark',
|
|
||||||
valueLight: 'light'
|
|
||||||
})
|
|
||||||
isDark.value = this.getIsDark
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
persist: true
|
persist: true
|
||||||
|
|
|
@ -5,7 +5,7 @@ import en from 'element-plus/es/locale/lang/en'
|
||||||
import { useStorage } from '@/hooks/web/useStorage'
|
import { useStorage } from '@/hooks/web/useStorage'
|
||||||
import { LocaleDropdownType } from '@/components/LocaleDropdown'
|
import { LocaleDropdownType } from '@/components/LocaleDropdown'
|
||||||
|
|
||||||
const { getStorage, setStorage } = useStorage('localStorage')
|
const { getStorage, setStorage } = useStorage()
|
||||||
|
|
||||||
const elLocaleMap = {
|
const elLocaleMap = {
|
||||||
'zh-CN': zhCn,
|
'zh-CN': zhCn,
|
||||||
|
|
|
@ -151,22 +151,3 @@ const subtractLight = (color: string, amount: number) => {
|
||||||
const c = cc < 0 ? 0 : cc
|
const c = cc < 0 ? 0 : cc
|
||||||
return c.toString(16).length > 1 ? c.toString(16) : `0${c.toString(16)}`
|
return c.toString(16).length > 1 ? c.toString(16) : `0${c.toString(16)}`
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Mixes two colors.
|
|
||||||
*
|
|
||||||
* @param {string} color1 - The first color, should be a 6-digit hexadecimal color code starting with `#`.
|
|
||||||
* @param {string} color2 - The second color, should be a 6-digit hexadecimal color code starting with `#`.
|
|
||||||
* @param {number} [weight=0.5] - The weight of color1 in the mix, should be a number between 0 and 1, where 0 represents 100% of color2, and 1 represents 100% of color1.
|
|
||||||
* @returns {string} The mixed color, a 6-digit hexadecimal color code starting with `#`.
|
|
||||||
*/
|
|
||||||
export const mix = (color1: string, color2: string, weight: number = 0.5): string => {
|
|
||||||
let color = '#'
|
|
||||||
for (let i = 0; i <= 2; i++) {
|
|
||||||
const c1 = parseInt(color1.substring(1 + i * 2, 3 + i * 2), 16)
|
|
||||||
const c2 = parseInt(color2.substring(1 + i * 2, 3 + i * 2), 16)
|
|
||||||
const c = Math.round(c1 * weight + c2 * (1 - weight))
|
|
||||||
color += c.toString(16).padStart(2, '0')
|
|
||||||
}
|
|
||||||
return color
|
|
||||||
}
|
|
||||||
|
|
|
@ -47,10 +47,6 @@ export const setCssVar = (prop: string, val: any, dom = document.documentElement
|
||||||
dom.style.setProperty(prop, val)
|
dom.style.setProperty(prop, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getCssVar = (prop: string, dom = document.documentElement) => {
|
|
||||||
return getComputedStyle(dom).getPropertyValue(prop)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查找数组对象的某个下标
|
* 查找数组对象的某个下标
|
||||||
* @param {Array} ary 查找的数组
|
* @param {Array} ary 查找的数组
|
||||||
|
@ -126,14 +122,3 @@ export function toAnyString() {
|
||||||
export function firstUpperCase(str: string) {
|
export function firstUpperCase(str: string) {
|
||||||
return str.toLowerCase().replace(/( |^)[a-z]/g, (L) => L.toUpperCase())
|
return str.toLowerCase().replace(/( |^)[a-z]/g, (L) => L.toUpperCase())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 把对象转为formData
|
|
||||||
*/
|
|
||||||
export function objToFormData(obj: Recordable) {
|
|
||||||
const formData = new FormData()
|
|
||||||
Object.keys(obj).forEach((key) => {
|
|
||||||
formData.append(key, obj[key])
|
|
||||||
})
|
|
||||||
return formData
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { LoginForm, RegisterForm } from './components'
|
||||||
import { ThemeSwitch } from '@/components/ThemeSwitch'
|
import { ThemeSwitch } from '@/components/ThemeSwitch'
|
||||||
import { LocaleDropdown } from '@/components/LocaleDropdown'
|
import { LocaleDropdown } from '@/components/LocaleDropdown'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { getCssVar, underlineToHump } from '@/utils'
|
import { underlineToHump } from '@/utils'
|
||||||
import { useAppStore } from '@/store/modules/app'
|
import { useAppStore } from '@/store/modules/app'
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
import { useDesign } from '@/hooks/web/useDesign'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
|
@ -26,12 +26,6 @@ const toRegister = () => {
|
||||||
const toLogin = () => {
|
const toLogin = () => {
|
||||||
isLogin.value = true
|
isLogin.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
const themeChange = () => {
|
|
||||||
const color = getCssVar('--el-bg-color')
|
|
||||||
appStore.setMenuTheme(color)
|
|
||||||
appStore.setHeaderTheme(color)
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -72,7 +66,7 @@ const themeChange = () => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-end items-center space-x-10px">
|
<div class="flex justify-end items-center space-x-10px">
|
||||||
<ThemeSwitch @change="themeChange" />
|
<ThemeSwitch />
|
||||||
<LocaleDropdown class="lt-xl:text-white dark:text-white" />
|
<LocaleDropdown class="lt-xl:text-white dark:text-white" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -20,8 +20,12 @@ module.exports = {
|
||||||
'function-no-unknown': null,
|
'function-no-unknown': null,
|
||||||
'no-empty-source': null,
|
'no-empty-source': null,
|
||||||
'named-grid-areas-no-invalid': null,
|
'named-grid-areas-no-invalid': null,
|
||||||
|
'unicode-bom': 'never',
|
||||||
'no-descending-specificity': null,
|
'no-descending-specificity': null,
|
||||||
'font-family-no-missing-generic-family-keyword': null,
|
'font-family-no-missing-generic-family-keyword': null,
|
||||||
|
'declaration-colon-space-after': 'always-single-line',
|
||||||
|
'declaration-colon-space-before': 'never',
|
||||||
|
'declaration-block-trailing-semicolon': null,
|
||||||
'rule-empty-line-before': [
|
'rule-empty-line-before': [
|
||||||
'always',
|
'always',
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"jsxImportSource": "vue",
|
|
||||||
"lib": ["esnext", "dom"],
|
"lib": ["esnext", "dom"],
|
||||||
"baseUrl": "./",
|
"baseUrl": "./",
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
|
|
|
@ -30,7 +30,6 @@ declare global {
|
||||||
| 'application/json'
|
| 'application/json'
|
||||||
| 'application/x-www-form-urlencoded'
|
| 'application/x-www-form-urlencoded'
|
||||||
| 'multipart/form-data'
|
| 'multipart/form-data'
|
||||||
| 'text/plain'
|
|
||||||
|
|
||||||
declare type AxiosMethod = 'get' | 'post' | 'delete' | 'put'
|
declare type AxiosMethod = 'get' | 'post' | 'delete' | 'put'
|
||||||
|
|
||||||
|
|
|
@ -1,49 +1,9 @@
|
||||||
import { defineConfig, toEscapedSelector as e, presetUno, presetIcons } from 'unocss'
|
import { defineConfig, toEscapedSelector as e, presetUno } from 'unocss'
|
||||||
import transformerVariantGroup from '@unocss/transformer-variant-group'
|
import transformerVariantGroup from '@unocss/transformer-variant-group'
|
||||||
import { loadEnv } from 'vite'
|
|
||||||
|
|
||||||
const root = process.cwd()
|
|
||||||
|
|
||||||
const createPresetIcons = () => {
|
|
||||||
const isBuild = !!process.argv[4]
|
|
||||||
let env = {} as any
|
|
||||||
if (!isBuild) {
|
|
||||||
env = loadEnv(process.argv[3], root)
|
|
||||||
} else {
|
|
||||||
env = loadEnv(process.argv[4], root)
|
|
||||||
}
|
|
||||||
// @ts-ignore
|
|
||||||
if (env.VITE_USE_ONLINE_ICON === 'true') {
|
|
||||||
return []
|
|
||||||
} else {
|
|
||||||
return [
|
|
||||||
presetIcons({
|
|
||||||
prefix: ''
|
|
||||||
// 由于默认加载的是所有的图标,启动会非常慢,可以在这里去加载需要的图标,确保启动速度
|
|
||||||
// collections: {
|
|
||||||
// carbon: () => import('@iconify-json/carbon/icons.json').then(i => i.default),
|
|
||||||
// mdi: () => import('@iconify-json/mdi/icons.json').then(i => i.default),
|
|
||||||
// logos: () => import('@iconify-json/logos/icons.json').then(i => i.default),
|
|
||||||
// }
|
|
||||||
})
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
// ...UnoCSS options
|
// ...UnoCSS options
|
||||||
rules: [
|
rules: [
|
||||||
[
|
|
||||||
/^overflow-ellipsis$/,
|
|
||||||
([], { rawSelector }) => {
|
|
||||||
const selector = e(rawSelector)
|
|
||||||
return `
|
|
||||||
${selector} {
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
/^custom-hover$/,
|
/^custom-hover$/,
|
||||||
([], { rawSelector }) => {
|
([], { rawSelector }) => {
|
||||||
|
@ -140,11 +100,6 @@ ${selector}:after {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
presets: [presetUno({ dark: 'class', attributify: false }), ...createPresetIcons()],
|
presets: [presetUno({ dark: 'class', attributify: false })],
|
||||||
transformers: [transformerVariantGroup()],
|
transformers: [transformerVariantGroup()]
|
||||||
content: {
|
|
||||||
pipeline: {
|
|
||||||
include: [/\.(vue|svelte|[jt]sx|mdx?|astro|elm|php|phtml|html|ts)($|\?)/]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -12,7 +12,6 @@ import VueI18nPlugin from "@intlify/unplugin-vue-i18n/vite"
|
||||||
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
|
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
|
||||||
import { createStyleImportPlugin, ElementPlusResolve } from 'vite-plugin-style-import'
|
import { createStyleImportPlugin, ElementPlusResolve } from 'vite-plugin-style-import'
|
||||||
import UnoCSS from 'unocss/vite'
|
import UnoCSS from 'unocss/vite'
|
||||||
import { visualizer } from 'rollup-plugin-visualizer'
|
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
const root = process.cwd()
|
const root = process.cwd()
|
||||||
|
@ -40,23 +39,19 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
|
||||||
}),
|
}),
|
||||||
VueJsx(),
|
VueJsx(),
|
||||||
progress(),
|
progress(),
|
||||||
env.VITE_USE_ALL_ELEMENT_PLUS_STYLE === 'false'
|
createStyleImportPlugin({
|
||||||
? createStyleImportPlugin({
|
resolves: [ElementPlusResolve()],
|
||||||
resolves: [ElementPlusResolve()],
|
libs: [{
|
||||||
libs: [
|
libraryName: 'element-plus',
|
||||||
{
|
esModule: true,
|
||||||
libraryName: 'element-plus',
|
resolveStyle: (name) => {
|
||||||
esModule: true,
|
if (name === 'click-outside') {
|
||||||
resolveStyle: (name) => {
|
return ''
|
||||||
if (name === 'click-outside') {
|
}
|
||||||
return ''
|
return `element-plus/es/components/${name.replace(/^el-/, '')}/style/css`
|
||||||
}
|
}
|
||||||
return `element-plus/es/components/${name.replace(/^el-/, '')}/style/css`
|
}]
|
||||||
}
|
}),
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
: undefined,
|
|
||||||
EslintPlugin({
|
EslintPlugin({
|
||||||
cache: false,
|
cache: false,
|
||||||
include: ['src/**/*.vue', 'src/**/*.ts', 'src/**/*.tsx'] // 检查的文件
|
include: ['src/**/*.vue', 'src/**/*.ts', 'src/**/*.tsx'] // 检查的文件
|
||||||
|
@ -72,19 +67,17 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
|
||||||
svgoOptions: true
|
svgoOptions: true
|
||||||
}),
|
}),
|
||||||
PurgeIcons(),
|
PurgeIcons(),
|
||||||
env.VITE_USE_MOCK === 'true'
|
viteMockServe({
|
||||||
? viteMockServe({
|
ignore: /^\_/,
|
||||||
ignore: /^\_/,
|
mockPath: 'mock',
|
||||||
mockPath: 'mock',
|
localEnabled: !isBuild,
|
||||||
localEnabled: !isBuild,
|
prodEnabled: isBuild,
|
||||||
prodEnabled: isBuild,
|
injectCode: `
|
||||||
injectCode: `
|
|
||||||
import { setupProdMockServer } from '../mock/_createProductionServer'
|
import { setupProdMockServer } from '../mock/_createProductionServer'
|
||||||
|
|
||||||
setupProdMockServer()
|
setupProdMockServer()
|
||||||
`
|
`
|
||||||
})
|
}),
|
||||||
: undefined,
|
|
||||||
ViteEjsPlugin({
|
ViteEjsPlugin({
|
||||||
title: env.VITE_APP_TITLE
|
title: env.VITE_APP_TITLE
|
||||||
}),
|
}),
|
||||||
|
@ -113,30 +106,20 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
esbuild: {
|
|
||||||
pure: env.VITE_DROP_CONSOLE === 'true' ? ['console.log'] : undefined,
|
|
||||||
drop: env.VITE_DROP_DEBUGGER === 'true' ? ['debugger'] : undefined
|
|
||||||
},
|
|
||||||
build: {
|
build: {
|
||||||
target: 'es2015',
|
minify: 'terser',
|
||||||
outDir: env.VITE_OUT_DIR || 'dist',
|
outDir: env.VITE_OUT_DIR || 'dist',
|
||||||
sourcemap: env.VITE_SOURCEMAP === 'true',
|
sourcemap: env.VITE_SOURCEMAP === 'true' ? 'inline' : false,
|
||||||
// brotliSize: false,
|
// brotliSize: false,
|
||||||
rollupOptions: {
|
terserOptions: {
|
||||||
plugins: env.VITE_USE_BUNDLE_ANALYZER === 'true' ? [visualizer()] : undefined,
|
compress: {
|
||||||
// 拆包
|
drop_debugger: env.VITE_DROP_DEBUGGER === 'true',
|
||||||
output: {
|
drop_console: env.VITE_DROP_CONSOLE === 'true'
|
||||||
manualChunks: {
|
|
||||||
'vue-chunks': ['vue', 'vue-router', 'pinia', 'vue-i18n'],
|
|
||||||
'element-plus': ['element-plus'],
|
|
||||||
'wang-editor': ['@wangeditor/editor', '@wangeditor/editor-for-vue']
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
cssCodeSplit: !(env.VITE_USE_CSS_SPLIT === 'false')
|
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
port: 3005,
|
port: 4000,
|
||||||
proxy: {
|
proxy: {
|
||||||
// 选项写法
|
// 选项写法
|
||||||
'/api': {
|
'/api': {
|
||||||
|
|
Loading…
Reference in New Issue