Implement login functionality and UI updates across the application. Added silent login process in App.vue, updated styles for various components, and integrated smoke record dialog. Enhanced onboarding and profile pages with improved layouts and user experience. Updated manifest and configuration files for deployment. Added easycom configuration for component auto-import.

This commit is contained in:
nepiedg
2026-01-25 14:48:20 +08:00
parent c883ae7b17
commit 661f39dfd7
24 changed files with 4569 additions and 572 deletions
+126 -66
View File
@@ -1,5 +1,5 @@
<template>
<view class="page container">
<view class="page">
<view class="tabs">
<view
v-for="tab in tabs"
@@ -12,7 +12,7 @@
</view>
</view>
<view class="insight-card card">
<view class="insight-card">
<view class="insight-icon"></view>
<view class="insight-content">
<text class="insight-title">每周洞察</text>
@@ -23,10 +23,10 @@
<view class="section">
<view class="section-header">
<text class="section-title">吸烟趋势</text>
<text class="section-change text-primary"> 减少 20%</text>
<text class="section-change"> 减少 20%</text>
</view>
<view class="chart-card card">
<view class="chart-card">
<view class="chart-header">
<text class="chart-label">日均吸烟量</text>
<view class="chart-value-row">
@@ -34,12 +34,10 @@
<text class="chart-unit">/</text>
</view>
</view>
<view class="chart-placeholder">
<view class="chart-bars">
<view v-for="(item, index) in weeklyData" :key="index" class="chart-bar-wrapper">
<view class="chart-bar" :style="{ height: item.height }"></view>
<text class="chart-bar-label">{{ item.label }}</text>
</view>
<view class="chart-bars">
<view v-for="(item, index) in weeklyData" :key="index" class="chart-bar-wrapper">
<view class="chart-bar" :style="{ height: item.height }"></view>
<text class="chart-bar-label" :class="{ 'chart-bar-label-active': index === 3 }">{{ item.label }}</text>
</view>
</view>
</view>
@@ -49,17 +47,22 @@
<text class="section-title">健康与储蓄</text>
<view class="health-row">
<view class="health-card card">
<view class="health-card">
<view class="health-ring">
<text class="health-value">¥145</text>
<view class="health-ring-inner">
<text class="health-prefix">已省</text>
<text class="health-value">¥145</text>
</view>
</view>
<text class="health-label">节省金额</text>
<text class="health-sub">目标 ¥200</text>
</view>
<view class="health-card card">
<view class="health-card">
<view class="health-ring health-ring-purple">
<text class="health-value">40%</text>
<view class="health-ring-inner">
<text class="health-value">40%</text>
</view>
</view>
<text class="health-label">肺部功能恢复</text>
<text class="health-sub">当前进度</text>
@@ -67,7 +70,7 @@
</view>
<view class="stats-grid">
<view class="mini-stat card">
<view class="mini-stat">
<text class="mini-stat-icon">🔥</text>
<text class="mini-stat-label">连续记录</text>
<view class="mini-stat-value-row">
@@ -77,7 +80,7 @@
<text class="mini-stat-sub">未吸烟</text>
</view>
<view class="mini-stat card">
<view class="mini-stat">
<text class="mini-stat-icon">🚫</text>
<text class="mini-stat-label">已拒绝</text>
<view class="mini-stat-value-row">
@@ -92,7 +95,12 @@
</template>
<script setup>
import { ref } from 'vue'
import { ref, onMounted } from 'vue'
import { useLogin } from '@/hooks/useLogin'
import * as api from '@/api'
const { waitForLogin } = useLogin()
const loading = ref(true)
const tabs = [
{ label: '周', value: 'week' },
@@ -102,7 +110,7 @@ const tabs = [
const currentTab = ref('week')
const weeklyData = [
const weeklyData = ref([
{ label: '一', height: '60%', count: 3 },
{ label: '二', height: '40%', count: 2 },
{ label: '三', height: '80%', count: 4 },
@@ -110,17 +118,46 @@ const weeklyData = [
{ label: '五', height: '60%', count: 3 },
{ label: '六', height: '20%', count: 1 },
{ label: '日', height: '40%', count: 2 }
]
])
async function initPage() {
loading.value = true
try {
await waitForLogin()
const res = await api.getDashboard()
if (res.data?.weekly) {
const maxCount = Math.max(...res.data.weekly.map(d => d.count), 1)
const weekLabels = ['一', '二', '三', '四', '五', '六', '日']
weeklyData.value = res.data.weekly.map((d, i) => ({
label: weekLabels[i] || '',
height: `${Math.max((d.count / maxCount) * 100, 5)}%`,
count: d.count
}))
}
} catch (e) {
console.error('initPage error:', e)
} finally {
loading.value = false
}
}
onMounted(() => {
initPage()
})
</script>
<style scoped>
.page {
padding-bottom: 120rpx;
min-height: 100vh;
background-color: #0D1F17;
padding: 32rpx;
padding-bottom: 180rpx;
box-sizing: border-box;
}
.tabs {
display: flex;
background-color: var(--color-bg-card);
background-color: #1A3325;
border-radius: 16rpx;
padding: 8rpx;
margin-bottom: 32rpx;
@@ -132,12 +169,12 @@ const weeklyData = [
padding: 20rpx;
border-radius: 12rpx;
font-size: 28rpx;
color: var(--color-text-secondary);
color: #9CA3AF;
}
.tab-active {
background-color: var(--color-primary);
color: var(--color-bg);
background-color: #4ADE80;
color: #0D1F17;
font-weight: 600;
}
@@ -146,37 +183,38 @@ const weeklyData = [
gap: 24rpx;
background-color: rgba(74, 222, 128, 0.1);
border: 2rpx solid rgba(74, 222, 128, 0.3);
border-radius: 24rpx;
padding: 32rpx;
margin-bottom: 32rpx;
}
.insight-icon {
font-size: 48rpx;
background-color: var(--color-primary);
width: 72rpx;
height: 72rpx;
font-size: 36rpx;
background-color: #4ADE80;
width: 64rpx;
height: 64rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.insight-content {
flex: 1;
}
.insight-content { flex: 1; }
.insight-title {
font-weight: 600;
color: #4ADE80;
display: block;
margin-bottom: 8rpx;
}
.insight-desc {
font-size: 24rpx;
color: var(--color-text-secondary);
font-size: 26rpx;
color: #9CA3AF;
line-height: 1.5;
}
.section {
margin-bottom: 32rpx;
}
.section { margin-bottom: 32rpx; }
.section-header {
display: flex;
@@ -188,23 +226,25 @@ const weeklyData = [
.section-title {
font-size: 32rpx;
font-weight: 600;
color: #FFFFFF;
}
.section-change {
font-size: 24rpx;
font-size: 26rpx;
color: #4ADE80;
}
.chart-card {
background-color: #1A3325;
border-radius: 24rpx;
padding: 32rpx;
}
.chart-header {
margin-bottom: 32rpx;
}
.chart-header { margin-bottom: 32rpx; }
.chart-label {
font-size: 24rpx;
color: var(--color-text-secondary);
color: #9CA3AF;
display: block;
}
@@ -217,11 +257,12 @@ const weeklyData = [
.chart-value {
font-size: 56rpx;
font-weight: 700;
color: #FFFFFF;
}
.chart-unit {
font-size: 24rpx;
color: var(--color-text-secondary);
color: #9CA3AF;
}
.chart-bars {
@@ -240,18 +281,25 @@ const weeklyData = [
}
.chart-bar {
width: 40rpx;
background: linear-gradient(to top, var(--color-primary), rgba(74, 222, 128, 0.5));
width: 36rpx;
background: linear-gradient(to top, #4ADE80, rgba(74, 222, 128, 0.4));
border-radius: 8rpx 8rpx 0 0;
min-height: 8rpx;
}
.chart-bar-label {
font-size: 22rpx;
color: var(--color-text-secondary);
font-size: 24rpx;
color: #9CA3AF;
margin-top: 12rpx;
}
.chart-bar-label-active {
color: #0D1F17;
background-color: #4ADE80;
padding: 4rpx 12rpx;
border-radius: 8rpx;
}
.health-row {
display: flex;
gap: 24rpx;
@@ -260,54 +308,60 @@ const weeklyData = [
.health-card {
flex: 1;
background-color: #1A3325;
border-radius: 24rpx;
padding: 32rpx;
display: flex;
flex-direction: column;
align-items: center;
padding: 32rpx;
}
.health-ring {
width: 160rpx;
height: 160rpx;
border-radius: 50%;
border: 12rpx solid rgba(74, 222, 128, 0.3);
background: conic-gradient(#4ADE80 0deg 252deg, rgba(74, 222, 128, 0.2) 252deg 360deg);
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 16rpx;
position: relative;
}
.health-ring::before {
content: '';
position: absolute;
top: -12rpx;
left: -12rpx;
right: -12rpx;
bottom: -12rpx;
.health-ring-purple {
background: conic-gradient(#A78BFA 0deg 144deg, rgba(167, 139, 250, 0.2) 144deg 360deg);
}
.health-ring-inner {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
border: 12rpx solid transparent;
border-top-color: var(--color-primary);
transform: rotate(-45deg);
background-color: #1A3325;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.health-ring-purple::before {
border-top-color: #A78BFA;
.health-prefix {
font-size: 20rpx;
color: #9CA3AF;
}
.health-value {
font-size: 32rpx;
font-size: 28rpx;
font-weight: 700;
color: #FFFFFF;
}
.health-label {
font-size: 26rpx;
color: #FFFFFF;
margin-bottom: 4rpx;
}
.health-sub {
font-size: 22rpx;
color: var(--color-text-secondary);
color: #9CA3AF;
}
.stats-grid {
@@ -317,17 +371,20 @@ const weeklyData = [
.mini-stat {
flex: 1;
background-color: #1A3325;
border-radius: 24rpx;
padding: 24rpx;
}
.mini-stat-icon {
font-size: 36rpx;
display: block;
margin-bottom: 12rpx;
}
.mini-stat-label {
font-size: 24rpx;
color: var(--color-text-secondary);
color: #9CA3AF;
display: block;
margin-bottom: 8rpx;
}
@@ -341,15 +398,18 @@ const weeklyData = [
.mini-stat-value {
font-size: 48rpx;
font-weight: 700;
color: #FFFFFF;
}
.mini-stat-unit {
font-size: 24rpx;
color: var(--color-text-secondary);
color: #9CA3AF;
}
.mini-stat-sub {
font-size: 22rpx;
color: var(--color-text-muted);
color: #6B7280;
display: block;
margin-top: 4rpx;
}
</style>