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:
+104
-76
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<view class="page container">
|
||||
<view class="page">
|
||||
<view class="stage-card">
|
||||
<view class="stage-badge">第 {{ stageDay }}/30 天</view>
|
||||
<text class="stage-label">当前减量计划阶段</text>
|
||||
@@ -7,7 +7,7 @@
|
||||
<text class="stage-days">本阶段还剩 {{ daysLeft }} 天</text>
|
||||
<view class="stage-progress-row">
|
||||
<text class="stage-progress-label">阶段进度</text>
|
||||
<text class="stage-progress-value text-primary">{{ Math.round(stageProgress * 100) }}%</text>
|
||||
<text class="stage-progress-value">{{ Math.round(stageProgress * 100) }}%</text>
|
||||
</view>
|
||||
<view class="stage-progress-bar">
|
||||
<view class="stage-progress-fill" :style="{ width: stageProgress * 100 + '%' }"></view>
|
||||
@@ -20,16 +20,16 @@
|
||||
<text class="section-title">每日 AI 分析</text>
|
||||
</view>
|
||||
|
||||
<view class="ai-chat card">
|
||||
<view class="ai-chat-header">
|
||||
<text class="ai-chat-name text-primary">AI 教练</text>
|
||||
<text class="ai-chat-time">· 刚刚</text>
|
||||
</view>
|
||||
<view class="ai-chat-bubble">
|
||||
<text class="ai-chat-text">{{ aiAdvice }}</text>
|
||||
</view>
|
||||
<view class="ai-avatar">
|
||||
<text>🤖</text>
|
||||
<view class="ai-chat">
|
||||
<view class="ai-avatar">🤖</view>
|
||||
<view class="ai-chat-content">
|
||||
<view class="ai-chat-header">
|
||||
<text class="ai-chat-name">AI 教练</text>
|
||||
<text class="ai-chat-time">· 刚刚</text>
|
||||
</view>
|
||||
<view class="ai-chat-bubble">
|
||||
<text class="ai-chat-text">{{ aiAdvice }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -44,19 +44,19 @@
|
||||
<view
|
||||
v-for="goal in goals"
|
||||
:key="goal.id"
|
||||
class="goal-item card"
|
||||
class="goal-item"
|
||||
@tap="toggleGoal(goal)"
|
||||
>
|
||||
<view class="goal-check" :class="{ 'goal-check-done': goal.done }">
|
||||
<text v-if="goal.done">✓</text>
|
||||
<text v-if="goal.done" class="goal-check-icon">✓</text>
|
||||
</view>
|
||||
<text class="goal-text" :class="{ 'goal-text-done': goal.done }">{{ goal.text }}</text>
|
||||
<text class="goal-icon">{{ goal.icon }}</text>
|
||||
<text v-if="goal.icon" class="goal-icon">{{ goal.icon }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="record-btn btn btn-primary" @tap="goRecord">
|
||||
<view class="record-btn" @tap="goRecord">
|
||||
<text class="record-icon">➕</text>
|
||||
<text>记录吸烟或烟瘾</text>
|
||||
</view>
|
||||
@@ -64,7 +64,12 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { useLogin } from '@/hooks/useLogin'
|
||||
import * as api from '@/api'
|
||||
|
||||
const { waitForLogin } = useLogin()
|
||||
const loading = ref(true)
|
||||
|
||||
const stageDay = ref(18)
|
||||
const stage = ref(2)
|
||||
@@ -91,39 +96,46 @@ function toggleGoal(goal) {
|
||||
function goRecord() {
|
||||
uni.switchTab({ url: '/pages/index/index' })
|
||||
}
|
||||
|
||||
async function initPage() {
|
||||
loading.value = true
|
||||
try {
|
||||
await waitForLogin()
|
||||
} catch (e) {
|
||||
console.error('initPage error:', e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initPage()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
padding-bottom: 180rpx;
|
||||
min-height: 100vh;
|
||||
background-color: #0D1F17;
|
||||
padding: 32rpx;
|
||||
padding-bottom: 200rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.stage-card {
|
||||
background: linear-gradient(135deg, rgba(74, 222, 128, 0.1) 0%, rgba(74, 222, 128, 0.05) 100%);
|
||||
background: linear-gradient(135deg, rgba(74, 222, 128, 0.15) 0%, rgba(74, 222, 128, 0.05) 100%);
|
||||
border-radius: 24rpx;
|
||||
padding: 32rpx;
|
||||
margin-bottom: 32rpx;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.stage-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: url('data:image/svg+xml,...') no-repeat center;
|
||||
opacity: 0.1;
|
||||
}
|
||||
|
||||
.stage-badge {
|
||||
position: absolute;
|
||||
top: 24rpx;
|
||||
right: 24rpx;
|
||||
background-color: var(--color-primary);
|
||||
color: var(--color-bg);
|
||||
background-color: #4ADE80;
|
||||
color: #0D1F17;
|
||||
padding: 8rpx 20rpx;
|
||||
border-radius: 20rpx;
|
||||
font-size: 24rpx;
|
||||
@@ -132,21 +144,22 @@ function goRecord() {
|
||||
|
||||
.stage-label {
|
||||
font-size: 24rpx;
|
||||
color: var(--color-primary);
|
||||
color: #4ADE80;
|
||||
display: block;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.stage-name {
|
||||
font-size: 48rpx;
|
||||
font-size: 44rpx;
|
||||
font-weight: 700;
|
||||
color: #FFFFFF;
|
||||
display: block;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.stage-days {
|
||||
font-size: 24rpx;
|
||||
color: var(--color-text-secondary);
|
||||
color: #9CA3AF;
|
||||
display: block;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
@@ -159,12 +172,13 @@ function goRecord() {
|
||||
|
||||
.stage-progress-label {
|
||||
font-size: 24rpx;
|
||||
color: var(--color-text-secondary);
|
||||
color: #9CA3AF;
|
||||
}
|
||||
|
||||
.stage-progress-value {
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
color: #4ADE80;
|
||||
}
|
||||
|
||||
.stage-progress-bar {
|
||||
@@ -176,13 +190,11 @@ function goRecord() {
|
||||
|
||||
.stage-progress-fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, var(--color-primary), #22C55E);
|
||||
background: linear-gradient(90deg, #4ADE80, #22C55E);
|
||||
border-radius: 6rpx;
|
||||
}
|
||||
|
||||
.section {
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
.section { margin-bottom: 32rpx; }
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
@@ -191,30 +203,45 @@ function goRecord() {
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.section-icon {
|
||||
font-size: 32rpx;
|
||||
}
|
||||
.section-icon { font-size: 32rpx; }
|
||||
|
||||
.section-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.section-badge {
|
||||
margin-left: auto;
|
||||
font-size: 24rpx;
|
||||
color: var(--color-primary);
|
||||
color: #4ADE80;
|
||||
background-color: rgba(74, 222, 128, 0.1);
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
|
||||
.ai-chat {
|
||||
position: relative;
|
||||
background-color: #1A3325;
|
||||
border-radius: 24rpx;
|
||||
padding: 32rpx;
|
||||
padding-left: 100rpx;
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.ai-avatar {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
background-color: #243D2E;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 32rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.ai-chat-content { flex: 1; }
|
||||
|
||||
.ai-chat-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -224,15 +251,16 @@ function goRecord() {
|
||||
|
||||
.ai-chat-name {
|
||||
font-weight: 600;
|
||||
color: #4ADE80;
|
||||
}
|
||||
|
||||
.ai-chat-time {
|
||||
font-size: 24rpx;
|
||||
color: var(--color-text-muted);
|
||||
color: #6B7280;
|
||||
}
|
||||
|
||||
.ai-chat-bubble {
|
||||
background-color: var(--color-bg-card-light);
|
||||
background-color: #243D2E;
|
||||
padding: 24rpx;
|
||||
border-radius: 24rpx;
|
||||
border-top-left-radius: 8rpx;
|
||||
@@ -241,23 +269,10 @@ function goRecord() {
|
||||
.ai-chat-text {
|
||||
font-size: 28rpx;
|
||||
line-height: 1.6;
|
||||
color: #FFFFFF;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.ai-avatar {
|
||||
position: absolute;
|
||||
left: 24rpx;
|
||||
bottom: 32rpx;
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
background-color: var(--color-bg-card-light);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.goals-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -268,49 +283,62 @@ function goRecord() {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
padding: 24rpx;
|
||||
background-color: #1A3325;
|
||||
border-radius: 24rpx;
|
||||
padding: 28rpx;
|
||||
}
|
||||
|
||||
.goal-check {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
border-radius: 50%;
|
||||
border: 4rpx solid var(--color-border);
|
||||
border: 4rpx solid #374151;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 28rpx;
|
||||
color: var(--color-bg);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.goal-check-done {
|
||||
background-color: var(--color-primary);
|
||||
border-color: var(--color-primary);
|
||||
background-color: #4ADE80;
|
||||
border-color: #4ADE80;
|
||||
}
|
||||
|
||||
.goal-check-icon {
|
||||
font-size: 28rpx;
|
||||
color: #0D1F17;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.goal-text {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.goal-text-done {
|
||||
text-decoration: line-through;
|
||||
color: var(--color-text-muted);
|
||||
color: #6B7280;
|
||||
}
|
||||
|
||||
.goal-icon {
|
||||
font-size: 32rpx;
|
||||
}
|
||||
.goal-icon { font-size: 32rpx; }
|
||||
|
||||
.record-btn {
|
||||
position: fixed;
|
||||
bottom: 140rpx;
|
||||
left: 32rpx;
|
||||
right: 32rpx;
|
||||
height: 96rpx;
|
||||
background-color: #4ADE80;
|
||||
border-radius: 48rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 12rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
color: #0D1F17;
|
||||
}
|
||||
|
||||
.record-icon {
|
||||
font-size: 32rpx;
|
||||
}
|
||||
.record-icon { font-size: 32rpx; }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user