feat(app): 项目重命名为干杯日记并优化UI设计
- 将应用名称从"喝了么"更改为"干杯日记" - 更新所有相关文件中的品牌标识和描述信息 - 升级HaveADrink依赖包从1.0.3到1.0.4版本 - 在pages.json中新增分享个人资料页面配置 - 重构DrinkCard组件UI,增加装饰背景、酒类图标支持、饮酒感受徽章等功能 - 优化API错误处理逻辑,增加静默模式支持 - 修改白酒类别图标为 urn emoji,黄酒图标为 tea emoji - 添加分享功能按钮并优化页面返回交互体验 - 引入新的工具函数用于获取酒类图标和路径判断 - 更新主题混入、常量定义等基础配置文件 - 调整全局样式和设计令牌以匹配新品牌形象
This commit is contained in:
@@ -0,0 +1,492 @@
|
||||
<template>
|
||||
<view :class="themeClass" class="page-container share-page">
|
||||
<!-- 氛围背景 -->
|
||||
<view class="ambient">
|
||||
<view class="glow glow-1"></view>
|
||||
<view class="glow glow-2"></view>
|
||||
</view>
|
||||
|
||||
<!-- 酒桌名片 -->
|
||||
<view class="biz-card">
|
||||
<!-- 品牌条 -->
|
||||
<view class="card-brand">
|
||||
<text class="brand-mark">🍻 干杯日记</text>
|
||||
<text class="brand-label">饮 酒 名 片</text>
|
||||
</view>
|
||||
|
||||
<!-- 身份区 -->
|
||||
<view class="identity">
|
||||
<view class="id-avatar-wrap">
|
||||
<image
|
||||
v-if="info.avatar && !avatarError"
|
||||
class="id-avatar"
|
||||
:src="info.avatar"
|
||||
mode="aspectFill"
|
||||
@error="avatarError = true"
|
||||
></image>
|
||||
<view v-else class="id-avatar id-avatar-fallback">
|
||||
<text class="id-avatar-emoji">🥃</text>
|
||||
</view>
|
||||
</view>
|
||||
<text class="id-name">{{ info.nick }}</text>
|
||||
<text class="id-slogan">这是我的饮酒档案,来交个酒友吧</text>
|
||||
</view>
|
||||
|
||||
<!-- 票券撕边分割线 -->
|
||||
<view class="perf-divider">
|
||||
<view class="perf-hole perf-hole-l"></view>
|
||||
<view class="perf-line"></view>
|
||||
<view class="perf-hole perf-hole-r"></view>
|
||||
</view>
|
||||
|
||||
<!-- 数据存根 -->
|
||||
<view class="stats-stub">
|
||||
<view class="stub-item">
|
||||
<text class="stub-num text-num">{{ anim.days }}</text>
|
||||
<text class="stub-label">打卡天数</text>
|
||||
</view>
|
||||
<view class="stub-sep"></view>
|
||||
<view class="stub-item">
|
||||
<text class="stub-num text-num">{{ anim.records }}</text>
|
||||
<text class="stub-label">饮酒次数</text>
|
||||
</view>
|
||||
<view class="stub-sep"></view>
|
||||
<view class="stub-item">
|
||||
<text class="stub-num stub-num-amber text-num">{{ anim.cups }}</text>
|
||||
<text class="stub-label">标准杯</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 连续记录 + 最爱酒类 -->
|
||||
<view class="extra-row">
|
||||
<view class="extra-chip">
|
||||
<text class="extra-chip-emoji">{{ info.streakType === 'drank' ? '🔥' : '💪' }}</text>
|
||||
<text class="extra-chip-text">{{ info.streakType === 'drank' ? '连续饮酒' : '连续戒酒' }} {{ info.streak }} 天</text>
|
||||
</view>
|
||||
<view v-if="favName" class="extra-chip">
|
||||
<text class="extra-chip-emoji">{{ favEmoji }}</text>
|
||||
<text class="extra-chip-text">最爱{{ favName }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- CTA -->
|
||||
<button class="cta-btn" @click="enterApp">
|
||||
<text class="cta-text">我也想记 · 打开干杯日记</text>
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<text class="page-footer">让每一杯酒都有迹可循</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import themeMixin from '../../common/theme-mixin'
|
||||
import { DRINK_CATEGORIES } from '../../common/constants'
|
||||
|
||||
export default {
|
||||
mixins: [themeMixin],
|
||||
data() {
|
||||
return {
|
||||
info: {
|
||||
nick: '酒友',
|
||||
avatar: '',
|
||||
days: 0,
|
||||
records: 0,
|
||||
cups: 0,
|
||||
streak: 0,
|
||||
streakType: 'drank',
|
||||
fav: ''
|
||||
},
|
||||
anim: { days: 0, records: 0, cups: 0 },
|
||||
avatarError: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
favCat() {
|
||||
return DRINK_CATEGORIES.find(c => c.id === this.info.fav) || null
|
||||
},
|
||||
favName() {
|
||||
return this.favCat ? this.favCat.name : ''
|
||||
},
|
||||
favEmoji() {
|
||||
return this.favCat ? this.favCat.emoji : '🍶'
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
this.parseOptions(options)
|
||||
},
|
||||
onReady() {
|
||||
this.animateStats()
|
||||
},
|
||||
// 好友可继续转发这张名片(病毒式传播,数据保持原始分享者)
|
||||
onShareAppMessage() {
|
||||
return {
|
||||
title: `${this.info.nick}的饮酒名片 - 干杯日记`,
|
||||
path: `/pages/share-profile/share-profile?${this.buildQuery()}`
|
||||
}
|
||||
},
|
||||
onShareTimeline() {
|
||||
return {
|
||||
title: `${this.info.nick}的饮酒名片 - 干杯日记`,
|
||||
query: this.buildQuery()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
parseOptions(options) {
|
||||
if (!options) return
|
||||
try {
|
||||
if (options.nick) this.info.nick = decodeURIComponent(options.nick)
|
||||
if (options.avatar) this.info.avatar = decodeURIComponent(options.avatar)
|
||||
this.info.days = parseInt(options.days) || 0
|
||||
this.info.records = parseInt(options.records) || 0
|
||||
this.info.cups = parseFloat(options.cups) || 0
|
||||
this.info.streak = parseInt(options.streak) || 0
|
||||
if (options.st) this.info.streakType = options.st === 'drank' ? 'drank' : 'abstain'
|
||||
if (options.fav) this.info.fav = String(options.fav)
|
||||
} catch (e) {
|
||||
console.warn('名片参数解析失败:', e)
|
||||
}
|
||||
},
|
||||
buildQuery() {
|
||||
const parts = [`nick=${encodeURIComponent(this.info.nick)}`]
|
||||
if (this.info.avatar) parts.push(`avatar=${encodeURIComponent(this.info.avatar)}`)
|
||||
parts.push(`days=${this.info.days}`)
|
||||
parts.push(`records=${this.info.records}`)
|
||||
parts.push(`cups=${this.info.cups}`)
|
||||
parts.push(`streak=${this.info.streak}`)
|
||||
parts.push(`st=${this.info.streakType}`)
|
||||
if (this.info.fav) parts.push(`fav=${this.info.fav}`)
|
||||
return parts.join('&')
|
||||
},
|
||||
// 数字滚动动画
|
||||
animateStats() {
|
||||
const t = { days: this.info.days, records: this.info.records, cups: this.info.cups }
|
||||
const hasDecimal = t.cups % 1 !== 0
|
||||
const duration = 900
|
||||
const start = Date.now()
|
||||
const timer = setInterval(() => {
|
||||
const p = Math.min((Date.now() - start) / duration, 1)
|
||||
const ease = 1 - Math.pow(1 - p, 3)
|
||||
this.anim.days = Math.round(t.days * ease)
|
||||
this.anim.records = Math.round(t.records * ease)
|
||||
this.anim.cups = hasDecimal
|
||||
? Math.round(t.cups * ease * 10) / 10
|
||||
: Math.round(t.cups * ease)
|
||||
if (p >= 1) clearInterval(timer)
|
||||
}, 16)
|
||||
},
|
||||
enterApp() {
|
||||
const isLoggedIn = uni.getStorageSync('is_logged_in')
|
||||
if (isLoggedIn === 'true') {
|
||||
uni.switchTab({ url: '/pages/index/index' })
|
||||
} else {
|
||||
uni.reLaunch({ url: '/pages/login/login' })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.share-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: $sp-xl;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 氛围光 */
|
||||
.ambient {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.glow {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
filter: blur(60rpx);
|
||||
}
|
||||
|
||||
.glow-1 {
|
||||
width: 480rpx;
|
||||
height: 480rpx;
|
||||
top: -120rpx;
|
||||
right: -100rpx;
|
||||
background: radial-gradient(circle, rgba(232,168,56,0.16) 0%, transparent 70%);
|
||||
animation: glow-drift 6s ease-in-out infinite alternate;
|
||||
}
|
||||
|
||||
.glow-2 {
|
||||
width: 400rpx;
|
||||
height: 400rpx;
|
||||
bottom: -80rpx;
|
||||
left: -120rpx;
|
||||
background: radial-gradient(circle, rgba(139,133,184,0.12) 0%, transparent 70%);
|
||||
animation: glow-drift 7s ease-in-out infinite alternate-reverse;
|
||||
}
|
||||
|
||||
@keyframes glow-drift {
|
||||
from { transform: translate(0, 0) scale(1); }
|
||||
to { transform: translate(30rpx, 40rpx) scale(1.12); }
|
||||
}
|
||||
|
||||
/* 名片主体 */
|
||||
.biz-card {
|
||||
width: 100%;
|
||||
max-width: 620rpx;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
background: linear-gradient(165deg, var(--card-gradient-start, #1A1510) 0%, var(--card-gradient-end, #0D0B08) 100%);
|
||||
border: 1rpx solid rgba(232,168,56,0.28);
|
||||
border-radius: $radius-xl;
|
||||
padding: $sp-xl $sp-xl $sp-2xl;
|
||||
box-shadow: $shadow-amber;
|
||||
overflow: hidden;
|
||||
animation: card-in 0.6s $ease-out both;
|
||||
}
|
||||
|
||||
@keyframes card-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(60rpx) scale(0.96);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* 品牌条 */
|
||||
.card-brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: $sp-xl;
|
||||
}
|
||||
|
||||
.brand-mark {
|
||||
font-size: $fs-sm;
|
||||
color: $text-secondary;
|
||||
font-weight: $fw-medium;
|
||||
}
|
||||
|
||||
.brand-label {
|
||||
font-size: $fs-xs;
|
||||
color: $amber;
|
||||
letter-spacing: 4rpx;
|
||||
font-weight: $fw-medium;
|
||||
padding: 6rpx 16rpx;
|
||||
border: 1rpx solid rgba(232,168,56,0.35);
|
||||
border-radius: $radius-full;
|
||||
}
|
||||
|
||||
/* 身份区 */
|
||||
.identity {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: $sp-md 0 $sp-xl;
|
||||
}
|
||||
|
||||
.id-avatar-wrap {
|
||||
position: relative;
|
||||
margin-bottom: $sp-lg;
|
||||
}
|
||||
|
||||
.id-avatar-wrap::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -16rpx;
|
||||
left: -16rpx;
|
||||
right: -16rpx;
|
||||
bottom: -16rpx;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(circle, rgba(232,168,56,0.22) 0%, transparent 70%);
|
||||
filter: blur(12rpx);
|
||||
}
|
||||
|
||||
.id-avatar {
|
||||
width: 168rpx;
|
||||
height: 168rpx;
|
||||
border-radius: 50%;
|
||||
border: 4rpx solid $amber;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.id-avatar-fallback {
|
||||
background: $bg-elevated;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.id-avatar-emoji {
|
||||
font-size: 84rpx;
|
||||
}
|
||||
|
||||
.id-name {
|
||||
font-size: $fs-2xl;
|
||||
font-weight: $fw-black;
|
||||
color: $text-primary;
|
||||
margin-bottom: $sp-sm;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.id-slogan {
|
||||
font-size: $fs-sm;
|
||||
color: $text-tertiary;
|
||||
}
|
||||
|
||||
/* 票券撕边 */
|
||||
.perf-divider {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0 (-$sp-xl);
|
||||
padding: 0 $sp-md;
|
||||
}
|
||||
|
||||
.perf-line {
|
||||
flex: 1;
|
||||
border-top: 2rpx dashed rgba(232,168,56,0.3);
|
||||
}
|
||||
|
||||
.perf-hole {
|
||||
position: absolute;
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
border-radius: 50%;
|
||||
background: $bg-base;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.perf-hole-l {
|
||||
left: -22rpx;
|
||||
}
|
||||
|
||||
.perf-hole-r {
|
||||
right: -22rpx;
|
||||
}
|
||||
|
||||
/* 数据存根 */
|
||||
.stats-stub {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: $sp-xl $sp-md;
|
||||
}
|
||||
|
||||
.stub-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: $sp-xs;
|
||||
}
|
||||
|
||||
.stub-num {
|
||||
font-size: $fs-3xl;
|
||||
font-weight: $fw-black;
|
||||
color: $text-primary;
|
||||
line-height: $lh-tight;
|
||||
}
|
||||
|
||||
.stub-num-amber {
|
||||
color: $amber;
|
||||
}
|
||||
|
||||
.stub-label {
|
||||
font-size: $fs-xs;
|
||||
color: $text-tertiary;
|
||||
letter-spacing: 2rpx;
|
||||
}
|
||||
|
||||
.stub-sep {
|
||||
width: 1rpx;
|
||||
height: 56rpx;
|
||||
background: rgba(232,168,56,0.2);
|
||||
}
|
||||
|
||||
/* 标签行 */
|
||||
.extra-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: $sp-md;
|
||||
padding: 0 $sp-md $sp-xl;
|
||||
}
|
||||
|
||||
.extra-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: $sp-xs;
|
||||
padding: $sp-sm $sp-lg;
|
||||
background: rgba(232,168,56,0.1);
|
||||
border: 1rpx solid rgba(232,168,56,0.22);
|
||||
border-radius: $radius-full;
|
||||
}
|
||||
|
||||
.extra-chip-emoji {
|
||||
font-size: $fs-base;
|
||||
}
|
||||
|
||||
.extra-chip-text {
|
||||
font-size: $fs-sm;
|
||||
color: $text-secondary;
|
||||
}
|
||||
|
||||
/* CTA */
|
||||
.cta-btn {
|
||||
margin: 0 $sp-md;
|
||||
background: linear-gradient(135deg, $amber-light, $amber, $amber-deep);
|
||||
border-radius: $radius-full;
|
||||
padding: $sp-md 0;
|
||||
border: none;
|
||||
line-height: 1.4;
|
||||
animation: cta-glow 2.4s ease-in-out infinite;
|
||||
|
||||
&::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: scale(0.97);
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes cta-glow {
|
||||
0%, 100% { box-shadow: 0 8rpx 28rpx rgba(232,168,56,0.28); }
|
||||
50% { box-shadow: 0 8rpx 44rpx rgba(232,168,56,0.5); }
|
||||
}
|
||||
|
||||
.cta-text {
|
||||
font-size: $fs-lg;
|
||||
font-weight: $fw-bold;
|
||||
color: $text-on-amber;
|
||||
}
|
||||
|
||||
/* 底部 */
|
||||
.page-footer {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
margin-top: $sp-2xl;
|
||||
font-size: $fs-xs;
|
||||
color: $text-tertiary;
|
||||
letter-spacing: 4rpx;
|
||||
animation: card-in 0.6s $ease-out 0.15s both;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user