feat: 接入 UserHome 前端业务代码(含真实 src/依赖,保留 projman 标准 CI)
deploy-userbase-front / build-and-deploy (push) Failing after 1m54s
build / build (push) Successful in 3m36s

This commit is contained in:
chenxing
2026-09-09 22:37:59 +08:00
parent a53ce07228
commit 4279f99be1
270 changed files with 12479 additions and 25715 deletions
+234
View File
@@ -0,0 +1,234 @@
<template>
<div :class="menuClass">
<ul class="menu-ul" v-if="menuVisible">
<li class="operate-item" @click="menuVisible = false" title="收起菜单">
<SvgIcon name="menu-operate" color="#ececec" />
</li>
<template v-for="(item, index) in menuList" :key="index">
<li
v-wave="myWave"
@click="linkPage(item, index)"
:class="{ active: index == activeIndex, 'first-bottom': index == menuFirstBottomIndex }"
>
<a :title="item.name">
<FetchSvg
size="24"
:src="$conf.serviceHost + item.icon"
:color="index == activeIndex ? '#fff' : '#ececec'"
/>
<span>{{ item.name }}</span>
</a>
</li>
</template>
<!-- <li class="fengche-item" v-wave="myWave">
<a href="javascript:void(0)">
<SvgIcon name="fengche" color="#ffffff" />
<span>随机壁纸</span>
</a>
</li> -->
<!-- <li class="fengche-item" v-wave="myWave">
<RouterLink :to="{ name: 'AppDetails', params: { type: 1, id: 500 } }">
<SvgIcon name="fengche" color="#ffffff" />
<span>随机壁纸</span>
</RouterLink>
</li> -->
</ul>
<div class="menu-arrow_box" title="展开菜单" v-else @click="menuVisible = true">
<SvgIcon name="menu-hide-arrow" color="white" />
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, computed, onMounted, watchEffect, inject, nextTick } from "vue";
// import { BaseDict } from "@/types/Basics.ts";
import SvgIcon from "@/components/SvgIcon.vue";
import { useRoute, useRouter } from "vue-router";
import { useDefaultStore } from "@/store";
import { storeToRefs } from "pinia";
import { LinkOpenTypeEnum, StateEnum } from "@/types";
import FetchSvg from "@/components/FetchSvg.vue";
import mittBus from "@/utils/mitt";
import useCurrentInstance from "@/utils/hook/useCurrentInstance";
import { bschLinkPage, isTickeRoterByName } from "@/utils/bschLinkPage";
const { $conf } = useCurrentInstance();
const myWave = ref({
color: "#fff",
initialOpacity: 0.5,
duration: 0.45,
easing: "ease-in",
});
const route = useRoute(),
router = useRouter();
const store = useDefaultStore();
const { menuVisible } = storeToRefs(store);
const menuList = computed<any[]>(() => {
let topArr = store.curUserMenuList.filter(x => x.isBottom !== true).sort((a, b) => a.orderNum - b.orderNum);
let bottomArr = store.curUserMenuList.filter(x => x.isBottom === true).sort((a, b) => a.orderNum - b.orderNum);
return [...topArr, ...bottomArr];
});
//第一个悬浮底部的index
const menuFirstBottomIndex = computed<number>(() => menuList.value.findIndex(x => x.isBottom === true));
const activeIndex = ref(-1);
watchEffect(() => {
let findIndex = menuList.value.findIndex(x => x.url === route.path);
if (findIndex > -1) {
activeIndex.value = findIndex;
return;
}
if (isTickeRoterByName(route.name as string)) {
let menuId = route.params.menuId as string;
activeIndex.value = menuList.value.findIndex(x => x.id == menuId);
}
});
onMounted(() => {
setTimeout(() => {
$(".app-desktop").addClass("app-desktop__animation");
}, 0);
});
const menuClass = computed(() => {
return ["menu-wrap", menuVisible.value ? "menu-wrap__show" : "menu-wrap__hide"];
});
const isAdmin = computed(() => store.getIsAdmin);
async function linkPage(item: any, index: number) {
// if (!item.isNative && !item.isHeader) {
// bschLinkPage({ url: item.url, type: item.openType });
// return;
// }
if (!item.isNative && item.openType === LinkOpenTypeEnum.Open) {
window.open(item.url);
return;
}
mittBus.emit("updateState", StateEnum.Desktop);
mittBus.emit("reload");
if (!!item.isNative) {
router.push(item.url);
} else {
router.push({ name: "AppDetails", params: { menuId: item.id } });
}
}
</script>
<style lang="scss">
.menu-wrap {
position: fixed;
left: 0;
top: 0;
height: 100%;
width: 70px;
z-index: 10;
// background: rgba(0, 0, 0, 0.4);
background-color: rgba(0, 0, 0, 0.3);
box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25);
backdrop-filter: blur(15px);
padding: 5px;
transition: left 0.2s ease-in-out, opacity 0.2s ease-in-out;
&__show {
left: 0;
}
&__hide {
left: -70px;
}
}
.menu-ul {
--textColor: #ececec;
display: flex;
flex-direction: column;
height: 100%;
li {
display: inline-block;
vertical-align: middle;
-webkit-transform: translateZ(0);
background-color: none;
transform: translateZ(0);
box-shadow: 0 0 1px rgba(0, 0, 0, 0);
backface-visibility: hidden;
-moz-osx-font-smoothing: grayscale;
overflow: hidden;
-webkit-transition-duration: 0.5s;
transition-duration: 0.5s;
-webkit-transition-property: color, background-color;
transition-property: color, background-color;
width: 60px;
height: 60px;
margin: 8px 0;
border-radius: 4px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
a {
color: var(--textColor);
text-align: center;
font-size: 13px;
display: block;
line-height: normal;
}
svg {
display: inline-block;
width: 24px;
height: 24px;
}
span {
display: block;
}
}
li.operate-item {
cursor: pointer;
svg {
width: 42px;
height: 42px;
}
&:hover {
background: none;
}
}
li.fengche-item {
position: absolute;
bottom: 8px;
left: 5px;
}
li:hover {
background-color: rgba(255, 255, 255, 0.15);
}
li.active {
background-color: rgba(255, 255, 255, 0.3);
--textColor: #fff;
// color: #fff;
}
li.first-bottom {
margin-top: auto;
}
}
.menu-arrow_box {
position: relative;
left: 62px;
top: 50%;
transform: translateY(-50%);
width: 20px;
height: 42px;
border-radius: 0px 8px 8px 0px;
background: rgba(0, 0, 0, 0.3);
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.2);
display: flex;
justify-content: center;
align-items: center;
backdrop-filter: blur(15px);
cursor: pointer;
svg {
width: 22px;
height: 22px;
display: inline-block;
}
}
</style>