【更新】使用Pinia代替Vuex

pull/103/head^2
xlzy 2023-03-23 16:48:13 +08:00 committed by 小诺
parent 1cdd40be28
commit 48736f6519
30 changed files with 1573 additions and 2236 deletions

View File

@ -102,7 +102,7 @@ snowy
|-layout == 基础布局 |-layout == 基础布局
|-locales == 多语言配置 |-locales == 多语言配置
|-router == 基础路由配置 |-router == 基础路由配置
|-store == VUEX缓存配置 |-store == Pinia缓存配置
|-style == 样式风格配置 |-style == 样式风格配置
|-utils == 工具类 |-utils == 工具类
|-views == 所有视图界面 |-views == 所有视图界面
@ -232,4 +232,4 @@ QQ技术群732230670已满、685395081
- 二次开发如用于开源竞品请先联系群主沟通,未经审核视为侵权 - 二次开发如用于开源竞品请先联系群主沟通,未经审核视为侵权
- 请不要删除和修改Snowy源码头部的版权与作者声明及出处 - 请不要删除和修改Snowy源码头部的版权与作者声明及出处

View File

@ -14,7 +14,6 @@ pnpm-debug.log*
# other files # other files
stats.html stats.html
package-lock.json
auto-imports.d.ts auto-imports.d.ts
# Editor directories and files # Editor directories and files

File diff suppressed because it is too large Load Diff

View File

