feat: 样式小规模优化

This commit is contained in:
digua
2026-04-15 23:00:05 +08:00
committed by digua
parent 1c46600988
commit a1a587f791
2 changed files with 22 additions and 33 deletions
+7 -7
View File
@@ -13,7 +13,7 @@ export type TimeSelectMode = 'recent' | 'quarter' | 'year' | 'custom'
/** 组件内部状态快照,用于父组件 URL 序列化 */
export interface TimeSelectState {
mode: TimeSelectMode
recentDays?: number // 最近模式:天数 (180/365/730/1825/0=全部)
recentDays?: number // 最近模式:天数 (365/730/1825/0=全部)
year?: number // 按年模式:年份
quarterYear?: number // 按季模式:年份
quarter?: number // 按季模式:季度 (1-4)
@@ -116,7 +116,6 @@ const modeOptions = computed(() => [
])
const recentOptions = computed(() => [
{ label: t('common.timeSelect.recent.halfYear'), value: 180 },
{ label: t('common.timeSelect.recent.oneYear'), value: 365 },
{ label: t('common.timeSelect.recent.twoYears'), value: 730 },
{ label: t('common.timeSelect.recent.fiveYears'), value: 1825 },
@@ -181,7 +180,6 @@ const yearDisplayLabel = computed(() => {
/** 最近模式 displayLabel 映射 */
function getRecentDisplayLabel(days: number): string {
const map: Record<number, string> = {
180: t('common.timeSelect.display.recent180'),
365: t('common.timeSelect.display.recent365'),
730: t('common.timeSelect.display.recent730'),
1825: t('common.timeSelect.display.recent1825'),
@@ -189,6 +187,10 @@ function getRecentDisplayLabel(days: number): string {
return map[days] || ''
}
function normalizeRecentDays(days: number): number {
return [365, 730, 1825, 0].includes(days) ? days : 365
}
function buildValue(): TimeRangeValue | null {
if (!fullTimeRange.value) return null
const stateBase: TimeSelectState = { mode: mode.value }
@@ -300,9 +302,7 @@ function initModeDefaults(newMode: TimeSelectMode) {
if (!fullTimeRange.value) return
switch (newMode) {
case 'recent':
if (![180, 365, 730, 1825, 0].includes(recentPeriod.value)) {
recentPeriod.value = 365
}
recentPeriod.value = normalizeRecentDays(recentPeriod.value)
break
case 'quarter': {
const { year, quarter } = getQuarterFromTs(fullTimeRange.value.end)
@@ -395,7 +395,7 @@ async function loadData() {
isInitializing.value = true
switch (initMode) {
case 'recent':
recentPeriod.value = init?.recentDays ?? 365
recentPeriod.value = normalizeRecentDays(init?.recentDays ?? 365)
break
case 'quarter': {
if (init?.quarterYear && init?.quarter) {
@@ -7,7 +7,7 @@ import { EChart } from '@/components/charts'
import RelationshipMetricCard from './RelationshipMetricCard.vue'
import type { EChartsOption } from 'echarts'
const { t } = useI18n()
const { t, locale } = useI18n()
interface TimeFilter {
startTs?: number
@@ -107,6 +107,8 @@ const timeRangeString = computed(() => {
return `${first} ${last}`
})
const heroTextMaxWidthClass = computed(() => (locale.value.startsWith('en') ? 'max-w-[420px]' : 'max-w-[320px]'))
function getOverallLabel(): string {
if (!stats.value || stats.value.totalSessions <= 3) {
return t('views.relationship.labels.distantBond')
@@ -117,14 +119,6 @@ function getOverallLabel(): string {
return t('views.relationship.labels.silentGuardian')
}
// ==================== 收尾者 ====================
const overallCloseRatio = computed(() => {
if (!memberA.value || !stats.value) return 50
const totalClose = (memberA.value.totalCloseCount ?? 0) + (memberB.value?.totalCloseCount ?? 0)
if (totalClose === 0) return 50
return Math.round((memberA.value.totalCloseCount / totalClose) * 100)
})
// 确保进度条视觉上可区分(至少 5% 最小宽度)
function clampBarWidth(ratio: number): number {
if (ratio <= 0) return 0
@@ -297,17 +291,9 @@ function formatDuration(seconds: number): string {
<div :class="isLoading ? 'h-full' : ''">
<LoadingState v-if="isLoading" variant="page" :text="t('common.loading')" />
<div v-else class="main-content mx-auto max-w-[920px] space-y-6 p-6">
<!-- 无会话索引 -->
<EmptyState
v-if="stats && !stats.hasSessionIndex"
icon="i-heroicons-clock"
:title="t('views.relationship.noIndex.title')"
:description="t('views.relationship.noIndex.description')"
/>
<!-- 无数据 -->
<EmptyState
v-else-if="stats && !hasData"
v-if="stats && !hasData"
icon="i-heroicons-heart"
:title="t('views.relationship.empty.title')"
:description="t('views.relationship.empty.description')"
@@ -316,21 +302,21 @@ function formatDuration(seconds: number): string {
<!-- 有数据 -->
<template v-else-if="stats && hasData">
<div class="space-y-6">
<!-- 关系大满贯 (Single Page Shareable Poster) -->
<!-- 关系卡片 -->
<ThemeCard id="shareable-poster" variant="elevated" decorative class="flex flex-col">
<!-- 1. 主视觉区域 (Primary Module) -->
<div
class="relative z-10 flex flex-col items-center justify-center gap-10 px-6 pt-10 pb-6 sm:px-8 lg:flex-row lg:gap-16 xl:gap-24"
class="relative z-10 flex flex-col items-center justify-center gap-10 px-6 pt-10 pb-6 sm:px-8 lg:flex-row lg:items-start lg:justify-between lg:gap-8 xl:gap-12"
>
<!-- 左侧文字描述与基础数据 -->
<div class="flex shrink-0 flex-col items-center justify-center">
<div class="flex w-fit flex-col items-start text-left">
<div class="flex min-w-0 max-w-full flex-1 flex-col items-center justify-center lg:items-start">
<div class="flex w-fit min-w-0 flex-col items-start text-left" :class="heroTextMaxWidthClass">
<div class="flex flex-col text-[15px] leading-relaxed text-gray-600 dark:text-gray-300">
<p class="mb-2 text-sm font-medium tracking-wide text-gray-500 dark:text-gray-400">
{{ timeRangeString }}
</p>
<div class="mb-4 flex items-baseline gap-2">
<div class="mb-4 flex min-w-0 flex-wrap items-baseline gap-2">
<span class="text-xl font-medium text-gray-700 dark:text-gray-300">
{{ t('views.relationship.hero.totalSessionsPrefix') }}
</span>
@@ -342,7 +328,7 @@ function formatDuration(seconds: number): string {
</span>
</div>
<div class="flex items-baseline flex-wrap gap-x-1.5 gap-y-1">
<div class="flex min-w-0 max-w-full flex-wrap items-baseline gap-x-1.5 gap-y-1">
<span class="text-base font-medium text-gray-600 dark:text-gray-300">
{{ t('views.relationship.hero.initiativePrefix') }}
</span>
@@ -352,7 +338,7 @@ function formatDuration(seconds: number): string {
<span class="text-base font-medium text-gray-600 dark:text-gray-300">
{{ t('views.relationship.hero.initiativeByPrefix') }}
</span>
<span class="font-bold text-xl text-gray-900 dark:text-white">
<span class="max-w-full break-all text-xl font-bold leading-snug text-gray-900 dark:text-white">
{{ overallInitiateRatio >= 50 ? memberA?.name : memberB?.name }}
</span>
<span class="text-base font-medium text-gray-600 dark:text-gray-300">
@@ -403,7 +389,10 @@ function formatDuration(seconds: number): string {
</div>
<!-- 右侧主动性趋势图 -->
<div v-if="stats.months.length >= 2" class="flex w-full max-w-[400px] shrink-0 flex-col justify-center">
<div
v-if="stats.months.length >= 2"
class="flex min-w-0 w-full max-w-[400px] flex-1 flex-col justify-center lg:max-w-[460px]"
>
<div class="mb-2 flex items-center justify-between px-1">
<span class="text-sm font-bold text-gray-900 dark:text-white">
{{ t('views.relationship.trend.title') }}