样式修改

master
lzq 2026-01-17 17:34:50 +08:00
parent bf8e1543d4
commit f22cd3fa7e
19 changed files with 438 additions and 328 deletions

View File

@ -5,8 +5,30 @@ charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
tab_width = 2
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 1000
[*.styl]
ij_continuation_indent_size = 4
ij_stylus_align_closing_brace_with_properties = false
ij_stylus_blank_lines_around_nested_selector = 1
ij_stylus_blank_lines_between_blocks = 1
ij_stylus_brace_placement = 0
ij_stylus_enforce_property_name_value_separator_on_format = false
ij_stylus_enforce_quotes_on_format = false
ij_stylus_hex_color_long_format = true
ij_stylus_hex_color_lower_case = false
ij_stylus_hex_color_short_format = false
ij_stylus_hex_color_upper_case = true
ij_stylus_is_property_name_value_separated_by_colon = false
ij_stylus_keep_blank_lines_in_code = 2
ij_stylus_keep_indents_on_empty_lines = false
ij_stylus_keep_single_line_blocks = false
ij_stylus_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow
ij_stylus_space_after_colon = true
ij_stylus_space_before_opening_brace = true
ij_stylus_use_double_quotes = true
ij_stylus_value_alignment = 0

View File

@ -1,112 +1,102 @@
import { defineStore } from 'pinia'
import Evt from '@/common/utils/evt.ts'
import Nav from '@/common/router/nav.ts'
const pageContextCache = new Map<string, AppTypes.PageContext>()
function initCache() {
pageContextCache.clear()
}
initCache()
import Strings from '@/common/utils/strings.ts'
import Utils from '@/common/utils'
import { SpecialPage } from '@/common/router/constants.ts'
export const useAppPageStore = defineStore('AppPage', () => {
const keepAliveInclude = ref<string[]>([])
const pages = ref<AppTypes.PageContext[]>([])
const pages = Utils.resetAble(reactive<AppTypes.PageContext[]>([]))/* as Reactive<AppTypes.PageContext[]> */
const currentPage = ref<string>('')
const currentPage = Utils.resetAble(reactive<AppTypes.PageContext>({
insId: '',
title: '',
keepAlive: false,
params: {},
routeName: '',
menuId: '',
icon: '',
breadcrumb: [],
}))/* as Reactive<AppTypes.PageContext> */
const ctx = computed(() => {
return pageContextCache.get(currentPage.value)!
const keepAliveInclude = computed(() => {
return pages.filter(it => it.keepAlive).map(it => it.routeName)
})
function open(ctx_: AppTypes.PageContext) {
currentPage.value = ctx_.insId
if (!pageContextCache.has(ctx_.insId)) {
pageContextCache.set(ctx_.insId, ctx_)
}
if (!keepAliveInclude.value.includes(ctx_.insId)) {
keepAliveInclude.value.push(ctx_.insId)
}
if (!pages.value.find(it => it.insId === ctx_.insId)) {
pages.value.push(ctx_)
}
function open(ctx?: AppTypes.PageContext) {
if (
ctx == null
|| Strings.isBlank(ctx.insId)
|| currentPage.insId === ctx.insId) return Promise.reject('已在当前页面')
const page = pages.find(it => it.insId === ctx.insId)
if (page == null) pages.push(ctx)
currentPage.$reset(ctx)
return Promise.resolve(ctx)
}
function reopen(insId: string) {
if (currentPage.value === insId) {
return
}
const page = pageContextCache.get(insId)
if (page) {
currentPage.value = insId
Nav.open(page.routeName)
}
const page = pages.find(it => it.insId === insId)
return open(page)
}
function closePage(insId: string) {
pageContextCache.delete(insId)
if (keepAliveInclude.value.includes(insId)) {
keepAliveInclude.value = keepAliveInclude.value.splice(keepAliveInclude.value.indexOf(insId), 1)
}
const index = pages.value.findIndex(it => it.insId === insId)
if (index !== -1) {
const oldLen = pages.value.length
pages.value = pages.value.filter(it => it.insId !== insId)
if (currentPage.value !== insId) {
return
}
if (index === 0) {
if (pages.value.length > 0) {
reopen(pages.value[0]?.insId)
} else {
Nav.open('home')
}
} else if (index === oldLen - 1) {
if (pages.value.length > 0) {
reopen(pages.value[pages.value.length - 1]?.insId)
} else {
Nav.open('home')
}
} else {
if (pages.value.length > 0) {
reopen(pages.value[index]?.insId)
} else {
Nav.open('home')
}
}
const index = pages.findIndex(it => it.insId === insId)
if (index < 1 || pages[index].routeName === SpecialPage.Home) return Promise.reject('不能关闭首页')
pages.splice(index, 1)
if (currentPage.insId !== insId) return Promise.resolve(null)
const newLen = pages.length
const oldLen = newLen + 1
let page: AppTypes.PageContext | undefined
if (index === 1) {
page = newLen > 1 ? pages[1] : pages[0]
} else if (index === oldLen - 1) {
page = pages[newLen - 1]
} else {
page = pages[index]
}
return open(page)
}
function closeCurrent() {
closePage(currentPage.value)
return closePage(currentPage.insId)
}
function closeLeft() {
const index = pages.findIndex(it => it.insId === currentPage.insId)
if (index < 2) return
pages.splice(1, index - 1)
}
function closeRight() {
const index = pages.findIndex(it => it.insId === currentPage.insId)
if (index < 0) return
pages.splice(index + 1, pages.length - index - 1)
}
function closeOther() {
pages.value = pages.value.filter(it => it.insId === currentPage.value)
const pageList = pages.filter(it => it.routeName === SpecialPage.Home || it.insId === currentPage.insId)
pages.$reset(pageList)
}
function closeAll() {
pages.value = []
Nav.open('home')
const page = pages.find(it => it.routeName === SpecialPage.Home)!
pages.$reset([ page ])
return open(page)
}
function $reset() {
keepAliveInclude.value = []
currentPage.value = ''
initCache()
pages.$reset()
currentPage.$reset()
}
Evt.on('logout', $reset)
return {
ctx,
reopen,
open,
closePage,
closeCurrent,
closeLeft,
closeRight,
closeOther,
closeAll,
pages,

View File

@ -11,7 +11,7 @@ const home = {
'sn': 'menus',
'pid': '0',
'title': '首页',
'icon': 'menus',
'icon': 'home-3-line',
'tier': 1,
'breadcrumb': [
'首页',
@ -22,7 +22,8 @@ const home = {
'routeName': 'home',
'path': '/home',
}
export const reloadUserInfo = () => {
export function reloadUserInfo() {
const appSettingStore = useAppSettingStore()
const appUserStore = useAppUserStore()
return LoginApi.my()
@ -49,31 +50,6 @@ export const reloadUserInfo = () => {
})
}
/* export const loadUserInfo = () => {
const appSettingStore = useAppSettingStore()
const appUserStore = useAppUserStore()
return LoginApi.my()
.then(({data}) => {
const menuTree = Utils.clone(Colls.toTree(data.menus))
appSettingStore.$patch({
menus: data.menus, menuTree,
theme: data.setting?.theme ?? 'light',
collectedMenus: data.setting?.collectedMenus ?? [],
logo: data.setting?.logo,
language: data.setting?.language ?? 'zh',
})
appUserStore.$patch({
userId: data.id,
nickname: data.nickname,
avatar: data.avatar,
tenantId: data.tenantId,
tenantName: data.tenantName,
bizObj: data.bizObj,
roles: data.roles,
})
})
} */
export function hasPermission(resSn?: string) {
const appSettingStore = useAppSettingStore()
const res = appSettingStore.menus.find(it => it.sn === resSn)

View File

@ -15,7 +15,6 @@ import {
getRoutes,
} from '@/common/router/route-config.ts'
import { SpecialPage } from '@/common/router/constants.ts'
import Nav from '@/common/router/nav.ts'
function addRoutes(routNames: string[]) {
if (Colls.isEmpty(routNames)) return
@ -81,7 +80,7 @@ router.beforeEach((to, from) => {
routeName = SpecialPage.Home
}
setTimeout(() => {
Nav.open(routeName)
Evt.emit('browserReflash', routeName)
})
return false
}
@ -118,19 +117,4 @@ export function reloadRouter() {
return true
}
Evt.on('login', (_) => {
Nav.open(SpecialPage.Home)
})
Evt.on('logout', (_) => {
const routes = router
.getRoutes()
.filter((it) => it.name !== SpecialPage.Main && it.name !== SpecialPage.Login && it.name !== SpecialPage.NotFound && it.name !== SpecialPage.Home)
.map((it) => it.name as string)
removeRoutes(routes)
router.push({replace: true, name: SpecialPage.Login}).then(() => {
// console.log(r)
})
})
export default router

View File

@ -1,10 +1,14 @@
import router, { reloadRouter } from '@/common/router/index.ts'
import router, {
reloadRouter,
removeRoutes,
} from '@/common/router/index.ts'
import Evt from '@/common/utils/evt.ts'
import { useAppSettingStore } from '@/common/app/app-setting-store.ts'
import { useAppPageStore } from '@/common/app/app-page-store.ts'
import { nanoid } from 'nanoid'
import { reloadUserInfo } from '@/common/app'
import { ElMessage } from 'element-plus'
import type { App } from 'vue'
import { SpecialPage } from '@/common/router/constants.ts'
type Option = Partial<Pick<AppTypes.PageContext, 'params' | 'insId' | 'title'>> & Pick<AppTypes.PageContext, 'routeName'>
@ -13,153 +17,280 @@ type Option = Partial<Pick<AppTypes.PageContext, 'params' | 'insId' | 'title'>>
*
* @param option
*/
function open(option: string | Option) {
let ctx: AppTypes.PageContext
const appSettingStore = useAppSettingStore()
/* function open(option: string | Option) {
let ctx: AppTypes.PageContext
const appSettingStore = useAppSettingStore()
if (typeof option === 'string') {
const routeName = option
if (!router.hasRoute(routeName)) {
return reloadUserInfo()
.then(reloadRouter)
.then(() => {
if (!router.hasRoute(routeName)) {
ElMessage.error('页面不存在')
return Promise.reject('页面不存在')
}
const menu = appSettingStore.menus.find(it => it.routeName === routeName)
if (menu == null) {
ElMessage.error('页面不存在')
return Promise.reject('页面不存在')
}
ctx = {
insId: routeName,
title: menu.title,
keepAlive: true,
params: {},
routeName,
menuId: menu.id,
icon: menu.icon,
breadcrumb: menu.breadcrumb,
}
useAppPageStore().open(ctx)
return router.push({name: ctx.routeName, params: ctx.params})
.then(err => {
if (err == null) {
Evt.emit('openPage')
return Promise.resolve(true)
} else {
return Promise.reject(err)
}
})
.catch(err => {
return Promise.reject(err)
})
})
}
const menu = appSettingStore.menus.find(it => it.routeName === routeName)
if (menu == null) {
ElMessage.error('页面不存在')
return Promise.reject('页面不存在')
}
ctx = {
insId: routeName ,
title: menu.title,
keepAlive: true,
params: {},
routeName,
menuId: menu.id,
icon: menu.icon,
breadcrumb: menu.breadcrumb,
}
} else {
const routeName = option.routeName
if (!router.hasRoute(routeName)) {
return reloadUserInfo()
.then(reloadRouter)
.then(() => {
if (!router.hasRoute(routeName)) {
ElMessage.error('页面不存在')
return Promise.reject('页面不存在')
}
const menu = appSettingStore.menus.find(it => it.routeName === routeName)
if (menu == null) {
ElMessage.error('页面不存在')
return Promise.reject('页面不存在')
}
const option_ = option as Option
ctx = {
insId: option_.insId ?? routeName,
title: option_.title ?? menu.title,
routeName: routeName,
keepAlive: true,
params: option_.params ?? {},
menuId: menu.id,
icon: menu.icon,
breadcrumb: menu.breadcrumb,
}
useAppPageStore().open(ctx)
return router.push({name: ctx.routeName, params: ctx.params})
.then(err => {
if (err == null) {
Evt.emit('openPage')
return Promise.resolve(true)
} else {
return Promise.reject(err)
}
})
.catch(err => {
return Promise.reject(err)
})
})
}
const menu = appSettingStore.menus.find(it => it.routeName === routeName)
if (menu == null) {
ElMessage.error('页面不存在')
return Promise.reject('页面不存在')
}
ctx = {
insId: option.insId ?? routeName,
title: option.title ?? menu.title,
routeName: routeName,
keepAlive: true,
params: option.params ?? {},
menuId: menu.id,
icon: menu.icon,
breadcrumb: menu.breadcrumb,
}
}
useAppPageStore().open(ctx)
return router.push({name: ctx.routeName, params: ctx.params})
.then(err => {
if (err == null) {
Evt.emit('openPage')
return Promise.resolve(true)
} else {
return Promise.reject(err)
}
})
.catch(err => {
return Promise.reject(err)
})
} */
function checkRoute(option: string | Option) {
let opt: Option
if (typeof option === 'string') {
const routeName = option
if (!router.hasRoute(routeName)) {
return reloadUserInfo()
.then(reloadRouter)
.then(() => {
if (!router.hasRoute(routeName)) {
ElMessage.error('页面不存在')
return Promise.reject('页面不存在')
}
const menu = appSettingStore.menus.find(it => it.routeName === routeName)
if (menu == null) {
ElMessage.error('页面不存在')
return Promise.reject('页面不存在')
}
ctx = {
insId: routeName + '_' + nanoid(),
title: menu.title,
keepAlive: true,
params: {},
routeName,
menuId: menu.id,
icon: menu.icon,
breadcrumb: menu.breadcrumb,
}
ctx.insId = ctx.routeName
useAppPageStore().open(ctx)
return router.push({name: ctx.routeName, params: ctx.params})
.then(err => {
if (err == null) {
Evt.emit('openPage')
return Promise.resolve(true)
} else {
return Promise.reject(err)
}
})
.catch(err => {
return Promise.reject(err)
})
})
}
const menu = appSettingStore.menus.find(it => it.routeName === routeName)
if (menu == null) {
ElMessage.error('页面不存在')
return Promise.reject('页面不存在')
}
ctx = {
insId: routeName + '_' + nanoid(),
title: menu.title,
keepAlive: true,
params: {},
routeName,
menuId: menu.id,
icon: menu.icon,
breadcrumb: menu.breadcrumb,
opt = {
routeName: option,
}
} else {
const routeName = option.routeName
if (!router.hasRoute(routeName)) {
return reloadUserInfo()
.then(reloadRouter)
.then(() => {
if (!router.hasRoute(routeName)) {
ElMessage.error('页面不存在')
return Promise.reject('页面不存在')
}
const menu = appSettingStore.menus.find(it => it.routeName === routeName)
if (menu == null) {
ElMessage.error('页面不存在')
return Promise.reject('页面不存在')
}
const option_ = option as Option
ctx = {
insId: option_.insId ?? routeName + '_' + nanoid(),
title: option_.title ?? menu.title,
routeName: routeName,
keepAlive: true,
params: option_.params ?? {},
menuId: menu.id,
icon: menu.icon,
breadcrumb: menu.breadcrumb,
}
ctx.insId = ctx.routeName
useAppPageStore().open(ctx)
return router.push({name: ctx.routeName, params: ctx.params})
.then(err => {
if (err == null) {
Evt.emit('openPage')
return Promise.resolve(true)
} else {
return Promise.reject(err)
}
})
.catch(err => {
return Promise.reject(err)
})
})
}
const menu = appSettingStore.menus.find(it => it.routeName === routeName)
if (menu == null) {
ElMessage.error('页面不存在')
return Promise.reject('页面不存在')
}
ctx = {
insId: option.insId ?? routeName + '_' + nanoid(),
title: option.title ?? menu.title,
routeName: routeName,
keepAlive: true,
params: option.params ?? {},
menuId: menu.id,
icon: menu.icon,
breadcrumb: menu.breadcrumb,
}
opt = option
}
ctx.insId = ctx.routeName
useAppPageStore().open(ctx)
const appSettingStore = useAppSettingStore()
const menu = appSettingStore.menus.find(it => it.routeName === opt.routeName)
if (menu == null
|| !router.hasRoute(opt.routeName)) {
return reloadUserInfo()
.then(reloadRouter)
.then(() => {
const menu_ = appSettingStore.menus.find(it => it.routeName === opt.routeName)
if (menu_ == null || !router.hasRoute(opt.routeName)) {
ElMessage.error('页面不存在')
return Promise.reject('页面不存在')
} else {
return {option: opt, menu: menu_}
}
})
}
return Promise.resolve({option: opt, menu})
}
function jump(ctx: AppTypes.PageContext) {
return router.push({name: ctx.routeName, params: ctx.params})
.then(err => {
if (err == null) {
Evt.emit('openPage')
return Promise.resolve(true)
} else {
return Promise.reject(err)
return Promise.resolve(ctx)
}
})
.catch(err => {
return Promise.reject(err)
})
}
function open(option: string | Option) {
return checkRoute(option)
.then(({option, menu}) => {
return jump({
insId: option.insId ?? option.routeName,
title: option.title ?? menu.title,
keepAlive: true,
params: option.params ?? {},
routeName: option.routeName,
menuId: menu.id,
icon: menu.icon,
breadcrumb: menu.breadcrumb,
})
})
.then(useAppPageStore().open)
}
/**
*
*
* @param id
*/
function close(id: string) {
useAppPageStore().close(id)
Evt.emit('closePage', id)
useAppPageStore()
.closePage(id)
.then(ctx => {
if (ctx == null) return Promise.resolve(null)
return jump(ctx)
})
}
function closeCurrent() {
return useAppPageStore().closeCurrent()
.then(ctx => {
if (ctx == null) return Promise.resolve(null)
return jump(ctx)
})
}
function closeLeft() {
useAppPageStore().closeLeft()
}
function closeRight() {
useAppPageStore().closeRight()
}
function closeOther() {
useAppPageStore().closeOther()
}
function closeAll() {
return useAppPageStore().closeAll()
.then(jump)
}
const install = (_: App): void => {
Evt.on('login', (_) => {
open(SpecialPage.Home)
})
Evt.on('browserReflash', (routeName: string) => {
if (routeName === SpecialPage.Home) {
open(routeName)
return
}
checkRoute(SpecialPage.Home)
.then(({option, menu}) => {
useAppPageStore().open({
insId: option.insId ?? option.routeName,
title: option.title ?? menu.title,
keepAlive: true,
params: option.params ?? {},
routeName: option.routeName,
menuId: menu.id,
icon: menu.icon,
breadcrumb: menu.breadcrumb,
})
open(routeName)
})
})
Evt.on('logout', (_) => {
const routes = router
.getRoutes()
.filter((it) => it.name !== SpecialPage.Main && it.name !== SpecialPage.Login && it.name !== SpecialPage.NotFound && it.name !== SpecialPage.Home)
.map((it) => it.name as string)
removeRoutes(routes)
router.push({replace: true, name: SpecialPage.Login}).then(() => {
// console.log(r)
})
})
}
export default {
open,
close,
closeCurrent,
closeLeft,
closeRight,
closeOther,
closeAll,
install,
}

View File

@ -3,6 +3,7 @@ import mitt, { type EventType } from 'mitt'
export interface EventList extends Record<EventType, unknown> {
login?: string
logout?: string
browserReflash: string
connect_ws?: string
disconnect_ws?: string
openPage?: string

View File

@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* 项目名称 再昇云 */
src: url('@/components/a-icon/iconfont.woff2?t=1768370216119') format('woff2'),
url('@/components/a-icon/iconfont.woff?t=1768370216119') format('woff'),
url('@/components/a-icon/iconfont.ttf?t=1768370216119') format('truetype');
src: url('@/components/a-icon/iconfont.woff2?t=1768642091253') format('woff2'),
url('@/components/a-icon/iconfont.woff?t=1768642091253') format('woff'),
url('@/components/a-icon/iconfont.ttf?t=1768642091253') format('truetype');
}
.iconfont {
@ -13,6 +13,10 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-home-3-line:before {
content: "\e6b3";
}
.icon-bell:before {
content: "\e7c4";
}

View File

@ -5,6 +5,13 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "17102563",
"name": "home-3-line",
"font_class": "home-3-line",
"unicode": "e6b3",
"unicode_decimal": 59059
},
{
"icon_id": "4766680",
"name": "bell",

View File

@ -5,6 +5,13 @@ export const icons = {
'css_prefix_text': 'icon-',
'description': '',
'glyphs': [
{
'icon_id': '17102563',
'name': 'home-3-line',
'font_class': 'home-3-line',
'unicode': 'e6b3',
'unicode_decimal': 59059,
},
{
'icon_id': '4766680',
'name': 'bell',

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -225,10 +225,11 @@ onMounted(doSearch)
</ElTooltip>
</div>
</div>
<ElTable
v-loading="loading"
:data="tableData"
:empty-text="tableProps.emptyText?? '暂无数据'"
:row-key="tableProps.rowKey?? 'id'"
ref="dataTable"
:lazy="tableProps.treeLoad ==null?undefined:true"
:load="tableProps.treeLoad?((row, expanded, resolve)=>tableProps.treeLoad!(searchForm as F, row, expanded, resolve)):undefined"
@ -543,8 +544,6 @@ onMounted(doSearch)
}
}
}
.pagination {
justify-content center

View File

@ -8,6 +8,7 @@ import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
// import Ws from '@/common/ws/ws.ts'
import element from '@/common/element/element.ts'
import router from '@/common/router'
import Nav from '@/common/router/nav.ts'
createApp(App)
.use(element)
@ -19,4 +20,5 @@ createApp(App)
})
.use(createPinia().use(piniaPluginPersistedstate))
.use(router)
.use(Nav)
.mount('#app')

View File

@ -4,6 +4,7 @@ import {
ElMenuItemGroup,
ElScrollbar,
ElSubMenu,
type MenuInstance,
type MenuItemRegistered,
} from 'element-plus'
import AIcon from '@/components/a-icon/AIcon.vue'
@ -12,10 +13,10 @@ import styles from '@/pages/a-frame/aaside.module.styl'
import { useAppSettingStore } from '@/common/app/app-setting-store.ts'
import Colls from '@/common/utils/colls.ts'
import { MenuCategory } from '@/common/app/constants.ts'
import { useRouter } from 'vue-router'
import { computed } from 'vue'
import Nav from '@/common/router/nav.ts'
import logo from '@/assets/images/zsy.png'
import { useAppPageStore } from '@/common/app/app-page-store.ts'
export interface Menu extends G.TreeNode {
// Id
@ -44,14 +45,16 @@ export interface Menu extends G.TreeNode {
export default defineComponent(
(props) => {
const router = useRouter()
const appSettingStore = useAppSettingStore()
const defaultActive = ref<any>('')
const menuIns = useTemplateRef<MenuInstance>('menu')
onMounted(() => {
const currentRouteName = router.currentRoute.value.name
defaultActive.value = appSettingStore.menus.find(it => it.routeName === currentRouteName)?.id
})
const appPageStore = useAppPageStore()
watch(
() => appPageStore.currentPage.menuId,
() => {
menuIns.value?.updateActiveIndex(appPageStore.currentPage.menuId)
})
const menuTree = computed(() => {
return Colls.toTree(appSettingStore.menus.filter((it) => it.menuCategory === MenuCategory.Page || it.menuCategory === MenuCategory.Group || it.menuCategory === MenuCategory.Catalog).sort((a, b) => (a.sort ?? 0) - (b.sort ?? 0)))
@ -59,10 +62,7 @@ export default defineComponent(
const onMenuClick = (menuItem: MenuItemRegistered) => {
const menu = appSettingStore.menus.find(it => it.id === menuItem.index)
Nav.open({
insId: menu?.routeName ?? '',
routeName: menu?.routeName ?? '',
})
Nav.open(menu?.routeName ?? '')
}
const renderMenu = (it: Menu) => {
let renderChildNode: (() => VNode[] | undefined) | undefined = undefined
@ -116,12 +116,13 @@ export default defineComponent(
return () => (
<>
<div class={[ styles.aAsideTop, {[styles.aAsideTopCollapse]: props.isCollapse} ]}>
<div class={[ styles.aAsideTop, {[styles.aAsideTopCollapse]: props.isCollapse} ]}
onClick={() => Nav.open('home')}>
<img alt="" src={logo}/>
<div></div>
</div>
<ElScrollbar class={styles.aScrollbar}>
<ElMenu default-active={defaultActive.value} collapse={props.isCollapse} class={[ styles.aMenus ]}>
<ElMenu collapse={props.isCollapse} class={[ styles.aMenus ]} ref="menu">
{{
default: () => menuTree.value.map(renderMenu),
}}

View File

@ -8,14 +8,15 @@
<div v-for="(item,i) in appPageStore.pages"
:id="item.insId"
:key="'a-frame-header-tab'+i"
:class="{'a-tab-item-active': item.insId === appPageStore.currentPage}"
:class="{'a-tab-item-active': item.insId === appPageStore.currentPage.insId}"
class="a-tab-item"
@click="reopen(item.insId)">
@click="Nav.open(item.routeName)">
<div>
<AIcon :name="item.icon as IconName"/>
<div class="title">{{ item.title }}</div>
</div>
<ElButton :icon="elIcons.Close" text @click.stop="appPageStore.closePage(item.insId)"/>
<div v-if="item.routeName === SpecialPage.Home"></div>
<ElButton v-else :icon="elIcons.Close" text @click.stop="Nav.close(item.insId)"/>
</div>
</div>
</ElScrollbar>
@ -23,9 +24,10 @@
<ElButton :icon="elIcons.More" text/>
<template #dropdown>
<ElDropdownMenu>
<ElDropdownItem command="closeCurrent">关闭当前</ElDropdownItem>
<ElDropdownItem command="closeOther">关闭其他</ElDropdownItem>
<ElDropdownItem command="closeAll">关闭所有</ElDropdownItem>
<ElDropdownItem :icon="elIcons.ArrowLeft" command="closeLeft">关闭左侧</ElDropdownItem>
<ElDropdownItem :icon="elIcons.ArrowRight" command="closeRight">关闭右侧</ElDropdownItem>
<ElDropdownItem :icon="elIcons.Close" command="closeOther">关闭其他</ElDropdownItem>
<ElDropdownItem :icon="elIcons.CircleClose" command="closeAll">关闭所有</ElDropdownItem>
</ElDropdownMenu>
</template>
</ElDropdown>
@ -37,15 +39,17 @@ import { elIcons } from '@/common/element/element.ts'
import type { IconName } from '@/components/a-icon/iconfont.ts'
import AIcon from '@/components/a-icon/AIcon.vue'
import type { ScrollbarInstance } from 'element-plus'
import Nav from '@/common/router/nav.ts'
import { SpecialPage } from '@/common/router/constants.ts'
const appPageStore = useAppPageStore()
const tabsScrollbarIns = useTemplateRef<ScrollbarInstance>('tabsScrollbar')
watch(
() => appPageStore.currentPage,
() => appPageStore.currentPage.insId,
() => {
nextTick(() => {
const tabItem = document.getElementById(appPageStore.currentPage)
const tabItem = document.getElementById(appPageStore.currentPage.insId)
if (tabItem != null) tabsScrollbarIns.value?.setScrollLeft(tabItem.offsetLeft)
})
})
@ -55,7 +59,7 @@ function reopen(insId: string) {
}
function handleCommand(command: 'closeCurrent' | 'closeOther' | 'closeAll') {
appPageStore[command]()
Nav[command]()
}
</script>
<style lang="stylus" scoped>

View File

@ -4,24 +4,20 @@
display: flex;
align-items: center;
box-sizing border-box
//padding 8px 8px 8px 18px;
padding-left 18px
//border-bottom: solid 1px var(--el-menu-border-color);
transition all 0.333s ease-in-out
gap 12px
overflow hidden
max-width 230px
//justify-content center
cursor pointer
& > img {
height 32px
width 32px
//margin-left 18px
//transition margin-left 0.333s ease-in-out
}
& > div {
color: #252f4a;
color: #252F4A;
font-weight: 700;
font-size: 1.5rem;
opacity 1
@ -62,42 +58,42 @@
&:global(.el-menu--collapse) {
width: 60px;
}
}
:global(.el-menu-item):global(.is-active) {
background-color #e8f4ff
:global(.el-menu-item):global(.is-active) {
background-color #E8F4FF !important
&::after {
height: 100%;
}
&::after {
height: 100%;
}
}
:global(.el-menu-item) {
position relative
transition: background-color, color .3s ease-in-out;
border-radius 4px
:global(.el-menu-item) {
position relative !important
transition: background-color, color .3s ease-in-out !important;
border-radius 4px !important
&::after {
content: '';
position: absolute;
top: 0;
right: 0;
width: 4px;
height: 0;
background-color: #1c6eff;
transition height 0.3s ease-in-out
}
&::after {
content: '';
position: absolute;
top: 0;
right: 0;
width: 4px;
height: 0;
background-color: #1C6EFF;
transition height 0.3s ease-in-out
}
}
:global(.el-sub-menu__title),
:global(.el-menu-item) {
height: 42px !important;
line-height: 42px !important;
margin-left: 8px;
margin-right: 8px;
:global(.el-sub-menu__title),
:global(.el-menu-item) {
height: 42px !important;
line-height: 42px !important;
margin-left: 8px !important;
margin-right: 8px !important;
&:hover {
background-color: #F2F4F5 !important;
}
&:hover {
background-color: #F2F4F5 !important;
}
}

View File

@ -1,12 +0,0 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = crlf
charset = utf-8
trim_trailing_whitespace = false
insert_final_newline = false

View File

@ -17,15 +17,15 @@
<ElInput v-model="searchForm.routeName" placeholder="路由名称"/>
</ElFormItem>
</template>
<template #simpleSearchFormItem="{ searchForm }">
<ElFormItem>
<ElInput v-model="searchForm.title" placeholder="菜单名称"/>
</ElFormItem>
<ElFormItem>
<ElInput v-model="searchForm.routeName" placeholder="路由名称"/>
</ElFormItem>
</template>
<template #columns>
<!--
:data="tableData"
lazy
:load="treeLoad"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
@expand-change="treeLoad"
-->
<ElTableColumn label="图标" prop="icon" width="100">
<template #default="scope">
<AIcon :name="scope.row.icon"/>
@ -61,7 +61,6 @@ import MenuApi from '@/pages/sys/menus/menu-api.ts'
import MenuForm from '@/pages/sys/menus/MenuForm.vue'
import Strings from '@/common/utils/strings.ts'
import AIcon from '@/components/a-icon/AIcon.vue'
import type { TableInstance } from 'element-plus'
import FormPage, {
type ActionColumnType,
type ToolType,
@ -69,7 +68,6 @@ import FormPage, {
import type { ComponentExposed } from 'vue-component-type-helpers'
const menuFormIns = useTemplateRef<InstanceType<typeof MenuForm>>('menuForm')
const dataTableIns = useTemplateRef<TableInstance>('dataTable')
const formPageIns = useTemplateRef<ComponentExposed<typeof FormPage>>('formPage')
const actionColumn = reactive<ActionColumnType<MenuTypes.SysMenu>>({
@ -126,7 +124,7 @@ function listAll(param: MenuTypes.SearchForm) {
}
function treeLoad(param: MenuTypes.SearchForm, row: MenuTypes.SysMenu, expanded: any, resolve: (data: MenuTypes.SysMenu[]) => void) {
function treeLoad(param: MenuTypes.SearchForm, row: MenuTypes.SysMenu, expanded: any, resolve?: (data: MenuTypes.SysMenu[]) => void) {
if (resolve == null && !expanded) return
MenuApi.listAll({...param, pid: row.id})
.then(res => {