|
|
|
@ -1,162 +1,178 @@
|
|
|
|
|
<script lang="ts" setup>
|
|
|
|
|
import { computed, inject, nextTick, onBeforeMount, onMounted, reactive, ref, shallowRef, unref, watch } from 'vue'
|
|
|
|
|
import { CustomFilterModalVue, FilterModal, NewFilterModal } from '@/views/final/comp'
|
|
|
|
|
import Search from '@/views/home/aside/comp/Search.vue'
|
|
|
|
|
import AdvanceFilter from '@/views/home/aside/comp/AdvanceFilter.vue'
|
|
|
|
|
import { getViewportOffset } from '@/utils/domUtils'
|
|
|
|
|
import { useWindowSizeFn } from '@/hooks/event/useWindowSizeFn'
|
|
|
|
|
import { useFinal } from '@/store/modules/final'
|
|
|
|
|
import type { Filter } from '/#/home'
|
|
|
|
|
import type { AsideEntity } from '@/config/aside'
|
|
|
|
|
import { asideMap } from '@/config/final'
|
|
|
|
|
import type { AsideConfig } from '/#/api'
|
|
|
|
|
import emitter from '@/utils/mitt'
|
|
|
|
|
|
|
|
|
|
const finalStore = useFinal()
|
|
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
computed,
|
|
|
|
|
inject,
|
|
|
|
|
nextTick,
|
|
|
|
|
onBeforeMount,
|
|
|
|
|
onMounted,
|
|
|
|
|
reactive,
|
|
|
|
|
ref,
|
|
|
|
|
shallowRef,
|
|
|
|
|
unref,
|
|
|
|
|
watch,
|
|
|
|
|
} from "vue";
|
|
|
|
|
import { CustomFilterModalVue, FilterModal, NewFilterModal } from "@/views/final/comp";
|
|
|
|
|
import Search from "@/views/home/aside/comp/Search.vue";
|
|
|
|
|
import AdvanceFilter from "@/views/home/aside/comp/AdvanceFilter.vue";
|
|
|
|
|
import { getViewportOffset } from "@/utils/domUtils";
|
|
|
|
|
import { useWindowSizeFn } from "@/hooks/event/useWindowSizeFn";
|
|
|
|
|
import { useFinal } from "@/store/modules/final";
|
|
|
|
|
import type { Filter } from "/#/home";
|
|
|
|
|
import type { AsideEntity } from "@/config/aside";
|
|
|
|
|
import { asideMap } from "@/config/final";
|
|
|
|
|
import type { AsideConfig } from "/#/api";
|
|
|
|
|
import emitter from "@/utils/mitt";
|
|
|
|
|
|
|
|
|
|
const emit = defineEmits(["inputChange"]);
|
|
|
|
|
const finalStore = useFinal();
|
|
|
|
|
// 所有左侧模块的值
|
|
|
|
|
const asideValue: Record<keyof typeof asideMap, any> = reactive({})
|
|
|
|
|
const asideValue: Record<keyof typeof asideMap, any> = reactive({});
|
|
|
|
|
// 左侧某个模块是否显示: 个人配置
|
|
|
|
|
const asideVisible: Partial<Record<keyof AsideConfig, boolean>> = reactive({})
|
|
|
|
|
const asideVisible: Partial<Record<keyof AsideConfig, boolean>> = reactive({});
|
|
|
|
|
// 当前显示的模块,按照数组顺序显示
|
|
|
|
|
const showItems = shallowRef<{ key: string, config: AsideEntity }[]>([])
|
|
|
|
|
const showItems = shallowRef<{ key: string; config: AsideEntity }[]>([]);
|
|
|
|
|
|
|
|
|
|
Object.keys(asideMap).forEach((key) => {
|
|
|
|
|
const { defaultValue, inFilterList } = asideMap[key]
|
|
|
|
|
if (inFilterList !== false)
|
|
|
|
|
asideValue[key] = defaultValue
|
|
|
|
|
})
|
|
|
|
|
const { defaultValue, inFilterList } = asideMap[key];
|
|
|
|
|
if (inFilterList !== false) asideValue[key] = defaultValue;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const filterModalRef = ref(null)
|
|
|
|
|
const newFilterModalRef = ref(null)
|
|
|
|
|
const customModalRef = ref(null)
|
|
|
|
|
const filterModalRef = ref(null);
|
|
|
|
|
const newFilterModalRef = ref(null);
|
|
|
|
|
const customModalRef = ref(null);
|
|
|
|
|
|
|
|
|
|
function showModal(modalRef: any) {
|
|
|
|
|
const modal = unref(modalRef)! as any
|
|
|
|
|
modal.showModal()
|
|
|
|
|
const modal = unref(modalRef)! as any;
|
|
|
|
|
modal.showModal();
|
|
|
|
|
}
|
|
|
|
|
const mousetrap = inject('mousetrap') as any
|
|
|
|
|
mousetrap.bind('[', collapseHandler)
|
|
|
|
|
const mousetrap = inject("mousetrap") as any;
|
|
|
|
|
mousetrap.bind("[", collapseHandler);
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
computeSlideHeight()
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
computeSlideHeight();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const collapse = ref(false)
|
|
|
|
|
const collapse = ref(false);
|
|
|
|
|
|
|
|
|
|
function collapseHandler() {
|
|
|
|
|
collapse.value = !collapse.value
|
|
|
|
|
collapse.value = !collapse.value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const asideWidth = computed(() => {
|
|
|
|
|
return collapse.value ? 0 : 308
|
|
|
|
|
})
|
|
|
|
|
return collapse.value ? 0 : 308;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const asideHeight = ref(500)
|
|
|
|
|
const asideHeight = ref(500);
|
|
|
|
|
const asideStyle = computed(() => {
|
|
|
|
|
return {
|
|
|
|
|
width: `${asideWidth.value}px`,
|
|
|
|
|
height: `${asideHeight.value}px`,
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const collapseIcon = computed(() => {
|
|
|
|
|
return collapse.value ? 'expand-cir' : 'collapse-cir'
|
|
|
|
|
})
|
|
|
|
|
return collapse.value ? "expand-cir" : "collapse-cir";
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
function computeSlideHeight() {
|
|
|
|
|
const headEl = document.querySelector('.aside-header')!
|
|
|
|
|
const { bottomIncludeBody } = getViewportOffset(headEl)
|
|
|
|
|
const height = bottomIncludeBody
|
|
|
|
|
asideHeight.value = height - 24
|
|
|
|
|
const headEl = document.querySelector(".aside-header")!;
|
|
|
|
|
const { bottomIncludeBody } = getViewportOffset(headEl);
|
|
|
|
|
const height = bottomIncludeBody;
|
|
|
|
|
asideHeight.value = height - 24;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
useWindowSizeFn(computeSlideHeight, 280)
|
|
|
|
|
useWindowSizeFn(computeSlideHeight, 280);
|
|
|
|
|
|
|
|
|
|
onBeforeMount(async () => {
|
|
|
|
|
finalStore.fetchCustomConfig()
|
|
|
|
|
})
|
|
|
|
|
finalStore.fetchCustomConfig();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
finalStore.$subscribe(() => {
|
|
|
|
|
const customConfig = finalStore.getCustomConfig
|
|
|
|
|
const customConfig = finalStore.getCustomConfig;
|
|
|
|
|
|
|
|
|
|
if (customConfig === null)
|
|
|
|
|
return
|
|
|
|
|
if (customConfig === null) return;
|
|
|
|
|
|
|
|
|
|
const showKeys: string[] = [...customConfig]
|
|
|
|
|
const defaultKeys = Object.keys(asideMap).filter(key => asideMap[key].isDefaultFilter)
|
|
|
|
|
showKeys.unshift(...defaultKeys)
|
|
|
|
|
const showKeys: string[] = [...customConfig];
|
|
|
|
|
const defaultKeys = Object.keys(asideMap).filter(
|
|
|
|
|
(key) => asideMap[key].isDefaultFilter
|
|
|
|
|
);
|
|
|
|
|
showKeys.unshift(...defaultKeys);
|
|
|
|
|
|
|
|
|
|
Object.keys(asideMap).forEach((key) => {
|
|
|
|
|
// 设置显示的或者默认显示的
|
|
|
|
|
if (key.startsWith('iz'))
|
|
|
|
|
asideVisible[key] = asideMap[key] && (showKeys.includes(key) || asideMap[key].isDefaultFilter)
|
|
|
|
|
})
|
|
|
|
|
if (key.startsWith("iz"))
|
|
|
|
|
asideVisible[key] =
|
|
|
|
|
asideMap[key] && (showKeys.includes(key) || asideMap[key].isDefaultFilter);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const items = showKeys.reduce((acc, key) => {
|
|
|
|
|
if (asideMap[key]) {
|
|
|
|
|
const config = {
|
|
|
|
|
key,
|
|
|
|
|
config: asideMap[key],
|
|
|
|
|
};
|
|
|
|
|
return [...acc, config];
|
|
|
|
|
} else {
|
|
|
|
|
return acc;
|
|
|
|
|
}
|
|
|
|
|
return [...acc, config]
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return acc
|
|
|
|
|
}
|
|
|
|
|
}, [])
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
showItems.value = items
|
|
|
|
|
})
|
|
|
|
|
showItems.value = items;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
watch(asideVisible, (newVal) => {
|
|
|
|
|
Object.keys(asideValue).forEach((key) => {
|
|
|
|
|
if (newVal[key] === false)
|
|
|
|
|
asideValue[key] = asideMap[key].defaultValue
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
if (newVal[key] === false) asideValue[key] = asideMap[key].defaultValue;
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const asideEnter = ref(false)
|
|
|
|
|
const asideEnter = ref(false);
|
|
|
|
|
|
|
|
|
|
const showCollapse = computed(() => {
|
|
|
|
|
return collapse.value ? true : asideEnter.value
|
|
|
|
|
})
|
|
|
|
|
return collapse.value ? true : asideEnter.value;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const showSearch = ref(false)
|
|
|
|
|
const showSearch = ref(false);
|
|
|
|
|
|
|
|
|
|
function setShowSearch(value: boolean) {
|
|
|
|
|
showSearch.value = value
|
|
|
|
|
showSearch.value = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 滚动容器,让key对应模块处于可视区域
|
|
|
|
|
function scrollHandler(key: string) {
|
|
|
|
|
const element = document.querySelector(`#${key}`)
|
|
|
|
|
element?.scrollIntoView(true)
|
|
|
|
|
const element = document.querySelector(`#${key}`);
|
|
|
|
|
element?.scrollIntoView(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function filterHandler(searchId: string) {
|
|
|
|
|
emitter.emit('filter-final', searchId)
|
|
|
|
|
emitter.emit("filter-final", searchId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function editFilter(filter: any) {
|
|
|
|
|
const modal = unref(newFilterModalRef)! as any
|
|
|
|
|
modal.showModal()
|
|
|
|
|
modal.edit(filter)
|
|
|
|
|
const modal = unref(newFilterModalRef)! as any;
|
|
|
|
|
modal.showModal();
|
|
|
|
|
modal.edit(filter);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
watch(asideValue, (newVal) => {
|
|
|
|
|
finalStore.setAsideValue(newVal)
|
|
|
|
|
})
|
|
|
|
|
finalStore.setAsideValue(newVal);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const inputChange = (keyword) => {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
console.log("Search Component", keyword);
|
|
|
|
|
emit("inputChange", keyword);
|
|
|
|
|
};
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
<div class="aside" :style="asideStyle" @mouseenter="asideEnter = true" @mouseleave="asideEnter = false">
|
|
|
|
|
<div
|
|
|
|
|
class="aside"
|
|
|
|
|
:style="asideStyle"
|
|
|
|
|
@mouseenter="asideEnter = true"
|
|
|
|
|
@mouseleave="asideEnter = false"
|
|
|
|
|
>
|
|
|
|
|
<div v-show="showCollapse" class="aside-collapse">
|
|
|
|
|
<div class="aside-collapse-btn" @click="collapseHandler">
|
|
|
|
|
<SvgIcon :name="collapseIcon" size="40" />
|
|
|
|
@ -165,23 +181,40 @@ const inputChange = (keyword)=>{
|
|
|
|
|
<n-scrollbar trigger="none">
|
|
|
|
|
<div class="aside-header">
|
|
|
|
|
<!-- 搜索跳转模块 -->
|
|
|
|
|
<Search v-show="showSearch" @select="scrollHandler" @close="setShowSearch(false)" @inputChange="inputChange" />
|
|
|
|
|
<Search
|
|
|
|
|
v-show="showSearch"
|
|
|
|
|
@select="scrollHandler"
|
|
|
|
|
@close="setShowSearch(false)"
|
|
|
|
|
@inputChange="inputChange"
|
|
|
|
|
/>
|
|
|
|
|
<!-- 高级筛选 -->
|
|
|
|
|
<AdvanceFilter
|
|
|
|
|
v-show="!showSearch" :type="1" @select="filterHandler" @update:search="setShowSearch(true)"
|
|
|
|
|
@show-custom="showModal(customModalRef)" @show-filter="showModal(filterModalRef)"
|
|
|
|
|
v-show="!showSearch"
|
|
|
|
|
:type="1"
|
|
|
|
|
@select="filterHandler"
|
|
|
|
|
@update:search="setShowSearch(true)"
|
|
|
|
|
@show-custom="showModal(customModalRef)"
|
|
|
|
|
@show-filter="showModal(filterModalRef)"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<component
|
|
|
|
|
:is="item.config.component" v-for="(item, index) in showItems" :id="item.key" :key="index"
|
|
|
|
|
v-model:value="asideValue[item.key]" :label="item.config.label"
|
|
|
|
|
:is="item.config.component"
|
|
|
|
|
v-for="(item, index) in showItems"
|
|
|
|
|
:id="item.key"
|
|
|
|
|
:key="index"
|
|
|
|
|
v-model:value="asideValue[item.key]"
|
|
|
|
|
:label="item.config.label"
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<!-- 筛选 -->
|
|
|
|
|
<CustomFilterModalVue ref="customModalRef" />
|
|
|
|
|
<!-- 过滤列表 -->
|
|
|
|
|
<FilterModal ref="filterModalRef" @edit-filter="editFilter" @show-new-filter="showModal(newFilterModalRef)" />
|
|
|
|
|
<FilterModal
|
|
|
|
|
ref="filterModalRef"
|
|
|
|
|
@edit-filter="editFilter"
|
|
|
|
|
@show-new-filter="showModal(newFilterModalRef)"
|
|
|
|
|
/>
|
|
|
|
|
<!-- 新增过滤 -->
|
|
|
|
|
<NewFilterModal ref="newFilterModalRef" />
|
|
|
|
|
</n-scrollbar>
|
|
|
|
@ -193,7 +226,7 @@ const inputChange = (keyword)=>{
|
|
|
|
|
display: flex;
|
|
|
|
|
position: relative;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
background: #FFF;
|
|
|
|
|
background: #fff;
|
|
|
|
|
border: 1px solid #efeff5;
|
|
|
|
|
border-radius: 3px;
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
@ -230,11 +263,17 @@ const inputChange = (keyword)=>{
|
|
|
|
|
right: -20px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
::v-deep(.n-collapse .n-collapse-item.n-collapse-item--right-arrow-placement .n-collapse-item__header .n-collapse-item-arrow) {
|
|
|
|
|
::v-deep(.n-collapse
|
|
|
|
|
.n-collapse-item.n-collapse-item--right-arrow-placement
|
|
|
|
|
.n-collapse-item__header
|
|
|
|
|
.n-collapse-item-arrow) {
|
|
|
|
|
margin-left: 8px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
::v-deep(.n-collapse .n-collapse-item .n-collapse-item__header .n-collapse-item__header-main) {
|
|
|
|
|
::v-deep(.n-collapse
|
|
|
|
|
.n-collapse-item
|
|
|
|
|
.n-collapse-item__header
|
|
|
|
|
.n-collapse-item__header-main) {
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
}
|
|
|
|
@ -247,11 +286,18 @@ const inputChange = (keyword)=>{
|
|
|
|
|
border-top: 0px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
::v-deep(.n-collapse .n-collapse-item .n-collapse-item__content-wrapper .n-collapse-item__content-inner) {
|
|
|
|
|
::v-deep(.n-collapse
|
|
|
|
|
.n-collapse-item
|
|
|
|
|
.n-collapse-item__content-wrapper
|
|
|
|
|
.n-collapse-item__content-inner) {
|
|
|
|
|
padding-top: 10px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
::v-deep(.n-scrollbar > .n-scrollbar-rail.n-scrollbar-rail--vertical > .n-scrollbar-rail__scrollbar, .n-scrollbar + .n-scrollbar-rail.n-scrollbar-rail--vertical > .n-scrollbar-rail__scrollbar) {
|
|
|
|
|
::v-deep(.n-scrollbar
|
|
|
|
|
> .n-scrollbar-rail.n-scrollbar-rail--vertical
|
|
|
|
|
> .n-scrollbar-rail__scrollbar, .n-scrollbar
|
|
|
|
|
+ .n-scrollbar-rail.n-scrollbar-rail--vertical
|
|
|
|
|
> .n-scrollbar-rail__scrollbar) {
|
|
|
|
|
width: 0px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|