@peng_kai/kit 0.0.8 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/admin/components/scroll-nav/index.ts +1 -0
- package/admin/components/scroll-nav/src/ScrollNav.vue +59 -0
- package/admin/hooks/useMenu.ts +5 -1
- package/admin/layout/large/Breadcrumb.vue +68 -0
- package/admin/layout/large/Content.vue +23 -0
- package/admin/layout/large/Menu.vue +73 -0
- package/admin/layout/large/PageTab.vue +70 -0
- package/admin/layout/large/index.ts +4 -0
- package/kitDependencies.ts +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as ScrollNav } from './src/ScrollNav.vue'
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from "vue";
|
|
3
|
+
import { useElementSize } from '@vueuse/core'
|
|
4
|
+
|
|
5
|
+
const props = defineProps<{
|
|
6
|
+
selector: string
|
|
7
|
+
}>()
|
|
8
|
+
|
|
9
|
+
const $content = document.querySelector(props.selector) as HTMLElement
|
|
10
|
+
const $contentParent = $content.parentElement
|
|
11
|
+
const { height: contentParentH } = useElementSize($contentParent)
|
|
12
|
+
const { height: contentH } = useElementSize($content)
|
|
13
|
+
const visible = computed(() => contentParentH.value * 2 < contentH.value)
|
|
14
|
+
|
|
15
|
+
function scrollTo(top: number) {
|
|
16
|
+
$contentParent?.scrollTo({ top })
|
|
17
|
+
}
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<div v-if="visible" class="wrapper">
|
|
22
|
+
<div class="btn" @click="scrollTo(0)">
|
|
23
|
+
<i class="i-fluent:arrow-previous-24-filled rotate-90" />
|
|
24
|
+
</div>
|
|
25
|
+
<div class="btn" @click="scrollTo($contentParent?.scrollHeight ?? Infinity)">
|
|
26
|
+
<i class="i-fluent:arrow-previous-24-filled rotate-270" />
|
|
27
|
+
</div>
|
|
28
|
+
<!-- <div v-if="showReturn" class="btn" @click="toLastY()">
|
|
29
|
+
<i class="i-fluent:arrow-hook-down-left-24-filled rotate-270" />
|
|
30
|
+
</div> -->
|
|
31
|
+
</div>
|
|
32
|
+
</template>
|
|
33
|
+
|
|
34
|
+
<style lang="scss" scoped>
|
|
35
|
+
.wrapper {
|
|
36
|
+
font-size: 18px;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.btn {
|
|
40
|
+
display: flex;
|
|
41
|
+
width: 2em;
|
|
42
|
+
height: 2em;
|
|
43
|
+
align-items: center;
|
|
44
|
+
justify-content: center;
|
|
45
|
+
border-radius: 2px;
|
|
46
|
+
background: #bcbcbc;
|
|
47
|
+
color: #000;
|
|
48
|
+
cursor: pointer;
|
|
49
|
+
opacity: 0.7;
|
|
50
|
+
|
|
51
|
+
&:active {
|
|
52
|
+
transform: scale(0.9);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
& + & {
|
|
56
|
+
margin-top: 1px;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
</style>
|
package/admin/hooks/useMenu.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createGlobalState } from '@vueuse/core'
|
|
2
|
-
import { reactive, ref, computed } from 'vue'
|
|
2
|
+
import { reactive, ref, computed, watch } from 'vue'
|
|
3
3
|
import type { UnwrapNestedRefs, VNode, Ref } from 'vue'
|
|
4
4
|
|
|
5
5
|
export { useMenu }
|
|
@@ -29,6 +29,10 @@ const useMenu = createGlobalState(() => {
|
|
|
29
29
|
const menus = reactive<TMenu[]>([])
|
|
30
30
|
const collapsed = ref(false)
|
|
31
31
|
|
|
32
|
+
watch(menus, (menus) => {
|
|
33
|
+
console.log('menus', menus);
|
|
34
|
+
})
|
|
35
|
+
|
|
32
36
|
const findMenu = (menus: TMenu[], key: string) => {
|
|
33
37
|
const queue = [...menus]
|
|
34
38
|
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { computed } from "vue";
|
|
3
|
+
import type { VNode } from 'vue'
|
|
4
|
+
import { Breadcrumb as ABreadcrumb } from "ant-design-vue";
|
|
5
|
+
import type { Route as AntdBreadcrumbRoute } from 'ant-design-vue/es/breadcrumb/Breadcrumb'
|
|
6
|
+
import { usePage } from '../../hooks'
|
|
7
|
+
import type { IBreadcrumb } from '../../hooks'
|
|
8
|
+
|
|
9
|
+
interface IBreadcrumbRoute extends AntdBreadcrumbRoute {
|
|
10
|
+
icon?: VNode | null
|
|
11
|
+
trigger?: () => void
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function _buildRoute(breadcrumb: IBreadcrumb): IBreadcrumbRoute {
|
|
15
|
+
return {
|
|
16
|
+
breadcrumbName: breadcrumb.title,
|
|
17
|
+
path: breadcrumb.title,
|
|
18
|
+
icon: breadcrumb.icon,
|
|
19
|
+
children: breadcrumb.children?.map(child => _buildRoute(child)),
|
|
20
|
+
trigger: breadcrumb.trigger,
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<script setup lang="ts">
|
|
26
|
+
const { currentPageState } = usePage()
|
|
27
|
+
const routes = computed(() => {
|
|
28
|
+
let breadcrumbs: IBreadcrumbRoute[] = []
|
|
29
|
+
|
|
30
|
+
if (!currentPageState.value)
|
|
31
|
+
return breadcrumbs
|
|
32
|
+
|
|
33
|
+
breadcrumbs = currentPageState.value.breadcrumbs.map(breadcrumb => _buildRoute(breadcrumb))
|
|
34
|
+
|
|
35
|
+
breadcrumbs.push({
|
|
36
|
+
path: currentPageState.value.title,
|
|
37
|
+
breadcrumbName: currentPageState.value.title,
|
|
38
|
+
icon: currentPageState.value.icon,
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
return breadcrumbs
|
|
42
|
+
})
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<template>
|
|
46
|
+
<ABreadcrumb class="breadcrumb" :routes="routes">
|
|
47
|
+
<template #itemRender="{ route }: {route: IBreadcrumbRoute}">
|
|
48
|
+
<div @click="route.trigger?.()">
|
|
49
|
+
<component :is="route.icon" v-if="route.icon" class="mb-0.2em mr-0.2em" />
|
|
50
|
+
<span>{{ route.breadcrumbName }}</span>
|
|
51
|
+
</div>
|
|
52
|
+
</template>
|
|
53
|
+
</ABreadcrumb>
|
|
54
|
+
</template>
|
|
55
|
+
|
|
56
|
+
<style lang="scss" scoped>
|
|
57
|
+
.breadcrumb {
|
|
58
|
+
font-size: 1rem;
|
|
59
|
+
|
|
60
|
+
:deep(.ant-dropdown-trigger) {
|
|
61
|
+
height: 1.6em;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
:deep(.anticon-down) {
|
|
65
|
+
display: none;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
</style>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { usePage } from '../../hooks'
|
|
3
|
+
|
|
4
|
+
const { pageCacheList, setPage } = usePage()
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<template>
|
|
8
|
+
<RouterView v-slot="{ Component, route }">
|
|
9
|
+
<KeepAlive :include="pageCacheList">
|
|
10
|
+
<Suspense>
|
|
11
|
+
<component :is="setPage(Component, route)" :key="(Component.type as any).name" />
|
|
12
|
+
<template #fallback>
|
|
13
|
+
<div class="flex justify-center items-center h-70">
|
|
14
|
+
<div class="flex items-center">
|
|
15
|
+
<i class="i-svg-spinners:180-ring-with-bg block color-primary scale-125 mr-2" />
|
|
16
|
+
<span class="text-gray">正在加载...</span>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
</template>
|
|
20
|
+
</Suspense>
|
|
21
|
+
</KeepAlive>
|
|
22
|
+
</RouterView>
|
|
23
|
+
</template>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { computed, ref, watch } from "vue";
|
|
3
|
+
import { Menu as AMenu } from "ant-design-vue";
|
|
4
|
+
import type { ItemType } from 'ant-design-vue'
|
|
5
|
+
import { useMenu } from '../../hooks'
|
|
6
|
+
import type { TMenu } from '../../hooks'
|
|
7
|
+
import { kitDependencies } from "../../../kitDependencies";
|
|
8
|
+
|
|
9
|
+
function formatMenu(menu: TMenu): ItemType {
|
|
10
|
+
return {
|
|
11
|
+
key: menu.key,
|
|
12
|
+
title: menu.label,
|
|
13
|
+
label: menu.label,
|
|
14
|
+
icon: menu.icon ?? undefined,
|
|
15
|
+
onClick: (e) => {
|
|
16
|
+
(e as any).stopPropagation()
|
|
17
|
+
menu.trigger()
|
|
18
|
+
},
|
|
19
|
+
children: menu.children?.map(formatMenu),
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<script setup lang="ts">
|
|
25
|
+
const router = kitDependencies.useRouter()
|
|
26
|
+
const { menus, getMenuPath } = useMenu()
|
|
27
|
+
const items = computed(() => menus.map(formatMenu))
|
|
28
|
+
const openKeys = ref<string[]>([])
|
|
29
|
+
const selectedKeys = ref<string[]>([])
|
|
30
|
+
console.log('获取 kitDependencies');
|
|
31
|
+
|
|
32
|
+
setTimeout(() => {
|
|
33
|
+
}, 3000)
|
|
34
|
+
console.log('菜单对象对比', kitDependencies, kitDependencies.menus === menus);
|
|
35
|
+
|
|
36
|
+
watch(
|
|
37
|
+
() => router?.currentRoute.value,
|
|
38
|
+
(route) => {
|
|
39
|
+
if (!route) return;
|
|
40
|
+
|
|
41
|
+
const menuPath = getMenuPath(route.name as string)
|
|
42
|
+
openKeys.value = menuPath.map(menu => menu.key)
|
|
43
|
+
selectedKeys.value = [openKeys.value.pop()!]
|
|
44
|
+
},
|
|
45
|
+
{ immediate: true },
|
|
46
|
+
)
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<template>
|
|
50
|
+
<AMenu
|
|
51
|
+
class="menu"
|
|
52
|
+
:items="items"
|
|
53
|
+
:openKeys="openKeys"
|
|
54
|
+
:selectedKeys="selectedKeys"
|
|
55
|
+
mode="inline"
|
|
56
|
+
:inlineIndent="14"
|
|
57
|
+
/>
|
|
58
|
+
</template>
|
|
59
|
+
|
|
60
|
+
<style lang="scss" scoped>
|
|
61
|
+
.menu {
|
|
62
|
+
border-inline-end: none !important;
|
|
63
|
+
|
|
64
|
+
&.ant-menu-inline-collapsed {
|
|
65
|
+
width: var(--app-siderbar-width);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
&,
|
|
69
|
+
.ant-menu {
|
|
70
|
+
background-color: transparent;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
</style>
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { Tabs as ATabs, TabPane as ATabPane } from "ant-design-vue";
|
|
3
|
+
import { usePageTab } from '../../hooks'
|
|
4
|
+
|
|
5
|
+
const { activeTab, tabList, openTab, closeTab } = usePageTab()
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<template>
|
|
9
|
+
<ATabs
|
|
10
|
+
class="app-page-tabs"
|
|
11
|
+
:activeKey="activeTab"
|
|
12
|
+
type="editable-card"
|
|
13
|
+
size="small"
|
|
14
|
+
:animated="false"
|
|
15
|
+
:hideAdd="true"
|
|
16
|
+
:tabBarGutter="4"
|
|
17
|
+
@tabClick="(openTab as any)"
|
|
18
|
+
@edit="(closeTab as any)"
|
|
19
|
+
>
|
|
20
|
+
<ATabPane v-for="tab of tabList" :key="tab.key" :tab="tab.title">
|
|
21
|
+
<template #closeIcon>
|
|
22
|
+
<i class="i-icon-park-outline:close" />
|
|
23
|
+
</template>
|
|
24
|
+
</ATabPane>
|
|
25
|
+
</ATabs>
|
|
26
|
+
</template>
|
|
27
|
+
|
|
28
|
+
<style scoped lang="scss">
|
|
29
|
+
.app-page-tabs {
|
|
30
|
+
:deep(.ant-tabs-nav) {
|
|
31
|
+
margin: 0;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
:deep(.ant-tabs-nav::before) {
|
|
35
|
+
display: none;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
:deep(.ant-tabs-tab) {
|
|
39
|
+
--uno: 'border-rd-3px! text-14px p-[3px_1px_3px_8px]! select-none';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
:deep(.ant-tabs-tab .ant-tabs-tab-btn) {
|
|
43
|
+
transform: translateX(8px);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
:deep(.ant-tabs-tab-active) {
|
|
47
|
+
--uno: 'border-[currentColor]!';
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
:deep(.ant-tabs-tab-remove) {
|
|
51
|
+
display: flex;
|
|
52
|
+
height: 100%;
|
|
53
|
+
align-items: center;
|
|
54
|
+
margin: 0;
|
|
55
|
+
opacity: 0;
|
|
56
|
+
transition: all 150ms;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
:deep(.ant-tabs-tab:hover .ant-tabs-tab-btn),
|
|
60
|
+
:deep(.ant-tabs-tab-active .ant-tabs-tab-btn) {
|
|
61
|
+
transform: translateX(0);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
:deep(.ant-tabs-tab:hover .ant-tabs-tab-remove),
|
|
65
|
+
:deep(.ant-tabs-tab-active .ant-tabs-tab-remove) {
|
|
66
|
+
margin-left: 0;
|
|
67
|
+
opacity: 1;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
</style>
|
package/kitDependencies.ts
CHANGED