Files
mom-web/src/views/Home/Index.vue

260 lines
6.8 KiB
Vue
Raw Normal View History

2026-03-05 16:52:12 +08:00
<template>
<div class="mobile-home">
<!-- 顶部Banner -->
<div class="mobile-home__banner">
<div class="mobile-home__banner-bg">
<div class="mobile-home__banner-content">
<div class="mobile-home__brand">
<div class="mobile-home__brand-logo">亚为MOM</div>
<div class="mobile-home__brand-text">
<div class="mobile-home__brand-title">智能一体化管理系统</div>
<div class="mobile-home__brand-sub">私有化部署可定制</div>
</div>
</div>
<div class="mobile-home__banner-deco">
<svg width="80" height="80" viewBox="0 0 80 80" fill="none">
<rect x="10" y="20" width="25" height="35" rx="3" fill="rgba(255,255,255,0.3)"/>
<rect x="40" y="10" width="30" height="45" rx="3" fill="rgba(255,255,255,0.2)"/>
<circle cx="55" cy="60" r="15" fill="rgba(255,255,255,0.15)"/>
<rect x="15" y="58" width="20" height="3" rx="1" fill="rgba(255,255,255,0.4)"/>
<rect x="15" y="64" width="14" height="3" rx="1" fill="rgba(255,255,255,0.3)"/>
</svg>
</div>
</div>
</div>
</div>
<!-- 常用功能区 -->
<div class="mobile-home__section">
<div class="mobile-home__section-header">
<div class="mobile-home__section-icon">
<svg viewBox="0 0 24 24" width="18" height="18" fill="#409eff">
<path d="M3.5 18.49l6-6.01 4 4L22 6.92l-1.41-1.41-7.09 7.97-4-4L2 16.99z"/>
</svg>
</div>
<span class="mobile-home__section-title">常用功能</span>
</div>
<div class="mobile-home__grid" v-loading="loading">
<div
v-for="item in shortcut"
:key="item.name"
class="mobile-home__grid-item"
@click="handleShortcutClick(item.url)"
>
<div class="mobile-home__grid-icon" :style="{ color: item.color, background: item.color + '18' }">
<Icon :icon="item.icon" />
</div>
<span class="mobile-home__grid-label">{{ item.name }}</span>
</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { useUserStore } from '@/store/modules/user'
import { usePermissionStore } from '@/store/modules/permission'
import type { Shortcut } from './types'
import { useRouter } from 'vue-router'
defineOptions({ name: 'Index' })
const { t } = useI18n()
const router = useRouter()
const userStore = useUserStore()
const permissionStore = usePermissionStore()
const loading = ref(true)
const avatar = userStore.getUser.avatar
const username = userStore.getUser.nickname
// 预设颜色列表
const colorList = [
'#1fdaca', '#ff6b6b', '#7c3aed', '#3fb27f', '#4daf1bc9', '#1a73e8',
'#f59e0b', '#10b981', '#6366f1', '#ef4444', '#8b5cf6', '#06b6d4',
'#84cc16', '#f97316', '#ec4899', '#14b8a6', '#22c55e', '#6b7280',
'#3b82f6', '#fbbf24'
]
// 获取快捷入口
let shortcut = reactive<Shortcut[]>([])
// 递归提取所有叶子节点路由
const extractLeafRoutes = (routes: any[], result: Shortcut[] = [], colorIndex = { value: 0 }, parentPath = ''): Shortcut[] => {
routes.forEach((route) => {
if (route.meta?.hidden) return
let fullPath = route.path || ''
if (fullPath && !fullPath.startsWith('/') && !fullPath.startsWith('http')) {
fullPath = parentPath.endsWith('/') ? `${parentPath}${fullPath}` : `${parentPath}/${fullPath}`
}
if (fullPath && !fullPath.startsWith('/') && !fullPath.startsWith('http')) {
fullPath = `/${fullPath}`
}
if (route.children && route.children.length > 0) {
extractLeafRoutes(route.children, result, colorIndex, fullPath)
} else {
if (fullPath) {
result.push({
name: route.meta?.title || route.name || '未命名',
icon: route.meta?.icon || 'mdi:application',
url: fullPath,
color: colorList[colorIndex.value % colorList.length]
})
colorIndex.value++
}
}
})
return result
}
const getShortcut = async () => {
const routes = permissionStore.getRouters
const leafRoutes = extractLeafRoutes(routes)
shortcut.splice(0, shortcut.length, ...leafRoutes)
}
const getAllApi = async () => {
await getShortcut()
loading.value = false
}
const handleShortcutClick = (url: string) => {
if (url.startsWith('http://') || url.startsWith('https://')) {
window.open(url, '_blank')
} else {
router.push(url)
}
}
getAllApi()
</script>
<style lang="scss" scoped>
.mobile-home {
background: #f5f5f5;
min-height: 100%;
padding-bottom: 16px;
}
/* Banner */
.mobile-home__banner {
padding: 0 12px;
margin-bottom: 12px;
}
.mobile-home__banner-bg {
background: linear-gradient(135deg, #43cea2 0%, #2a9d8f 50%, #264653 100%);
border-radius: 0 0 16px 16px;
padding: 20px 16px 24px;
position: relative;
overflow: hidden;
}
.mobile-home__banner-content {
display: flex;
justify-content: space-between;
align-items: center;
}
.mobile-home__brand {
display: flex;
flex-direction: column;
gap: 8px;
}
.mobile-home__brand-logo {
font-size: 28px;
font-weight: 800;
color: #fff;
letter-spacing: 2px;
text-shadow: 0 2px 8px rgba(0,0,0,0.2);
}
.mobile-home__brand-text {
color: #fff;
}
.mobile-home__brand-title {
font-size: 16px;
font-weight: 600;
margin-bottom: 2px;
}
.mobile-home__brand-sub {
font-size: 12px;
opacity: 0.8;
}
.mobile-home__banner-deco {
opacity: 0.7;
flex-shrink: 0;
}
/* 功能区 */
.mobile-home__section {
margin: 0 12px;
background: #fff;
border-radius: 12px;
padding: 14px;
box-shadow: 0 1px 4px rgba(0,0,0,0.06);
}
.mobile-home__section-header {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 16px;
padding-bottom: 10px;
border-bottom: 2px solid #409eff;
}
.mobile-home__section-icon {
width: 28px;
height: 28px;
background: rgba(64,158,255,0.1);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.mobile-home__section-title {
font-size: 16px;
font-weight: 600;
color: #303133;
}
/* 功能网格 */
.mobile-home__grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 16px 8px;
min-height: 100px;
}
.mobile-home__grid-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
&:active {
opacity: 0.7;
}
}
.mobile-home__grid-icon {
width: 44px;
height: 44px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
font-size: 22px;
transition: transform 0.2s;
&:active {
transform: scale(0.92);
}
}
.mobile-home__grid-label {
font-size: 11px;
color: #303133;
text-align: center;
line-height: 1.3;
max-width: 64px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>