权益增加总额统计
This commit is contained in:
parent
01ee09524b
commit
66ae382b55
@ -43,7 +43,7 @@
|
||||
</view>
|
||||
<view class="field-block">
|
||||
<view class="field-label">折扣</view>
|
||||
<picker class="discount-picker" mode="multiSelector" :range="getDiscountPickerRange(entry)" :value="getDiscountPickerValue(entry)" :disabled="!entry.enableDiscount" @change="changeDiscount($event, entry)">
|
||||
<picker class="discount-picker" :class="{ 'discount-disabled': !entry.enableDiscount }" mode="multiSelector" :range="getDiscountPickerRange(entry)" :value="getDiscountPickerValue(entry)" :disabled="!entry.enableDiscount" @change="changeDiscount($event, entry)">
|
||||
<view class="number-input picker-value value-text">{{ Number(entry.discount).toFixed(1) }}</view>
|
||||
</picker>
|
||||
</view>
|
||||
@ -143,7 +143,7 @@
|
||||
<view class="field-block">
|
||||
<view class="field-label">折扣</view>
|
||||
<view class="discount-input-wrap">
|
||||
<picker class="discount-picker" mode="multiSelector" :range="getDiscountPickerRange(entry)" :value="getDiscountPickerValue(entry)" :disabled="entry.isFree || !entry.isDiscount" @change="changeDiscount($event, entry)">
|
||||
<picker class="discount-picker" :class="{ 'discount-disabled': entry.isFree || !entry.isDiscount }" mode="multiSelector" :range="getDiscountPickerRange(entry)" :value="getDiscountPickerValue(entry)" :disabled="entry.isFree || !entry.isDiscount" @change="changeDiscount($event, entry)">
|
||||
<view class="number-input picker-value value-text">{{ Number(entry.discount).toFixed(1) }}</view>
|
||||
</picker>
|
||||
<checkbox-group v-if="entry.isGift" class="free-check" @change="handleFreeChange($event, entry)">
|
||||
@ -319,9 +319,41 @@
|
||||
|
||||
<template #footer>
|
||||
<view class="footer-bar">
|
||||
<button class="cancel-button" @click="goBack">取消</button>
|
||||
<view v-if="showBenefitAmount" class="footer-summary">
|
||||
<view class="total-summary" @tap="toggleBenefitDetail">
|
||||
<text class="summary-label">总金额</text>
|
||||
<text class="summary-total-value">¥{{ benefitSummary.totalAmount.toFixed(2) }}</text>
|
||||
<uni-icons :type="benefitDetailVisible ? 'top' : 'bottom'" size="16" color="#6b7280" />
|
||||
</view>
|
||||
<text class="detail-trigger" @tap="toggleBenefitDetail">明细</text>
|
||||
</view>
|
||||
<view
|
||||
v-if="showBenefitAmount"
|
||||
class="benefit-detail-panel"
|
||||
:class="{ 'benefit-detail-panel-visible': benefitDetailVisible }"
|
||||
>
|
||||
<view class="detail-header">
|
||||
<text class="detail-project-name">权益项目</text>
|
||||
<text class="detail-quantity">数量</text>
|
||||
<text class="detail-discount">折扣</text>
|
||||
<text class="detail-amount">最终金额</text>
|
||||
</view>
|
||||
<view v-for="item in benefitDetailItems" :key="item.key" class="detail-row">
|
||||
<text class="detail-project-name detail-project-name-value">{{ item.name }}</text>
|
||||
<text class="detail-quantity">{{ item.quantity }}</text>
|
||||
<text class="detail-discount">{{ item.isFree ? "赠送" : `${item.discount.toFixed(1)}折` }}</text>
|
||||
<text class="detail-amount">¥{{ item.totalAmount.toFixed(2) }}</text>
|
||||
</view>
|
||||
<view v-if="!benefitDetailItems.length" class="detail-empty">暂无已选择权益</view>
|
||||
<view class="detail-row detail-row-total">
|
||||
<text>合计</text>
|
||||
<text class="detail-amount">¥{{ benefitSummary.totalAmount.toFixed(2) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="footer-actions">
|
||||
<button class="submit-button" :loading="saving" @click="submitEntries">生成权益</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</full-page>
|
||||
</template>
|
||||
@ -369,10 +401,67 @@ const todoExecutorPickerVisible = ref(false);
|
||||
const todoExecutorTarget = ref(null);
|
||||
const todoExecutorKeyword = ref("");
|
||||
const todoExecutorRefreshing = ref(false);
|
||||
const benefitDetailVisible = ref(false);
|
||||
const todoTypeOptions = Object.entries(TODO_EVENT_TYPE_LABELS).map(([value, label]) => ({ value, label }));
|
||||
let searchTimer = null;
|
||||
let entryKey = 0;
|
||||
|
||||
function toggleBenefitDetail() {
|
||||
benefitDetailVisible.value = !benefitDetailVisible.value;
|
||||
}
|
||||
|
||||
const benefitDetailItems = computed(() => entries.value.flatMap((entry) => {
|
||||
if (entry.isPackage) {
|
||||
return (entry.projects || [])
|
||||
.filter((project) => project.selected)
|
||||
.map((project) => ({
|
||||
key: `${entry.key}_${project.key}`,
|
||||
name: project.project?.projectName || "未命名权益",
|
||||
quantity: Math.max(0, toNumber(project.usageCount, 1)),
|
||||
discount: toNumber(project.discount),
|
||||
totalAmount: Math.max(0, toNumber(project.totalPrice)),
|
||||
isFree: false,
|
||||
}));
|
||||
}
|
||||
|
||||
if (!entry.project?._id) return [];
|
||||
return [{
|
||||
key: entry.key,
|
||||
name: entry.project.projectName || "未命名权益",
|
||||
quantity: Math.max(0, toNumber(entry.usageCount, 1)),
|
||||
discount: toNumber(entry.discount),
|
||||
totalAmount: Math.max(0, toNumber(entry.isFree ? 0 : entry.totalPrice)),
|
||||
isFree: Boolean(entry.isFree),
|
||||
}];
|
||||
}));
|
||||
|
||||
const benefitSummary = computed(() => entries.value.reduce((summary, entry) => {
|
||||
if (entry.isPackage) {
|
||||
summary.selectedCount += 1;
|
||||
const originalAmount = toNumber(entry.packagePrice || entry.price) * Math.max(0, toNumber(entry.usageCount, 1));
|
||||
const totalAmount = entry.isFree ? 0 : Math.max(0, toNumber(entry.totalPrice));
|
||||
summary.originalAmount += originalAmount;
|
||||
summary.totalAmount += totalAmount;
|
||||
summary.savedAmount += Math.max(0, originalAmount - totalAmount);
|
||||
return summary;
|
||||
}
|
||||
|
||||
if (!entry.project?._id) return summary;
|
||||
summary.selectedCount += 1;
|
||||
const usageCount = Math.max(0, toNumber(entry.usageCount, 1));
|
||||
const originalAmount = toNumber(entry.price) * usageCount;
|
||||
const totalAmount = entry.isFree ? 0 : Math.max(0, toNumber(entry.totalPrice));
|
||||
summary.originalAmount += originalAmount;
|
||||
summary.totalAmount += totalAmount;
|
||||
summary.savedAmount += Math.max(0, originalAmount - totalAmount);
|
||||
return summary;
|
||||
}, {
|
||||
selectedCount: 0,
|
||||
originalAmount: 0,
|
||||
savedAmount: 0,
|
||||
totalAmount: 0,
|
||||
}));
|
||||
|
||||
function formatDate(date) {
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, "0");
|
||||
@ -1755,6 +1844,18 @@ async function submitEntries() {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.discount-picker.discount-disabled {
|
||||
opacity: 0.62;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.discount-picker.discount-disabled .number-input {
|
||||
border-color: #d1d5db;
|
||||
background: #f3f4f6;
|
||||
color: #9ca3af;
|
||||
-webkit-text-fill-color: #9ca3af;
|
||||
}
|
||||
|
||||
.field-row {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
@ -1876,17 +1977,163 @@ async function submitEntries() {
|
||||
}
|
||||
|
||||
.footer-bar {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
padding: 20rpx 24rpx;
|
||||
background: rgba(245, 246, 248, 0.96);
|
||||
padding: 14rpx 24rpx 18rpx;
|
||||
background: #fff;
|
||||
border-top: 1rpx solid #eef2f7;
|
||||
backdrop-filter: blur(12px);
|
||||
box-shadow: 0 -4rpx 16rpx rgba(15, 23, 42, 0.04);
|
||||
box-sizing: border-box;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.footer-bar button {
|
||||
.footer-summary {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14rpx;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.total-summary {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: baseline;
|
||||
gap: 6rpx;
|
||||
min-width: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.summary-label {
|
||||
color: #6b7280;
|
||||
font-size: 22rpx;
|
||||
line-height: 1.2;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.summary-saving {
|
||||
color: #16a34a;
|
||||
}
|
||||
|
||||
.summary-total-value {
|
||||
color: #e85c2f;
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.detail-trigger {
|
||||
flex-shrink: 0;
|
||||
padding-left: 14rpx;
|
||||
border-left: 1rpx solid #edf0f3;
|
||||
color: #6b7280;
|
||||
font-size: 24rpx;
|
||||
line-height: 1.2;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.benefit-detail-panel {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 100%;
|
||||
left: 0;
|
||||
max-height: calc(100vh - 220rpx);
|
||||
overflow: hidden;
|
||||
padding: 20rpx 24rpx 18rpx;
|
||||
border-top: 1rpx solid #eef2f7;
|
||||
border-radius: 24rpx 24rpx 0 0;
|
||||
background: #fff;
|
||||
box-shadow: 0 -8rpx 24rpx rgba(15, 23, 42, 0.08);
|
||||
box-sizing: border-box;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
pointer-events: none;
|
||||
transform: translateY(100%);
|
||||
transform-origin: bottom center;
|
||||
transition:
|
||||
opacity 180ms ease,
|
||||
transform 180ms ease,
|
||||
visibility 180ms ease;
|
||||
}
|
||||
|
||||
.benefit-detail-panel-visible {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
pointer-events: auto;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.detail-header,
|
||||
.detail-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
min-height: 60rpx;
|
||||
color: #6b7280;
|
||||
font-size: 27rpx;
|
||||
}
|
||||
|
||||
.detail-header {
|
||||
min-height: 48rpx;
|
||||
color: #9ca3af;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.detail-project-name {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.detail-project-name-value {
|
||||
overflow: hidden;
|
||||
color: #374151;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.detail-quantity,
|
||||
.detail-discount {
|
||||
flex: 0 0 72rpx;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.detail-amount {
|
||||
flex: 0 0 130rpx;
|
||||
color: #374151;
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.detail-empty {
|
||||
padding: 22rpx 0;
|
||||
color: #9ca3af;
|
||||
font-size: 26rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.detail-row-total {
|
||||
margin-top: 8rpx;
|
||||
padding-top: 14rpx;
|
||||
border-top: 1rpx solid #eef2f7;
|
||||
color: #1f2937;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.detail-row-total .detail-amount {
|
||||
color: #e85c2f;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.footer-actions {
|
||||
flex: 0 0 250rpx;
|
||||
}
|
||||
|
||||
.footer-actions button {
|
||||
width: 100%;
|
||||
min-height: 88rpx;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
@ -1897,12 +2144,6 @@ async function submitEntries() {
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.cancel-button {
|
||||
color: #0877f1;
|
||||
background: #fff;
|
||||
border: 1rpx solid #0877f1;
|
||||
}
|
||||
|
||||
.submit-button {
|
||||
color: #fff;
|
||||
background: linear-gradient(135deg, #0f84ff 0%, #0877f1 100%);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user