feat: 同步master代码
This commit is contained in:
parent
607b73a7b3
commit
6a83d08309
11
.env.base
11
.env.base
|
@ -1,5 +1,5 @@
|
|||
# 环境
|
||||
NODE_ENV=development
|
||||
VITE_NODE_ENV=development
|
||||
|
||||
# 接口前缀
|
||||
VITE_API_BASE_PATH=
|
||||
|
@ -9,3 +9,12 @@ VITE_BASE_PATH=/
|
|||
|
||||
# 标题
|
||||
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 @@
|
|||
# 环境
|
||||
NODE_ENV=production
|
||||
VITE_NODE_ENV=production
|
||||
|
||||
# 接口前缀
|
||||
VITE_API_BASE_PATH=
|
||||
|
@ -21,3 +21,18 @@ VITE_OUT_DIR=dist-dev
|
|||
|
||||
# 标题
|
||||
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 @@
|
|||
# 环境
|
||||
NODE_ENV=production
|
||||
VITE_NODE_ENV=production
|
||||
|
||||
# 接口前缀
|
||||
VITE_API_BASE_PATH=
|
||||
|
@ -21,3 +21,18 @@ VITE_OUT_DIR=dist-pro
|
|||
|
||||
# 标题
|
||||
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 @@
|
|||
# 环境
|
||||
NODE_ENV=production
|
||||
VITE_NODE_ENV=production
|
||||
|
||||
# 接口前缀
|
||||
VITE_API_BASE_PATH=
|
||||
|
@ -21,3 +21,18 @@ VITE_OUT_DIR=dist-pro
|
|||
|
||||
# 标题
|
||||
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
|
16
.env.test
16
.env.test
|
@ -1,8 +1,8 @@
|
|||
# 环境
|
||||
NODE_ENV=production
|
||||
VITE_NODE_ENV=production
|
||||
|
||||
# 接口前缀
|
||||
VITE_API_BASE_PATH=test
|
||||
VITE_API_BASE_PATH=
|
||||
|
||||
# 打包路径
|
||||
VITE_BASE_PATH=/dist-test/
|
||||
|
@ -21,3 +21,15 @@ VITE_OUT_DIR=dist-test
|
|||
|
||||
# 标题
|
||||
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
|
|
@ -6,3 +6,4 @@ dist-ssr
|
|||
/dist*
|
||||
*-lock.*
|
||||
pnpm-debug
|
||||
stats.html
|
||||
|
|
|
@ -61,7 +61,6 @@
|
|||
"@commitlint/config-conventional": "^18.4.3",
|
||||
"@iconify/json": "^2.2.153",
|
||||
"@intlify/unplugin-vue-i18n": "^1.5.0",
|
||||
"@purge-icons/generated": "^0.10.0",
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"@types/inquirer": "^9.0.7",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
|
@ -97,6 +96,7 @@
|
|||
"prettier": "^3.1.0",
|
||||
"rimraf": "^5.0.5",
|
||||
"rollup": "^4.6.1",
|
||||
"rollup-plugin-visualizer": "^5.12.0",
|
||||
"stylelint": "^15.11.0",
|
||||
"stylelint-config-html": "^1.1.0",
|
||||
"stylelint-config-recommended": "^13.0.0",
|
||||
|
|
|
@ -25,6 +25,11 @@ const symbolId = computed(() => {
|
|||
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 { color, size } = props
|
||||
return {
|
||||
|
@ -40,7 +45,10 @@ const getIconifyStyle = computed(() => {
|
|||
<use :xlink:href="symbolId" />
|
||||
</svg>
|
||||
|
||||
<Icon v-else :icon="icon" :style="getIconifyStyle" />
|
||||
<template v-else>
|
||||
<Icon v-if="isUseOnline" :icon="icon" :style="getIconifyStyle" />
|
||||
<div v-else :class="`${icon} iconify`" :style="getIconifyStyle"></div>
|
||||
</template>
|
||||
</ElIcon>
|
||||
</template>
|
||||
|
||||
|
@ -49,11 +57,18 @@ const getIconifyStyle = computed(() => {
|
|||
|
||||
.@{prefix-cls},
|
||||
.iconify {
|
||||
&:hover {
|
||||
:deep(svg) {
|
||||
&:hover {
|
||||
// stylelint-disable-next-line
|
||||
color: v-bind(hoverColor) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.iconify {
|
||||
&:hover {
|
||||
// stylelint-disable-next-line
|
||||
color: v-bind(hoverColor) !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<script setup lang="ts">
|
||||
import { ElDrawer, ElDivider, ElMessage } from 'element-plus'
|
||||
import { ref, unref, computed, watch } from 'vue'
|
||||
import { ref, unref, computed } from 'vue'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { ThemeSwitch } from '@/components/ThemeSwitch'
|
||||
import { colorIsDark, lighten, hexToRGB } from '@/utils/color'
|
||||
import { useCssVar } from '@vueuse/core'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { trim, setCssVar } from '@/utils'
|
||||
import { trim, setCssVar, getCssVar } from '@/utils'
|
||||
import ColorRadioPicker from './components/ColorRadioPicker.vue'
|
||||
import InterfaceDisplay from './components/InterfaceDisplay.vue'
|
||||
import LayoutRadioPicker from './components/LayoutRadioPicker.vue'
|
||||
|
@ -95,17 +95,17 @@ const setMenuTheme = (color: string) => {
|
|||
}
|
||||
|
||||
// 监听layout变化,重置一些主题色
|
||||
watch(
|
||||
() => layout.value,
|
||||
(n) => {
|
||||
if (n === 'top' && !appStore.getIsDark) {
|
||||
headerTheme.value = '#fff'
|
||||
setHeaderTheme('#fff')
|
||||
} else {
|
||||
setMenuTheme(unref(menuTheme))
|
||||
}
|
||||
}
|
||||
)
|
||||
// watch(
|
||||
// () => layout.value,
|
||||
// (n) => {
|
||||
// if (n === 'top' && !appStore.getIsDark) {
|
||||
// headerTheme.value = '#fff'
|
||||
// setHeaderTheme('#fff')
|
||||
// } else {
|
||||
// setMenuTheme(unref(menuTheme))
|
||||
// }
|
||||
// }
|
||||
// )
|
||||
|
||||
// 拷贝
|
||||
const copyConfig = async () => {
|
||||
|
@ -192,6 +192,12 @@ const clear = () => {
|
|||
storageClear()
|
||||
window.location.reload()
|
||||
}
|
||||
|
||||
const themeChange = () => {
|
||||
const color = getCssVar('--el-bg-color')
|
||||
setMenuTheme(color)
|
||||
setHeaderTheme(color)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -211,7 +217,7 @@ const clear = () => {
|
|||
<div class="text-center">
|
||||
<!-- 主题 -->
|
||||
<ElDivider>{{ t('setting.theme') }}</ElDivider>
|
||||
<ThemeSwitch />
|
||||
<ThemeSwitch @change="themeChange" />
|
||||
|
||||
<!-- 布局 -->
|
||||
<ElDivider>{{ t('setting.layout') }}</ElDivider>
|
||||
|
|
|
@ -7,6 +7,8 @@ import { useDesign } from '@/hooks/web/useDesign'
|
|||
|
||||
const { getPrefixCls } = useDesign()
|
||||
|
||||
const emit = defineEmits(['change'])
|
||||
|
||||
const prefixCls = getPrefixCls('theme-switch')
|
||||
|
||||
const Sun = useIcon({ icon: 'emojione-monotone:sun', color: '#fde047' })
|
||||
|
@ -23,6 +25,7 @@ const blackColor = 'var(--el-color-black)'
|
|||
|
||||
const themeChange = (val: boolean) => {
|
||||
appStore.setIsDark(val)
|
||||
emit('change', val)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { useAppStoreWithOut } from '@/store/modules/app'
|
||||
|
||||
const appStore = useAppStoreWithOut()
|
||||
|
||||
export const usePageLoading = () => {
|
||||
const loadStart = () => {
|
||||
const appStore = useAppStoreWithOut()
|
||||
appStore.setPageLoading(true)
|
||||
}
|
||||
|
||||
const loadDone = () => {
|
||||
const appStore = useAppStoreWithOut()
|
||||
appStore.setPageLoading(false)
|
||||
}
|
||||
|
||||
|
|
|
@ -3,10 +3,10 @@ import { isString } from '@/utils/is'
|
|||
import { useAppStoreWithOut } from '@/store/modules/app'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
|
||||
const appStore = useAppStoreWithOut()
|
||||
|
||||
export const useTitle = (newTitle?: string) => {
|
||||
const { t } = useI18n()
|
||||
const appStore = useAppStoreWithOut()
|
||||
|
||||
const title = ref(
|
||||
newTitle ? `${appStore.getTitle} - ${t(newTitle as string)}` : appStore.getTitle
|
||||
)
|
||||
|
|
|
@ -41,8 +41,7 @@ export default defineComponent({
|
|||
id={`${variables.namespace}-tool-header`}
|
||||
class={[
|
||||
prefixCls,
|
||||
'h-[var(--top-tool-height)] relative px-[var(--top-tool-p-x)] flex items-center justify-between',
|
||||
'dark:bg-[var(--el-bg-color)]'
|
||||
'h-[var(--top-tool-height)] relative px-[var(--top-tool-p-x)] flex items-center justify-between'
|
||||
]}
|
||||
>
|
||||
{layout.value !== 'top' ? (
|
||||
|
|
|
@ -12,7 +12,13 @@ export const setupElementPlus = (app: App<Element>) => {
|
|||
app.use(plugin)
|
||||
})
|
||||
|
||||
// 为了开发环境启动更快,一次性引入所有样式
|
||||
if (import.meta.env.VITE_USE_ALL_ELEMENT_PLUS_STYLE === 'true') {
|
||||
import('element-plus/dist/index.css')
|
||||
return
|
||||
}
|
||||
|
||||
components.forEach((component) => {
|
||||
app.component(component.name, component)
|
||||
app.component(component.name!, component)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,3 +1 @@
|
|||
import 'virtual:svg-icons-register'
|
||||
|
||||
import '@purge-icons/generated'
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { defineStore } from 'pinia'
|
||||
import { store } from '../index'
|
||||
import { setCssVar, humpToUnderline } from '@/utils'
|
||||
import { mix } from '@/utils/color'
|
||||
import { ElMessage, ComponentSize } from 'element-plus'
|
||||
|
||||
interface AppState {
|
||||
|
@ -239,6 +240,7 @@ export const useAppStore = defineStore('app', {
|
|||
document.documentElement.classList.add('light')
|
||||
document.documentElement.classList.remove('dark')
|
||||
}
|
||||
this.setPrimaryLight()
|
||||
},
|
||||
setCurrentSize(currentSize: ComponentSize) {
|
||||
this.currentSize = currentSize
|
||||
|
@ -253,9 +255,21 @@ export const useAppStore = defineStore('app', {
|
|||
for (const key in this.theme) {
|
||||
setCssVar(`--${humpToUnderline(key)}`, this.theme[key])
|
||||
}
|
||||
this.setPrimaryLight()
|
||||
},
|
||||
setFooter(footer: boolean) {
|
||||
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))
|
||||
}
|
||||
}
|
||||
},
|
||||
persist: true
|
||||
|
|
|
@ -151,3 +151,22 @@ const subtractLight = (color: string, amount: number) => {
|
|||
const c = cc < 0 ? 0 : cc
|
||||
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,6 +47,10 @@ export const setCssVar = (prop: string, val: any, dom = document.documentElement
|
|||
dom.style.setProperty(prop, val)
|
||||
}
|
||||
|
||||
export const getCssVar = (prop: string, dom = document.documentElement) => {
|
||||
return getComputedStyle(dom).getPropertyValue(prop)
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找数组对象的某个下标
|
||||
* @param {Array} ary 查找的数组
|
||||
|
|
|
@ -1,9 +1,33 @@
|
|||
import { defineConfig, toEscapedSelector as e, presetUno } from 'unocss'
|
||||
import { defineConfig, toEscapedSelector as e, presetUno, presetIcons } from 'unocss'
|
||||
import transformerVariantGroup from '@unocss/transformer-variant-group'
|
||||
|
||||
const createPresetIcons = () => {
|
||||
// @ts-ignore
|
||||
if (import.meta.env.VITE_USE_ONLINE_ICON === 'true') {
|
||||
return [
|
||||
presetIcons({
|
||||
prefix: ''
|
||||
})
|
||||
]
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
export default defineConfig({
|
||||
// ...UnoCSS options
|
||||
rules: [
|
||||
[
|
||||
/^overflow-ellipsis$/,
|
||||
([], { rawSelector }) => {
|
||||
const selector = e(rawSelector)
|
||||
return `
|
||||
${selector} {
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
`
|
||||
}
|
||||
],
|
||||
[
|
||||
/^custom-hover$/,
|
||||
([], { rawSelector }) => {
|
||||
|
@ -100,6 +124,11 @@ ${selector}:after {
|
|||
}
|
||||
]
|
||||
],
|
||||
presets: [presetUno({ dark: 'class', attributify: false })],
|
||||
transformers: [transformerVariantGroup()]
|
||||
presets: [presetUno({ dark: 'class', attributify: false }), ...createPresetIcons()],
|
||||
transformers: [transformerVariantGroup()],
|
||||
content: {
|
||||
pipeline: {
|
||||
include: [/\.(vue|svelte|[jt]sx|mdx?|astro|elm|php|phtml|html|ts)($|\?)/]
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -12,6 +12,7 @@ import VueI18nPlugin from "@intlify/unplugin-vue-i18n/vite"
|
|||
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
|
||||
import { createStyleImportPlugin, ElementPlusResolve } from 'vite-plugin-style-import'
|
||||
import UnoCSS from 'unocss/vite'
|
||||
import { visualizer } from 'rollup-plugin-visualizer'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
const root = process.cwd()
|
||||
|
@ -39,9 +40,11 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
|
|||
}),
|
||||
VueJsx(),
|
||||
progress(),
|
||||
createStyleImportPlugin({
|
||||
env.VITE_USE_ALL_ELEMENT_PLUS_STYLE === 'false'
|
||||
? createStyleImportPlugin({
|
||||
resolves: [ElementPlusResolve()],
|
||||
libs: [{
|
||||
libs: [
|
||||
{
|
||||
libraryName: 'element-plus',
|
||||
esModule: true,
|
||||
resolveStyle: (name) => {
|
||||
|
@ -50,8 +53,10 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
|
|||
}
|
||||
return `element-plus/es/components/${name.replace(/^el-/, '')}/style/css`
|
||||
}
|
||||
}]
|
||||
}),
|
||||
}
|
||||
]
|
||||
})
|
||||
: undefined,
|
||||
EslintPlugin({
|
||||
cache: false,
|
||||
include: ['src/**/*.vue', 'src/**/*.ts', 'src/**/*.tsx'] // 检查的文件
|
||||
|
@ -67,7 +72,8 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
|
|||
svgoOptions: true
|
||||
}),
|
||||
PurgeIcons(),
|
||||
viteMockServe({
|
||||
env.VITE_USE_MOCK === 'true'
|
||||
? viteMockServe({
|
||||
ignore: /^\_/,
|
||||
mockPath: 'mock',
|
||||
localEnabled: !isBuild,
|
||||
|
@ -77,7 +83,8 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
|
|||
|
||||
setupProdMockServer()
|
||||
`
|
||||
}),
|
||||
})
|
||||
: undefined,
|
||||
ViteEjsPlugin({
|
||||
title: env.VITE_APP_TITLE
|
||||
}),
|
||||
|
@ -106,18 +113,28 @@ 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: {
|
||||
minify: 'terser',
|
||||
target: 'es2015',
|
||||
outDir: env.VITE_OUT_DIR || 'dist',
|
||||
sourcemap: env.VITE_SOURCEMAP === 'true' ? 'inline' : false,
|
||||
sourcemap: env.VITE_SOURCEMAP === 'true',
|
||||
// brotliSize: false,
|
||||
terserOptions: {
|
||||
compress: {
|
||||
drop_debugger: env.VITE_DROP_DEBUGGER === 'true',
|
||||
drop_console: env.VITE_DROP_CONSOLE === 'true'
|
||||
rollupOptions: {
|
||||
plugins: env.VITE_USE_BUNDLE_ANALYZER === 'true' ? [visualizer()] : undefined,
|
||||
// 拆包
|
||||
output: {
|
||||
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: {
|
||||
port: 4000,
|
||||
proxy: {
|
||||
|
|
Loading…
Reference in New Issue