Files
smt/pages/ai/index.vue
T

345 lines
6.7 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>
<view class="page">
<view class="stage-card">
<view class="stage-badge"> {{ stageDay }}/30 </view>
<text class="stage-label">当前减量计划阶段</text>
<text class="stage-name">阶段 {{ stage }} : {{ stageName }}</text>
<text class="stage-days">本阶段还剩 {{ daysLeft }} </text>
<view class="stage-progress-row">
<text class="stage-progress-label">阶段进度</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>
</view>
</view>
<view class="section">
<view class="section-header">
<text class="section-icon">🤖</text>
<text class="section-title">每日 AI 分析</text>
</view>
<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>
<view class="section">
<view class="section-header">
<text class="section-title">今日目标</text>
<text class="section-badge">已完成 {{ completedGoals }}/{{ goals.length }}</text>
</view>
<view class="goals-list">
<view
v-for="goal in goals"
:key="goal.id"
class="goal-item"
@tap="toggleGoal(goal)"
>
<view class="goal-check" :class="{ 'goal-check-done': goal.done }">
<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 v-if="goal.icon" class="goal-icon">{{ goal.icon }}</text>
</view>
</view>
</view>
<view class="record-btn" @tap="goRecord">
<text class="record-icon"></text>
<text>记录吸烟或烟瘾</text>
</view>
</view>
</template>
<script setup>
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)
const stageName = ref('减量期')
const daysLeft = ref(12)
const stageProgress = ref(0.4)
const aiAdvice = ref('早上好 Alex。昨天你的吸烟量比限额少了 2 支。这是一个巨大的胜利!🏆\n\n数据显示你的烟瘾在下午 2 点左右达到顶峰——今天试着那个时候去散散步。')
const goals = ref([
{ id: 1, text: '喝 2 升水', icon: '🏆', done: true },
{ id: 2, text: '控制在 5 支烟以内', icon: '', done: false },
{ id: 3, text: '阅读激励卡片', icon: '🏆', done: false }
])
const completedGoals = computed(() => {
return goals.value.filter(g => g.done).length
})
function toggleGoal(goal) {
goal.done = !goal.done
}
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 {
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.15) 0%, rgba(74, 222, 128, 0.05) 100%);
border-radius: 24rpx;
padding: 32rpx;
margin-bottom: 32rpx;
position: relative;
}
.stage-badge {
position: absolute;
top: 24rpx;
right: 24rpx;
background-color: #4ADE80;
color: #0D1F17;
padding: 8rpx 20rpx;
border-radius: 20rpx;
font-size: 24rpx;
font-weight: 600;
}
.stage-label {
font-size: 24rpx;
color: #4ADE80;
display: block;
margin-bottom: 8rpx;
}
.stage-name {
font-size: 44rpx;
font-weight: 700;
color: #FFFFFF;
display: block;
margin-bottom: 8rpx;
}
.stage-days {
font-size: 24rpx;
color: #9CA3AF;
display: block;
margin-bottom: 24rpx;
}
.stage-progress-row {
display: flex;
justify-content: space-between;
margin-bottom: 12rpx;
}
.stage-progress-label {
font-size: 24rpx;
color: #9CA3AF;
}
.stage-progress-value {
font-size: 24rpx;
font-weight: 600;
color: #4ADE80;
}
.stage-progress-bar {
height: 12rpx;
background-color: rgba(74, 222, 128, 0.2);
border-radius: 6rpx;
overflow: hidden;
}
.stage-progress-fill {
height: 100%;
background: linear-gradient(90deg, #4ADE80, #22C55E);
border-radius: 6rpx;
}
.section { margin-bottom: 32rpx; }
.section-header {
display: flex;
align-items: center;
gap: 12rpx;
margin-bottom: 16rpx;
}
.section-icon { font-size: 32rpx; }
.section-title {
font-size: 32rpx;
font-weight: 600;
color: #FFFFFF;
}
.section-badge {
margin-left: auto;
font-size: 24rpx;
color: #4ADE80;
background-color: rgba(74, 222, 128, 0.1);
padding: 8rpx 16rpx;
border-radius: 16rpx;
}
.ai-chat {
background-color: #1A3325;
border-radius: 24rpx;
padding: 32rpx;
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;
gap: 8rpx;
margin-bottom: 16rpx;
}
.ai-chat-name {
font-weight: 600;
color: #4ADE80;
}
.ai-chat-time {
font-size: 24rpx;
color: #6B7280;
}
.ai-chat-bubble {
background-color: #243D2E;
padding: 24rpx;
border-radius: 24rpx;
border-top-left-radius: 8rpx;
}
.ai-chat-text {
font-size: 28rpx;
line-height: 1.6;
color: #FFFFFF;
white-space: pre-wrap;
}
.goals-list {
display: flex;
flex-direction: column;
gap: 16rpx;
}
.goal-item {
display: flex;
align-items: center;
gap: 20rpx;
background-color: #1A3325;
border-radius: 24rpx;
padding: 28rpx;
}
.goal-check {
width: 48rpx;
height: 48rpx;
border-radius: 50%;
border: 4rpx solid #374151;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.goal-check-done {
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: #6B7280;
}
.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; }
</style>