first commit

This commit is contained in:
仲么了
2023-12-21 16:42:39 +08:00
commit 0f7b59f55b
79 changed files with 7638 additions and 0 deletions

37
src/stores/adminInfo.ts Normal file
View File

@@ -0,0 +1,37 @@
import { defineStore } from 'pinia'
import { ADMIN_INFO } from '@/stores/constant/cacheKey'
import type { AdminInfo } from '@/stores/interface'
export const useAdminInfo = defineStore('adminInfo', {
state: (): AdminInfo => {
return {
id: 0,
username: '',
nickname: '',
avatar: '',
last_login_time: '',
token: '',
refresh_token: '',
super: false
}
},
actions: {
dataFill(state: AdminInfo) {
this.$state = { ...this.$state, ...state }
},
removeToken() {
this.token = ''
this.refresh_token = ''
},
setToken(token: string, type: 'auth' | 'refresh') {
const field = type == 'auth' ? 'token' : 'refresh_token'
this[field] = token
},
getToken(type: 'auth' | 'refresh' = 'auth') {
return type === 'auth' ? this.token : this.refresh_token
}
},
persist: {
key: ADMIN_INFO
}
})

125
src/stores/config.ts Normal file
View File

@@ -0,0 +1,125 @@
import { reactive } from 'vue'
import { defineStore } from 'pinia'
import { STORE_CONFIG } from '@/stores/constant/cacheKey'
import type { Layout } from '@/stores/interface'
export const useConfig = defineStore(
'config',
() => {
const layout: Layout = reactive({
/* 全局 */
showDrawer: false,
// 是否收缩布局(小屏设备)
shrink: false,
// 后台布局方式,可选值<Default|Classic|Streamline|Double>
layoutMode: 'Default',
// 后台主页面切换动画,可选值<slide-right|slide-left|el-fade-in-linear|el-fade-in|el-zoom-in-center|el-zoom-in-top|el-zoom-in-bottom>
mainAnimation: 'slide-right',
// 是否暗黑模式
isDark: false,
/* 侧边菜单 */
// 侧边菜单背景色
menuBackground: ['#ffffff', '#1d1e1f'],
// 侧边菜单文字颜色
menuColor: ['#303133', '#CFD3DC'],
// 侧边菜单激活项背景色
menuActiveBackground: ['#ffffff', '#1d1e1f'],
// 侧边菜单激活项文字色
menuActiveColor: ['#409eff', '#3375b9'],
// 侧边菜单顶栏背景色
menuTopBarBackground: ['#fcfcfc', '#1d1e1f'],
// 侧边菜单宽度(展开时)单位px
menuWidth: 260,
// 侧边菜单项默认图标
menuDefaultIcon: 'fa fa-circle-o',
// 是否水平折叠收起菜单
menuCollapse: false,
// 是否只保持一个子菜单的展开(手风琴)
menuUniqueOpened: false,
// 显示菜单栏顶栏(LOGO)
menuShowTopBar: true,
/* 顶栏 */
// 顶栏文字色
headerBarTabColor: ['#000000', '#CFD3DC'],
// 顶栏激活项背景色
headerBarTabActiveBackground: ['#ffffff', '#1d1e1f'],
// 顶栏激活项文字色
headerBarTabActiveColor: ['#000000', '#409EFF'],
// 顶栏背景色
headerBarBackground: ['#ffffff', '#1d1e1f'],
// 顶栏悬停时背景色
headerBarHoverBackground: ['#f5f5f5', '#18222c']
})
const lang = reactive({
// 默认语言,可选值<zh-cn|en>
defaultLang: 'zh-cn',
// 当在默认语言包找不到翻译时,继续在 fallbackLang 语言包内查找翻译
fallbackLang: 'zh-cn',
// 支持的语言列表
langArray: [
{ name: 'zh-cn', value: '中文简体' },
{ name: 'en', value: 'English' }
]
})
function menuWidth() {
if (layout.shrink) {
return layout.menuCollapse ? '0px' : layout.menuWidth + 'px'
}
// 菜单是否折叠
return layout.menuCollapse ? '64px' : layout.menuWidth + 'px'
}
function setLang(val: string) {
lang.defaultLang = val
}
function onSetLayoutColor(data = layout.layoutMode) {
// 切换布局时,如果是为默认配色方案,对菜单激活背景色重新赋值
const tempValue = layout.isDark
? { idx: 1, color: '#1d1e1f', newColor: '#141414' }
: { idx: 0, color: '#ffffff', newColor: '#f5f5f5' }
if (
data == 'Classic' &&
layout.headerBarBackground[tempValue.idx] == tempValue.color &&
layout.headerBarTabActiveBackground[tempValue.idx] == tempValue.color
) {
layout.headerBarTabActiveBackground[tempValue.idx] = tempValue.newColor
} else if (
data == 'Default' &&
layout.headerBarBackground[tempValue.idx] == tempValue.color &&
layout.headerBarTabActiveBackground[tempValue.idx] == tempValue.newColor
) {
layout.headerBarTabActiveBackground[tempValue.idx] = tempValue.color
}
}
function setLayoutMode(data: string) {
layout.layoutMode = data
onSetLayoutColor(data)
}
const setLayout = (name: keyof Layout, value: any) => {
layout[name] = value as never
}
const getColorVal = function (name: keyof Layout): string {
const colors = layout[name] as string[]
if (layout.isDark) {
return colors[1]
} else {
return colors[0]
}
}
return { layout, lang, menuWidth, setLang, setLayoutMode, setLayout, getColorVal, onSetLayoutColor }
},
{
persist: {
key: STORE_CONFIG
}
}
)

