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

308 lines
7.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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;
}
/* 功能网格 */
.mobile-home__grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 12px 6px; // 网格间距变小
min-height: 100px;
}
.mobile-home__grid-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 4px; // 图标和文字间距变小
cursor: pointer;
-webkit-tap-highlight-color: transparent;
&:active {
opacity: 0.7;
}
}
.mobile-home__grid-icon {
width: 65px; // 图标变大
height: 65px;
border-radius: 14px;
display: flex;
align-items: center;
justify-content: center;
font-size: 26px; // 图标字体大小变大
transition: transform 0.2s;
&:active {
transform: scale(0.92);
}
}
.mobile-home__grid-label {
font-size: 12px; // 文字略大,可根据需求微调
color: #303133;
text-align: center;
line-height: 1.2;
max-width: 64px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>