feat(Breadcrumbe): Add Breadcrumb component
style: change function to arrow function
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
<script lang="tsx">
|
||||
import { ElBreadcrumb, ElBreadcrumbItem } from 'element-plus'
|
||||
import { ref, watch, computed, unref, defineComponent, TransitionGroup } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
// import { compile } from 'path-to-regexp'
|
||||
import { usePermissionStore } from '@/store/modules/permission'
|
||||
import { filterBreadcrumb } from './helper'
|
||||
import { filter, treeToList } from '@/utils/tree'
|
||||
import type { RouteLocationNormalizedLoaded, RouteMeta } from 'vue-router'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { Icon } from '@/components/Icon'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Breadcrumb',
|
||||
setup() {
|
||||
const { currentRoute } = useRouter()
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const levelList = ref<AppRouteRecordRaw[]>([])
|
||||
|
||||
const permissionStore = usePermissionStore()
|
||||
|
||||
const menuRouters = computed(() => {
|
||||
const routers = permissionStore.getRouters
|
||||
return filterBreadcrumb(routers)
|
||||
})
|
||||
|
||||
const getBreadcrumb = () => {
|
||||
const currentPath = currentRoute.value.path
|
||||
|
||||
levelList.value = filter<AppRouteRecordRaw>(unref(menuRouters), (node: AppRouteRecordRaw) => {
|
||||
return node.path === currentPath
|
||||
})
|
||||
}
|
||||
|
||||
const renderBreadcrumb = () => {
|
||||
const breadcrumbList = treeToList<AppRouteRecordRaw[]>(unref(levelList))
|
||||
return breadcrumbList.map((v) => {
|
||||
const disabled = v.redirect === 'noredirect'
|
||||
const meta = v.meta as RouteMeta
|
||||
return (
|
||||
<ElBreadcrumbItem to={{ path: disabled ? '' : v.path }} key={v.name}>
|
||||
{meta?.icon ? (
|
||||
<>
|
||||
<Icon icon={meta.icon} class="mr-[5px]"></Icon> {t(v?.meta?.title)}
|
||||
</>
|
||||
) : (
|
||||
t(v?.meta?.title)
|
||||
)}
|
||||
</ElBreadcrumbItem>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
watch(
|
||||
() => currentRoute.value,
|
||||
(route: RouteLocationNormalizedLoaded) => {
|
||||
if (route.path.startsWith('/redirect/')) {
|
||||
return
|
||||
}
|
||||
getBreadcrumb()
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
|
||||
return () => (
|
||||
<ElBreadcrumb separator="/" class="flex items-center h-full ml-[10px]">
|
||||
<TransitionGroup appear enter-active-class="animate__animated animate__fadeInRight">
|
||||
{renderBreadcrumb()}
|
||||
</TransitionGroup>
|
||||
</ElBreadcrumb>
|
||||
)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
:deep(.el-breadcrumb__item) {
|
||||
display: flex;
|
||||
|
||||
.el-breadcrumb__inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
31
src/components/Breadcrumb/src/helper.ts
Normal file
31
src/components/Breadcrumb/src/helper.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { pathResolve } from '@/utils/routerHelper'
|
||||
import type { RouteMeta } from 'vue-router'
|
||||
|
||||
export const filterBreadcrumb = (
|
||||
routes: AppRouteRecordRaw[],
|
||||
parentPath = ''
|
||||
): AppRouteRecordRaw[] => {
|
||||
const res: AppRouteRecordRaw[] = []
|
||||
|
||||
for (const route of routes) {
|
||||
const meta = route?.meta as RouteMeta
|
||||
if (meta.hidden && !meta.showMainRoute) {
|
||||
continue
|
||||
}
|
||||
|
||||
const data: AppRouteRecordRaw =
|
||||
!meta.alwaysShow && route.children?.length === 1
|
||||
? { ...route.children[0], path: pathResolve(route.path, route.children[0].path) }
|
||||
: { ...route }
|
||||
|
||||
data.path = pathResolve(parentPath, data.path)
|
||||
|
||||
if (data.children) {
|
||||
data.children = filterBreadcrumb(data.children, data.path)
|
||||
}
|
||||
if (data) {
|
||||
res.push(data)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
@@ -1,13 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, unref } from 'vue'
|
||||
import { Icon } from '@/components/Icon'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
|
||||
const appStore = useAppStore()
|
||||
|
||||
const collapse = computed(() => appStore.getCollapse)
|
||||
|
||||
function toggleCollapse() {
|
||||
const toggleCollapse = () => {
|
||||
const collapsed = unref(collapse)
|
||||
appStore.setCollapse(!collapsed)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,33 @@
|
||||
<script setup lang="ts">
|
||||
import { provide, computed } from 'vue'
|
||||
import { provide, computed, watch } from 'vue'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import { ElConfigProvider } from 'element-plus'
|
||||
import { useLocaleStore } from '@/store/modules/locale'
|
||||
import { useWindowSize } from '@vueuse/core'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { setCssVar } from '@/utils'
|
||||
|
||||
const appStore = useAppStore()
|
||||
|
||||
const { width } = useWindowSize()
|
||||
|
||||
watch(
|
||||
() => width.value,
|
||||
(width: number) => {
|
||||
if (width < 768) {
|
||||
!appStore.getMobile ? appStore.setMobile(true) : undefined
|
||||
setCssVar('--left-menu-min-width', '0')
|
||||
appStore.setCollapse(true)
|
||||
appStore.getLayout !== 'classic' ? appStore.setLayout('classic') : undefined
|
||||
} else {
|
||||
appStore.getMobile ? appStore.setMobile(false) : undefined
|
||||
setCssVar('--left-menu-min-width', '64px')
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
|
||||
const localeStore = useLocaleStore()
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ export default defineComponent({
|
||||
})
|
||||
|
||||
// 对表单赋值
|
||||
function setValues(data: FormSetValuesType[]) {
|
||||
const setValues = (data: FormSetValuesType[]) => {
|
||||
if (!data.length) return
|
||||
const formData: Recordable = {}
|
||||
for (const v of data) {
|
||||
@@ -89,7 +89,7 @@ export default defineComponent({
|
||||
)
|
||||
|
||||
// 渲染包裹标签,是否使用栅格布局
|
||||
function renderWrap() {
|
||||
const renderWrap = () => {
|
||||
const content = isCol ? (
|
||||
<ElRow gutter={20}>{renderFormItemWrap()}</ElRow>
|
||||
) : (
|
||||
@@ -99,7 +99,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
// 是否要渲染el-col
|
||||
function renderFormItemWrap() {
|
||||
const renderFormItemWrap = () => {
|
||||
// hidden属性表示隐藏,不做渲染
|
||||
return schema
|
||||
.filter((v) => !v.hidden)
|
||||
@@ -119,7 +119,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
// 渲染formItem
|
||||
function renderFormItem(item: FormSchema) {
|
||||
const renderFormItem = (item: FormSchema) => {
|
||||
// 单独给只有options属性的组件做判断
|
||||
const notRenderOptions = ['SelectV2', 'Cascader', 'Transfer']
|
||||
const slotsMap: Recordable = {
|
||||
@@ -162,7 +162,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
// 渲染options
|
||||
function renderOptions(item: FormSchema) {
|
||||
const renderOptions = (item: FormSchema) => {
|
||||
switch (item.component) {
|
||||
case 'Select':
|
||||
const { renderSelectOptions } = useRenderSelect(slots)
|
||||
@@ -181,7 +181,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
// 过滤传入Form组件的属性
|
||||
function getFormBindValue() {
|
||||
const getFormBindValue = () => {
|
||||
// 避免在标签上出现多余的属性
|
||||
const delKeys = ['schema', 'isCol', 'autoSetPlaceholder', 'isCustom', 'model']
|
||||
const props = { ...unref(getProps) }
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { ElCheckbox, ElCheckboxButton } from 'element-plus'
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export function useRenderChcekbox() {
|
||||
function renderChcekboxOptions(item: FormSchema) {
|
||||
export const useRenderChcekbox = () => {
|
||||
const renderChcekboxOptions = (item: FormSchema) => {
|
||||
// 如果有别名,就取别名
|
||||
const labelAlias = item?.componentProps?.optionsAlias?.labelField
|
||||
const valueAlias = item?.componentProps?.optionsAlias?.valueField
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { ElRadio, ElRadioButton } from 'element-plus'
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export function useRenderRadio() {
|
||||
function renderRadioOptions(item: FormSchema) {
|
||||
export const useRenderRadio = () => {
|
||||
const renderRadioOptions = (item: FormSchema) => {
|
||||
// 如果有别名,就取别名
|
||||
const labelAlias = item?.componentProps?.optionsAlias?.labelField
|
||||
const valueAlias = item?.componentProps?.optionsAlias?.valueField
|
||||
|
||||
@@ -2,9 +2,9 @@ import { ElOption, ElOptionGroup } from 'element-plus'
|
||||
import { getSlot } from '@/utils/tsxHelper'
|
||||
import { Slots } from 'vue'
|
||||
|
||||
export function useRenderSelect(slots: Slots) {
|
||||
export const useRenderSelect = (slots: Slots) => {
|
||||
// 渲染 select options
|
||||
function renderSelectOptions(item: FormSchema) {
|
||||
const renderSelectOptions = (item: FormSchema) => {
|
||||
// 如果有别名,就取别名
|
||||
const labelAlias = item?.componentProps?.optionsAlias?.labelField
|
||||
return item?.componentProps?.options?.map((option) => {
|
||||
@@ -25,7 +25,7 @@ export function useRenderSelect(slots: Slots) {
|
||||
}
|
||||
|
||||
// 渲染 select option item
|
||||
function renderSelectOptionItem(item: FormSchema, option: ComponentOptions) {
|
||||
const renderSelectOptionItem = (item: FormSchema, option: ComponentOptions) => {
|
||||
// 如果有别名,就取别名
|
||||
const labelAlias = item?.componentProps?.optionsAlias?.labelField
|
||||
const valueAlias = item?.componentProps?.optionsAlias?.valueField
|
||||
|
||||
@@ -17,7 +17,7 @@ interface PlaceholderMoel {
|
||||
* @returns 返回提示信息对象
|
||||
* @description 用于自动设置placeholder
|
||||
*/
|
||||
export function setTextPlaceholder(schema: FormSchema): PlaceholderMoel {
|
||||
export const setTextPlaceholder = (schema: FormSchema): PlaceholderMoel => {
|
||||
const textMap = ['Input', 'Autocomplete', 'InputNumber', 'InputPassword']
|
||||
const selectMap = ['Select', 'TimePicker', 'DatePicker', 'TimeSelect', 'TimeSelect']
|
||||
if (textMap.includes(schema?.component as string)) {
|
||||
@@ -53,7 +53,7 @@ export function setTextPlaceholder(schema: FormSchema): PlaceholderMoel {
|
||||
* @returns 返回栅格属性
|
||||
* @description 合并传入进来的栅格属性
|
||||
*/
|
||||
export function setGridProp(col: ColProps = {}): ColProps {
|
||||
export const setGridProp = (col: ColProps = {}): ColProps => {
|
||||
const colProps: ColProps = {
|
||||
// 如果有span,代表用户优先级更高,所以不需要默认栅格
|
||||
...(col.span
|
||||
@@ -75,7 +75,7 @@ export function setGridProp(col: ColProps = {}): ColProps {
|
||||
* @param item 传入的组件属性
|
||||
* @returns 默认添加 clearable 属性
|
||||
*/
|
||||
export function setComponentProps(item: FormSchema): Recordable {
|
||||
export const setComponentProps = (item: FormSchema): Recordable => {
|
||||
const notNeedClearable = ['ColorPicker']
|
||||
const componentProps: Recordable = notNeedClearable.includes(item.component as string)
|
||||
? { ...item.componentProps }
|
||||
@@ -94,11 +94,11 @@ export function setComponentProps(item: FormSchema): Recordable {
|
||||
* @param slotsProps 插槽属性
|
||||
* @param field 字段名
|
||||
*/
|
||||
export function setItemComponentSlots(
|
||||
export const setItemComponentSlots = (
|
||||
slots: Slots,
|
||||
slotsProps: Recordable = {},
|
||||
field: string
|
||||
): Recordable {
|
||||
): Recordable => {
|
||||
const slotObj: Recordable = {}
|
||||
for (const key in slotsProps) {
|
||||
if (slotsProps[key]) {
|
||||
@@ -118,7 +118,7 @@ export function setItemComponentSlots(
|
||||
* @returns FormMoel
|
||||
* @description 生成对应的formModel
|
||||
*/
|
||||
export function initModel(schema: FormSchema[], formModel: Recordable) {
|
||||
export const initModel = (schema: FormSchema[], formModel: Recordable) => {
|
||||
const model: Recordable = { ...formModel }
|
||||
schema.map((v) => {
|
||||
// 如果是hidden,就删除对应的值
|
||||
@@ -138,7 +138,7 @@ export function initModel(schema: FormSchema[], formModel: Recordable) {
|
||||
* @param field 字段名
|
||||
* @returns 返回FormIiem插槽
|
||||
*/
|
||||
export function setFormItemSlots(slots: Slots, field: string): Recordable {
|
||||
export const setFormItemSlots = (slots: Slots, field: string): Recordable => {
|
||||
const slotObj: Recordable = {}
|
||||
if (slots[`${field}-error`]) {
|
||||
slotObj['error'] = (data: Recordable) => {
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, unref, ref, watch, nextTick } from 'vue'
|
||||
import { ElIcon } from 'element-plus'
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import Iconify from '@purge-icons/generated'
|
||||
|
||||
const { getPrefixCls } = useDesign()
|
||||
|
||||
const prefixCls = getPrefixCls('icon')
|
||||
|
||||
const props = defineProps({
|
||||
// icon name
|
||||
icon: propTypes.string,
|
||||
@@ -34,7 +29,7 @@ const getIconifyStyle = computed(() => {
|
||||
}
|
||||
})
|
||||
|
||||
async function updateIcon(icon: string) {
|
||||
const updateIcon = async (icon: string) => {
|
||||
if (unref(isLocal)) return
|
||||
|
||||
const el = unref(elRef)
|
||||
@@ -66,7 +61,7 @@ watch(
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ElIcon :class="prefixCls" :size="size" :color="color">
|
||||
<ElIcon class="v-icon" :size="size" :color="color">
|
||||
<svg v-if="isLocal" aria-hidden="true">
|
||||
<use :xlink:href="symbolId" />
|
||||
</svg>
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import { ref, unref, computed, watch } from 'vue'
|
||||
import { ElInput } from 'element-plus'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
import { useConfigGlobal } from '@/hooks/web/useConfigGlobal'
|
||||
import { zxcvbn } from '@zxcvbn-ts/core'
|
||||
import type { ZxcvbnResult } from '@zxcvbn-ts/core'
|
||||
@@ -25,15 +24,10 @@ const { configGlobal } = useConfigGlobal()
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
// 生成class前缀
|
||||
const { getPrefixCls } = useDesign()
|
||||
|
||||
const prefixCls = ref(getPrefixCls('input-password'))
|
||||
|
||||
// 设置input的type属性
|
||||
const textType = ref<'password' | 'text'>('password')
|
||||
|
||||
function changeTextType() {
|
||||
const changeTextType = () => {
|
||||
textType.value = unref(textType) === 'text' ? 'password' : 'text'
|
||||
}
|
||||
|
||||
@@ -61,7 +55,7 @@ const getIconName = computed(() =>
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="[prefixCls, `${prefixCls}--${configGlobal?.size}`]">
|
||||
<div :class="['v-input-password', `v-input-password--${configGlobal?.size}`]">
|
||||
<ElInput v-bind="$attrs" v-model="valueRef" :type="textType">
|
||||
<template #suffix>
|
||||
<Icon class="el-input__icon cursor-pointer" :icon="getIconName" @click="changeTextType" />
|
||||
@@ -69,10 +63,9 @@ const getIconName = computed(() =>
|
||||
</ElInput>
|
||||
<div
|
||||
v-if="strength"
|
||||
:class="`${prefixCls}__bar`"
|
||||
class="relative h-6px mt-10px mb-6px mr-auto ml-auto"
|
||||
class="v-input-password__bar relative h-6px mt-10px mb-6px mr-auto ml-auto"
|
||||
>
|
||||
<div :class="`${prefixCls}__bar--fill`" :data-score="getPasswordStrength"></div>
|
||||
<div class="v-input-password__bar--fill" :data-score="getPasswordStrength"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -10,7 +10,7 @@ const langMap = computed(() => localeStore.getLocaleMap)
|
||||
|
||||
const currentLang = computed(() => localeStore.getLocale)
|
||||
|
||||
function setLang(lang: LocaleType) {
|
||||
const setLang = (lang: LocaleType) => {
|
||||
if (lang === unref(currentLang).lang) return
|
||||
// 需要重新加载页面让整个语言多初始化
|
||||
window.location.reload()
|
||||
@@ -24,13 +24,7 @@ function setLang(lang: LocaleType) {
|
||||
|
||||
<template>
|
||||
<ElDropdown trigger="click" @command="setLang">
|
||||
<Icon
|
||||
:size="18"
|
||||
icon="ion:language-sharp"
|
||||
color="var(--el-text-color-primary)"
|
||||
class="cursor-pointer"
|
||||
:class="$attrs.class"
|
||||
/>
|
||||
<Icon :size="18" icon="ion:language-sharp" class="cursor-pointer" :class="$attrs.class" />
|
||||
<template #dropdown>
|
||||
<ElDropdownMenu>
|
||||
<ElDropdownItem v-for="item in langMap" :key="item.lang" :command="item.lang">
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<script lang="tsx">
|
||||
import { computed, defineComponent } from 'vue'
|
||||
import { ElMenu, ElScrollbar } from 'element-plus'
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { usePermissionStore } from '@/store/modules/permission'
|
||||
import type { LayoutType } from '@/config/app'
|
||||
@@ -18,10 +17,6 @@ export default defineComponent({
|
||||
|
||||
const permissionStore = usePermissionStore()
|
||||
|
||||
const { getPrefixCls } = useDesign()
|
||||
|
||||
const preFixCls = getPrefixCls('menu')
|
||||
|
||||
const menuMode = computed((): 'vertical' | 'horizontal' => {
|
||||
// 竖
|
||||
const vertical: LayoutType[] = ['classic']
|
||||
@@ -46,7 +41,7 @@ export default defineComponent({
|
||||
return path
|
||||
})
|
||||
|
||||
function menuSelect(index: string) {
|
||||
const menuSelect = (index: string) => {
|
||||
if (isUrl(index)) {
|
||||
window.open(index)
|
||||
} else {
|
||||
@@ -57,8 +52,8 @@ export default defineComponent({
|
||||
return () => (
|
||||
<div
|
||||
class={[
|
||||
preFixCls,
|
||||
'h-[100%] overflow-hidden',
|
||||
'v-menu',
|
||||
'h-[100%] overflow-hidden z-100',
|
||||
appStore.getCollapse
|
||||
? 'w-[var(--left-menu-min-width)]'
|
||||
: 'w-[var(--left-menu-max-width)]',
|
||||
@@ -147,7 +142,7 @@ export default defineComponent({
|
||||
|
||||
// 折叠动画的时候,就需要把文字给隐藏掉
|
||||
:deep(.horizontal-collapse-transition) {
|
||||
transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out !important;
|
||||
// transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out !important;
|
||||
.@{prefix-cls}__title {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@ import { useRenderMenuTitle } from './useRenderMenuTitle'
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
import { pathResolve } from '@/utils/routerHelper'
|
||||
|
||||
export function useRenderMenuItem(
|
||||
export const useRenderMenuItem = (
|
||||
allRouters: AppRouteRecordRaw[] = [],
|
||||
menuMode: 'vertical' | 'horizontal'
|
||||
) {
|
||||
function renderMenuItem(routers?: AppRouteRecordRaw[]) {
|
||||
) => {
|
||||
const renderMenuItem = (routers?: AppRouteRecordRaw[]) => {
|
||||
return (routers || allRouters).map((v) => {
|
||||
const meta = (v.meta ?? {}) as RouteMeta
|
||||
if (!meta.hidden) {
|
||||
|
||||
@@ -2,18 +2,18 @@ import type { RouteMeta } from 'vue-router'
|
||||
import { Icon } from '@/components/Icon'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
|
||||
export function useRenderMenuTitle() {
|
||||
function renderMenuTitle(meta: RouteMeta) {
|
||||
export const useRenderMenuTitle = () => {
|
||||
const renderMenuTitle = (meta: RouteMeta) => {
|
||||
const { t } = useI18n()
|
||||
const { title = 'Please set title', icon } = meta
|
||||
|
||||
return icon ? (
|
||||
<>
|
||||
<Icon icon={meta.icon}></Icon>
|
||||
<span>{t(title as string)}</span>
|
||||
<span class="v-menu__title">{t(title as string)}</span>
|
||||
</>
|
||||
) : (
|
||||
<span>{t(title as string)}</span>
|
||||
<span class="v-menu__title">{t(title as string)}</span>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
import type { RouteMeta } from 'vue-router'
|
||||
import { ref, unref } from 'vue'
|
||||
|
||||
interface TreeConfig {
|
||||
id: string
|
||||
children: string
|
||||
pid: string
|
||||
}
|
||||
import { findPath } from '@/utils/tree'
|
||||
|
||||
type OnlyOneChildType = AppRouteRecordRaw & { noShowingChildren?: boolean }
|
||||
|
||||
@@ -14,50 +9,15 @@ interface HasOneShowingChild {
|
||||
onlyOneChild?: OnlyOneChildType
|
||||
}
|
||||
|
||||
const DEFAULT_CONFIG: TreeConfig = {
|
||||
id: 'id',
|
||||
children: 'children',
|
||||
pid: 'pid'
|
||||
}
|
||||
|
||||
const getConfig = (config: Partial<TreeConfig>) => Object.assign({}, DEFAULT_CONFIG, config)
|
||||
|
||||
export function getAllParentPath<T = Recordable>(treeData: T[], path: string) {
|
||||
export const getAllParentPath = <T = Recordable>(treeData: T[], path: string) => {
|
||||
const menuList = findPath(treeData, (n) => n.path === path) as AppRouteRecordRaw[]
|
||||
return (menuList || []).map((item) => item.path)
|
||||
}
|
||||
|
||||
export function findPath<T = any>(
|
||||
tree: any,
|
||||
func: Fn,
|
||||
config: Partial<TreeConfig> = {}
|
||||
): T | T[] | null {
|
||||
config = getConfig(config)
|
||||
const path: T[] = []
|
||||
const list = [...tree]
|
||||
const visitedSet = new Set()
|
||||
const { children } = config
|
||||
while (list.length) {
|
||||
const node = list[0]
|
||||
if (visitedSet.has(node)) {
|
||||
path.pop()
|
||||
list.shift()
|
||||
} else {
|
||||
visitedSet.add(node)
|
||||
node[children!] && list.unshift(...node[children!])
|
||||
path.push(node)
|
||||
if (func(node)) {
|
||||
return path
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export function hasOneShowingChild(
|
||||
export const hasOneShowingChild = (
|
||||
children: AppRouteRecordRaw[] = [],
|
||||
parent: AppRouteRecordRaw
|
||||
): HasOneShowingChild {
|
||||
): HasOneShowingChild => {
|
||||
const onlyOneChild = ref<OnlyOneChildType>()
|
||||
|
||||
const showingChildren = children.filter((v) => {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useFullscreen } from '@vueuse/core'
|
||||
|
||||
const { toggle, isFullscreen } = useFullscreen()
|
||||
|
||||
function toggleFullscreen() {
|
||||
const toggleFullscreen = () => {
|
||||
toggle()
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -9,7 +9,7 @@ const appStore = useAppStore()
|
||||
|
||||
const sizeMap = computed(() => appStore.sizeMap)
|
||||
|
||||
function setSize(size: ElememtPlusSzie) {
|
||||
const setSize = (size: ElememtPlusSzie) => {
|
||||
appStore.setSize(size)
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<div>tagsView</div>
|
||||
<div class="h-[var(--tags-view-height)]">tagsView</div>
|
||||
</template>
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import { ref } from 'vue'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { ElSwitch } from 'element-plus'
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
import { useIcon } from '@/hooks/web/useIcon'
|
||||
|
||||
const Sun = useIcon({ icon: 'emojione-monotone:sun', color: '#fde047' })
|
||||
@@ -14,21 +13,17 @@ const appStore = useAppStore()
|
||||
// 初始化获取是否是暗黑主题
|
||||
const isDark = ref(appStore.getIsDark)
|
||||
|
||||
const { getPrefixCls } = useDesign()
|
||||
|
||||
const prefixCls = getPrefixCls('theme-switch')
|
||||
|
||||
// 设置switch的背景颜色
|
||||
const blackColor = 'var(--el-color-black)'
|
||||
|
||||
function themeChange(val: boolean) {
|
||||
const themeChange = (val: boolean) => {
|
||||
appStore.setIsDark(val)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ElSwitch
|
||||
:class="prefixCls"
|
||||
class="v-theme-switch"
|
||||
v-model="isDark"
|
||||
inline-prompt
|
||||
:border-color="blackColor"
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
import { resetRouter } from '@/router'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { loginOutApi } from '@/api/login'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
@@ -11,16 +12,19 @@ const { wsCache } = useCache()
|
||||
|
||||
const { replace } = useRouter()
|
||||
|
||||
function loginOut() {
|
||||
const loginOut = () => {
|
||||
ElMessageBox.confirm(t('common.loginOutMessage'), t('common.reminder'), {
|
||||
confirmButtonText: t('common.ok'),
|
||||
cancelButtonText: t('common.cancel'),
|
||||
type: 'warning'
|
||||
})
|
||||
.then(() => {
|
||||
wsCache.clear()
|
||||
resetRouter() // 重置静态路由表
|
||||
replace('/login')
|
||||
.then(async () => {
|
||||
const res = await loginOutApi().catch(() => {})
|
||||
if (res) {
|
||||
wsCache.clear()
|
||||
resetRouter() // 重置静态路由表
|
||||
replace('/login')
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { App } from 'vue'
|
||||
import { Icon } from './Icon'
|
||||
|
||||
export function setupGlobCom(app: App<Element>): void {
|
||||
export const setupGlobCom = (app: App<Element>): void => {
|
||||
app.component('Icon', Icon)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user