@ -36,6 +36,7 @@
"js-pinyin": "^0.1.9", "js-pinyin": "^0.1.9",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"pinia": "^2.0.33",
"screenfull": "^6.0.2", "screenfull": "^6.0.2",
"sm-crypto": "^0.3.11", "sm-crypto": "^0.3.11",
"snowflake-id": "^1.1.0", "snowflake-id": "^1.1.0",
@ -47,8 +48,7 @@
"vue-router": "^4.1.6", "vue-router": "^4.1.6",
"vue3-colorpicker": "2.0.4", "vue3-colorpicker": "2.0.4",
"vue3-tree-org": "^4.1.1", "vue3-tree-org": "^4.1.1",
"vuedraggable-es": "^4.1.1", "vuedraggable-es": "^4.1.1"
"vuex": "^4.1.0"
}, },
"devDependencies": { "devDependencies": {
"@antfu/eslint-config": "^0.29.3", "@antfu/eslint-config": "^0.29.3",

View File

@ -6,8 +6,9 @@
<script setup name="App"> <script setup name="App">
import i18n from '@/locales' import i18n from '@/locales'
import store from '@/store' import { globalStore } from '@/store'
store.commit('initTheme') const store = globalStore()
store.initTheme()
const locale = i18n.global.messages[i18n.global.locale].lang const locale = i18n.global.messages[i18n.global.locale].lang
</script> </script>

View File

@ -1,18 +1,8 @@
/* eslint-disable eqeqeq */
<!--
* @Descripttion: 处理iframe持久化涉及store(VUEX)
* @version: 1.0
* @Author: sakuya
* @Date: 2021年6月30日13:20:41
* @LastEditors:
* @LastEditTime:
-->
<template> <template>
<div v-show="$route.meta.type == 'iframe'" class="iframe-pages"> <div v-show="$route.meta.type === 'iframe'" class="iframe-pages">
<iframe <iframe
v-for="item in iframeList" v-for="item in iframeList"
v-show="$route.meta.url == item.meta.url" v-show="$route.meta.url === item.meta.url"
:key="item.meta.url" :key="item.meta.url"
:src="item.meta.url" :src="item.meta.url"
frameborder="0" frameborder="0"
@ -21,20 +11,16 @@
</template> </template>
<script> <script>
import { mapState, mapActions } from 'pinia'
import { iframeStore, globalStore } from '@/store'
export default { export default {
data() { data() {
return {} return {}
}, },
computed: { computed: {
iframeList() { ...mapState(iframeStore, ['iframeList']),
return this.$store.state.iframe.iframeList ...mapState(globalStore, ['ismobile', 'layoutTags'])
},
ismobile() {
return this.$store.state.global.ismobile
},
layoutTags() {
return this.$store.state.global.layoutTags
}
}, },
watch: { watch: {
$route(e) { $route(e) {
@ -46,16 +32,16 @@
}, },
mounted() {}, mounted() {},
methods: { methods: {
...mapActions(iframeStore, ['setIframeList', 'pushIframeList', 'clearIframeList']),
push(route) { push(route) {
// eslint-disable-next-line eqeqeq if (route.meta.type === 'iframe') {
if (route.meta.type == 'iframe') {
if (this.ismobile || !this.layoutTags) { if (this.ismobile || !this.layoutTags) {
this.$store.commit('setIframeList', route) this.setIframeList(route)
} else { } else {
this.$store.commit('pushIframeList', route) this.pushIframeList(route)
} }
} else if (this.ismobile || !this.layoutTags) { } else if (this.ismobile || !this.layoutTags) {
this.$store.commit('clearIframeList') this.clearIframeList()
} }
} }
} }

View File

@ -1,5 +1,6 @@
import { mapState, mapMutations } from 'vuex' import { mapState, mapActions } from 'pinia'
import hotkeys from 'hotkeys-js' import hotkeys from 'hotkeys-js'
import { searchStore } from '@/store'
export default { export default {
mounted() { mounted() {
@ -19,19 +20,16 @@ export default {
hotkeys.unbind(this.searchHotkey.close) hotkeys.unbind(this.searchHotkey.close)
}, },
computed: { computed: {
...mapState('search', { ...mapState(searchStore, {
searchActive: (state) => state.active, searchActive: (state) => state.active,
searchHotkey: (state) => state.hotkey searchHotkey: (state) => state.hotkey
}) })
}, },
methods: { methods: {
...mapMutations({ ...mapActions(searchStore, ['toggleActive', 'setActive']),
searchToggle: 'search/toggle',
searchSet: 'search/set'
}),
// 接收点击搜索按钮 // 接收点击搜索按钮
handleSearchClick() { handleSearchClick() {
this.searchToggle() this.toggleActive()
if (this.searchActive) { if (this.searchActive) {
setTimeout(() => { setTimeout(() => {
if (this.$refs.panelSearch) { if (this.$refs.panelSearch) {
@ -42,7 +40,7 @@ export default {
}, },
searchPanelOpen() { searchPanelOpen() {
if (!this.searchActive) { if (!this.searchActive) {
this.searchSet(true) this.setActive(true)
setTimeout(() => { setTimeout(() => {
if (this.$refs.panelSearch) { if (this.$refs.panelSearch) {
this.$refs.panelSearch.focus() this.$refs.panelSearch.focus()
@ -53,7 +51,7 @@ export default {
// 关闭搜索面板 // 关闭搜索面板
searchPanelClose() { searchPanelClose() {
if (this.searchActive) { if (this.searchActive) {
this.searchSet(false) this.setActive(false)
} }
} }
} }

View File

@ -1,11 +1,22 @@
<template> <template>
<div v-if="moduleUnfoldOpen"> <div v-if="moduleUnfoldOpen">
<a-menu v-model:selectedKeys="selectedKeys" mode="horizontal" v-if="menu && menu.length > 1" class="module-menu" id="moduleMunu"> <a-menu
<a-menu-item v-for="item in menu" :key="item.id" style="padding-right: 5px;position: relative;" @click="moduleClick(item.id)"> v-model:selectedKeys="selectedKeys"
mode="horizontal"
v-if="menu && menu.length > 1"
class="module-menu"
id="moduleMunu"
>
<a-menu-item
v-for="item in menu"
:key="item.id"
style="padding-right: 5px; position: relative"
@click="moduleClick(item.id)"
>
<template #icon> <template #icon>
<component :is="item.meta.icon"/> <component :is="item.meta.icon" />
</template> </template>
<span style="margin-left:-5px">{{ item.meta.title }}</span> <span style="margin-left: -5px">{{ item.meta.title }}</span>
</a-menu-item> </a-menu-item>
</a-menu> </a-menu>
</div> </div>
@ -33,18 +44,23 @@
<script setup> <script setup>
import router from '@/router' import router from '@/router'
import tool from '@/utils/tool' import tool from '@/utils/tool'
import store from '@/store' import { globalStore } from '@/store'
import { watch } from 'vue' import { watch } from 'vue'
import { storeToRefs } from 'pinia'
const store = globalStore()
const { moduleUnfoldOpen, topHanderThemeColorOpen } = storeToRefs(store)
const moduleBackColor = ref(topHanderThemeColorOpen)
// //
watch(() => store.state.global.moduleUnfoldOpen, (newValue) => { watch(moduleUnfoldOpen, (newValue) => {
moduleUnfoldOpen.value = newValue
nextTick(() => { nextTick(() => {
setModuleBackColor() setModuleBackColor()
}) })
}) })
// //
watch(() => store.state.global.topHanderThemeColorOpen, (newValue) => { watch(topHanderThemeColorOpen, (newValue) => {
moduleBackColor.value = newValue moduleBackColor.value = newValue
setModuleBackColor() setModuleBackColor()
}) })
@ -60,9 +76,6 @@
}) })
} }
const moduleUnfoldOpen = ref(store.state.global.moduleUnfoldOpen)
const moduleBackColor = ref(store.state.global.topHanderThemeColorOpen)
onMounted(() => { onMounted(() => {
setModuleBackColor() setModuleBackColor()
}) })
@ -71,17 +84,19 @@
if (moduleUnfoldOpen.value) { if (moduleUnfoldOpen.value) {
try { try {
const moduleMunu = document.getElementById('moduleMunu') const moduleMunu = document.getElementById('moduleMunu')
moduleBackColor.value? moduleMunu.classList.add('module-menu-color') moduleBackColor.value
? moduleMunu.classList.add('module-menu-color')
: moduleMunu.classList.remove('module-menu-color') : moduleMunu.classList.remove('module-menu-color')
} catch (err) { } } catch (err) {}
setSelectedKeys() setSelectedKeys()
} }
} }
// //
const setSelectedKeys = () => { const setSelectedKeys = () => {
// //
moduleBackColor.value? selectedKeys.value = new Array([]) moduleBackColor.value
: selectedKeys.value = [tool.data.get('SNOWY_MENU_MODULE_ID')] ? (selectedKeys.value = new Array([]))
: (selectedKeys.value = [tool.data.get('SNOWY_MENU_MODULE_ID')])
} }
</script> </script>
@ -119,15 +134,16 @@
.module-comp:hover { .module-comp:hover {
background: var(--header-color-split); background: var(--header-color-split);
} }
.ant-menu-horizontal > .ant-menu-item::after, .ant-menu-horizontal > .ant-menu-submenu::after { .ant-menu-horizontal > .ant-menu-item::after,
.ant-menu-horizontal > .ant-menu-submenu::after {
content: none; content: none;
} }
.module-menu{ .module-menu {
line-height: 50px; line-height: 50px;
border-bottom: 0px; border-bottom: 0px;
width: 105%; width: 105%;
} }
.module-menu-color{ .module-menu-color {
color: white; color: white;
background-color: var(--primary-color); background-color: var(--primary-color);
} }

View File

@ -78,7 +78,8 @@
<script> <script>
import Fuse from 'fuse.js' import Fuse from 'fuse.js'
import { mapState } from 'vuex' import { mapState } from 'pinia'
import { searchStore } from '@/store'
export default { export default {
data() { data() {
@ -89,7 +90,7 @@
} }
}, },
computed: { computed: {
...mapState('search', ['pool']), ...mapState(searchStore, ['pool']),
// //
resultsList() { resultsList() {
return this.results.length === 0 || this.searchText === '' ? this.pool : this.results return this.results.length === 0 || this.searchText === '' ? this.pool : this.results
@ -207,22 +208,22 @@
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
:deep(.ant-input){ :deep(.ant-input) {
height: 35px; height: 35px;
} }
:deep(.ant-input:not(:first-child)){ :deep(.ant-input:not(:first-child)) {
padding-left: 10px; padding-left: 10px;
} }
:deep(.ant-input-prefix){ :deep(.ant-input-prefix) {
font-size: 20px; font-size: 20px;
} }
:deep(.ant-list-sm .ant-list-item){ :deep(.ant-list-sm .ant-list-item) {
padding: 4px 16px; padding: 4px 16px;
} }
:deep(.ant-list-item-meta){ :deep(.ant-list-item-meta) {
align-items: center; align-items: center;
} }
:deep(.ant-list-item.active){ :deep(.ant-list-item.active) {
background-color: var(--primary-1); background-color: var(--primary-1);
} }
.search-box { .search-box {

View File

@ -4,9 +4,9 @@
<h3>整体风格设置</h3> <h3>整体风格设置</h3>
<div class="snowy-setting-checkbox"> <div class="snowy-setting-checkbox">
<a-tooltip v-for="(a, i) in sideStyleList" :key="i" placement="top"> <a-tooltip v-for="(a, i) in sideStyleList" :key="i" placement="top">
<template #title <template #title>
><span>{{ a.tips }}</span></template <span>{{ a.tips }}</span>
> </template>
<div :class="['snowy-setting-checkbox-item', a.style]" @click="setSideStyle(a.value)"> <div :class="['snowy-setting-checkbox-item', a.style]" @click="setSideStyle(a.value)">
<check-outlined v-if="sideStyle === a.value" class="snowy-setting-checkbox-item-select-icon" /> <check-outlined v-if="sideStyle === a.value" class="snowy-setting-checkbox-item-select-icon" />
</div> </div>
@ -15,9 +15,10 @@
<h3>整体界面布局</h3> <h3>整体界面布局</h3>
<div class="snowy-setting-checkbox"> <div class="snowy-setting-checkbox">
<a-tooltip v-for="(a, i) in layoutList" :key="i" placement="top"> <a-tooltip v-for="(a, i) in layoutList" :key="i" placement="top">
<template #title <template #title>
><span>{{ a.tips }}</span></template <span>{{ a.tips }}</span>
> </template>
<div :class="['snowy-setting-checkbox-item', a.style]" @click="layoutStyle(a.value)"> <div :class="['snowy-setting-checkbox-item', a.style]" @click="layoutStyle(a.value)">
<div class="snowy-setting-layout-menu-doublerow-inner" /> <div class="snowy-setting-layout-menu-doublerow-inner" />
<check-outlined v-if="layout === a.value" class="snowy-setting-checkbox-item-select-icon" /> <check-outlined v-if="layout === a.value" class="snowy-setting-checkbox-item-select-icon" />
@ -40,45 +41,52 @@
</div> </div>
<div :style="{ marginBottom: '24px' }"> <div :style="{ marginBottom: '24px' }">
<span <span
><h4>顶栏应用主题色<a-switch style="float: right" v-model:checked="topHanderThemeColorOpen" /></h4 ><h4>
顶栏应用主题色<a-switch
style="float: right"
:checked="topHanderThemeColorOpen"
@change="changeTopHanderThemeColorOpen"
/></h4
></span> ></span>
</div> </div>
<div :style="{ marginBottom: '24px' }"> <div :style="{ marginBottom: '24px' }">
<span <span>
><h4> <h4>
顶栏主题色通栏<a-switch 顶栏主题色通栏<a-switch
style="float: right" style="float: right"
v-model:checked="topHanderThemeColorSpread" :checked="topHanderThemeColorSpread"
:disabled="!topHanderThemeColorOpen" :disabled="!topHanderThemeColorOpen"
/></h4 @change="changeTopHanderThemeColorOpen"
></span> />
</h4>
</span>
</div> </div>
<a-divider /> <a-divider />
<a-form ref="form" style="text-align: right"> <a-form ref="form" style="text-align: right">
<a-form-item label="模块坞"> <a-form-item label="模块坞">
<a-switch v-model:checked="moduleUnfoldOpen" /> <a-switch :checked="moduleUnfoldOpen" @change="toggleState('moduleUnfoldOpen')" />
</a-form-item> </a-form-item>
<a-form-item label="面包屑"> <a-form-item label="面包屑">
<a-switch v-model:checked="breadcrumbOpen" /> <a-switch :checked="breadcrumbOpen" @change="toggleState('breadcrumbOpen')" />
</a-form-item> </a-form-item>
<a-form-item label="多标签"> <a-form-item label="多标签">
<a-switch v-model:checked="layoutTagsOpen" /> <a-switch :checked="layoutTagsOpen" @change="toggleState('layoutTagsOpen')" />
</a-form-item> </a-form-item>
<a-form-item label="折叠菜单"> <a-form-item label="折叠菜单">
<a-switch v-model:checked="menuIsCollapse" /> <a-switch :checked="menuIsCollapse" @change="toggleState('menuIsCollapse')" />
</a-form-item> </a-form-item>
<a-form-item label="菜单排他展开"> <a-form-item label="菜单排他展开">
<a-switch v-model:checked="sideUniqueOpen" /> <a-switch :checked="sideUniqueOpen" @change="toggleState('sideUniqueOpen')" />
</a-form-item>
<a-form-item label="表单风格">
<a-select
v-model:value="formStyle"
style="width: 80px"
size="small"
:options="xnFormStyleOptions"
@change="formStyleChange"
/>
</a-form-item> </a-form-item>
<a-form-item label="表单风格">
<a-select
v-model:value="formStyle"
style="width: 80px"
size="small"
:options="xnFormStyleOptions"
@change="formStyleChange"
/>
</a-form-item>
</a-form> </a-form>
<a-alert <a-alert
message="以上配置可实时预览,开发者可在 config/index.js 中配置默认值,不建议在生产环境下开放布局设置" message="以上配置可实时预览,开发者可在 config/index.js 中配置默认值,不建议在生产环境下开放布局设置"
@ -89,15 +97,27 @@
</template> </template>
<script> <script>
import { colorList } from '@/config/settingConfig' import { colorList } from '../../config/settingConfig'
import { ThemeModeEnum } from '@/utils/enum' import { ThemeModeEnum } from '../../utils/enum'
import tool from '@/utils/tool' import { globalStore } from '@/store'
import { mapState, mapStores } from 'pinia'
import tool from '@/utils/tool'
const toolDataNameMap = {
menuIsCollapse: 'MENU_COLLAPSE',
sideUniqueOpen: 'SIDE_UNIQUE_OPEN',
layoutTagsOpen: 'LAYOUT_TAGS_OPEN',
breadcrumbOpen: 'BREADCRUMD_OPEN',
topHanderThemeColorOpen: 'TOP_HANDER_THEME_COLOR_OPEN',
topHanderThemeColorSpread: 'TOP_HANDER_THEME_COLOR_SPREAD',
moduleUnfoldOpen: 'MODULE_UNFOLD_OPEN'
}
export default defineComponent({ export default defineComponent({
data() { data() {
return { return {
// //
sideStyle: tool.data.get('SNOWY_THEME') || this.$store.state.global.theme, sideStyle: tool.data.get('SNOWY_THEME') || this.theme,
sideStyleList: [ sideStyleList: [
{ {
tips: '暗色主题风格', tips: '暗色主题风格',
@ -115,7 +135,6 @@
style: 'snowy-setting-checkbox-item-realdark' style: 'snowy-setting-checkbox-item-realdark'
} }
], ],
layout: tool.data.get('SNOWY_LAYOUT') || this.$store.state.global.layout,
layoutList: [ layoutList: [
{ {
tips: '经典', tips: '经典',
@ -128,117 +147,70 @@
style: 'snowy-setting-layout-menu-doublerow' style: 'snowy-setting-layout-menu-doublerow'
} }
], ],
xnFormStyleOptions: [ xnFormStyleOptions: [
{ {
label: '抽屉', label: '抽屉',
value: 'drawer' value: 'drawer'
}, },
{ {
label: '对话框', label: '对话框',
value: 'modal' value: 'modal'
} }
], ],
topHanderThemeColorOpen:
tool.data.get('SNOWY_TOP_HANDER_THEME_COLOR_OPEN') || this.$store.state.global.topHanderThemeColorOpen,
topHanderThemeColorSpread:
tool.data.get('SNOWY_TOP_HANDER_THEME_COLOR_SPREAD') ||
this.$store.state.global.topHanderThemeColorSpread,
menuIsCollapse: tool.data.get('SNOWY_MENU_COLLAPSE') || this.$store.state.global.menuIsCollapse,
sideUniqueOpen: tool.data.get('SNOWY_SIDE_UNIQUE_OPEN') || this.$store.state.global.sideUniqueOpen,
layoutTagsOpen: tool.data.get('SNOWY_LAYOUT_TAGS_OPEN') || this.$store.state.global.layoutTagsOpen,
breadcrumbOpen: tool.data.get('SNOWY_BREADCRUMD_OPEN') || this.$store.state.global.breadcrumbOpen,
moduleUnfoldOpen: tool.data.get('SNOWY_MODULE_UNFOLD_OPEN') || this.$store.state.global.moduleUnfoldOpen,
theme: tool.data.get('APP_THEME') || this.$store.state.global.theme,
themeColor: tool.data.get('SNOWY_THEME_COLOR') || this.$store.state.global.themeColor,
formStyle: tool.data.get('SNOWY_FORM_STYLE') || this.$store.state.global.formStyle,
colorList colorList
} }
}, },
watch: { computed: {
menuIsCollapse() { ...mapStores(globalStore),
this.$store.commit('TOGGLE_menuIsCollapse') ...mapState(globalStore, [
if (this.$store.state.global.menuIsCollapse) { 'theme',
tool.data.set('SNOWY_MENU_COLLAPSE', true) 'themeColor',
} else { 'layout',
tool.data.set('SNOWY_MENU_COLLAPSE', false) 'menuIsCollapse',
} 'sideUniqueOpen',
}, 'layoutTagsOpen',
sideUniqueOpen() { 'breadcrumbOpen',
this.$store.commit('TOGGLE_sideUniqueOpen') 'moduleUnfoldOpen',
if (this.$store.state.global.sideUniqueOpen) { 'topHanderThemeColorOpen',
tool.data.set('SNOWY_SIDE_UNIQUE_OPEN', true) 'topHanderThemeColorSpread'
} else { ])
tool.data.set('SNOWY_SIDE_UNIQUE_OPEN', false)
}
},
layoutTagsOpen() {
this.$store.commit('TOGGLE_layoutTagsOpen')
if (this.$store.state.global.layoutTagsOpen) {
tool.data.set('SNOWY_LAYOUT_TAGS_OPEN', true)
} else {
tool.data.set('SNOWY_LAYOUT_TAGS_OPEN', false)
}
},
breadcrumbOpen() {
this.$store.commit('TOGGLE_breadcrumbOpen')
if (this.$store.state.global.breadcrumbOpen) {
tool.data.set('SNOWY_BREADCRUMD_OPEN', true)
} else {
tool.data.set('SNOWY_BREADCRUMD_OPEN', false)
}
},
topHanderThemeColorOpen() {
this.$store.commit('TOGGLE_topHanderThemeColorOpen')
if (this.$store.state.global.topHanderThemeColorOpen) {
tool.data.set('SNOWY_TOP_HANDER_THEME_COLOR_OPEN', true)
} else {
//
tool.data.set('SNOWY_TOP_HANDER_THEME_COLOR_OPEN', false)
// false
this.topHanderThemeColorSpread = false
}
},
topHanderThemeColorSpread() {
this.$store.commit('TOGGLE_topHanderThemeColorSpread')
if (this.$store.state.global.topHanderThemeColorSpread) {
tool.data.set('SNOWY_TOP_HANDER_THEME_COLOR_SPREAD', true)
} else {
tool.data.set('SNOWY_TOP_HANDER_THEME_COLOR_SPREAD', false)
}
},
moduleUnfoldOpen() {
this.$store.commit('TOGGLE_moduleUnfoldOpen')
if (this.$store.state.global.moduleUnfoldOpen) {
tool.data.set('SNOWY_MODULE_UNFOLD_OPEN', true)
} else {
tool.data.set('SNOWY_MODULE_UNFOLD_OPEN', false)
}
},
}, },
mounted() {},
methods: { methods: {
// changeTopHanderThemeColorOpen() {
setSideStyle(value) { this.toggleState('topHanderThemeColorOpen')
this.$store.commit('SET_theme', value) if (!this.topHanderThemeColorOpen) {
this.sideStyle = value this.globalStore.topHanderThemeColorSpread = false
tool.data.set('SNOWY_THEME', value) }
}, },
// toggleState(stateName) {
this.globalStore.toggleConfig(stateName)
const toolDataName = toolDataNameMap[stateName]
tool.data.set(`SNOWY_${toolDataName}`, this.globalStore[stateName])
},
//
setSideStyle(value) {
this.globalStore.setTheme(value)
this.sideStyle = value
tool.data.set('SNOWY_THEME', value)
},
//
layoutStyle(value) { layoutStyle(value) {
this.$store.commit('SET_layout', value) this.globalStore.setLayout(value)
tool.data.set('SNOWY_LAYOUT', value) tool.data.set('SNOWY_LAYOUT', value)
this.layout = value this.layout = value
}, },
// //
tagColor(value) { tagColor(value) {
this.themeColor = value this.globalStore.themeColor = value
tool.data.set('SNOWY_THEME_COLOR', value) tool.data.set('SNOWY_THEME_COLOR', value)
this.$store.commit('SET_themeColor', value) this.globalStore.setThemeColor(value)
}, },
// //
formStyleChange(value) { formStyleChange(value) {
tool.data.set('SNOWY_FORM_STYLE', value) tool.data.set('SNOWY_FORM_STYLE', value)
this.$store.commit('SET_formStyle', value) this.$store.commit('SET_formStyle', value)
} }
} }
}) })
</script> </script>

View File

@ -19,8 +19,8 @@
<script> <script>
import NavMenu from './NavMenu.vue' import NavMenu from './NavMenu.vue'
import tool from '@/utils/tool' import { globalStore } from '@/store'
import store from '@/store' import { mapState } from 'pinia'
export default { export default {
components: { components: {
@ -69,10 +69,12 @@
data() { data() {
return { return {
visible: false, visible: false,
menu: [], menu: []
sysBaseConfig: tool.data.get('SNOWY_SYS_BASE_CONFIG') || store.state.global.sysBaseConfig
} }
}, },
computed: {
...mapState(globalStore, ['sysBaseConfig'])
},
created() { created() {
const menu = this.$router.getMenu() const menu = this.$router.getMenu()
this.menu = this.filterUrl(menu) this.menu = this.filterUrl(menu)

View File

@ -60,6 +60,8 @@
<script> <script>
import tool from '@/utils/tool' import tool from '@/utils/tool'
import XnContextMenu from '@/components/XnContextMenu/index.vue' import XnContextMenu from '@/components/XnContextMenu/index.vue'
import { iframeStore, keepAliveStore, viewTagsStore } from '@/store'
import { mapState, mapActions } from 'pinia'
export default { export default {
name: 'Tags', name: 'Tags',
@ -67,7 +69,7 @@
props: {}, props: {},
data() { data() {
return { return {
tagList: this.$store.state.viewTags.viewTags, // tagList: [],
activeKey: this.$route.fullPath, activeKey: this.$route.fullPath,
maxTabs: 20, maxTabs: 20,
contextMenuTarget: null, contextMenuTarget: null,
@ -75,6 +77,12 @@
currentContextMenuTabIndex: 0 currentContextMenuTabIndex: 0
} }
}, },
computed: {
...mapState(viewTagsStore, ['viewTags']),
tagList() {
return this.viewTags
}
},
watch: { watch: {
$route(to) { $route(to) {
this.addViewTags(to) this.addViewTags(to)
@ -98,6 +106,9 @@
} }
}, },
methods: { methods: {
...mapActions(viewTagsStore, ['addViewTags', 'pushViewTags', 'removeViewTags']),
...mapActions(iframeStore, ['addIframe', 'removeIframeList', 'refreshIframe']),
...mapActions(keepAliveStore, ['pushKeepLive', 'removeKeepLive', 'setRouteShow']),
handleTabContextMenu(evt) { handleTabContextMenu(evt) {
evt.preventDefault() evt.preventDefault()
let target = evt.target let target = evt.target
@ -152,12 +163,12 @@
this.activeKey = route.fullPath this.activeKey = route.fullPath
if (route.name && !route.meta.fullpage) { if (route.name && !route.meta.fullpage) {
this.$store.commit('pushViewTags', route) this.pushViewTags(route)
this.$store.commit('pushKeepLive', route.name) this.pushKeepLive(route.name)
} }
if (this.tagList.length - 1 > this.maxTabs) { if (this.tagList.length - 1 > this.maxTabs) {
const firstTag = this.tagList[1] const firstTag = this.tagList[1]
this.$store.commit('removeViewTags', firstTag) this.removeViewTags(firstTag)
} }
}, },
// tag // tag
@ -166,9 +177,9 @@
}, },
// tag // tag
closeSelectedTag(tag, autoPushLatestView = true) { closeSelectedTag(tag, autoPushLatestView = true) {
this.$store.commit('removeViewTags', tag) this.removeViewTags(tag)
this.$store.commit('removeIframeList', tag) this.removeIframeList(tag)
this.$store.commit('removeKeepLive', tag.name) this.removeKeepLive(tag.name)
if (autoPushLatestView && this.isActive(tag)) { if (autoPushLatestView && this.isActive(tag)) {
const latestView = this.tagList.slice(-1)[0] const latestView = this.tagList.slice(-1)[0]
if (latestView) { if (latestView) {
@ -190,13 +201,13 @@
query: nowTag.query query: nowTag.query
}) })
} }
this.$store.commit('refreshIframe', nowTag) this.refreshIframe(nowTag)
setTimeout(() => { setTimeout(() => {
this.$store.commit('removeKeepLive', nowTag.name) this.removeKeepLive(nowTag.name)
this.$store.commit('setRouteShow', false) this.setRouteShow(false)
this.$nextTick(() => { this.$nextTick(() => {
this.$store.commit('pushKeepLive', nowTag.name) this.pushKeepLive(nowTag.name)
this.$store.commit('setRouteShow', true) this.setRouteShow(true)
}) })
}, 0) }, 0)
}, },

View File

@ -81,6 +81,8 @@
import devUserMessage from './message.vue' import devUserMessage from './message.vue'
import panelSearch from './panel-search/index.vue' import panelSearch from './panel-search/index.vue'
import mixinSearch from './mixins/search' import mixinSearch from './mixins/search'
import { mapState } from 'pinia'
import { globalStore } from '@/store'
export default { export default {
components: { components: {
setting, setting,
@ -99,18 +101,9 @@
} }
}, },
computed: { computed: {
ismobile() { ...mapState(globalStore, ['ismobile', 'userInfo'])
return this.$store.state.global.ismobile
},
userInfoWatch() {
return this.$store.state.global.userInfo
}
},
watch: {
userInfoWatch(newVal, oldVal) {
this.userInfo = newVal
}
}, },
created() { created() {
// //
this.lang = new Array(this.$TOOL.data.get('APP_LANG') || this.$CONFIG.LANG) this.lang = new Array(this.$TOOL.data.get('APP_LANG') || this.$CONFIG.LANG)

View File

@ -4,7 +4,7 @@
<a-layout> <a-layout>
<a-layout-sider <a-layout-sider
v-if="!ismobile" v-if="!ismobile"
v-model:collapsed="$store.state.global.menuIsCollapse" v-model:collapsed="menuIsCollapse"
:trigger="null" :trigger="null"
collapsible collapsible
:theme="sideTheme" :theme="sideTheme"
@ -18,7 +18,7 @@
</div> </div>
</div> </div>
</header> </header>
<div :class="$store.state.global.menuIsCollapse ? 'aminui-side isCollapse' : 'aminui-side'"> <div :class="menuIsCollapse ? 'aminui-side isCollapse' : 'aminui-side'">
<div class="adminui-side-scroll"> <div class="adminui-side-scroll">
<a-menu <a-menu
v-model:openKeys="openKeys" v-model:openKeys="openKeys"
@ -51,8 +51,8 @@
<a-layout-content class="main-content-wrapper"> <a-layout-content class="main-content-wrapper">
<div id="adminui-main" class="adminui-main"> <div id="adminui-main" class="adminui-main">
<router-view v-slot="{ Component }"> <router-view v-slot="{ Component }">
<keep-alive :include="$store.state.keepAlive.keepLiveRoute"> <keep-alive :include="keepLiveRoute">
<component :is="Component" :key="$route.name" v-if="$store.state.keepAlive.routeShow" /> <component :is="Component" :key="$route.name" v-if="routeShow" />
</keep-alive> </keep-alive>
</router-view> </router-view>
<iframe-view></iframe-view> <iframe-view></iframe-view>
@ -115,7 +115,7 @@
<a-layout-sider <a-layout-sider
v-if="!ismobile" v-if="!ismobile"
v-show="layoutSiderDowbleMenu" v-show="layoutSiderDowbleMenu"
v-model:collapsed="$store.state.global.menuIsCollapse" v-model:collapsed="menuIsCollapse"
:trigger="null" :trigger="null"
width="170" width="170"
collapsible collapsible
@ -125,7 +125,7 @@
<h2 class="snowy-title">{{ pmenu.meta.title }}</h2> <h2 class="snowy-title">{{ pmenu.meta.title }}</h2>
</div> </div>
<a-menu <a-menu
v-model:collapsed="$store.state.global.menuIsCollapse" v-model:collapsed="menuIsCollapse"
v-model:openKeys="openKeys" v-model:openKeys="openKeys"
v-model:selectedKeys="selectedKeys" v-model:selectedKeys="selectedKeys"
mode="inline" mode="inline"
@ -152,14 +152,14 @@
<a-layout-content class="main-content-wrapper"> <a-layout-content class="main-content-wrapper">
<div id="adminui-main" class="adminui-main"> <div id="adminui-main" class="adminui-main">
<router-view v-slot="{ Component }"> <router-view v-slot="{ Component }">
<keep-alive :include="$store.state.keepAlive.keepLiveRoute"> <keep-alive :include="keepLiveRoute">
<component :is="Component" v-if="$store.state.keepAlive.routeShow" :key="$route.name" /> <component :is="Component" v-if="routeShow" :key="$route.name" />
</keep-alive> </keep-alive>
</router-view> </router-view>
<iframe-view></iframe-view> <iframe-view></iframe-view>
<div class="main-bottom-wrapper"> <div class="main-bottom-wrapper">
<a style="color: #a0a0a0" :href="sysBaseConfig.SNOWY_SYS_COPYRIGHT_URL" target="_blank">{{ <a style="color: #a0a0a0" :href="sysBaseConfig.SNOWY_SYS_COPYRIGHT_URL" target="_blank">{{
sysBaseConfig.SNOWY_SYS_COPYRIGHT sysBaseConfig.SNOWY_SYS_COPYRIGHT
}}</a> }}</a>
</div> </div>
</div> </div>
@ -183,8 +183,8 @@
import iframeView from './components/iframeView.vue' import iframeView from './components/iframeView.vue'
import moduleMenu from './components/moduleMenu.vue' import moduleMenu from './components/moduleMenu.vue'
import { ThemeModeEnum } from '@/utils/enum' import { ThemeModeEnum } from '@/utils/enum'
import tool from '@/utils/tool' import { globalStore, keepAliveStore } from '@/store'
import store from '@/store' import { mapState, mapActions } from 'pinia'
export default defineComponent({ export default defineComponent({
name: 'Index', name: 'Index',
@ -208,39 +208,30 @@
onSelectTag: false, onSelectTag: false,
selectedKeys: [], selectedKeys: [],
openKeys: [], openKeys: [],
openKeysOther: [], openKeysOther: []
sysBaseConfig: tool.data.get('SNOWY_SYS_BASE_CONFIG') || store.state.global.sysBaseConfig
} }
}, },
computed: { computed: {
...mapState(globalStore, [
'theme',
'ismobile',
'layout',
'layoutTagsOpen',
'menuIsCollapse',
'breadcrumbOpen',
'topHanderThemeColorOpen',
'topHanderThemeColor',
'sideUniqueOpen',
'sysBaseConfig'
]),
...mapState(keepAliveStore, ['keepLiveRoute', 'routeShow']),
sideTheme() { sideTheme() {
const theme = this.$store.state.global.theme const theme = this.theme
return theme === ThemeModeEnum.REAL_DARK ? ThemeModeEnum.DARK : theme return theme === ThemeModeEnum.REAL_DARK ? ThemeModeEnum.DARK : theme
}, },
secondMenuSideTheme() { secondMenuSideTheme() {
const theme = this.$store.state.global.theme const theme = this.theme
return theme === ThemeModeEnum.REAL_DARK ? ThemeModeEnum.DARK : ThemeModeEnum.LIGHT return theme === ThemeModeEnum.REAL_DARK ? ThemeModeEnum.DARK : ThemeModeEnum.LIGHT
},
ismobile() {
return this.$store.state.global.ismobile
},
layout() {
return this.$store.state.global.layout
},
layoutTagsOpen() {
return this.$store.state.global.layoutTagsOpen
},
menuIsCollapse() {
return this.$store.state.global.menuIsCollapse
},
breadcrumbOpen() {
return this.$store.state.global.breadcrumbOpen
},
topHanderThemeColorOpen() {
return this.$store.state.global.topHanderThemeColorOpen
},
topHanderThemeColorSpread() {
return this.$store.state.global.topHanderThemeColorSpread
} }
}, },
watch: { watch: {
@ -294,6 +285,7 @@
this.switchoverTopHanderThemeColor() this.switchoverTopHanderThemeColor()
}, },
methods: { methods: {
...mapActions(globalStore, ['setTheme', 'setIsmobile', 'setLayout', 'setMenuIsCollapse']),
// //
switchModule(id) { switchModule(id) {
const menu = this.moduleMenu const menu = this.moduleMenu
@ -335,11 +327,7 @@
}, },
onLayoutResize() { onLayoutResize() {
const clientWidth = document.body.clientWidth const clientWidth = document.body.clientWidth
if (clientWidth < 992) { this.setIsmobile(clientWidth < 992)
this.$store.commit('SET_ismobile', true)
} else {
this.$store.commit('SET_ismobile', false)
}
}, },
// //
showThis() { showThis() {
@ -361,7 +349,7 @@
if (!this.onSelectTag) { if (!this.onSelectTag) {
const pidKey = this.getParentKeys(this.menu, active) const pidKey = this.getParentKeys(this.menu, active)
this.openKeys = pidKey this.openKeys = pidKey
} else if (this.$store.state.global.sideUniqueOpen) { } else if (this.sideUniqueOpen) {
const pidKey = this.getParentKeys(this.menu, active) const pidKey = this.getParentKeys(this.menu, active)
this.openKeys = pidKey this.openKeys = pidKey
} }
@ -412,7 +400,7 @@
}, },
// / // /
onOpenChange(keys) { onOpenChange(keys) {
if (this.$store.state.global.sideUniqueOpen) { if (this.sideUniqueOpen) {
// //
const openKey = keys[keys.length - 1] const openKey = keys[keys.length - 1]
if (keys.length > 1) { if (keys.length > 1) {
@ -477,19 +465,19 @@
: header.classList.remove('snowy-header-primary-color') : header.classList.remove('snowy-header-primary-color')
// //
const headerLogin = document.getElementById('snowyHeaderLogo') const headerLogin = document.getElementById('snowyHeaderLogo')
try{ try {
this.topHanderThemeColorSpread this.topHanderThemeColorSpread
? headerLogin.classList.add('snowy-header-logo-primary-color') ? headerLogin.classList.add('snowy-header-logo-primary-color')
: headerLogin.classList.remove('snowy-header-logo-primary-color') : headerLogin.classList.remove('snowy-header-logo-primary-color')
}catch (e) { } } catch (e) {}
// //
if (this.layout === 'doublerow') { if (this.layout === 'doublerow') {
const snowyDoublerowSideTop = document.getElementById('snowyDoublerowSideTop') const snowyDoublerowSideTop = document.getElementById('snowyDoublerowSideTop')
try{ try {
this.topHanderThemeColorSpread this.topHanderThemeColorSpread
? snowyDoublerowSideTop.classList.add('snowy-doublerow-side-top-primary-color') ? snowyDoublerowSideTop.classList.add('snowy-doublerow-side-top-primary-color')
: snowyDoublerowSideTop.classList.remove('snowy-doublerow-side-top-primary-color') : snowyDoublerowSideTop.classList.remove('snowy-doublerow-side-top-primary-color')
}catch (e) { } } catch (e) {}
} }
} }
} }

View File

@ -1,15 +1,16 @@
import { createApp } from 'vue' import { createApp } from 'vue'
import Antd from 'ant-design-vue' import Antd from 'ant-design-vue'
import { createPinia } from 'pinia'
import './style/index.less' import './style/index.less'
import snowy from './snowy' import snowy from './snowy'
import i18n from './locales' import i18n from './locales'
import router from './router' import router from './router'
import store from './store'
import App from './App.vue' import App from './App.vue'
import './tailwind.css' import './tailwind.css'
const app = createApp(App) const app = createApp(App)
app.use(store) app.use(createPinia())
app.use(router) app.use(router)
app.use(Antd) app.use(Antd)
app.use(i18n) app.use(i18n)

View File

@ -19,8 +19,7 @@ import userRoutes from '@/config/route'
import tool from '@/utils/tool' import tool from '@/utils/tool'
import { cloneDeep } from 'lodash-es' import { cloneDeep } from 'lodash-es'
const modules = import.meta.glob('/src/views/**/**.vue') const modules = import.meta.glob('/src/views/**/**.vue')
import store from '@/store' import { globalStore, searchStore } from '@/store'
const sysBaseConfig = tool.data.get('SNOWY_SYS_BASE_CONFIG') || store.state.global.sysBaseConfig
// 进度条配置 // 进度条配置
NProgress.configure({ showSpinner: false, speed: 500 }) NProgress.configure({ showSpinner: false, speed: 500 })
@ -42,7 +41,7 @@ const router = createRouter({
}) })
// 设置标题 // 设置标题
document.title = sysBaseConfig.SNOWY_SYS_NAME // document.title = sysBaseConfig.SNOWY_SYS_NAME
// 判断是否已加载过动态/静态路由 // 判断是否已加载过动态/静态路由
const isGetRouter = ref(false) const isGetRouter = ref(false)
@ -57,6 +56,9 @@ const whiteList = exportWhiteListFromRouter(whiteListRouters)
router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from, next) => {
NProgress.start() NProgress.start()
const store = globalStore()
const sysBaseConfig = tool.data.get('SNOWY_SYS_BASE_CONFIG') || store.sysBaseConfig
// 动态标题 // 动态标题
document.title = to.meta.title document.title = to.meta.title
? `${to.meta.title} - ${sysBaseConfig.SNOWY_SYS_NAME}` ? `${to.meta.title} - ${sysBaseConfig.SNOWY_SYS_NAME}`
@ -109,7 +111,9 @@ router.beforeEach(async (to, from, next) => {
menuRouter.forEach((item) => { menuRouter.forEach((item) => {
router.addRoute('layout', item) router.addRoute('layout', item)
}) })
store.commit('search/init', menuRouter)
const search_store = searchStore()
search_store.init(menuRouter)
isGetRouter.value = true isGetRouter.value = true
next({ ...to, replace: true }) next({ ...to, replace: true })
return false return false

View File

@ -9,14 +9,15 @@
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip * 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/ */
import { nextTick } from 'vue' import { nextTick } from 'vue'
import store from '@/store' import { viewTagsStore } from '@/store'
export function beforeEach(to, from) { export function beforeEach(to, from) {
const adminMain = document.querySelector('#adminui-main') const adminMain = document.querySelector('#adminui-main')
if (!adminMain) { if (!adminMain) {
return false return false
} }
store.commit('updateViewTags', { const store = viewTagsStore()
store.updateViewTags({
fullPath: from.fullPath, fullPath: from.fullPath,
scrollTop: adminMain.scrollTop scrollTop: adminMain.scrollTop
}) })
@ -28,7 +29,8 @@ export function afterEach(to) {
return false return false
} }
nextTick(() => { nextTick(() => {
const beforeRoute = store.state.viewTags.viewTags.filter((v) => v.fullPath == to.fullPath)[0] const store = viewTagsStore()
const beforeRoute = store.viewTags.filter((v) => v.fullPath == to.fullPath)[0]
if (beforeRoute) { if (beforeRoute) {
adminMain.scrollTop = beforeRoute.scrollTop || 0 adminMain.scrollTop = beforeRoute.scrollTop || 0
} }

View File

@ -0,0 +1,100 @@
import { defineStore } from 'pinia'
import { changeColor } from '@/utils/themeUtil'
import config from '@/config'
import { message } from 'ant-design-vue'
import tool from '@/utils/tool'
const toolDataGet = (key) => {
return tool.data.get(key)
}
// 获取缓存中的,如果取不到那就用配置的
const getCacheConfig = (value) => {
const data = toolDataGet(value)
if (data === null) {
return config[value]
}
return data
}
export const globalStore = defineStore({
id: 'global',
state: () => ({
// 移动端布局
ismobile: false,
// 布局
layout: getCacheConfig('SNOWY_LAYOUT'),
// 菜单是否折叠 toggle
menuIsCollapse: getCacheConfig('SNOWY_MENU_COLLAPSE'),
// 侧边菜单是否排他展开
sideUniqueOpen: getCacheConfig('SNOWY_SIDE_UNIQUE_OPEN'),
// 多标签栏
layoutTagsOpen: getCacheConfig('SNOWY_LAYOUT_TAGS_OPEN'),
// 是否展示面包屑
breadcrumbOpen: getCacheConfig('SNOWY_BREADCRUMD_OPEN'),
// 顶栏是否应用主题色
topHanderThemeColorOpen: getCacheConfig('SNOWY_TOP_HANDER_THEME_COLOR_OPEN'),
// 顶栏主题色通栏
topHanderThemeColorSpread: getCacheConfig('SNOWY_TOP_HANDER_THEME_COLOR_SPREAD'),
// 模块坞
moduleUnfoldOpen: getCacheConfig('SNOWY_MODULE_UNFOLD_OPEN'),
// 主题
theme: getCacheConfig('SNOWY_THEME'),
// 主题颜色
themeColor: toolDataGet('SNOWY_THEME_COLOR') || config.COLOR,
// 用户信息
userInfo: toolDataGet('USER_INFO') || {},
// 系统配置
sysBaseConfig: toolDataGet('SNOWY_SYS_BASE_CONFIG') || config.SYS_BASE_CONFIG
}),
getters: {},
actions: {
setIsmobile(key) {
this.ismobile = key
},
setLayout(key) {
this.layout = key
},
setTheme(key) {
this.theme = key
const closeMessage = message.loading(`加载中...`)
changeColor(this.themeColor, key).then(closeMessage)
},
setThemeColor(key) {
this.themeColor = key
const closeMessage = message.loading(`加载中...`)
changeColor(key, this.theme).then(closeMessage)
},
initTheme() {
const closeMessage = message.loading(`加载中...`)
changeColor(this.themeColor, this.theme).then(closeMessage)
},
toggleConfig(key) {
this[key] = !this[key]
},
toggle_SideUniqueOpen() {
this.sideUniqueOpen = !this.sideUniqueOpen
},
toggle_LayoutTagsOpen() {
this.layoutTagsOpen = !this.layoutTagsOpen
},
toggle_BreadcrumbOpen() {
this.breadcrumbOpen = !this.breadcrumbOpen
},
toggle_TopHanderThemeColorOpen() {
this.topHanderThemeColorOpen = !this.topHanderThemeColorOpen
},
toggle_TopHanderThemeColorSpread() {
this.topHanderThemeColorSpread = !this.topHanderThemeColorSpread
},
toggle_ModuleUnfoldOpen() {
this.moduleUnfoldOpen = !this.moduleUnfoldOpen
},
setUserInfo(key) {
this.userInfo = key
},
setSysBaseConfig(key) {
this.sysBaseConfig = key
}
}
})

View File

@ -8,31 +8,34 @@
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作 * 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip * 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/ */
/* eslint-disable eqeqeq */ import { defineStore } from 'pinia'
export default {
state: { export const iframeStore = defineStore({
id: 'iframe',
state: () => ({
iframeList: [] iframeList: []
}, }),
mutations: { getters: {},
setIframeList(state, route) { actions: {
state.iframeList = [] setIframeList(route) {
state.iframeList.push(route) this.iframeList = []
this.iframeList.push(route)
}, },
pushIframeList(state, route) { pushIframeList(route) {
const target = state.iframeList.find((item) => item.path === route.path) const target = this.iframeList.find((item) => item.path === route.path)
if (!target) { if (!target) {
state.iframeList.push(route) this.iframeList.push(route)
} }
}, },
removeIframeList(state, route) { removeIframeList(route) {
state.iframeList.forEach((item, index) => { this.iframeList.forEach((item, index) => {
if (item.path === route.path) { if (item.path === route.path) {
state.iframeList.splice(index, 1) this.iframeList.splice(index, 1)
} }
}) })
}, },
refreshIframe(state, route) { refreshIframe(route) {
state.iframeList.forEach((item) => { this.iframeList.forEach((item) => {
if (item.path === route.path) { if (item.path === route.path) {
const url = route.meta.url const url = route.meta.url
item.meta.url = '' item.meta.url = ''
@ -42,8 +45,8 @@ export default {
} }
}) })
}, },
clearIframeList(state) { clearIframeList() {
state.iframeList = [] this.iframeList = []
} }
} }
} })

View File

@ -1,27 +1,5 @@
/** export * from './global'
* Copyright [2022] [https://www.xiaonuo.vip] export * from './search'
* Snowy采用APACHE LICENSE 2.0开源协议您在使用过程中需要注意以下几点 export * from './iframe'
* 1.请不要删除和修改根目录下的LICENSE文件 export * from './keepAlive'
* 2.请不要删除和修改Snowy源码头部的版权声明 export * from './viewTags'
* 3.本项目代码可免费商业使用商业使用请保留源码和相关描述文件的项目出处作者声明等
* 4.分发源码时候请注明软件出处 https://www.xiaonuo.vip
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
import { createStore } from 'vuex'
import global from './modules/global'
import iframe from './modules/iframe'
import keepAlive from './modules/keepAlive'
import viewTags from './modules/viewTags'
import search from './modules/search'
// 自动import导入所有 vuex 模块
export default createStore({
modules: {
global,
iframe,
keepAlive,
viewTags,
search
}
})

View File

@ -8,37 +8,39 @@
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作 * 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip * 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/ */
export default { import { defineStore } from 'pinia'
state: {
export const keepAliveStore = defineStore({
id: 'keepAlive',
state: () => ({
keepLiveRoute: [], keepLiveRoute: [],
routeKey: null, routeKey: null,
routeShow: true routeShow: true
}, }),
mutations: { getters: {},
pushKeepLive(state, component) {
if (!state.keepLiveRoute.includes(component)) {
state.keepLiveRoute.push(component)
}
},
removeKeepLive(state, component) {
const index = state.keepLiveRoute.indexOf(component)
if (index !== -1) {
state.keepLiveRoute.splice(index, 1)
}
},
clearKeepLive(state) {
state.keepLiveRoute = []
},
setRouteKey(state, key) {
state.routeKey = key
},
setRouteShow(state, key) {
state.routeShow = key
}
},
actions: { actions: {
setRouteKey({ commit }, key) { pushKeepLive(component) {
commit('setRouteKey', key) if (!this.keepLiveRoute.includes(component)) {
this.keepLiveRoute.push(component)
}
},
removeKeepLive(component) {
const index = this.keepLiveRoute.indexOf(component)
if (index !== -1) {
this.keepLiveRoute.splice(index, 1)
}
},
clearKeepLive() {
this.keepLiveRoute = []
},
setRouteKey(key) {
this.routeKey = key
},
setRouteShow(key) {
this.routeShow = key
},
setRouteKeyAction(key) {
this.setRouteKey(key)
} }
} }
} })

View File

@ -1,112 +0,0 @@
/**
* Copyright [2022] [https://www.xiaonuo.vip]
* Snowy采用APACHE LICENSE 2.0开源协议您在使用过程中需要注意以下几点
* 1.请不要删除和修改根目录下的LICENSE文件
* 2.请不要删除和修改Snowy源码头部的版权声明
* 3.本项目代码可免费商业使用商业使用请保留源码和相关描述文件的项目出处作者声明等
* 4.分发源码时候请注明软件出处 https://www.xiaonuo.vip
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
import { changeColor, getLocalSetting } from '@/utils/themeUtil'
import config from '@/config'
import { message } from 'ant-design-vue'
import tool from '@/utils/tool'
const toolDataGet = (key) => {
return tool.data.get(key)
}
// 获取缓存中的,如果取不到那就用配置的
const getCacheConfig = (value) => {
const data = toolDataGet(value)
if (data === null) {
return config[value]
}
return data
}
export default {
state: {
// 移动端布局
ismobile: false,
// 布局
layout: getCacheConfig('SNOWY_LAYOUT'),
// 菜单是否折叠 toggle
menuIsCollapse: getCacheConfig('SNOWY_MENU_COLLAPSE'),
// 侧边菜单是否排他展开
sideUniqueOpen: getCacheConfig('SNOWY_SIDE_UNIQUE_OPEN'),
// 多标签栏
layoutTagsOpen: getCacheConfig('SNOWY_LAYOUT_TAGS_OPEN'),
// 是否展示面包屑
breadcrumbOpen: getCacheConfig('SNOWY_BREADCRUMD_OPEN'),
// 顶栏是否应用主题色
topHanderThemeColorOpen: getCacheConfig('SNOWY_TOP_HANDER_THEME_COLOR_OPEN'),
// 顶栏主题色通栏
topHanderThemeColorSpread:
getCacheConfig('SNOWY_TOP_HANDER_THEME_COLOR_SPREAD'),
// 模块坞
moduleUnfoldOpen: getCacheConfig('SNOWY_MODULE_UNFOLD_OPEN'),
// 主题
theme: getCacheConfig('SNOWY_THEME'),
// 主题颜色
themeColor: toolDataGet('SNOWY_THEME_COLOR') || config.COLOR,
// 整体表单风格
formStyle: getCacheConfig('SNOWY_FORM_STYLE'),
// 用户信息
userInfo: toolDataGet('USER_INFO') || {},
// 系统配置
sysBaseConfig: toolDataGet('SNOWY_SYS_BASE_CONFIG') || config.SYS_BASE_CONFIG
},
mutations: {
SET_ismobile(state, key) {
state.ismobile = key
},
SET_layout(state, key) {
state.layout = key
},
SET_theme(state, key) {
state.theme = key
const closeMessage = message.loading(`加载中...`)
changeColor(state.themeColor, key).then(closeMessage)
},
SET_themeColor(state, key) {
state.themeColor = key
const closeMessage = message.loading(`加载中...`)
changeColor(key, state.theme).then(closeMessage)
},
initTheme(state) {
const closeMessage = message.loading(`加载中...`)
changeColor(state.themeColor, state.theme).then(closeMessage)
},
TOGGLE_menuIsCollapse(state) {
state.menuIsCollapse = !state.menuIsCollapse
},
TOGGLE_sideUniqueOpen(state) {
state.sideUniqueOpen = !state.sideUniqueOpen
},
TOGGLE_layoutTagsOpen(state) {
state.layoutTagsOpen = !state.layoutTagsOpen
},
TOGGLE_breadcrumbOpen(state) {
state.breadcrumbOpen = !state.breadcrumbOpen
},
TOGGLE_topHanderThemeColorOpen(state) {
state.topHanderThemeColorOpen = !state.topHanderThemeColorOpen
},
TOGGLE_topHanderThemeColorSpread(state) {
state.topHanderThemeColorSpread = !state.topHanderThemeColorSpread
},
TOGGLE_moduleUnfoldOpen(state) {
state.moduleUnfoldOpen = !state.moduleUnfoldOpen
},
SET_formStyle(state, key) {
state.formStyle = key
},
SET_userInfo(state, key) {
state.userInfo = key
},
SET_sysBaseConfig(state, key) {
state.sysBaseConfig = key
}
}
}

View File

@ -1,29 +1,25 @@
import '@/utils/objects' import '@/utils/objects'
import { defineStore } from 'pinia'
export default { export const searchStore = defineStore({
namespaced: true, id: 'search',
state: { state: () => ({
// 搜索面板激活状态
active: false, active: false,
// 快捷键
hotkey: { hotkey: {
open: 's', open: 's',
close: 'esc' close: 'esc'
}, },
// 所有可以搜索的页面
pool: [] pool: []
}, }),
mutations: { getters: {},
// 切换激活状态 actions: {
toggle(state) { toggleActive() {
state.active = !state.active this.active = !this.active
}, },
// 设置激活模式 setActive(active) {
set(state, active) { this.active = active
state.active = active
}, },
// 初始化 init(menu) {
init(state, menu) {
const pool = [] const pool = []
const getFullName = function (meta) { const getFullName = function (meta) {
if (meta.breadcrumb) { if (meta.breadcrumb) {
@ -40,7 +36,7 @@ export default {
if ('menu' === m.meta.type) { if ('menu' === m.meta.type) {
if (m.children) { if (m.children) {
push(m.children) push(m.children)
} else if (m.children === null){ } else if (m.children === null) {
pool.push({ pool.push({
icon: m.meta.icon, icon: m.meta.icon,
path: m.path, path: m.path,
@ -55,7 +51,7 @@ export default {
}) })
} }
push(menu) push(menu)
state.pool = pool this.pool = pool
} }
} }
} })

View File

@ -8,43 +8,46 @@
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作 * 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip * 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/ */
/* eslint-disable eqeqeq */ import { defineStore } from 'pinia'
export default {
state: { export const viewTagsStore = defineStore({
id: 'viewTags',
state: () => ({
viewTags: [] viewTags: []
}, }),
mutations: { getters: {},
pushViewTags(state, route) { actions: {
const target = state.viewTags.find((item) => item.fullPath === route.fullPath) pushViewTags(route) {
const target = this.viewTags.find((item) => item.fullPath === route.fullPath)
const isName = route.name const isName = route.name
if (!target && isName) { if (!target && isName) {
state.viewTags.push(route) this.viewTags.push(route)
} }
}, },
removeViewTags(state, route) { removeViewTags(route) {
state.viewTags.forEach((item, index) => { this.viewTags.forEach((item, index) => {
if (item.fullPath === route.fullPath) { if (item.fullPath === route.fullPath) {
state.viewTags.splice(index, 1) this.viewTags.splice(index, 1)
} }
}) })
}, },
updateViewTags(state, route) { updateViewTags(route) {
state.viewTags.forEach((item) => { this.viewTags.forEach((item) => {
if (item.fullPath == route.fullPath) { if (item.fullPath == route.fullPath) {
item = Object.assign(item, route) Object.assign(item, route)
} }
}) })
}, },
updateViewTagsTitle(state, title = '') { updateViewTagsTitle(title = '') {
const nowFullPath = location.hash.substring(1) const nowFullPath = location.hash.substring(1)
state.viewTags.forEach((item) => { this.viewTags.forEach((item) => {
if (item.fullPath == nowFullPath) { if (item.fullPath == nowFullPath) {
item.meta.title = title item.meta.title = title
} }
}) })
}, },
clearViewTags(state) { clearViewTags() {
state.viewTags = [] this.viewTags = []
} }
} }
} })

View File

@ -12,28 +12,29 @@ import { nextTick } from 'vue'
import NProgress from 'nprogress' import NProgress from 'nprogress'
import 'nprogress/nprogress.css' import 'nprogress/nprogress.css'
import router from '@/router' import router from '@/router'
import store from '@/store' import { iframeStore, keepAliveStore, viewTagsStore } from '@/store'
export default { export default {
// 刷新标签 // 刷新标签
refresh() { refresh() {
NProgress.start() NProgress.start()
const keepAlive = keepAliveStore()
const route = router.currentRoute.value const route = router.currentRoute.value
store.commit('removeKeepLive', route.name) keepAlive.removeKeepLive(route.name)
store.commit('setRouteShow', false) keepAlive.setRouteShow(false)
nextTick(() => { nextTick(() => {
store.commit('pushKeepLive', route.name) keepAlive.pushKeepLive(route.name)
store.commit('setRouteShow', true) keepAlive.setRouteShow(true)
NProgress.done() NProgress.done()
}) })
}, },
// 关闭标签 // 关闭标签
close(tag) { close(tag) {
const route = tag || router.currentRoute.value const route = tag || router.currentRoute.value
store.commit('removeViewTags', route) const store = viewTagsStore()
store.commit('removeIframeList', route) store.removeViewTags(route)
store.commit('removeKeepLive', route.name) iframeStore().removeIframeList(route)
const tagList = store.state.viewTags.viewTags keepAliveStore().removeKeepLive(route.name)
const tagList = store.viewTags
const latestView = tagList.slice(-1)[0] const latestView = tagList.slice(-1)[0]
if (latestView) { if (latestView) {
router.push(latestView) router.push(latestView)
@ -44,21 +45,23 @@ export default {
// 关闭标签后处理 // 关闭标签后处理
closeNext(next) { closeNext(next) {
const route = router.currentRoute.value const route = router.currentRoute.value
store.commit('removeViewTags', route) const store = viewTagsStore()
store.commit('removeIframeList', route) store.removeViewTags(route)
store.commit('removeKeepLive', route.name) iframeStore().removeIframeList(route)
keepAliveStore().removeKeepLive(route.name)
if (next) { if (next) {
const tagList = store.state.viewTags.viewTags const tagList = store.viewTags
next(tagList) next(tagList)
} }
}, },
// 关闭其他 // 关闭其他
closeOther() { closeOther() {
const route = router.currentRoute.value const route = router.currentRoute.value
const tagList = [...store.state.viewTags.viewTags] const store = viewTagsStore()
const tagList = [...store.viewTags]
tagList.forEach((tag) => { tagList.forEach((tag) => {
// eslint-disable-next-line prettier/prettier // eslint-disable-next-line prettier/prettier
if (tag.meta && tag.meta.affix || route.fullPath == tag.fullPath) { if ((tag.meta && tag.meta.affix) || route.fullPath == tag.fullPath) {
return true return true
} else { } else {
this.close(tag) this.close(tag)
@ -67,6 +70,6 @@ export default {
}, },
// 设置标题 // 设置标题
setTitle(title) { setTitle(title) {
store.commit('updateViewTagsTitle', title) viewTagsStore().updateViewTagsTitle(title)
} }
} }

View File

@ -108,7 +108,8 @@
import config from '@/config' import config from '@/config'
import configApi from '@/api/dev/configApi' import configApi from '@/api/dev/configApi'
import tool from '@/utils/tool' import tool from '@/utils/tool'
import store from '@/store' import { globalStore, iframeStore, keepAliveStore, viewTagsStore } from '@/store'
import { mapActions, mapState } from 'pinia'
export default { export default {
name: 'Login', name: 'Login',
@ -119,7 +120,6 @@
data() { data() {
return { return {
activeKey: 'userAccount', activeKey: 'userAccount',
sysBaseConfig: store.state.global.sysBaseConfig || tool.data.get('SNOWY_SYS_BASE_CONFIG'),
captchaOpen: config.SYS_BASE_CONFIG.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN, captchaOpen: config.SYS_BASE_CONFIG.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN,
validCodeBase64: '', validCodeBase64: '',
ruleForm: { ruleForm: {
@ -150,6 +150,12 @@
] ]
} }
}, },
computed: {
...mapState(globalStore, ['sysBaseConfig']),
// captchaOpen() {
// return this.sysBaseConfig.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN === 'true'
// }
},
watch: { watch: {
'config.theme': function (val) { 'config.theme': function (val) {
document.body.setAttribute('data-theme', val) document.body.setAttribute('data-theme', val)
@ -160,9 +166,9 @@
} }
}, },
created() { created() {
store.commit('clearViewTags') this.clearViewTags()
store.commit('clearKeepLive') this.clearKeepLive()
store.commit('clearIframeList') this.clearIframeList()
}, },
mounted() { mounted() {
let formData = ref(config.SYS_BASE_CONFIG) let formData = ref(config.SYS_BASE_CONFIG)
@ -173,12 +179,16 @@
}) })
this.captchaOpen = formData.value.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN this.captchaOpen = formData.value.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN
tool.data.set('SNOWY_SYS_BASE_CONFIG', formData.value) tool.data.set('SNOWY_SYS_BASE_CONFIG', formData.value)
store.commit('SET_sysBaseConfig', formData.value) this.setSysBaseConfig(formData.value)
this.refreshSwitch() this.refreshSwitch()
} }
}) })
}, },
methods: { methods: {
...mapActions(keepAliveStore, ['clearKeepLive']),
...mapActions(viewTagsStore, ['clearViewTags']),
...mapActions(iframeStore, ['clearIframeList']),
...mapActions(globalStore, ['setSysBaseConfig']),
// //
refreshSwitch() { refreshSwitch() {
// //

View File

@ -66,7 +66,7 @@
import { onMounted } from 'vue' import { onMounted } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import tool from '@/utils/tool' import tool from '@/utils/tool'
import store from '@/store' import { globalStore } from '@/store'
import userCenterApi from '@/api/sys/userCenterApi' import userCenterApi from '@/api/sys/userCenterApi'
import accountBasic from './userTab/accountBasic.vue' import accountBasic from './userTab/accountBasic.vue'
import CropUpload from '@/components/CropUpload/index.vue' import CropUpload from '@/components/CropUpload/index.vue'
@ -75,6 +75,8 @@
import accountBind from './userTab/accountBind.vue' import accountBind from './userTab/accountBind.vue'
import userMessage from './userTab/userMessage.vue' import userMessage from './userTab/userMessage.vue'
const global_store = globalStore()
const userInfo = ref(tool.data.get('USER_INFO')) const userInfo = ref(tool.data.get('USER_INFO'))
const cropUpload = ref() const cropUpload = ref()
const avatarLoading = ref(false) const avatarLoading = ref(false)
@ -126,7 +128,7 @@
userInfo.value.avatar = data userInfo.value.avatar = data
// //
tool.data.set('USER_INFO', userInfo.value) tool.data.set('USER_INFO', userInfo.value)
store.commit('SET_userInfo', userInfo.value) global_store.setUserInfo(userInfo.value)
}) })
} }
// //
@ -138,7 +140,7 @@
userInfo.value.signature = value userInfo.value.signature = value
// //
tool.data.set('USER_INFO', userInfo.value) tool.data.set('USER_INFO', userInfo.value)
store.commit('SET_userInfo', userInfo.value) global_store.setUserInfo(userInfo.value)
}) })
} }
</script> </script>

View File

@ -39,7 +39,10 @@
import { required } from '@/utils/formRules' import { required } from '@/utils/formRules'
import userCenterApi from '@/api/sys/userCenterApi' import userCenterApi from '@/api/sys/userCenterApi'
import tool from '@/utils/tool' import tool from '@/utils/tool'
import store from '@/store' import { globalStore } from '@/store'
const store = globalStore()
const formRef = ref() const formRef = ref()
// //
const userInfo = tool.data.get('USER_INFO') const userInfo = tool.data.get('USER_INFO')
@ -61,7 +64,7 @@
userCenterApi.userUpdateUserInfo(formData.value).then(() => { userCenterApi.userUpdateUserInfo(formData.value).then(() => {
submitLoading.value = false submitLoading.value = false
// //
store.commit('SET_userInfo', formData.value) store.setUserInfo(formData.value)
tool.data.set('USER_INFO', formData.value) tool.data.set('USER_INFO', formData.value)
}) })
}) })

View File

@ -78,7 +78,7 @@ export default defineConfig(({ command, mode }) => {
manualChunks: { manualChunks: {
echarts: ['echarts'], echarts: ['echarts'],
'ant-design-vue': ['ant-design-vue'], 'ant-design-vue': ['ant-design-vue'],
vue: ['vue', 'vue-router', 'vuex', 'vue-i18n'] vue: ['vue', 'vue-router', 'pinia', 'vue-i18n']
} }
} }
}, },