Files
digital-psychology/apps/user-h5/src/components/home/HomeToolGrid.vue
T
jackyu66gitandCursor 19d3cd5945 refactor(ECR-001): 接入 ESS 并完成结构对齐 Phase A–E
绑定 ESS 双轨治理,拆分超大 H5 页与 Go 引擎,抽出 membership 服务,
并将 star/fortune 重命名为 outlook(JSON 双写兼容);同时修复 /psy API 代理与首页 + 菜单层级。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-05 17:51:40 +08:00

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>