View File

@@ -0,0 +1,12 @@
/**
* 本地缓存Key
*/
// 管理员资料
export const ADMIN_INFO = 'adminInfo'
// WEB端布局配置
export const STORE_CONFIG = 'storeConfig'
// 后台标签页
export const STORE_TAB_VIEW_CONFIG = 'storeTabViewConfig'

7
src/stores/index.ts Normal file
View File

@@ -0,0 +1,7 @@
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
export default pinia

View File

@@ -0,0 +1,45 @@
// 变量名对应含义请在 /stores/* 里边找
import type { RouteRecordRaw, RouteLocationNormalized } from 'vue-router'
export interface Layout {
showDrawer: boolean
shrink: boolean
layoutMode: string
mainAnimation: string
isDark: boolean
menuWidth: number
menuDefaultIcon: string
menuCollapse: boolean
menuUniqueOpened: boolean
menuShowTopBar: boolean
menuBackground: string[]
menuColor: string[]
menuActiveBackground: string[]
menuActiveColor: string[]
menuTopBarBackground: string[]
headerBarTabColor: string[]
headerBarBackground: string[]
headerBarHoverBackground: string[]
headerBarTabActiveBackground: string[]
headerBarTabActiveColor: string[]
}
export interface NavTabs {
activeIndex: number
activeRoute: RouteLocationNormalized | null
tabsView: RouteLocationNormalized[]
tabFullScreen: boolean
tabsViewRoutes: RouteRecordRaw[]
authNode: Map<string, string[]>
}
export interface AdminInfo {
id: number
username: string
nickname: string
avatar: string
last_login_time: string
token: string
refresh_token: string
super:boolean
}

108
src/stores/navTabs.ts Normal file
View File

@@ -0,0 +1,108 @@
import { reactive } from 'vue'
import { defineStore } from 'pinia'
import { STORE_TAB_VIEW_CONFIG } from '@/stores/constant/cacheKey'
import type { NavTabs } from '@/stores/interface/index'
import type { RouteLocationNormalized, RouteRecordRaw } from 'vue-router'
import { adminBaseRoutePath } from '@/router/static'
export const useNavTabs = defineStore(
'navTabs',
() => {
const state: NavTabs = reactive({
// 激活tab的index
activeIndex: 0,
// 激活的tab
activeRoute: null,
// tab列表
tabsView: [],
// 当前tab是否全屏
tabFullScreen: false,
// 从后台加载到的菜单路由列表
tabsViewRoutes: [],
// 按钮权限节点
authNode: new Map(),
})
function addTab(route: RouteLocationNormalized) {
if (!route.meta.addtab) return
for (const key in state.tabsView) {
if (state.tabsView[key].path === route.path) {
state.tabsView[key].params = route.params ? route.params : state.tabsView[key].params
state.tabsView[key].query = route.query ? route.query : state.tabsView[key].query
return
}
}
state.tabsView.push(route)
}
function closeTab(route: RouteLocationNormalized) {
state.tabsView.map((v, k) => {
if (v.path == route.path) {
state.tabsView.splice(k, 1)
return
}
})
}
/**
* 关闭多个标签
* @param retainMenu 需要保留的标签,否则关闭全部标签
*/
const closeTabs = (retainMenu: RouteLocationNormalized | false = false) => {
if (retainMenu) {
state.tabsView = [retainMenu]
} else {
state.tabsView = []
}
}
const setActiveRoute = (route: RouteLocationNormalized): void => {
const currentRouteIndex: number = state.tabsView.findIndex((item: RouteLocationNormalized) => {
return item.path === route.path
})
if (currentRouteIndex === -1) return
state.activeRoute = route
state.activeIndex = currentRouteIndex
}
const setTabsViewRoutes = (data: RouteRecordRaw[]): void => {
state.tabsViewRoutes = encodeRoutesURI(data)
}
const setAuthNode = (key: string, data: string[]) => {
state.authNode.set(key, data)
}
const fillAuthNode = (data: Map<string, string[]>) => {
state.authNode = data
}
const setFullScreen = (fullScreen: boolean): void => {
state.tabFullScreen = fullScreen
}
return { state, addTab, closeTab, closeTabs, setActiveRoute, setTabsViewRoutes, setAuthNode, fillAuthNode, setFullScreen }
},
{
persist: {
key: STORE_TAB_VIEW_CONFIG,
paths: ['state.tabFullScreen'],
},
}
)
/**
* 对iframe的url进行编码
*/
function encodeRoutesURI(data: RouteRecordRaw[]) {
data.forEach((item) => {
if (item.meta?.menu_type == 'iframe') {
item.path = adminBaseRoutePath + '/iframe/' + encodeURIComponent(item.path)
}
if (item.children && item.children.length) {
item.children = encodeRoutesURI(item.children)
}
})
return data
}