feat(app): 项目重命名为干杯日记并优化UI设计
- 将应用名称从"喝了么"更改为"干杯日记" - 更新所有相关文件中的品牌标识和描述信息 - 升级HaveADrink依赖包从1.0.3到1.0.4版本 - 在pages.json中新增分享个人资料页面配置 - 重构DrinkCard组件UI,增加装饰背景、酒类图标支持、饮酒感受徽章等功能 - 优化API错误处理逻辑,增加静默模式支持 - 修改白酒类别图标为 urn emoji,黄酒图标为 tea emoji - 添加分享功能按钮并优化页面返回交互体验 - 引入新的工具函数用于获取酒类图标和路径判断 - 更新主题混入、常量定义等基础配置文件 - 调整全局样式和设计令牌以匹配新品牌形象
This commit is contained in:
+177
-40
@@ -91,24 +91,37 @@
|
||||
<view v-if="selectedRecord.mode === 'drank'" class="day-record-info">
|
||||
<view class="day-drinks">
|
||||
<view v-for="(drink, i) in selectedRecord.drinks" :key="i" class="day-drink-item">
|
||||
<text>{{ getCatEmoji(drink.category) }} {{ drink.brand }} {{ drink.product }}</text>
|
||||
<view class="day-drink-row">
|
||||
<view class="day-drink-name">
|
||||
<image v-if="isIconPath(getCatIcon(drink.category))" :src="getCatIcon(drink.category)" class="day-drink-icon" mode="aspectFit"></image>
|
||||
<text v-else>{{ getCatEmoji(drink.category) }}</text>
|
||||
<text>{{ drink.brand }} {{ drink.product }}</text>
|
||||
</view>
|
||||
<text v-if="drink.customAmount != null" class="day-drink-amount text-num">{{ drink.customAmount }}{{ getUnitLabel(drink.customUnit) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="day-meta flex-between">
|
||||
<text class="text-caption">{{ getFeelingName(selectedRecord.feeling) }}</text>
|
||||
<text class="text-caption text-amber text-num">{{ selectedRecord.standardCupsTotal }} 标准杯</text>
|
||||
</view>
|
||||
<button class="btn-ghost day-toggle-btn" @click="toggleToAbstain">改为未饮酒</button>
|
||||
<view class="day-action-row">
|
||||
<button class="btn-ghost day-action-btn" @click="editRecord">修改</button>
|
||||
<button class="btn-ghost day-action-btn" @click="toggleToAbstain">改为未饮酒</button>
|
||||
</view>
|
||||
<button class="btn-danger day-delete-btn" @click="deleteRecord">删除记录</button>
|
||||
</view>
|
||||
<view v-else class="day-abstain">
|
||||
<text class="day-abstain-emoji">🚫</text>
|
||||
<text class="text-caption">今日未饮酒,好样的</text>
|
||||
<button class="btn-ghost day-toggle-btn" @click="toggleToDrank">改为饮酒</button>
|
||||
<button class="btn-danger day-delete-btn" @click="deleteRecord">删除记录</button>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="day-empty">
|
||||
<text class="text-caption">当天无记录</text>
|
||||
<button class="btn-ghost" @click="backfillDate">补打卡</button>
|
||||
<button v-if="isSelectedToday" class="btn-primary day-record-btn" @click="goRecordToday">去记录</button>
|
||||
<button v-else class="btn-ghost" @click="backfillDate">补打卡</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -118,9 +131,9 @@
|
||||
<script>
|
||||
import DrinkCalendar from '../../components/DrinkCalendar.vue'
|
||||
import client from '../../common/api'
|
||||
import { GetCalendarReq } from 'HaveADrink'
|
||||
import { getGreeting, formatDate, getWeekStart } from '../../common/utils'
|
||||
import { FEELINGS, DRINK_CATEGORIES } from '../../common/constants'
|
||||
import { GetCalendarReq, DeleteRecordReq, CreateRecordReq, GetRecordDetailReq } from 'HaveADrink'
|
||||
import { getGreeting, formatDate, getWeekStart, getCatIcon, isIconPath } from '../../common/utils'
|
||||
import { FEELINGS, DRINK_CATEGORIES, DRINK_UNITS } from '../../common/constants'
|
||||
import themeMixin from '../../common/theme-mixin'
|
||||
|
||||
export default {
|
||||
@@ -152,6 +165,9 @@ export default {
|
||||
healthPercent() {
|
||||
// 建议每周不超过14标准杯
|
||||
return Math.min((this.stats.weekCups / 14) * 100, 100)
|
||||
},
|
||||
isSelectedToday() {
|
||||
return this.selectedDate === formatDate(new Date(), 'YYYY-MM-DD')
|
||||
}
|
||||
},
|
||||
onShow() {
|
||||
@@ -163,6 +179,18 @@ export default {
|
||||
}
|
||||
this.loadData()
|
||||
},
|
||||
onShareAppMessage() {
|
||||
return {
|
||||
title: '干杯日记 - 让每一杯酒都有迹可循',
|
||||
path: '/pages/index/index'
|
||||
}
|
||||
},
|
||||
onShareTimeline() {
|
||||
return {
|
||||
title: '干杯日记 - 让每一杯酒都有迹可循',
|
||||
query: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async loadData() {
|
||||
this.greeting = getGreeting()
|
||||
@@ -178,15 +206,8 @@ export default {
|
||||
if (userResp.status === 'fulfilled' && userResp.value) {
|
||||
const user = userResp.value
|
||||
this.userName = user.nickname || '酒友'
|
||||
uni.setStorageSync('user_info', JSON.stringify(user))
|
||||
} else {
|
||||
// 降级读取本地缓存
|
||||
try {
|
||||
const cached = JSON.parse(uni.getStorageSync('user_info') || '{}')
|
||||
this.userName = cached.nickname || '酒友'
|
||||
} catch (e) {
|
||||
this.userName = '酒友'
|
||||
}
|
||||
this.userName = '酒友'
|
||||
}
|
||||
|
||||
// 统计概览
|
||||
@@ -218,7 +239,9 @@ export default {
|
||||
standardCupsTotal: d.standardCupsTotal || 0,
|
||||
drinks: (d.drinks || []).map(dr => ({
|
||||
...dr,
|
||||
category: String(dr.category)
|
||||
category: String(dr.category),
|
||||
customAmount: dr.customAmount,
|
||||
customUnit: dr.customUnit ? String(dr.customUnit) : ''
|
||||
})),
|
||||
food: d.food ? { category: String(d.food.category), name: d.food.name || '' } : null,
|
||||
feeling: d.feeling ? String(d.feeling) : null,
|
||||
@@ -228,13 +251,7 @@ export default {
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('加载首页数据失败:', e)
|
||||
// 降级:读取本地缓存
|
||||
try {
|
||||
const cached = JSON.parse(uni.getStorageSync('user_info') || '{}')
|
||||
this.userName = cached.nickname || '酒友'
|
||||
} catch (err) {
|
||||
this.userName = '酒友'
|
||||
}
|
||||
this.userName = '酒友'
|
||||
}
|
||||
},
|
||||
onMonthChange({ year, month }) {
|
||||
@@ -255,7 +272,9 @@ export default {
|
||||
standardCupsTotal: d.standardCupsTotal || 0,
|
||||
drinks: (d.drinks || []).map(dr => ({
|
||||
...dr,
|
||||
category: String(dr.category)
|
||||
category: String(dr.category),
|
||||
customAmount: dr.customAmount,
|
||||
customUnit: dr.customUnit ? String(dr.customUnit) : ''
|
||||
})),
|
||||
food: d.food ? { category: String(d.food.category), name: d.food.name || '' } : null,
|
||||
feeling: d.feeling ? String(d.feeling) : null,
|
||||
@@ -266,10 +285,37 @@ export default {
|
||||
console.warn('加载月度记录失败:', e)
|
||||
}
|
||||
},
|
||||
onDateSelect(dateStr) {
|
||||
async onDateSelect(dateStr) {
|
||||
this.selectedDate = dateStr
|
||||
this.selectedRecord = this.records.find(r => r.date === dateStr) || null
|
||||
this.showDayDetail = true
|
||||
const localRecord = this.records.find(r => r.date === dateStr) || null
|
||||
// 如果有记录且有id,拉取完整详情(确保拿到 customAmount/customUnit 等全量字段)
|
||||
if (localRecord && localRecord.id && localRecord.mode === 'drank') {
|
||||
this.selectedRecord = localRecord // 先用本地数据展示
|
||||
this.showDayDetail = true
|
||||
try {
|
||||
const resp = await client.GetRecordDetail(new GetRecordDetailReq(localRecord.id))
|
||||
const rec = resp.data || resp
|
||||
if (rec) {
|
||||
this.selectedRecord = {
|
||||
...localRecord,
|
||||
...rec,
|
||||
mode: String(rec.mode || localRecord.mode),
|
||||
drinks: (rec.drinks || localRecord.drinks || []).map(d => ({
|
||||
...d,
|
||||
category: String(d.category),
|
||||
customUnit: d.customUnit ? String(d.customUnit) : ''
|
||||
})),
|
||||
feeling: rec.feeling ? String(rec.feeling) : localRecord.feeling,
|
||||
visibility: rec.visibility ? String(rec.visibility) : localRecord.visibility
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('获取记录详情失败,使用本地数据:', e)
|
||||
}
|
||||
} else {
|
||||
this.selectedRecord = localRecord
|
||||
this.showDayDetail = true
|
||||
}
|
||||
},
|
||||
getFeelingName(feelingId) {
|
||||
const f = FEELINGS.find(f => f.id === feelingId)
|
||||
@@ -279,28 +325,45 @@ export default {
|
||||
const cat = DRINK_CATEGORIES.find(c => c.id === catId)
|
||||
return cat ? cat.emoji : '🥃'
|
||||
},
|
||||
getCatIcon,
|
||||
isIconPath,
|
||||
getUnitLabel(unitId) {
|
||||
if (!unitId) return ''
|
||||
const u = DRINK_UNITS.find(u => u.id === unitId)
|
||||
return u ? u.name : unitId
|
||||
},
|
||||
backfillDate() {
|
||||
this.showDayDetail = false
|
||||
uni.navigateTo({
|
||||
url: `/pages/record/record?date=${this.selectedDate}&mode=backfill`
|
||||
})
|
||||
},
|
||||
// 修改记录(跳转到记录页编辑)
|
||||
editRecord() {
|
||||
this.showDayDetail = false
|
||||
uni.navigateTo({
|
||||
url: `/pages/record/record?date=${this.selectedDate}&mode=edit`
|
||||
})
|
||||
},
|
||||
// 改为未饮酒
|
||||
toggleToAbstain() {
|
||||
uni.showModal({
|
||||
title: '确认修改',
|
||||
content: '确定将这天改为未饮酒吗?饮酒记录将被清除。',
|
||||
success: (res) => {
|
||||
success: async (res) => {
|
||||
if (!res.confirm) return
|
||||
const idx = this.records.findIndex(r => r.date === this.selectedDate)
|
||||
if (idx === -1) return
|
||||
this.records[idx].mode = 'abstain'
|
||||
this.records[idx].drinks = []
|
||||
this.records[idx].food = null
|
||||
this.records[idx].feeling = null
|
||||
this.records[idx].standardCupsTotal = 0
|
||||
this.selectedRecord = this.records[idx]
|
||||
this.saveRecords()
|
||||
const recordId = this.selectedRecord && this.selectedRecord.id
|
||||
try {
|
||||
if (recordId) {
|
||||
await client.DeleteRecord(new DeleteRecordReq(recordId))
|
||||
}
|
||||
uni.showToast({ title: '已修改', icon: 'success' })
|
||||
this.showDayDetail = false
|
||||
this.loadData()
|
||||
} catch (e) {
|
||||
console.warn('修改为未饮酒失败:', e)
|
||||
uni.showToast({ title: '修改失败,请重试', icon: 'none' })
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -311,13 +374,37 @@ export default {
|
||||
url: `/pages/record/record?date=${this.selectedDate}&mode=backfill`
|
||||
})
|
||||
},
|
||||
// 保存记录到本地存储
|
||||
saveRecords() {
|
||||
uni.setStorageSync('drink_records', JSON.stringify(this.records))
|
||||
// 删除记录
|
||||
deleteRecord() {
|
||||
uni.showModal({
|
||||
title: '确认删除',
|
||||
content: `确定删除 ${this.selectedDate} 的记录吗?删除后不可恢复。`,
|
||||
confirmColor: '#e85d3a',
|
||||
success: async (res) => {
|
||||
if (!res.confirm) return
|
||||
const recordId = this.selectedRecord && this.selectedRecord.id
|
||||
try {
|
||||
if (recordId) {
|
||||
await client.DeleteRecord(new DeleteRecordReq(recordId))
|
||||
}
|
||||
this.showDayDetail = false
|
||||
uni.showToast({ title: '已删除', icon: 'success' })
|
||||
// 重新加载统计和日历数据
|
||||
this.loadData()
|
||||
} catch (e) {
|
||||
console.warn('删除记录失败:', e)
|
||||
uni.showToast({ title: '删除失败,请重试', icon: 'none' })
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
goRecord() {
|
||||
uni.navigateTo({ url: '/pages/record/record' })
|
||||
},
|
||||
goRecordToday() {
|
||||
this.showDayDetail = false
|
||||
uni.navigateTo({ url: '/pages/record/record' })
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
@@ -555,6 +642,33 @@ export default {
|
||||
border-bottom: 2rpx solid var(--border-micro, rgba(255, 255, 255, 0.05));
|
||||
}
|
||||
|
||||
.day-drink-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.day-drink-name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $sp-xs;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.day-drink-icon {
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.day-drink-amount {
|
||||
font-size: $fs-sm;
|
||||
color: $text-secondary;
|
||||
white-space: nowrap;
|
||||
margin-left: $sp-sm;
|
||||
}
|
||||
|
||||
.day-meta {
|
||||
margin-top: $sp-lg;
|
||||
}
|
||||
@@ -574,11 +688,34 @@ export default {
|
||||
text-align: center;
|
||||
padding: $sp-xl 0;
|
||||
|
||||
.btn-ghost {
|
||||
.btn-ghost, .day-record-btn {
|
||||
margin-top: $sp-lg;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.day-action-row {
|
||||
display: flex;
|
||||
gap: $sp-sm;
|
||||
margin-top: $sp-lg;
|
||||
}
|
||||
|
||||
.day-action-btn {
|
||||
flex: 1;
|
||||
font-size: $fs-sm;
|
||||
color: $text-secondary;
|
||||
border-color: var(--border-active, rgba(255, 255, 255, 0.12));
|
||||
}
|
||||
|
||||
.day-delete-btn {
|
||||
margin-top: $sp-md;
|
||||
width: 100%;
|
||||
font-size: $fs-sm;
|
||||
color: #e85d3a;
|
||||
background: rgba(232, 93, 58, 0.08);
|
||||
border: 2rpx solid rgba(232, 93, 58, 0.2);
|
||||
}
|
||||
|
||||
.day-toggle-btn {
|
||||
margin-top: $sp-lg;
|
||||
width: 100%;
|
||||
|
||||
Reference in New Issue
Block a user