fix: TransactionItem小头像+预算页双显+账单静默刷新
TransactionItem: - meta 区域改为 view+flex 布局,小头像作为独立元素渲染 - creator-tag 容器包裹头像+昵称,小程序端 image 不嵌套在 text 内 预算页: - 群组模式顶部显示概览行(群组预算 | 我的预算) - 下方显示「设置我的预算」卡片,编辑作用于个人预算 - 个人模式保持原样 账单页: - loadTx 添加 silent 参数,静默刷新时不清空列表 - onShow 调用 loadTx(true, true) 避免骨架屏闪烁
This commit is contained in:
@@ -17,12 +17,14 @@
|
|||||||
/>
|
/>
|
||||||
<view class="info">
|
<view class="info">
|
||||||
<text class="name">{{ item.note || item.category_name || '未分类' }}</text>
|
<text class="name">{{ item.note || item.category_name || '未分类' }}</text>
|
||||||
<text class="meta">
|
<view class="meta">
|
||||||
<image v-if="isOtherCreator && creatorAvatarUrl" :src="creatorAvatarUrl" class="creator-mini-avatar" mode="aspectFill" />
|
<view v-if="isOtherCreator" class="creator-tag">
|
||||||
<text v-else-if="isOtherCreator" class="creator-mini-initial">{{ item.creator_nickname?.[0] }}</text>
|
<image v-if="creatorAvatarUrl" :src="creatorAvatarUrl" class="creator-mini-avatar" mode="aspectFill" />
|
||||||
<text v-if="isOtherCreator" class="creator-name">{{ item.creator_nickname }} · </text>
|
<text v-else class="creator-mini-initial">{{ item.creator_nickname?.[0] }}</text>
|
||||||
{{ item.category_name || '未分类' }}{{ hideDate ? '' : ' · ' + formatDate(item.date) }}
|
<text class="creator-name">{{ item.creator_nickname }}</text>
|
||||||
</text>
|
</view>
|
||||||
|
<text>{{ (isOtherCreator ? ' · ' : '') + (item.category_name || '未分类') }}{{ hideDate ? '' : ' · ' + formatDate(item.date) }}</text>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<text class="amount" :class="item.type">{{ item.type === 'expense' ? '-' : '+' }}{{ formatAmount(item.amount) }}</text>
|
<text class="amount" :class="item.type">{{ item.type === 'expense' ? '-' : '+' }}{{ formatAmount(item.amount) }}</text>
|
||||||
</view>
|
</view>
|
||||||
@@ -148,16 +150,22 @@ function onTouchEnd() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.creator-tag {
|
||||||
|
margin-right: 4rpx;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
.creator-mini-avatar {
|
.creator-mini-avatar {
|
||||||
width: 28rpx;
|
width: 28rpx;
|
||||||
height: 28rpx;
|
height: 28rpx;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
vertical-align: middle;
|
|
||||||
margin-right: 4rpx;
|
margin-right: 4rpx;
|
||||||
|
position: relative;
|
||||||
|
top: 4rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.creator-mini-initial {
|
.creator-mini-initial {
|
||||||
display: inline-flex;
|
display: flex;
|
||||||
width: 28rpx;
|
width: 28rpx;
|
||||||
height: 28rpx;
|
height: 28rpx;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
@@ -166,8 +174,7 @@ function onTouchEnd() {
|
|||||||
color: #FF8C69;
|
color: #FF8C69;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
vertical-align: middle;
|
flex-shrink: 0;
|
||||||
margin-right: 4rpx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.info {
|
.info {
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ onMounted(async () => {
|
|||||||
|
|
||||||
// 静默刷新(切换群组/返回时)
|
// 静默刷新(切换群组/返回时)
|
||||||
onShow(() => {
|
onShow(() => {
|
||||||
if (initialLoaded.value) loadTx(true)
|
if (initialLoaded.value) loadTx(true, true)
|
||||||
})
|
})
|
||||||
|
|
||||||
function switchFilter(type: string) {
|
function switchFilter(type: string) {
|
||||||
@@ -130,10 +130,10 @@ function switchFilter(type: string) {
|
|||||||
loadTx(true)
|
loadTx(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadTx(reset = false) {
|
async function loadTx(reset = false, silent = false) {
|
||||||
if (reset) {
|
if (reset) {
|
||||||
page.value = 1
|
page.value = 1
|
||||||
txList.value = []
|
if (!silent) txList.value = []
|
||||||
}
|
}
|
||||||
const seq = ++loadSeq
|
const seq = ++loadSeq
|
||||||
const params: any = { page: page.value, pageSize }
|
const params: any = { page: page.value, pageSize }
|
||||||
|
|||||||
@@ -12,45 +12,40 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="content">
|
<view class="content">
|
||||||
<!-- 群组模式:群组总预算(只读) -->
|
<!-- 群组模式:顶部概览 -->
|
||||||
<view class="preview-card" v-if="groupStore.isGroupMode && !loading">
|
<view class="overview-row" v-if="groupStore.isGroupMode && !loading">
|
||||||
<view class="preview-header">
|
<view class="overview-item">
|
||||||
<text class="preview-label">群组预算</text>
|
<text class="overview-label">群组预算</text>
|
||||||
<text class="preview-month">{{ currentMonth }}</text>
|
<text class="overview-value">{{ budget ? formatAmount(budget.amount) : '未设置' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="overview-divider"></view>
|
||||||
|
<view class="overview-item">
|
||||||
|
<text class="overview-label">我的预算</text>
|
||||||
|
<text class="overview-value highlight">{{ budgetAmount > 0 ? formatAmount(budgetAmount) : '未设置' }}</text>
|
||||||
</view>
|
</view>
|
||||||
<text class="preview-amount">
|
|
||||||
{{ budget ? formatAmount(budget.amount) : '未设置' }}
|
|
||||||
</text>
|
|
||||||
<BudgetBar
|
|
||||||
v-if="budget"
|
|
||||||
:total="budget.amount"
|
|
||||||
:used="monthExpense"
|
|
||||||
:showLabel="true"
|
|
||||||
/>
|
|
||||||
<text class="preview-hint" v-else>群组成员均未设置预算</text>
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 我的预算 / 个人模式预算 -->
|
<!-- 当前预算预览(编辑目标) -->
|
||||||
<view class="preview-card">
|
<view class="preview-card">
|
||||||
<view class="preview-header">
|
<view class="preview-header">
|
||||||
<text class="preview-label">{{ groupStore.isGroupMode ? '我的预算' : '本月预算' }}</text>
|
<text class="preview-label">{{ groupStore.isGroupMode ? '我的预算' : '本月预算' }}</text>
|
||||||
<text class="preview-month">{{ currentMonth }}</text>
|
<text class="preview-month">{{ currentMonth }}</text>
|
||||||
</view>
|
</view>
|
||||||
<text class="preview-amount" v-if="!loading">
|
<text class="preview-amount" v-if="!loading">
|
||||||
{{ myBudgetAmount > 0 ? formatAmount(myBudgetAmount) : '未设置' }}
|
{{ budgetAmount > 0 ? formatAmount(budgetAmount) : '未设置' }}
|
||||||
</text>
|
</text>
|
||||||
<view class="preview-skeleton" v-else></view>
|
<view class="preview-skeleton" v-else></view>
|
||||||
<BudgetBar
|
<BudgetBar
|
||||||
v-if="myBudgetAmount > 0"
|
v-if="budgetAmount > 0"
|
||||||
:total="myBudgetAmount"
|
:total="budgetAmount"
|
||||||
:used="myExpense"
|
:used="monthExpense"
|
||||||
:showLabel="true"
|
:showLabel="true"
|
||||||
/>
|
/>
|
||||||
<text class="preview-hint" v-else>设置预算,掌控开支</text>
|
<text class="preview-hint" v-else>设置预算,掌控开支</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 快捷金额 -->
|
<!-- 快捷金额 -->
|
||||||
<view class="section-title">{{ groupStore.isGroupMode ? '设置我的预算' : '快捷金额' }}</view>
|
<view class="section-title">快捷金额</view>
|
||||||
<view class="preset-grid">
|
<view class="preset-grid">
|
||||||
<view
|
<view
|
||||||
class="preset-item"
|
class="preset-item"
|
||||||
@@ -97,9 +92,8 @@ const groupStore = useGroupStore()
|
|||||||
|
|
||||||
const currentMonth = getCurrentMonth()
|
const currentMonth = getCurrentMonth()
|
||||||
const budget = ref<any>(null)
|
const budget = ref<any>(null)
|
||||||
|
const budgetAmount = ref(0)
|
||||||
const monthExpense = ref(0)
|
const monthExpense = ref(0)
|
||||||
const myBudgetAmount = ref(0)
|
|
||||||
const myExpense = ref(0)
|
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
const initialLoaded = ref(false)
|
const initialLoaded = ref(false)
|
||||||
const amountStr = ref('')
|
const amountStr = ref('')
|
||||||
@@ -113,17 +107,12 @@ function formatPreset(val: number) {
|
|||||||
function syncBudgetData() {
|
function syncBudgetData() {
|
||||||
budget.value = budgetStore.budget
|
budget.value = budgetStore.budget
|
||||||
monthExpense.value = statsStore.overview.expense
|
monthExpense.value = statsStore.overview.expense
|
||||||
// 群组模式用 myAmount,个人模式用 amount
|
// 群组模式用 myAmount(个人预算),个人模式用 amount
|
||||||
if (budget.value) {
|
budgetAmount.value = budget.value
|
||||||
myBudgetAmount.value = groupStore.isGroupMode ? (budget.value.myAmount || 0) : budget.value.amount
|
? (groupStore.isGroupMode ? (budget.value.myAmount || 0) : budget.value.amount)
|
||||||
myExpense.value = groupStore.isGroupMode ? statsStore.overview.expense : statsStore.overview.expense
|
: 0
|
||||||
} else {
|
if (budgetAmount.value > 0) {
|
||||||
myBudgetAmount.value = 0
|
amountStr.value = (budgetAmount.value / 100).toString()
|
||||||
myExpense.value = 0
|
|
||||||
}
|
|
||||||
// 预填输入框(个人预算)
|
|
||||||
if (myBudgetAmount.value > 0) {
|
|
||||||
amountStr.value = (myBudgetAmount.value / 100).toString()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,6 +225,45 @@ function goBack() {
|
|||||||
padding: 0 40rpx;
|
padding: 0 40rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.overview-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background: #FFFFFF;
|
||||||
|
border-radius: 28rpx;
|
||||||
|
padding: 28rpx 32rpx;
|
||||||
|
margin-bottom: 24rpx;
|
||||||
|
border: 2rpx solid #F0E0D6;
|
||||||
|
box-shadow: 4rpx 4rpx 12rpx rgba(45, 27, 27, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.overview-item {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overview-label {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #8B7E7E;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overview-value {
|
||||||
|
font-family: 'Fredoka', sans-serif;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #2D1B1B;
|
||||||
|
|
||||||
|
&.highlight { color: #FF8C69; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.overview-divider {
|
||||||
|
width: 2rpx;
|
||||||
|
height: 56rpx;
|
||||||
|
background: #F0E0D6;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.preview-card {
|
.preview-card {
|
||||||
background: #FFFFFF;
|
background: #FFFFFF;
|
||||||
border-radius: 40rpx;
|
border-radius: 40rpx;
|
||||||
|
|||||||
Reference in New Issue
Block a user