feat: 完成项目基础功能搭建与样式优化
1. 新增评估选择组件、本地草稿存储与新闻/金融内容服务 2. 重构页面布局与样式:调整按钮阴影、图标尺寸、导航栏样式 3. 更新启动页、报告页、消息中心等页面UI与交互逻辑 4. 替换图标资源,调整禁用态透明度 5. 补充README文档与本地数据模拟实现
This commit is contained in:
+114
-37
@@ -1,12 +1,31 @@
|
||||
<template>
|
||||
<view class="page" :style="pageStyle()">
|
||||
<AppHeader title="积分中心" />
|
||||
<scroll-view scroll-y class="points-scroll" :style="contentStyle(96, false)">
|
||||
<scroll-view scroll-y :style="contentStyle(96, false)">
|
||||
<view class="points-content">
|
||||
<view class="points-hero"><text class="points-label">我的积分</text><text class="points-number">2680</text><button @click="showRules" class="points-hero-button">积分规则</button><view class="points-shine"></view></view>
|
||||
<view class="task-grid"><view class="task" v-for="item in tasks" :key="item.name" @click="doTask(item.name)"><view class="task-icon"><AppIcon :name="item.icon" :size="42" /></view><text class="task-name">{{ item.name }}</text><text class="task-score">+{{ item.score }}</text></view></view>
|
||||
<view class="invite-panel"><text class="section-title">邀请有礼</text><text class="invite-copy">每邀请1位好友,双方都可获得积分</text><view class="invite-code"><text>我的邀请码</text><text class="code">AI2680</text><text class="copy" @click="copyCode">复制</text></view><button class="primary-button invite-button" @click="invite">立即邀请</button></view>
|
||||
<view class="records"><view class="record-head"><text class="section-title">积分明细</text><text class="more">全部 ›</text></view><view class="record" v-for="item in records" :key="item.name"><view><text class="record-name">{{ item.name }}</text><text class="record-date">{{ item.date }}</text></view><text class="record-score">+{{ item.score }}</text></view></view>
|
||||
<view class="points-hero">
|
||||
<view class="points-hero-top"><text class="points-label">我的体验积分</text><button @click="showRules" class="points-hero-button">积分规则</button></view>
|
||||
<text class="points-number">{{ totalPoints }}</text><text class="points-note">本地体验 · 仅在本机记录</text>
|
||||
</view>
|
||||
<view class="task-grid">
|
||||
<view class="task" v-for="item in tasks" :key="item.id" @click="doTask(item.id)">
|
||||
<AppIcon :name="item.icon" :size="52" />
|
||||
<text class="task-name">{{ item.id == 'checkin' && signedToday ? '已签到' : item.name }}</text>
|
||||
<text :class="item.id == 'checkin' && signedToday ? 'task-caption completed-caption' : 'task-caption'">{{ item.id == 'checkin' && signedToday ? '明天再来' : item.caption }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="invite-panel">
|
||||
<text class="panel-title">与好友一起了解融资</text><text class="invite-copy">分享实用知识,提前做好申请准备。</text>
|
||||
<view class="invite-code"><text class="code-label">体验邀请码</text><text class="code">AI2680</text><view class="copy-action" @click="copyCode"><text class="copy-text">复制</text></view></view>
|
||||
<button class="primary-button invite-button" @click="invite">复制邀请文案</button><text class="invite-note">当前为本地体验,复制或分享不会发放积分。</text>
|
||||
</view>
|
||||
<view class="records">
|
||||
<view class="record-head" @click="recordsExpanded = !recordsExpanded"><text class="panel-title">积分明细</text><view class="record-toggle"><text class="more">{{ recordsExpanded ? '收起' : '展开' }}</text><AppIcon name="chevron-right" :size="26" :class="recordsExpanded ? 'record-arrow expanded-arrow' : 'record-arrow'" muted /></view></view>
|
||||
<view v-if="recordsExpanded">
|
||||
<view v-if="records.length == 0" class="empty-records"><text class="empty-record-title">还没有积分记录</text><text class="empty-record-copy">完成今日签到,获得 10 体验积分。</text></view>
|
||||
<view class="record" v-for="(item, index) in records" :key="item.date" :class="index == records.length - 1 ? 'last-record' : ''"><view class="record-copy"><text class="record-name">每日签到</text><text class="record-date">{{ item.date }} · 本地体验</text></view><text class="record-score">+{{ item.score }}</text></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
@@ -14,42 +33,100 @@
|
||||
|
||||
<script setup lang="uts">
|
||||
import { usePageLayout } from '@/services/layout.uts'
|
||||
const { contentStyle, pageStyle } = usePageLayout()
|
||||
import AppHeader from '@/components/AppHeader.uvue'
|
||||
import AppIcon from '@/components/AppIcon.uvue'
|
||||
type PointsTask = { icon: string, name: string, score: number }
|
||||
const tasks: PointsTask[] = [{ icon: 'calendar-check', name: '签到', score: 10 }, { icon: 'share', name: '分享', score: 20 }, { icon: 'edit-file', name: '完善任务', score: 50 }, { icon: 'gift', name: '邀请好友', score: 100 }]
|
||||
type PointsRecord = { name: string, date: string, score: number }
|
||||
const records: PointsRecord[] = [{ name: '每日签到', date: '今天 09:20', score: 10 }, { name: '完成融资评估', date: '昨天 18:36', score: 50 }, { name: '邀请好友', date: '09-02 14:20', score: 100 }]
|
||||
const showRules = () => { uni.showModal({ title: '积分规则', content: '签到、评估、分享和邀请好友均可获得积分。', showCancel: false }) }
|
||||
const doTask = (name: string) => { uni.showToast({ title: name + '任务入口', icon: 'none' }) }
|
||||
const copyCode = () => { uni.setClipboardData({ data: 'AI2680' }) }
|
||||
const invite = () => { uni.showToast({ title: '分享入口已预留', icon: 'none' }) }
|
||||
const { contentStyle, pageStyle } = usePageLayout()
|
||||
type PointsTask = { id: string, icon: string, name: string, caption: string }
|
||||
type PointsRecord = { date: string, score: number }
|
||||
const tasks: PointsTask[] = [
|
||||
{ id: 'checkin', icon: 'calendar-check', name: '签到', caption: '每日 +10' },
|
||||
{ id: 'share', icon: 'share', name: '分享', caption: '复制文案' },
|
||||
{ id: 'profile', icon: 'edit-file', name: '完善资料', caption: '查看档案' },
|
||||
{ id: 'invite', icon: 'gift', name: '邀请好友', caption: '复制邀请' }
|
||||
]
|
||||
const signDays = ref<string[]>([])
|
||||
const today = ref('')
|
||||
const recordsExpanded = ref(true)
|
||||
const totalPoints = computed((): number => signDays.value.length * 10)
|
||||
const signedToday = computed((): boolean => signDays.value.includes(today.value))
|
||||
const records = computed((): PointsRecord[] => signDays.value.map((date: string): PointsRecord => ({ date, score: 10 })))
|
||||
const localDate = (): string => {
|
||||
const date = new Date()
|
||||
const month = date.getMonth() + 1
|
||||
const day = date.getDate()
|
||||
return date.getFullYear() + '-' + (month < 10 ? '0' : '') + month + '-' + (day < 10 ? '0' : '') + day
|
||||
}
|
||||
const restore = (): void => {
|
||||
today.value = localDate()
|
||||
const stored = uni.getStorageSync('finance.points.checkin.days')
|
||||
if (typeof stored != 'string' || stored == '') { signDays.value = []; return }
|
||||
const restored = (stored as string).split(',')
|
||||
const unique: string[] = []
|
||||
restored.forEach((day: string): void => { if (/^\d{4}-\d{2}-\d{2}$/.test(day) && !unique.includes(day)) unique.push(day) })
|
||||
signDays.value = unique
|
||||
}
|
||||
onShow(() => { restore() })
|
||||
const checkIn = (): void => {
|
||||
restore()
|
||||
if (signedToday.value) { uni.showToast({ title: '今天已签到,明天再来', icon: 'none' }); return }
|
||||
const next = signDays.value.slice()
|
||||
next.unshift(today.value)
|
||||
uni.setStorageSync('finance.points.checkin.days', next.join(','))
|
||||
signDays.value = next
|
||||
recordsExpanded.value = true
|
||||
uni.showToast({ title: '签到完成,体验积分 +10', icon: 'none' })
|
||||
}
|
||||
const showRules = (): void => {
|
||||
uni.showModal({ title: '体验积分规则', content: '当前积分仅供本地体验,不代表真实账户权益。每天可签到一次,每次增加 10 体验积分。分享、邀请和完善资料暂不发放积分;清除应用数据后,本地记录也会清除。', showCancel: false, confirmText: '知道了' })
|
||||
}
|
||||
const copyText = (value: string, message: string): void => {
|
||||
uni.setClipboardData({ data: value, success: () => { uni.showToast({ title: message, icon: 'none' }) }, fail: () => { uni.showToast({ title: '复制失败,请稍后重试', icon: 'none' }) } })
|
||||
}
|
||||
const copyCode = (): void => { copyText('AI2680', '体验邀请码已复制') }
|
||||
const invite = (): void => { copyText('邀请你一起了解 AI融资:学习融资知识,梳理申请资料,提前做好融资准备。体验邀请码:AI2680。', '邀请文案已复制,可自行分享') }
|
||||
const doTask = (id: string): void => {
|
||||
if (id == 'checkin') { checkIn(); return }
|
||||
if (id == 'profile') { uni.navigateTo({ url: '/pages/archive/archive' }); return }
|
||||
if (id == 'invite') { invite(); return }
|
||||
copyText('分享一个融资准备方法:先梳理信用、收入与负债,再比较适合自己的产品。可以在 AI融资的融资课堂中学习相关知识。', '分享文案已复制,可自行分享')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.points-scroll { }
|
||||
.points-content { padding: 26rpx 28rpx 70rpx; }
|
||||
.points-hero { height: 260rpx; padding: 36rpx; border-radius: 20rpx; color: white; background: linear-gradient(125deg, #5140e8, #9c56f6); overflow: hidden; position: relative; }
|
||||
.points-label { font-size: 24rpx; color: #e7e1ff; }
|
||||
.points-number { font-size: 72rpx; line-height: 90rpx; font-weight: 900; }
|
||||
.points-hero-button { position: absolute; right: 28rpx; top: 32rpx; width: 150rpx; height: 58rpx; line-height: 58rpx; padding: 0; margin: 0; border-radius: 29rpx; color: #6348de; background-color: #fff; font-size: 21rpx; }
|
||||
.points-shine { position: absolute; width: 260rpx; height: 260rpx; border-radius: 50%; background-color: rgba(255,255,255,.1); right: -60rpx; bottom: -110rpx; }
|
||||
.task-grid { height: 180rpx; flex-direction: row; background-color: #fff; border: 1rpx solid #e5ecf5; border-radius: 18rpx; margin-top: 22rpx; }
|
||||
.task { flex: 1; align-items: center; justify-content: center; }
|
||||
.task-icon { width: 56rpx; height: 56rpx; border-radius: 18rpx; color: #0868f7; background-color: #e9f2ff; align-items: center; justify-content: center; font-size: 22rpx; font-weight: 800; }
|
||||
.task-name { margin-top: 10rpx; font-size: 21rpx; color: #3d4b61; }
|
||||
.task-score { margin-top: 4rpx; font-size: 18rpx; color: #8e9aab; }
|
||||
.invite-panel, .records { margin-top: 24rpx; padding: 28rpx; border-radius: 18rpx; background-color: #fff; border: 1rpx solid #e5ecf5; }
|
||||
.invite-copy { margin-top: 12rpx; color: #7a8799; font-size: 22rpx; }
|
||||
.invite-code { height: 92rpx; padding: 0 22rpx; margin-top: 24rpx; background-color: #f3f6fa; border-radius: 13rpx; flex-direction: row; align-items: center; color: #788599; font-size: 22rpx; }
|
||||
.code { flex: 1; margin-left: 22rpx; color: #1b2940; font-size: 30rpx; font-weight: 800; }
|
||||
.copy { color: #0868f7; }
|
||||
.points-content { padding: 24rpx 28rpx 48rpx; }
|
||||
.points-hero { padding: 28rpx; border-radius: 20rpx; background-color: #5148d8; }
|
||||
.points-hero-top { flex-direction: row; align-items: center; justify-content: space-between; }
|
||||
.points-label { font-size: 26rpx; color: #f0efff; }
|
||||
.points-number { font-size: 74rpx; line-height: 94rpx; font-weight: 700; color: #ffffff; margin-top: 12rpx; }
|
||||
.points-note { color: #e5e1ff; font-size: 22rpx; line-height: 34rpx; margin-top: 4rpx; }
|
||||
.points-hero-button { width: 144rpx; height: 56rpx; line-height: 56rpx; padding: 0; margin: 0; border-radius: 28rpx; color: #5148d8; background-color: #ffffff; font-size: 23rpx; }
|
||||
.task-grid { min-height: 186rpx; flex-direction: row; background-color: #ffffff; border-radius: 18rpx; margin-top: 20rpx; }
|
||||
.task { flex: 1; align-items: center; justify-content: center; padding: 24rpx 0; }
|
||||
.task-name { margin-top: 14rpx; font-size: 24rpx; color: #172640; font-weight: 600; }
|
||||
.task-caption { margin-top: 7rpx; font-size: 22rpx; color: #66758a; }
|
||||
.completed-caption { color: #168454; }
|
||||
.invite-panel, .records { margin-top: 22rpx; padding: 24rpx; border-radius: 18rpx; background-color: #ffffff; }
|
||||
.panel-title { color: #172640; font-size: 30rpx; line-height: 42rpx; font-weight: 700; }
|
||||
.invite-copy { margin-top: 12rpx; color: #66758a; font-size: 25rpx; line-height: 38rpx; }
|
||||
.invite-code { min-height: 92rpx; padding: 12rpx 18rpx; margin-top: 22rpx; background-color: #f4f7fb; border-radius: 12rpx; flex-direction: row; align-items: center; }
|
||||
.code-label { color: #66758a; font-size: 23rpx; }
|
||||
.code { flex: 1; margin-left: 16rpx; color: #172640; font-size: 29rpx; font-weight: 700; }
|
||||
.copy-action { padding: 12rpx 0 12rpx 16rpx; }
|
||||
.copy-text { color: #0868f7; font-size: 24rpx; }
|
||||
.invite-button { margin-top: 22rpx; }
|
||||
.record-head { flex-direction: row; justify-content: space-between; align-items: center; }
|
||||
.more { color: #0868f7; font-size: 22rpx; }
|
||||
.record { min-height: 100rpx; flex-direction: row; justify-content: space-between; align-items: center; border-bottom: 1rpx solid #edf1f6; }
|
||||
.record-name { font-size: 24rpx; color: #29374d; }
|
||||
.record-date { color: #9ba6b6; font-size: 19rpx; margin-top: 8rpx; }
|
||||
.record-score { color: #0daa74; font-size: 27rpx; font-weight: 700; }
|
||||
.invite-note { color: #66758a; font-size: 22rpx; line-height: 34rpx; margin-top: 14rpx; }
|
||||
.record-head { flex-direction: row; justify-content: space-between; align-items: center; min-height: 52rpx; }
|
||||
.record-toggle { flex-direction: row; align-items: center; padding-left: 20rpx; }
|
||||
.more { color: #0868f7; font-size: 23rpx; margin-right: 6rpx; }
|
||||
.record-arrow { transform: rotate(90deg); }
|
||||
.expanded-arrow { transform: rotate(-90deg); }
|
||||
.record { min-height: 116rpx; padding: 18rpx 0; flex-direction: row; justify-content: space-between; align-items: center; border-bottom: 1rpx solid #edf1f6; }
|
||||
.last-record { border-bottom-width: 0; }
|
||||
.record-copy { flex: 1; }
|
||||
.record-name { font-size: 27rpx; color: #172640; }
|
||||
.record-date { color: #66758a; font-size: 22rpx; line-height: 34rpx; margin-top: 8rpx; }
|
||||
.record-score { color: #168454; font-size: 30rpx; font-weight: 700; margin-left: 16rpx; }
|
||||
.empty-records { padding: 28rpx 0 12rpx; }
|
||||
.empty-record-title { color: #66758a; font-size: 26rpx; }
|
||||
.empty-record-copy { color: #66758a; font-size: 23rpx; line-height: 36rpx; margin-top: 10rpx; }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user