| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- <template>
- <view class="page">
- <NavBar :title="isCreate ? '新建优惠券' : '优惠券详情'" :showBack="true" />
- <scroll-view class="detail-scroll" scroll-y>
- <view class="section">
- <text class="section-title">基本信息</text>
- <view class="form-item">
- <text class="form-label">优惠券名称</text>
- <input class="form-input" v-model="form.name" placeholder="请输入名称" />
- </view>
- <view class="form-item">
- <text class="form-label">优惠类型</text>
- <picker :range="typeOptions" range-key="label" :value="typeIndex" @change="onTypeChange" :disabled="!isCreate">
- <view class="form-picker">{{ typeOptions[typeIndex]?.label || '请选择' }}</view>
- </picker>
- </view>
- <view class="form-item" v-if="form.type === 1">
- <text class="form-label">满减金额</text>
- <input class="form-input" v-model="form.amount" type="digit" placeholder="抵扣金额" />
- </view>
- <view class="form-item" v-if="form.type === 2">
- <text class="form-label">折扣比例(%)</text>
- <input class="form-input" v-model="form.discount" type="number" placeholder="如 80 表示8折" />
- </view>
- <view class="form-item">
- <text class="form-label">最低消费(元)</text>
- <input class="form-input" v-model="form.minAmount" type="digit" placeholder="使用门槛" />
- </view>
- <view class="form-item">
- <text class="form-label">开始日期</text>
- <picker mode="date" :value="form.startTime" @change="onStartDateChange">
- <view class="form-picker">{{ form.startTime || '请选择' }}</view>
- </picker>
- </view>
- <view class="form-item">
- <text class="form-label">结束日期</text>
- <picker mode="date" :value="form.endTime" @change="onEndDateChange">
- <view class="form-picker">{{ form.endTime || '请选择' }}</view>
- </picker>
- </view>
- <view class="form-item">
- <text class="form-label">发行总量</text>
- <input class="form-input" v-model="form.totalQuantity" type="number" placeholder="发行数量" />
- </view>
- </view>
- <view class="section" v-if="!isCreate && stats">
- <text class="section-title">统计数据</text>
- <view class="stats-grid">
- <view class="stat-item"><text class="stat-value">{{ stats.receivedCount || 0 }}</text><text class="stat-label">已领取</text></view>
- <view class="stat-item"><text class="stat-value">{{ stats.usedCount || 0 }}</text><text class="stat-label">已使用</text></view>
- <view class="stat-item"><text class="stat-value">{{ formatMoney(stats.totalDiscount || 0) }}</text><text class="stat-label">总优惠</text></view>
- </view>
- <view class="distribute-btn" @click="handleDistribute" v-if="form.status === 1"><text>发放优惠券</text></view>
- </view>
- </scroll-view>
- <view class="bottom-actions">
- <view class="save-btn" @click="isCreate ? handleCreate() : handleSave()"><text>{{ isCreate ? '创建优惠券' : '保存修改' }}</text></view>
- </view>
- </view>
- </template>
- <script setup lang="ts">
- import { ref } from 'vue'
- import { onLoad } from '@dcloudio/uni-app';
- import NavBar from '@/components/NavBar.vue';
- import { getCouponById, createCoupon, updateCouponStatus, distributeCoupon, getCouponStatistics } from '@/api/coupon';
- import { CouponTypeText } from '@/utils/constants';
- import { formatMoney as formatMoneyUtil, showToast, showConfirm } from '@/utils/common';
- const typeOptions = [{ label: CouponTypeText[1], value: 1 }, { label: CouponTypeText[2], value: 2 }];
- const isCreate = ref(true);
- const typeIndex = ref(0);
- const form = ref<any>({ type: 1, startTime: '', endTime: '' });
- const stats = ref<any>(null);
- const formatMoney = formatMoneyUtil;
- onLoad((options?: Record<string, string>) => {
- const id = options?.id ? Number(options.id) : 0;
- if (id > 0) { isCreate.value = false; loadDetail(id); }
- });
- const loadDetail = async (id: number) => {
- try {
- const data = await getCouponById(id);
- form.value = data;
- typeIndex.value = typeOptions.findIndex(t => t.value === data.type);
- if (typeIndex.value < 0) typeIndex.value = 0;
- loadStats(id);
- } catch { showToast('加载失败'); uni.navigateBack(); }
- };
- const loadStats = async (id: number) => {
- try { stats.value = await getCouponStatistics(id); } catch { /* ignore */ }
- };
- const onTypeChange = (e: any) => { typeIndex.value = e.detail.value; form.value.type = typeOptions[typeIndex.value].value; };
- const onStartDateChange = (e: any) => { form.value.startTime = e.detail.value; };
- const onEndDateChange = (e: any) => { form.value.endTime = e.detail.value; };
- const handleCreate = async () => {
- try { await createCoupon(form.value); showToast('创建成功', 'success'); setTimeout(() => uni.navigateBack(), 1500); } catch { showToast('创建失败'); }
- };
- const handleSave = async () => {
- try { await updateCouponStatus(form.value.id, form.value.status); showToast('保存成功', 'success'); } catch { showToast('保存失败'); }
- };
- const handleDistribute = async () => {
- if (!(await showConfirm('确认向全部用户发放此优惠券?'))) return;
- try { await distributeCoupon({ templateId: form.value.id, targetType: 1 }); showToast('发放成功', 'success'); } catch { showToast('发放失败'); }
- };
- </script>
- <style lang="scss" scoped>
- .page { height: 100vh; background: $bg-color-page; display: flex; flex-direction: column; padding-bottom: env(safe-area-inset-bottom); }
- .detail-scroll { flex: 1; height: 0; }
- .section { background: $bg-color-card; margin-bottom: $spacing-2; padding: $spacing-3 $spacing-4; }
- .section-title { display: block; font-size: 28rpx; font-weight: 600; color: $text-color-primary; margin-bottom: $spacing-3; padding-bottom: $spacing-2; border-bottom: 1rpx solid $border-color-light; }
- .form-item { display: flex; align-items: center; justify-content: space-between; padding: $spacing-2 0; border-bottom: 1rpx solid $border-color-light; }
- .form-item:last-child { border-bottom: none; }
- .form-label { font-size: 28rpx; color: $text-color-secondary; flex-shrink: 0; width: 180rpx; }
- .form-input { flex: 1; text-align: right; font-size: 28rpx; color: $text-color-primary; }
- .form-picker { flex: 1; text-align: right; font-size: 28rpx; color: $text-color-muted; }
- .stats-grid { display: flex; }
- .stat-item { flex: 1; display: flex; flex-direction: column; align-items: center; padding: $spacing-2; }
- .stat-value { font-size: $font-size-xl; font-weight: 700; color: $text-color-primary; margin-bottom: $spacing-1; }
- .stat-label { font-size: 22rpx; color: $text-color-muted; }
- .distribute-btn { margin-top: $spacing-4; background: $primary-color; padding: 24rpx 0; border-radius: $radius-base; display: flex; align-items: center; justify-content: center; }
- .distribute-btn text { font-size: 28rpx; font-weight: 600; color: $text-color-primary; }
- .bottom-actions { padding: $spacing-3 $spacing-4; padding-bottom: calc(24rpx + env(safe-area-inset-bottom)); background: $bg-color-card; border-top: 1rpx solid $border-color-light; flex-shrink: 0; }
- .save-btn { width: 100%; background: $primary-color; padding: 28rpx 0; border-radius: $radius-xl; display: flex; align-items: center; justify-content: center; }
- .save-btn text { font-size: $font-size-lg; font-weight: 600; color: $text-color-primary; }
- </style>
|