样式修改
parent
29d808402d
commit
1b0f9368fd
|
|
@ -18,6 +18,7 @@
|
|||
padding: 0;
|
||||
border: 0;
|
||||
font-size: var(--el-font-size-medium);
|
||||
font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
}
|
||||
|
||||
html,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// 优化 Element Plus 组件库默认样式
|
||||
|
||||
:root {
|
||||
--custom-radius: 5px;
|
||||
--custom-radius: 9px;
|
||||
// 系统主色
|
||||
--main-color: #1C6EFF;
|
||||
--el-color-white: white !important;
|
||||
|
|
@ -11,6 +11,11 @@
|
|||
--el-button-hover-border-color: #458FFF !important;
|
||||
--el-color-primary-light-3: #458FFF !important;
|
||||
--el-color-danger: #CF171D !important;
|
||||
--el-menu-text-color: #29343D !important;
|
||||
--el-menu-hover-text-color: #29343D !important;
|
||||
--el-menu-bg-color: #FFFFFF !important;
|
||||
--el-menu-hover-bg-color: rgb(204, 204, 204) !important;
|
||||
--el-menu-level: 0;
|
||||
// 输入框边框颜色
|
||||
// --el-border-color: #E4E4E7 !important; // DCDFE6
|
||||
// 按钮粗度
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
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>()
|
||||
|
||||
|
|
@ -12,6 +13,7 @@ initCache()
|
|||
|
||||
export const useAppPageStore = defineStore('AppPage', () => {
|
||||
const keepAliveInclude = ref<string[]>([])
|
||||
const pages = ref<AppTypes.PageContext[]>([])
|
||||
|
||||
const currentPage = ref<string>('')
|
||||
|
||||
|
|
@ -27,13 +29,68 @@ export const useAppPageStore = defineStore('AppPage', () => {
|
|||
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 close(insId: string) {
|
||||
function reopen(insId: string) {
|
||||
if (currentPage.value === insId) {
|
||||
return
|
||||
}
|
||||
const page = pageContextCache.get(insId)
|
||||
if (page) {
|
||||
currentPage.value = insId
|
||||
Nav.open(page.routeName)
|
||||
}
|
||||
}
|
||||
|
||||
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')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function closeCurrent() {
|
||||
closePage(currentPage.value)
|
||||
}
|
||||
|
||||
function closeOther() {
|
||||
pages.value = pages.value.filter(it => it.insId === currentPage.value)
|
||||
}
|
||||
|
||||
function closeAll() {
|
||||
pages.value = []
|
||||
Nav.open('home')
|
||||
}
|
||||
|
||||
function $reset() {
|
||||
|
|
@ -46,8 +103,14 @@ export const useAppPageStore = defineStore('AppPage', () => {
|
|||
|
||||
return {
|
||||
ctx,
|
||||
reopen,
|
||||
open,
|
||||
close,
|
||||
closePage,
|
||||
closeCurrent,
|
||||
closeOther,
|
||||
closeAll,
|
||||
pages,
|
||||
currentPage,
|
||||
keepAliveInclude,
|
||||
$reset,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ declare global {
|
|||
params: Record<string, any>
|
||||
routeName: string
|
||||
menuId: string
|
||||
icon: string
|
||||
breadcrumb: string[]
|
||||
}
|
||||
|
||||
// 菜单
|
||||
|
|
|
|||
|
|
@ -4,13 +4,32 @@ import { useAppSettingStore } from '@/common/app/app-setting-store.ts'
|
|||
import { useAppUserStore } from '@/common/app/app-user-store.ts'
|
||||
import Utils from '@/common/utils'
|
||||
import type { R } from '@/common/utils/http-util.ts'
|
||||
import { MenuCategory } from '@/common/app/constants.ts'
|
||||
|
||||
const home = {
|
||||
'id': '-1',
|
||||
'sn': 'menus',
|
||||
'pid': '0',
|
||||
'title': '首页',
|
||||
'icon': 'menus',
|
||||
'tier': 1,
|
||||
'breadcrumb': [
|
||||
'首页',
|
||||
],
|
||||
'menuCategory': MenuCategory.Page,
|
||||
'freeze': null,
|
||||
'sort': 0,
|
||||
'routeName': 'home',
|
||||
'path': '/home',
|
||||
}
|
||||
export const reloadUserInfo = () => {
|
||||
const appSettingStore = useAppSettingStore()
|
||||
const appUserStore = useAppUserStore()
|
||||
return LoginApi.my()
|
||||
.then(({data}) => {
|
||||
const menuTree = Utils.clone(Colls.toTree(data.menus))
|
||||
data.menus.unshift(home)
|
||||
menuTree.unshift(home)
|
||||
appSettingStore.$patch({
|
||||
menus: data.menus, menuTree,
|
||||
theme: data.setting?.theme ?? 'light',
|
||||
|
|
@ -30,7 +49,7 @@ export const reloadUserInfo = () => {
|
|||
})
|
||||
}
|
||||
|
||||
export const loadUserInfo = () => {
|
||||
/* export const loadUserInfo = () => {
|
||||
const appSettingStore = useAppSettingStore()
|
||||
const appUserStore = useAppUserStore()
|
||||
return LoginApi.my()
|
||||
|
|
@ -53,7 +72,7 @@ export const loadUserInfo = () => {
|
|||
roles: data.roles,
|
||||
})
|
||||
})
|
||||
}
|
||||
} */
|
||||
|
||||
export function hasPermission(resSn?: string) {
|
||||
const appSettingStore = useAppSettingStore()
|
||||
|
|
|
|||
|
|
@ -9,11 +9,13 @@ import { useAppUserStore } from '@/common/app/app-user-store.ts'
|
|||
import { MenuCategory } from '@/common/app/constants.ts'
|
||||
import { appBaseUrl } from '@/common'
|
||||
import strings from '@/common/utils/strings.ts'
|
||||
import Strings from '@/common/utils/strings.ts'
|
||||
import {
|
||||
getRoute,
|
||||
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
|
||||
|
|
@ -74,10 +76,17 @@ router.beforeEach((to, from) => {
|
|||
name: SpecialPage.Home,
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
replace: true,
|
||||
path: to.fullPath,
|
||||
let routeName = router.getRoutes().find((it) => it.path === to.path)?.name as string
|
||||
console.log('reloadRouter11', routeName, Strings.isBlank(routeName))
|
||||
if (Strings.isBlank(routeName)) {
|
||||
routeName = SpecialPage.Home
|
||||
ElMessage.error('页面不存在222')
|
||||
}
|
||||
console.log('reloadRouter', to, router.getRoutes(), routeName)
|
||||
setTimeout(() => {
|
||||
Nav.open(routeName)
|
||||
})
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
|
@ -113,7 +122,7 @@ export function reloadRouter() {
|
|||
}
|
||||
|
||||
Evt.on('login', (_) => {
|
||||
router.replace('/')
|
||||
Nav.open(SpecialPage.Home)
|
||||
})
|
||||
|
||||
Evt.on('logout', (_) => {
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ function open(option: string | Option) {
|
|||
params: {},
|
||||
routeName,
|
||||
menuId: menu.id,
|
||||
icon: menu.icon,
|
||||
breadcrumb: menu.breadcrumb,
|
||||
}
|
||||
ctx.insId = ctx.routeName
|
||||
useAppPageStore().open(ctx)
|
||||
|
|
@ -67,6 +69,8 @@ function open(option: string | Option) {
|
|||
params: {},
|
||||
routeName,
|
||||
menuId: menu.id,
|
||||
icon: menu.icon,
|
||||
breadcrumb: menu.breadcrumb,
|
||||
}
|
||||
} else {
|
||||
const routeName = option.routeName
|
||||
|
|
@ -91,6 +95,8 @@ function open(option: string | Option) {
|
|||
keepAlive: true,
|
||||
params: option_.params ?? {},
|
||||
menuId: menu.id,
|
||||
icon: menu.icon,
|
||||
breadcrumb: menu.breadcrumb,
|
||||
}
|
||||
ctx.insId = ctx.routeName
|
||||
useAppPageStore().open(ctx)
|
||||
|
|
@ -121,6 +127,8 @@ function open(option: string | Option) {
|
|||
keepAlive: true,
|
||||
params: option.params ?? {},
|
||||
menuId: menu.id,
|
||||
icon: menu.icon,
|
||||
breadcrumb: menu.breadcrumb,
|
||||
}
|
||||
}
|
||||
ctx.insId = ctx.routeName
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<script generic="F extends G.PageParam,TT extends DefaultRow" lang="ts" setup>
|
||||
<script generic="F extends object,TT extends DefaultRow" lang="ts" setup>
|
||||
import {
|
||||
elIcons,
|
||||
type ElIconType,
|
||||
|
|
@ -10,6 +10,7 @@ import Strings from '@/common/utils/strings.ts'
|
|||
import type { R } from '@/common/utils/http-util.ts'
|
||||
import type {
|
||||
TableColumnCtx,
|
||||
TableInstance,
|
||||
TableProps,
|
||||
} from 'element-plus'
|
||||
import type { DefaultRow } from 'element-plus/es/components/table/src/table/defaults'
|
||||
|
|
@ -44,17 +45,20 @@ export interface ActionColumnType<T> {
|
|||
tableActions: TableActionType<T>[]
|
||||
}
|
||||
|
||||
export type TablePropsType<T extends DefaultRow> = Omit<TableProps<T>, 'data' | 'headerRowClassName' | 'cellClassName' | 'context'>
|
||||
export type TablePropsType<T extends DefaultRow, F extends object> = Omit<TableProps<T>, 'data' | 'headerRowClassName' | 'cellClassName' | 'context'> & {
|
||||
treeLoad?: (param: F, row: T, expanded: any, resolve?: (data: T[]) => void) => void
|
||||
}
|
||||
export type FormPropsType = Partial<FormProps>
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
defaultSearchForm?: F
|
||||
paging: (param: F) => Promise<R<G.PageResult<TT>>>
|
||||
paging?: (param: F) => Promise<R<G.PageResult<TT>>>
|
||||
list?: (param: F) => Promise<R<TT[]>>
|
||||
actionColumn?: ActionColumnType<TT>
|
||||
leftTools?: ToolType[]
|
||||
rightTools?: Required<Omit<ToolType, 'type' | 'label'>>[]
|
||||
tableProps?: TablePropsType<TT>
|
||||
tableProps?: TablePropsType<TT, F>
|
||||
searchFormProps?: FormPropsType
|
||||
simpleSearchFormProps?: FormPropsType
|
||||
formStyle?: {
|
||||
|
|
@ -100,6 +104,7 @@ const tableData = Utils.resetAble(reactive<TT[]>([])) as ResetAble<TT[]>
|
|||
const totalCount = ref(0)
|
||||
const loading = ref<boolean>(false)
|
||||
const showSearchForm = ref<boolean>(false)
|
||||
const dataTableIns = useTemplateRef<TableInstance>('dataTable')
|
||||
|
||||
function doReset() {
|
||||
searchForm.$reset()
|
||||
|
|
@ -108,6 +113,7 @@ function doReset() {
|
|||
|
||||
function doSearch() {
|
||||
loading.value = true
|
||||
if (props.paging != null) {
|
||||
props.paging(searchForm.$clone() as F)
|
||||
.then((res) => {
|
||||
totalCount.value = res.data?.total ?? 0
|
||||
|
|
@ -117,6 +123,20 @@ function doSearch() {
|
|||
.finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
return
|
||||
}
|
||||
if (props.list != null) {
|
||||
props.list(searchForm.$clone() as F)
|
||||
.then((res) => {
|
||||
totalCount.value = res.data?.length ?? 0
|
||||
const records = res.data ?? ([] as TT[])
|
||||
tableData.$reset(records)
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function showSearchFormHandle() {
|
||||
|
|
@ -146,6 +166,7 @@ function rowAction(data: { row: TT, column: TableColumnCtx, $index: number }, ac
|
|||
|
||||
defineExpose({
|
||||
doSearch,
|
||||
dataTableIns,
|
||||
})
|
||||
onMounted(doSearch)
|
||||
</script>
|
||||
|
|
@ -156,7 +177,6 @@ onMounted(doSearch)
|
|||
<ElScrollbar>
|
||||
<ElForm :class="{'border-form':formStyle.border}" v-bind="searchFormProps" @submit.prevent="doSearch">
|
||||
<slot :searchForm="searchForm" name="searchFormItem"/>
|
||||
|
||||
<ElFormItem class="form-action-btn">
|
||||
<ElButton :icon="elIcons.Search" :loading="loading" native-type="submit" type="primary">搜索</ElButton>
|
||||
<ElButton :icon="elIcons.Refresh" :loading="loading" @click="doReset">重置</ElButton>
|
||||
|
|
@ -165,7 +185,7 @@ onMounted(doSearch)
|
|||
</ElScrollbar>
|
||||
</div>
|
||||
<div class="data-list">
|
||||
<div v-if="!Colls.isEmpty(leftTools) || !Colls.isEmpty(rightTools)" class="tool-bar">
|
||||
<div class="tool-bar">
|
||||
<div class="tool-bar-left">
|
||||
<template v-if="!Colls.isEmpty(leftTools)">
|
||||
<ElButton v-for="(tool,i) in leftTools" :key="'tool-bar-left-'+i"
|
||||
|
|
@ -209,6 +229,10 @@ onMounted(doSearch)
|
|||
<ElTable
|
||||
v-loading="loading"
|
||||
:data="tableData"
|
||||
ref="dataTable"
|
||||
:lazy="tableProps.treeLoad ==null?undefined:true"
|
||||
:load="tableProps.treeLoad?((row, expanded, resolve)=>tableProps.treeLoad!(searchForm as F, row, expanded, resolve)):undefined"
|
||||
@expand-change="tableProps.treeLoad?((row:any, expandedRows:any)=>tableProps.treeLoad!(searchForm as F, row, expandedRows, undefined)):undefined"
|
||||
cell-class-name="table-cell"
|
||||
class="table-list"
|
||||
header-row-class-name="table-header"
|
||||
|
|
@ -311,9 +335,10 @@ onMounted(doSearch)
|
|||
</ElTableColumn>
|
||||
</ElTable>
|
||||
<ElPagination
|
||||
v-if="paging!=null"
|
||||
class="pagination"
|
||||
v-model:current-page="searchForm.current"
|
||||
v-model:page-size="searchForm.size"
|
||||
v-model:current-page="(searchForm as G.PageParam).current"
|
||||
v-model:page-size="(searchForm as G.PageParam).size"
|
||||
:hide-on-single-page="false"
|
||||
:page-sizes="[10, 20, 50, 100, 500]"
|
||||
:teleported="false"
|
||||
|
|
@ -329,7 +354,7 @@ onMounted(doSearch)
|
|||
<style lang="stylus" scoped>
|
||||
.form-page {
|
||||
.search-form {
|
||||
border: 1px solid #00000014;
|
||||
border: 1px solid #EAEBF1;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
background-color: white;
|
||||
|
|
@ -401,7 +426,7 @@ onMounted(doSearch)
|
|||
flex 1
|
||||
display flex
|
||||
flex-direction column
|
||||
border: 1px solid #00000014;
|
||||
border: 1px solid #EAEBF1;
|
||||
padding: 15px 20px 20px 15px;
|
||||
border-radius: 8px;
|
||||
background-color: white;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@
|
|||
width 100%;
|
||||
overflow hidden
|
||||
padding 5px
|
||||
|
||||
contain: layout paint;
|
||||
transform: translateZ(0);
|
||||
box-sizing border-box
|
||||
//box-shadow: inset rgba(30, 35, 43, 0.16) 0px 0 10px 1px;
|
||||
//background-color: white;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ declare module 'vue' {
|
|||
export interface GlobalComponents {
|
||||
ElAside: typeof import('element-plus/es')['ElAside']
|
||||
ElAvatar: typeof import('element-plus/es')['ElAvatar']
|
||||
ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
|
||||
ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem']
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
||||
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
|
||||
|
|
@ -32,8 +34,6 @@ declare module 'vue' {
|
|||
ElHeader: typeof import('element-plus/es')['ElHeader']
|
||||
ElIcon: typeof import('element-plus/es')['ElIcon']
|
||||
ElIconCircleClose: typeof import('@element-plus/icons-vue')['CircleClose']
|
||||
ElIconCirclePlus: typeof import('@element-plus/icons-vue')['CirclePlus']
|
||||
ElIconDelete: typeof import('@element-plus/icons-vue')['Delete']
|
||||
ElIconPicture: typeof import('@element-plus/icons-vue')['Picture']
|
||||
ElIconPlus: typeof import('@element-plus/icons-vue')['Plus']
|
||||
ElImage: typeof import('element-plus/es')['ElImage']
|
||||
|
|
@ -71,6 +71,8 @@ declare module 'vue' {
|
|||
declare global {
|
||||
const ElAside: typeof import('element-plus/es')['ElAside']
|
||||
const ElAvatar: typeof import('element-plus/es')['ElAvatar']
|
||||
const ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
|
||||
const ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem']
|
||||
const ElButton: typeof import('element-plus/es')['ElButton']
|
||||
const ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
||||
const ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
|
||||
|
|
@ -90,8 +92,6 @@ declare global {
|
|||
const ElHeader: typeof import('element-plus/es')['ElHeader']
|
||||
const ElIcon: typeof import('element-plus/es')['ElIcon']
|
||||
const ElIconCircleClose: typeof import('@element-plus/icons-vue')['CircleClose']
|
||||
const ElIconCirclePlus: typeof import('@element-plus/icons-vue')['CirclePlus']
|
||||
const ElIconDelete: typeof import('@element-plus/icons-vue')['Delete']
|
||||
const ElIconPicture: typeof import('@element-plus/icons-vue')['Picture']
|
||||
const ElIconPlus: typeof import('@element-plus/icons-vue')['Plus']
|
||||
const ElImage: typeof import('element-plus/es')['ElImage']
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
import {
|
||||
ElButton,
|
||||
ElIcon,
|
||||
ElMenu,
|
||||
ElMenuItem,
|
||||
ElMenuItemGroup,
|
||||
ElScrollbar,
|
||||
ElSubMenu,
|
||||
type MenuItemRegistered,
|
||||
} from 'element-plus'
|
||||
import { elIcons } from '@/common/element/element.ts'
|
||||
import AIcon from '@/components/a-icon/AIcon.vue'
|
||||
import type { IconName } from '@/components/a-icon/iconfont.ts'
|
||||
import styles from '@/pages/a-frame/aaside.module.styl'
|
||||
|
|
@ -17,6 +15,7 @@ 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'
|
||||
|
||||
export interface Menu extends G.TreeNode {
|
||||
// Id
|
||||
|
|
@ -44,11 +43,10 @@ export interface Menu extends G.TreeNode {
|
|||
}
|
||||
|
||||
export default defineComponent(
|
||||
() => {
|
||||
(props) => {
|
||||
const router = useRouter()
|
||||
const appSettingStore = useAppSettingStore()
|
||||
const defaultActive = ref<any>('')
|
||||
const isCollapse = ref(false)
|
||||
|
||||
onMounted(() => {
|
||||
const currentRouteName = router.currentRoute.value.name
|
||||
|
|
@ -118,23 +116,27 @@ export default defineComponent(
|
|||
|
||||
return () => (
|
||||
<>
|
||||
<ElMenu default-active={defaultActive.value} collapse={isCollapse.value} class={[ styles.aMenus ]}>
|
||||
<div class={[ styles.aAsideTop, {[styles.aAsideTopCollapse]: props.isCollapse} ]}>
|
||||
<img alt="" src={logo}/>
|
||||
<div>再昇云</div>
|
||||
</div>
|
||||
<ElScrollbar class={styles.aScrollbar}>
|
||||
<ElMenu default-active={defaultActive.value} collapse={props.isCollapse} class={[ styles.aMenus ]}>
|
||||
{{
|
||||
default: () => menuTree.value.map(renderMenu),
|
||||
}}
|
||||
</ElMenu>
|
||||
<ElButton
|
||||
class={[ styles.aCollapseBtn, {[styles.aCollapseBtnCollapse]: isCollapse.value} ]}
|
||||
onClick={() => {
|
||||
isCollapse.value = !isCollapse.value
|
||||
}}
|
||||
>
|
||||
<ElIcon style={{cursor: 'pointer'}}>{isCollapse.value ? <elIcons.Fold/> : <elIcons.Expand/>}</ElIcon>
|
||||
</ElButton>
|
||||
</ElScrollbar>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
name: 'AAside',
|
||||
props: {
|
||||
isCollapse: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,15 @@
|
|||
<script lang="ts" setup>
|
||||
import AAside from '@/pages/a-frame/AAside.tsx'
|
||||
import AAvatar from '@/pages/a-frame/AAvatar.vue'
|
||||
import { appName } from '@/common'
|
||||
import Evt from '@/common/utils/evt.ts'
|
||||
import AIcon from '@/components/a-icon/AIcon.vue'
|
||||
import { useAppPageStore } from '@/common/app/app-page-store.ts'
|
||||
import { elIcons } from '@/common/element/element.ts'
|
||||
import ATabbar from '@/pages/a-frame/ATabbar.vue'
|
||||
|
||||
const appPageStore = useAppPageStore()
|
||||
const isCollapse = ref(false)
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
Evt.emit('connect_ws')
|
||||
|
|
@ -16,10 +22,17 @@ onUnmounted(() => {
|
|||
|
||||
<template>
|
||||
<ElContainer class="a-frame">
|
||||
<ElHeader>
|
||||
<ElAside class="a-frame-aside">
|
||||
<AAside :is-collapse="isCollapse"/>
|
||||
</ElAside>
|
||||
<ElContainer>
|
||||
<ElHeader class="a-frame-header">
|
||||
<div>
|
||||
<img alt="" src="@/assets/images/zsy.png"/>
|
||||
<div>{{ appName }}</div>
|
||||
<div>
|
||||
<ElButton :icon="isCollapse?elIcons.Fold:elIcons.Expand" text @click="isCollapse = !isCollapse"/>
|
||||
<ElBreadcrumb :separator-icon="elIcons.ArrowRight">
|
||||
<ElBreadcrumbItem v-for="(item, i) in appPageStore?.ctx?.breadcrumb??[]" :key="'a-frame-header-breadcrumb'+i">{{ item }}</ElBreadcrumbItem>
|
||||
</ElBreadcrumb>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
|
|
@ -32,16 +45,12 @@ onUnmounted(() => {
|
|||
</div>
|
||||
<AAvatar/>
|
||||
</div>
|
||||
</div>
|
||||
<ATabbar/>
|
||||
</ElHeader>
|
||||
<ElContainer>
|
||||
<ElAside>
|
||||
<ElScrollbar>
|
||||
<AAside/>
|
||||
</ElScrollbar>
|
||||
</ElAside>
|
||||
<ElMain>
|
||||
<ElMain class="a-frame-main">
|
||||
<RouterView #="{ Component }">
|
||||
<Transition name="el-fade-in-linear">
|
||||
<Transition name="slide-fade">
|
||||
<component :is="Component"/>
|
||||
</Transition>
|
||||
</RouterView>
|
||||
|
|
@ -55,31 +64,51 @@ onUnmounted(() => {
|
|||
height 100%
|
||||
width 100%;
|
||||
overflow hidden
|
||||
box-shadow: inset rgba(0, 0, 0, 0.12) 0px 0px 12px 0px;
|
||||
box-shadow: inset #0000001F 0 0 12px 0;
|
||||
background-color #F7F9FC
|
||||
|
||||
& > header {
|
||||
display flex
|
||||
justify-content space-between
|
||||
border-bottom 1px solid #E5E7EB;
|
||||
height 60px
|
||||
.a-frame-aside {
|
||||
height 100%;
|
||||
width auto
|
||||
position relative
|
||||
border-right: solid 1px #EAEBF1;
|
||||
//border-right: solid 1px var(--el-menu-border-color);
|
||||
background-color white
|
||||
box-sizing border-box
|
||||
}
|
||||
|
||||
& > section {
|
||||
height 100%
|
||||
|
||||
.a-frame-header {
|
||||
height 100px
|
||||
padding: 0 10px 0 0
|
||||
|
||||
background-color white
|
||||
|
||||
& > div:first-child {
|
||||
& > div:nth-child(1) {
|
||||
height 60px
|
||||
width 100%
|
||||
|
||||
display flex
|
||||
justify-content space-between
|
||||
box-sizing border-box
|
||||
|
||||
& > div:nth-child(1) {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
box-sizing border-box
|
||||
|
||||
img {
|
||||
height 50%
|
||||
margin-right 12px
|
||||
:deep(.el-breadcrumb) {
|
||||
.el-breadcrumb__inner {
|
||||
color #7987A1
|
||||
cursor default
|
||||
}
|
||||
|
||||
& > div {
|
||||
color: #165DFF;
|
||||
font-weight: 700;
|
||||
font-size: 1.5rem;
|
||||
.el-breadcrumb__separator {
|
||||
color #7987A1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -101,28 +130,69 @@ onUnmounted(() => {
|
|||
}
|
||||
}
|
||||
|
||||
& > section {
|
||||
width 100%;
|
||||
height calc(100% - 60px)
|
||||
|
||||
& > aside {
|
||||
height 100%;
|
||||
width auto
|
||||
position relative
|
||||
border-right: solid 1px var(--el-menu-border-color);
|
||||
|
||||
background-color white
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
& > main {
|
||||
height 100%
|
||||
width calc(100% - 300px)
|
||||
.a-frame-main {
|
||||
height calc(100% - 60px)
|
||||
width 100%;
|
||||
padding 0
|
||||
overflow auto
|
||||
//background-color #F7F9FC
|
||||
overflow hidden
|
||||
background-color rgb(250, 251, 252)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*.slide-fade-enter-active {
|
||||
transition:
|
||||
transform 0.4s cubic-bezier(0.25, 0.1, 0.25, 1),
|
||||
opacity 0.4s ease-out;
|
||||
will-change: transform, opacity;
|
||||
backface-visibility: hidden;
|
||||
transform-origin: 50% 50%;
|
||||
}
|
||||
|
||||
.slide-fade-leave-active {
|
||||
transition:
|
||||
transform 0.3s cubic-bezier(0.5, 0, 0.2, 1),
|
||||
opacity 0.3s ease-in;
|
||||
will-change: transform, opacity;
|
||||
backface-visibility: hidden;
|
||||
transform-origin: 50% 50%;
|
||||
}
|
||||
|
||||
.slide-fade-enter-from,
|
||||
.slide-fade-leave-to {
|
||||
transform: scaleY(0);
|
||||
opacity: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.slide-fade-enter-to,
|
||||
.slide-fade-leave-from {
|
||||
transform: scaleY(1);
|
||||
opacity: 1;
|
||||
}*/
|
||||
|
||||
.slide-fade-enter-active {
|
||||
//transition: transform 0.3s cubic-bezier(0.25, 0.1, 0.25, 1),
|
||||
// opacity 0.3s ease-out;
|
||||
transition: transform 0.3s ease-in-out,
|
||||
opacity 0.3s ease-in-out;
|
||||
will-change: transform, opacity;
|
||||
}
|
||||
|
||||
.slide-fade-leave-active {
|
||||
//transition: transform 0.3s cubic-bezier(0.5, 0, 0.2, 1),
|
||||
// opacity 0.3s ease-in;
|
||||
transition: transform 0.3s cubic-bezier(1, 0.5, 0.8, 1),
|
||||
opacity 0.3s ease-in-out;
|
||||
will-change: transform, opacity;
|
||||
}
|
||||
|
||||
.slide-fade-enter-from,
|
||||
.slide-fade-leave-to {
|
||||
transform: translateX(20px);
|
||||
opacity: 0;
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,150 @@
|
|||
<template>
|
||||
<div class="a-tabs">
|
||||
<ElScrollbar class="a-tabs-scrollbar">
|
||||
<div class="a-tabs-wrapper">
|
||||
<div v-for="(item,i) in appPageStore.pages"
|
||||
:key="'a-frame-header-tab'+i"
|
||||
:class="{'a-tab-item-active': item.insId === appPageStore.currentPage}"
|
||||
class="a-tab-item"
|
||||
@click="reopen(item.insId)">
|
||||
<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>
|
||||
</div>
|
||||
</ElScrollbar>
|
||||
<ElDropdown placement="bottom" @command="handleCommand">
|
||||
<ElButton :icon="elIcons.More" text/>
|
||||
<template #dropdown>
|
||||
<ElDropdownMenu>
|
||||
<ElDropdownItem command="closeCurrent">关闭当前</ElDropdownItem>
|
||||
<ElDropdownItem command="closeOther">关闭其他</ElDropdownItem>
|
||||
<ElDropdownItem command="closeAll">关闭所有</ElDropdownItem>
|
||||
</ElDropdownMenu>
|
||||
</template>
|
||||
</ElDropdown>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { useAppPageStore } from '@/common/app/app-page-store.ts'
|
||||
import { elIcons } from '@/common/element/element.ts'
|
||||
import type { IconName } from '@/components/a-icon/iconfont.ts'
|
||||
import AIcon from '@/components/a-icon/AIcon.vue'
|
||||
|
||||
const appPageStore = useAppPageStore()
|
||||
|
||||
function reopen(insId: string) {
|
||||
appPageStore.reopen(insId)
|
||||
}
|
||||
|
||||
function handleCommand(command: 'closeCurrent' | 'closeOther' | 'closeAll') {
|
||||
appPageStore[command]()
|
||||
}
|
||||
</script>
|
||||
<style lang="stylus" scoped>
|
||||
.a-tabs {
|
||||
height 32px
|
||||
width 100%;
|
||||
box-sizing border-box
|
||||
border-top 1px solid #EAEBF1;
|
||||
border-bottom 1px solid #EAEBF1;
|
||||
display flex
|
||||
justify-content space-between
|
||||
align-items center
|
||||
color #303133
|
||||
|
||||
:deep(.el-dropdown) {
|
||||
width: 32px;
|
||||
padding: 0;
|
||||
margin-right 20px
|
||||
}
|
||||
}
|
||||
|
||||
.a-tabs-scrollbar {
|
||||
height 100%
|
||||
width calc(100% - 52px);
|
||||
box-sizing border-box
|
||||
|
||||
:deep(.el-scrollbar__wrap) {
|
||||
height 100%
|
||||
box-sizing border-box
|
||||
}
|
||||
|
||||
:deep(.el-scrollbar__view) {
|
||||
height 100%
|
||||
box-sizing border-box
|
||||
}
|
||||
}
|
||||
|
||||
.a-tabs-wrapper {
|
||||
height 100%
|
||||
width: fit-content;
|
||||
display flex
|
||||
box-sizing border-box
|
||||
align-items center
|
||||
|
||||
.a-tab-item {
|
||||
height 100%
|
||||
max-width 160px
|
||||
padding 5px 10px
|
||||
cursor pointer
|
||||
display flex
|
||||
justify-content space-between
|
||||
gap 20px
|
||||
align-items center
|
||||
box-sizing border-box
|
||||
position relative
|
||||
border-right 1px solid #EAEBF1
|
||||
transition color 0.2s ease-in-out
|
||||
font-size 14px
|
||||
|
||||
& > div:first-child {
|
||||
display flex
|
||||
gap 10px
|
||||
align-items center
|
||||
}
|
||||
|
||||
& > button {
|
||||
padding 0
|
||||
width 14px
|
||||
height 14px !important
|
||||
line-height 14px
|
||||
border-radius 50%
|
||||
|
||||
&:hover {
|
||||
color var(--el-color-danger)
|
||||
}
|
||||
}
|
||||
|
||||
&::after {
|
||||
content ''
|
||||
height 2px
|
||||
width 0
|
||||
background-color var(--main-color)
|
||||
position absolute
|
||||
bottom 0
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
transition width 0.2s ease-in-out
|
||||
}
|
||||
|
||||
&.a-tab-item-active {
|
||||
color var(--main-color)
|
||||
|
||||
&::after {
|
||||
width 100%
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color var(--main-color)
|
||||
|
||||
&::after {
|
||||
width 100%
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,3 +1,55 @@
|
|||
.a-aside-top {
|
||||
height 60px
|
||||
width 100%;
|
||||
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
|
||||
|
||||
& > img {
|
||||
height 32px
|
||||
width 32px
|
||||
//margin-left 18px
|
||||
//transition margin-left 0.333s ease-in-out
|
||||
}
|
||||
|
||||
& > div {
|
||||
color: #252f4a;
|
||||
font-weight: 700;
|
||||
font-size: 1.5rem;
|
||||
opacity 1
|
||||
width 168px;
|
||||
overflow hidden
|
||||
transition all 0.333s ease-in-out
|
||||
text-wrap nowrap
|
||||
letter-spacing 10px
|
||||
}
|
||||
|
||||
&.a-aside-top-collapse {
|
||||
width 60px;
|
||||
padding-left 14px
|
||||
|
||||
& > div {
|
||||
opacity 0
|
||||
width 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.a-scrollbar {
|
||||
height calc(100% - 60px)
|
||||
width 100%;
|
||||
padding: 0 0 10px 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.a-menus {
|
||||
height: 100%;
|
||||
--el-menu-base-level-padding: 10px;
|
||||
|
|
@ -65,7 +117,7 @@
|
|||
bottom: 6px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
transition right 0.3s ease-in-out;
|
||||
transition right 0.333s ease-in-out;
|
||||
|
||||
&.a-collapse-btn-collapse {
|
||||
right: calc(50% - 16px);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,13 @@
|
|||
|
||||
<template>
|
||||
<div>
|
||||
<div class="home">
|
||||
<div class="home-top">
|
||||
<div class="home-top-title">
|
||||
首页
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import {
|
|||
} from 'element-plus'
|
||||
import Strings from '@/common/utils/strings.ts'
|
||||
import FormUtil from '@/common/utils/formUtil.ts'
|
||||
import { loadUserInfo } from '@/common/app'
|
||||
import { reloadUserInfo } from '@/common/app'
|
||||
|
||||
const loginFormIns = useTemplateRef<FormInstance>('loginFormRef')
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ function loginSubmitHandler() {
|
|||
() => LoginApi.login(loginForm))
|
||||
.then(({data}) => {
|
||||
appUserStore.$patch({token: data.token})
|
||||
return loadUserInfo()
|
||||
return reloadUserInfo()
|
||||
})
|
||||
.then(() => {
|
||||
Evt.emit('login')
|
||||
|
|
|
|||
|
|
@ -1,34 +1,31 @@
|
|||
<template>
|
||||
<Page>
|
||||
<ElForm v-show="showSearchForm" inline @submit.prevent="listAll">
|
||||
<ElFormItem label-width="90" label="菜单名称">
|
||||
<FormPage
|
||||
ref="formPage"
|
||||
:action-column="actionColumn"
|
||||
:left-tools="leftTools"
|
||||
:list="listAll"
|
||||
:table-props="{
|
||||
treeProps: { children: 'children', hasChildren: 'hasChildren' },
|
||||
treeLoad: treeLoad,
|
||||
}"
|
||||
>
|
||||
<template #searchFormItem="{ searchForm }">
|
||||
<ElFormItem label="菜单名称">
|
||||
<ElInput v-model="searchForm.title" placeholder="菜单名称"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label-width="90" label="路由名称">
|
||||
<ElFormItem label="路由名称">
|
||||
<ElInput v-model="searchForm.routeName" placeholder="路由名称"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem>
|
||||
<ElButton :icon="elIcons.Search" :loading="searching" native-type="submit" type="primary">搜索</ElButton>
|
||||
<ElButton :icon="elIcons.Refresh" :loading="searching" @click="reset">重置</ElButton>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<div class="tool-bar">
|
||||
<ElButton :icon="elIcons.Plus" type="primary" @click="addHandler">新建</ElButton>
|
||||
<ElButton :icon="elIcons.Filter" type="default" @click="showSearchForm = !showSearchForm"/>
|
||||
</div>
|
||||
<ElTable v-loading="searching"
|
||||
</template>
|
||||
<template #columns>
|
||||
|
||||
<!--
|
||||
:data="tableData"
|
||||
lazy
|
||||
:load="treeLoad"
|
||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
||||
@expand-change="treeLoad"
|
||||
cell-class-name="table-cell"
|
||||
class="table-list"
|
||||
empty-text="暂无数据"
|
||||
header-row-class-name="table-header"
|
||||
ref="dataTable"
|
||||
row-key="id">
|
||||
<!-- <ElTableColumn type="expand" width="60"/> -->
|
||||
-->
|
||||
<ElTableColumn label="图标" prop="icon" width="100">
|
||||
<template #default="scope">
|
||||
<AIcon :name="scope.row.icon"/>
|
||||
|
|
@ -37,7 +34,6 @@
|
|||
<ElTableColumn label="类型" prop="menuCategoryTxt" width="140"/>
|
||||
<ElTableColumn label="菜单名称" prop="title"/>
|
||||
<ElTableColumn label="编码" prop="sn" width="180"/>
|
||||
<!-- <ElTableColumn label="路径" prop="breadcrumb"/> -->
|
||||
<ElTableColumn label="路由名称" prop="routeName">
|
||||
<template #default="scope">
|
||||
<span>
|
||||
|
|
@ -52,102 +48,87 @@
|
|||
</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<!-- <ElTableColumn label="排序" prop="sort" width="60"/> -->
|
||||
<ElTableColumn label="操作" width="180">
|
||||
<template #default="scope">
|
||||
<ElPopconfirm
|
||||
cancel-button-text="否"
|
||||
cancel-button-type="primary"
|
||||
confirm-button-text="是"
|
||||
confirm-button-type="danger"
|
||||
placement="top"
|
||||
title="是否删除当前数据?"
|
||||
width="180"
|
||||
@confirm="delHandler(scope)">
|
||||
<template #reference>
|
||||
<ElButton :loading="deling" text type="danger">删除</ElButton>
|
||||
</template>
|
||||
</ElPopconfirm>
|
||||
<ElButton text type="primary" @click="modifyHandler(scope)">修改</ElButton>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</ElTable>
|
||||
|
||||
<MenuForm ref="menuForm" @editSucc="editSuccHandler"/>
|
||||
</template>
|
||||
|
||||
</Page>
|
||||
<MenuForm ref="menuForm" @editSucc="research"/>
|
||||
|
||||
</FormPage>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import MenuApi from '@/pages/sys/menus/menu-api.ts'
|
||||
import Page from '@/components/page/Page.vue'
|
||||
import { onMounted } from 'vue'
|
||||
import { elIcons } from '@/common/element/element.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,
|
||||
} from '@/components/page/FormPage.vue'
|
||||
import type { ComponentExposed } from 'vue-component-type-helpers'
|
||||
|
||||
const tableData = ref<MenuTypes.SysMenu[]>([])
|
||||
const searchForm = ref<MenuTypes.SearchForm>({})
|
||||
const searching = ref(false)
|
||||
const showSearchForm = ref(true)
|
||||
const menuFormIns = useTemplateRef<InstanceType<typeof MenuForm>>('menuForm')
|
||||
const dataTableIns = useTemplateRef<TableInstance>('dataTable')
|
||||
const deling = ref(false)
|
||||
const formPageIns = useTemplateRef<ComponentExposed<typeof FormPage>>('formPage')
|
||||
|
||||
function showDialog(data?: MenuTypes.MenuForm) {
|
||||
menuFormIns.value?.open(data)
|
||||
}
|
||||
|
||||
function delHandler({row}: { row: MenuTypes.MenuForm, }) {
|
||||
deling.value = true
|
||||
|
||||
MenuApi.del([ row.id! ])
|
||||
const actionColumn = reactive<ActionColumnType<MenuTypes.SysMenu>>({
|
||||
tableActions: [
|
||||
{
|
||||
tooltip: '编辑',
|
||||
icon: 'Edit',
|
||||
action({row}) {
|
||||
menuFormIns.value?.open(row as MenuTypes.MenuForm)
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: 'Delete',
|
||||
loading: false,
|
||||
type: 'danger',
|
||||
tooltip: '删除',
|
||||
confirm: {
|
||||
title: '是否删除当前数据',
|
||||
},
|
||||
action({row}) {
|
||||
return MenuApi.del([ row.id! ])
|
||||
.then(() => {
|
||||
ElMessage.success('删除成功')
|
||||
listAll()
|
||||
return true
|
||||
})
|
||||
.finally(() => deling.value = false)
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
const leftTools: ToolType[] = [
|
||||
{
|
||||
icon: 'Plus',
|
||||
label: '新建',
|
||||
action() {
|
||||
menuFormIns.value?.open()
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
function research() {
|
||||
formPageIns.value?.doSearch()
|
||||
}
|
||||
|
||||
function modifyHandler({row}: { row: MenuTypes.MenuForm, }) {
|
||||
showDialog(row)
|
||||
}
|
||||
|
||||
function addHandler() {
|
||||
showDialog()
|
||||
}
|
||||
|
||||
function reset() {
|
||||
searchForm.value = {}
|
||||
listAll()
|
||||
}
|
||||
|
||||
function editSuccHandler() {
|
||||
listAll()
|
||||
}
|
||||
|
||||
function listAll() {
|
||||
searching.value = true
|
||||
MenuApi.listAll({...searchForm.value, pid: '0'})
|
||||
function listAll(param: MenuTypes.SearchForm) {
|
||||
return MenuApi.listAll({...param, pid: '0'})
|
||||
.then(res => {
|
||||
tableData.value = []
|
||||
tableData.value = res.data?.map(it => {
|
||||
const data = res.data ?? []
|
||||
for (let it of data) {
|
||||
it.hasChildren = true
|
||||
it.children = []
|
||||
return it
|
||||
}) ?? []
|
||||
})
|
||||
.finally(() => {
|
||||
searching.value = false
|
||||
}
|
||||
return res
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
function treeLoad(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
|
||||
searching.value = true
|
||||
MenuApi.listAll({...searchForm.value, pid: row.id})
|
||||
MenuApi.listAll({...param, pid: row.id})
|
||||
.then(res => {
|
||||
if (resolve != null) {
|
||||
resolve(res.data?.map(it => {
|
||||
|
|
@ -155,64 +136,14 @@ function treeLoad(row: MenuTypes.SysMenu, expanded: any, resolve: (data: MenuTyp
|
|||
return it
|
||||
}) ?? [])
|
||||
} else {
|
||||
dataTableIns.value?.updateKeyChildren(row.id, res.data?.map(it => {
|
||||
formPageIns.value?.dataTableIns?.updateKeyChildren(row.id, res.data?.map(it => {
|
||||
it.hasChildren = true
|
||||
it.children = []
|
||||
return it
|
||||
}) ?? [])
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
searching.value = false
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
listAll()
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.table-list {
|
||||
flex 1;
|
||||
width 100%
|
||||
|
||||
:deep(.table-header) {
|
||||
color #454C59
|
||||
|
||||
th {
|
||||
background-color #EDF1F7
|
||||
font-weight 500
|
||||
position relative
|
||||
|
||||
& > div {
|
||||
display flex
|
||||
gap 5px
|
||||
align-items center
|
||||
}
|
||||
|
||||
&:not(:first-child) > div::before {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 1px;
|
||||
width: 1px;
|
||||
background-color: #D3D7DE;
|
||||
transform: translateY(-50%);
|
||||
content: "";
|
||||
height 50%
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.table-cell) {
|
||||
color #2F3540
|
||||
}
|
||||
}
|
||||
|
||||
.tool-bar {
|
||||
display flex
|
||||
justify-content space-between
|
||||
margin 0 0 20px 0
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Reference in New Issue