cashier_app/pageMarket/exchangeCoupon/index.vue

380 lines
9.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="container">
<view class="header-wrap">
<view class="fixed-header-wrap">
<scroll-view scroll-x direction="horizontal" class="tabs-wrap" :scroll-left="scrollLeft" scroll-with-animation>
<view
class="item"
:class="{ active: couponType == item.value }"
v-for="(item, index) in emunList.couponTypes"
:key="index"
:data-index="index"
@click="changeType(item.value, index)"
>
<div class="item-flex">
<text class="t">{{ item.label }}</text>
</div>
</view>
</scroll-view>
<view class="search-wrap">
<view class="ipt">
<u-input
placeholder="搜索优惠券名称"
shape="circle"
prefixIcon="search"
prefixIconStyle="font-size: 22px;color: #909399"
clearable
:customStyle="{ border: 'none', background: '#F9F9F9' }"
v-model="tableData.query"
@confirm="searchHandle"
@clear="searchHandle"
></u-input>
</view>
<div class="btn">
<u-button shape="circle" type="primary" :customStyle="{ height: '36px' }" @click="searchHandle">搜索</u-button>
</div>
</view>
</view>
</view>
<view class="my-coupon-item-list">
<view class="my-coupon-item-item" v-for="item in tableData.list" :key="item.id">
<my-coupon-item :item="item" @delete="deleteHandle" @editor="editorHandle">
<view class="my-coupon-item-row-wrap">
<template v-if="couponType == 5">
<view class="row">
<text class="title">赠券门槛</text>
<text class="info">满{{ item.fullAmount }}元赠送</text>
</view>
<view class="row">
<text class="title">每人限量</text>
<text class="info">
<template v-if="item.useLimit == -10086">无限制</template>
<template v-else>{{ item.useLimit }}张</template>
</text>
</view>
<view class="row">
<text class="title">每次赠送</text>
<text class="info">
<template v-if="item.getLimit == -10086">无限制</template>
<template v-else>{{ item.getLimit }}张</template>
</text>
</view>
</template>
<template v-else>
<view class="row" v-if="couponType == 1">
<text class="title">使用门槛</text>
<text class="info">满{{ item.fullAmount }}元减{{ item.discountAmount }}元</text>
</view>
<view class="row" v-if="couponType == 2">
<text class="title">使用门槛</text>
<text class="info">满{{ item.fullAmount }}元可用</text>
</view>
<view class="row" v-if="couponType == 3">
<text class="title">最大折扣金额</text>
<text class="info">满{{ item.discountAmount }}元可用</text>
</view>
<view class="row">
<text class="title">发放方式</text>
<text class="info">用户{{ getEmunListLabel('getType', item.getType) }}</text>
</view>
<view class="row">
<text class="title">有效期</text>
<text class="info">
<template v-if="item.validType == 'fixed'">领券后{{ item.validDays }}天过期</template>
<template v-if="item.validType == 'custom'">
{{ dayjs(item.validStartTime).format('YYYY-MM-DD') }} 至 {{ dayjs(item.validEndTime).format('YYYY-MM-DD') }}
</template>
</text>
</view>
</template>
<view class="row">
<text class="title">创建时间</text>
<text class="info">{{ item.createTime }}</text>
</view>
</view>
</my-coupon-item>
</view>
</view>
<u-loadmore :status="tableData.status"></u-loadmore>
<my-footer-btn :confirmText="`+ 添加${getEmunListLabel('couponTypes', couponType)}`" @confirm="toAddCounpon"></my-footer-btn>
</view>
</template>
<script setup>
import dayjs from 'dayjs';
import { ref, reactive, nextTick, getCurrentInstance } from 'vue';
import go from '@/commons/utils/go.js';
import { couponPage, couponDel, getConsumerCouponPage, deleteConsumerCoupon } from '@/http/api/market/index.js';
import { onLoad, onShow, onReachBottom } from '@dcloudio/uni-app';
import { getEmunListLabel, emunList } from '../utils/couponUtils.js';
const instance = getCurrentInstance();
const couponType = ref(1); // 当前选中的优惠券类型
const scrollLeft = ref(0); // scroll-view的滚动距离
// 切换类型
function changeType(type, index) {
couponType.value = type;
resetGetData();
calculateCenterScroll(index);
}
// item居中
const calculateCenterScroll = (activeIndex) => {
// 1. 查询ScrollView的可视宽度全局查询无需ref
uni.createSelectorQuery()
.select('.tabs-wrap')
.boundingClientRect((scrollViewRect) => {
if (!scrollViewRect) return;
const viewWidth = scrollViewRect.width; // ScrollView可视宽度px
const viewHalfWidth = viewWidth / 2; // ScrollView中心位置px
// 2. 查询所有Tab项的DOM信息计算选中项左侧总宽度
uni.createSelectorQuery()
.selectAll('.item')
.boundingClientRect((tabItemsRect) => {
if (!tabItemsRect || tabItemsRect.length === 0) return;
// 3. 计算选中项左侧所有Tab的宽度总和
let leftTotalWidth = 0;
for (let i = 0; i < activeIndex; i++) {
leftTotalWidth += tabItemsRect[i].width; // 累加左侧Tab宽度px
leftTotalWidth += 28 * (uni.getSystemInfoSync().windowWidth / 750); // 累加左侧Tab的margin-left28rpx转px
}
// 4. 获取选中项自身的宽度和位置
const activeItemRect = tabItemsRect[activeIndex];
const itemHalfWidth = activeItemRect.width / 2; // 选中项中心位置px
// 5. 计算最终滚动距离(核心公式)
let targetScrollLeft = leftTotalWidth + itemHalfWidth - viewHalfWidth;
// 6. 边界处理不小于0不超过最大滚动距离
uni.createSelectorQuery()
.select('.tabs-wrap')
.scrollOffset((scrollOffset) => {
const maxScrollLeft = scrollOffset.scrollWidth - viewWidth; // 最大滚动距离
targetScrollLeft = Math.max(0, Math.min(targetScrollLeft, maxScrollLeft));
scrollLeft.value = targetScrollLeft; // 赋值滚动距离
console.log('最终滚动距离:', targetScrollLeft);
})
.exec();
})
.exec();
})
.exec();
};
// 搜索
function searchHandle() {
resetGetData();
}
// 重置获取数据
function resetGetData() {
tableData.page = 1;
tableData.status = 'loading';
tableData.list = [];
couponPageAjax();
}
function toAddCounpon() {
if (couponType.value == 5) {
go.to('PAGES_ADD_CONSUME_COUPON');
} else {
go.to('PAGES_ADD_COUPON', { couponType: couponType.value });
}
}
// 删除
function deleteHandle(item) {
console.log('del', item);
uni.showModal({
title: '注意',
content: `确定要删除${item.title || '该'}优惠券吗?`,
success: async (res) => {
if (res.confirm) {
try {
uni.showLoading({
title: '删除中...',
mask: true
});
if (couponType.value == 5) {
await deleteConsumerCoupon(item.id);
} else {
await couponDel(item.id);
}
uni.showToast({
title: '已删除',
icon: 'none'
});
let index = tableData.list.findIndex((val) => val.id == item.id);
tableData.list.splice(index, 1);
} catch (error) {
console.log(error);
}
setTimeout(() => {
uni.hideLoading();
}, 500);
}
}
});
}
// 编辑
function editorHandle(item) {
console.log('editor', item);
if (couponType.value == 5) {
go.to('PAGES_ADD_CONSUME_COUPON', {
couponType: item.couponType,
id: item.id
});
} else {
go.to('PAGES_ADD_COUPON', {
couponType: item.couponType,
id: item.id
});
}
}
// 获取优惠券
const tableData = reactive({
query: '',
status: 'loading',
page: 1,
size: 10,
list: []
});
async function couponPageAjax() {
try {
tableData.status = 'loading';
let res = null;
let params = {
couponType: couponType.value,
title: tableData.query,
page: tableData.page,
size: tableData.size
};
if (couponType.value == 5) {
res = await getConsumerCouponPage(params);
res.records.map((item) => {
item.couponType = 5;
});
} else {
res = await couponPage(params);
}
if (tableData.page == 1) {
tableData.list = res.records;
} else {
tableData.list.push(...res.records);
}
if (res.pageNumber >= res.totalPage) {
tableData.status = 'nomore';
}
} catch (error) {
console.log(error);
}
}
onReachBottom(() => {
if (tableData.status != 'nomore') {
tableData.page++;
couponPageAjax();
}
});
onShow(() => {
couponPageAjax();
});
onLoad((options) => {
couponType.value = options.couponType;
const index = emunList.couponTypes.findIndex((item) => item.value == couponType.value);
setTimeout(() => {
if (index !== -1) {
calculateCenterScroll(index);
}
}, 100);
});
</script>
<style>
page {
background-color: #f7f7f7;
}
</style>
<style scoped lang="scss">
.container {
padding: 28upx;
}
.header-wrap {
$height: 86px;
$scrollHeight: 30px;
$color: #318afe;
width: 100%;
height: $height;
.fixed-header-wrap {
width: 100%;
height: $height;
position: fixed;
top: 0;
left: 0;
z-index: 99;
background-color: #fff;
.tabs-wrap {
white-space: nowrap;
width: 100%;
height: $scrollHeight;
box-sizing: border-box;
.item {
height: 100%;
display: inline-block;
margin-left: 28upx;
&:last-child {
margin-right: 28upx;
}
&.active {
.item-flex {
background-color: #e6f0ff;
.t {
color: $color;
}
}
}
.item-flex {
width: 100%;
height: 100%;
display: flex;
align-items: center;
padding: 0 20upx;
border-radius: 4upx;
background-color: #f7f7fa;
.t {
color: #666666;
font-size: 28upx;
}
}
}
}
.search-wrap {
height: $height - $scrollHeight;
display: flex;
align-items: center;
padding: 10px 28upx 10px;
gap: 28upx;
box-sizing: border-box;
.ipt {
flex: 1;
height: 36px;
}
.btn {
width: 160upx;
height: 36px;
}
}
}
}
</style>