绑定 ESS 双轨治理,拆分超大 H5 页与 Go 引擎,抽出 membership 服务, 并将 star/fortune 重命名为 outlook(JSON 双写兼容);同时修复 /psy API 代理与首页 + 菜单层级。 Co-authored-by: Cursor <cursoragent@cursor.com>
134 lines
3.0 KiB
Vue
134 lines
3.0 KiB
Vue
<template>
|
|
<section class="section grid-sec">
|
|
<div class="tool-scroll" aria-label="功能入口">
|
|
<div class="tool-rows">
|
|
<div class="tool-row">
|
|
<router-link
|
|
v-for="t in row1"
|
|
:key="t.to + t.label"
|
|
:to="t.to"
|
|
class="tool-item"
|
|
@click="$emit('track', t.label)"
|
|
>
|
|
<div class="icon" aria-hidden="true">
|
|
<HomeToolIcon :name="t.icon" />
|
|
</div>
|
|
<div class="label">{{ t.label }}</div>
|
|
<span v-if="t.badge" class="badge" :class="'b-' + (t.badgeTone || 'hot')">{{ t.badge }}</span>
|
|
</router-link>
|
|
</div>
|
|
<div class="tool-row">
|
|
<router-link
|
|
v-for="t in row2"
|
|
:key="t.to + t.label"
|
|
:to="t.to"
|
|
class="tool-item"
|
|
@click="$emit('track', t.label)"
|
|
>
|
|
<div class="icon" aria-hidden="true">
|
|
<HomeToolIcon :name="t.icon" />
|
|
</div>
|
|
<div class="label">{{ t.label }}</div>
|
|
<span v-if="t.badge" class="badge" :class="'b-' + (t.badgeTone || 'hot')">{{ t.badge }}</span>
|
|
</router-link>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import HomeToolIcon from '../HomeToolIcon.vue'
|
|
import type { HomeTool } from '../../lib/homeCatalog'
|
|
|
|
defineProps<{
|
|
row1: HomeTool[]
|
|
row2: HomeTool[]
|
|
}>()
|
|
|
|
defineEmits<{ track: [label: string] }>()
|
|
</script>
|
|
|
|
<style scoped>
|
|
.section {
|
|
padding: 0 var(--spacing-md);
|
|
margin-top: 18px;
|
|
}
|
|
.grid-sec {
|
|
padding-right: 0;
|
|
margin-top: 14px;
|
|
}
|
|
.tool-scroll {
|
|
overflow-x: auto;
|
|
-webkit-overflow-scrolling: touch;
|
|
scrollbar-width: none;
|
|
padding-right: var(--spacing-md);
|
|
}
|
|
.tool-scroll::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
.tool-rows {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 16px;
|
|
width: max-content;
|
|
padding: 4px 0 2px;
|
|
}
|
|
.tool-row {
|
|
display: flex;
|
|
gap: 2px;
|
|
}
|
|
.tool-item {
|
|
width: 74px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 8px;
|
|
color: var(--color-text-primary);
|
|
position: relative;
|
|
flex-shrink: 0;
|
|
transition: transform var(--duration-fast) ease;
|
|
}
|
|
.tool-item:active {
|
|
transform: scale(0.9);
|
|
}
|
|
.tool-item .icon {
|
|
width: 54px;
|
|
height: 54px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: transparent;
|
|
border-radius: 0;
|
|
box-shadow: none;
|
|
overflow: visible;
|
|
}
|
|
.tool-item .label {
|
|
font-size: 11px;
|
|
color: #555;
|
|
text-align: center;
|
|
line-height: 1.2;
|
|
font-weight: 500;
|
|
}
|
|
.badge {
|
|
position: absolute;
|
|
top: -2px;
|
|
right: 6px;
|
|
font-size: 9px;
|
|
color: #fff;
|
|
padding: 2px 5px;
|
|
border-radius: 7px;
|
|
line-height: 1.3;
|
|
font-weight: 650;
|
|
box-shadow: 0 2px 6px rgba(229, 77, 66, 0.25);
|
|
z-index: 2;
|
|
}
|
|
.badge.b-hot {
|
|
background: linear-gradient(135deg, #ff7a6e, var(--color-primary));
|
|
}
|
|
.badge.b-new {
|
|
background: linear-gradient(135deg, #6eb6ff, #4a90e2);
|
|
box-shadow: 0 2px 6px rgba(74, 144, 226, 0.28);
|
|
}
|
|
</style>
|