Files
digital-psychology/apps/user-h5/src/components/home/HomeSelfCard.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

216 lines
4.4 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>
<section class="self-card reveal" style="--d: 80ms" @click="$emit('open-portrait')">
<div class="self-head">
<button type="button" class="who-btn" @click.stop="$emit('open-profile')">
{{ profileLabel }}
<span class="caret" aria-hidden="true"></span>
</button>
<router-link class="more" to="/profile" @click.stop>更多</router-link>
</div>
<div class="self-body">
<div class="mood-col">
<div class="mood-label">
今日心情 <em>{{ mood.score }}</em><span></span>
</div>
<p class="mood-text">{{ mood.text }}</p>
</div>
<div class="dims" role="list">
<div
v-for="d in mood.dims"
:key="d.key"
class="dim"
role="listitem"
:style="{ '--bar': d.color, '--h': d.score + '%' }"
>
<b class="dim-score">{{ d.score }}</b>
<div class="dim-track">
<i class="dim-fill" />
</div>
<span class="dim-label">{{ d.label }}</span>
</div>
</div>
</div>
</section>
</template>
<script setup lang="ts">
defineProps<{
profileLabel: string
mood: {
score: number
text: string
dims: { key: string; label: string; score: number; color: string }[]
}
}>()
defineEmits<{
'open-portrait': []
'open-profile': []
}>()
</script>
<style scoped>
.self-card {
margin: 12px 16px 0;
position: relative;
z-index: 2;
padding: 14px 14px 16px;
background: var(--color-surface);
border-radius: var(--radius-xl);
box-shadow: var(--shadow-hero);
transition: transform var(--duration-fast) ease;
}
.self-card:active {
transform: scale(0.99);
}
.self-head {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
.who-btn {
border: none;
background: transparent;
font-size: 16px;
font-weight: 700;
color: var(--color-text-primary);
display: inline-flex;
align-items: center;
gap: 4px;
padding: 0;
font-family: var(--font-sans);
}
.caret {
font-size: 10px;
color: var(--color-text-tertiary);
}
.self-head .more {
font-size: 12px;
color: var(--color-text-tertiary);
}
.self-head .more::after {
content: ' ';
}
.self-body {
display: flex;
gap: 10px;
align-items: stretch;
}
.mood-col {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
justify-content: center;
padding-right: 4px;
}
.mood-label {
font-size: 13px;
font-weight: 600;
color: var(--color-text-primary);
line-height: 1.2;
}
.mood-label em {
font-style: normal;
font-family: var(--font-display);
font-size: 34px;
font-weight: 700;
color: var(--color-primary);
margin: 0 1px 0 4px;
letter-spacing: -0.02em;
vertical-align: -4px;
}
.mood-label span {
font-size: 12px;
color: var(--color-text-tertiary);
font-weight: 500;
}
.mood-text {
margin-top: 8px;
font-size: 12px;
color: #777;
line-height: 1.55;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
.dims {
display: flex;
gap: 7px;
align-items: flex-end;
flex-shrink: 0;
padding-bottom: 2px;
}
.dim {
width: 28px;
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
}
.dim-score {
font-size: 11px;
font-weight: 700;
color: var(--color-text-primary);
line-height: 1;
}
.dim-track {
width: 12px;
height: 64px;
border-radius: var(--radius-pill);
background: #f3ece8;
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: flex-end;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.04);
}
.dim-fill {
display: block;
width: 100%;
height: var(--h);
border-radius: var(--radius-pill);
background: linear-gradient(180deg, color-mix(in srgb, var(--bar) 70%, #fff) 0%, var(--bar) 100%);
box-shadow: 0 -1px 0 rgba(255, 255, 255, 0.35) inset;
animation: fillUp 0.7s cubic-bezier(0.22, 1, 0.36, 1) both;
animation-delay: calc(var(--d, 80ms) + 120ms);
}
@keyframes fillUp {
from {
height: 0;
}
to {
height: var(--h);
}
}
.dim-label {
font-size: 10px;
color: var(--color-text-secondary);
line-height: 1;
white-space: nowrap;
}
.reveal {
animation: rise 0.45s cubic-bezier(0.22, 1, 0.36, 1) both;
animation-delay: var(--d, 0ms);
}
@keyframes rise {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@media (prefers-reduced-motion: reduce) {
.reveal,
.dim-fill {
animation: none !important;
}
}
</style>