This commit is contained in:
2025-11-20 10:35:09 +08:00
13 changed files with 884 additions and 368 deletions

View File

@@ -0,0 +1,7 @@
<template>
<view class="">添加优惠券</view>
</template>
<script></script>
<style></style>

View File

@@ -0,0 +1,243 @@
<template>
<view class="container">
<view class="header-wrap">
<view class="fixed-header-wrap">
<scroll-view scroll-x direction="horizontal" class="tabs-wrap">
<view class="item" :class="{ active: couponType == item.value }" v-for="item in emunList.couponTypes" :key="item.value" @click="changeType(item.value)">
<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">
<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'">{{ item.validStartTime }}{{ item.validEndTime }}</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="+ 添加商品兑换券" @confirm="go.to('PAGES_ADD_COUPON')"></my-footer-btn>
</view>
</template>
<script setup>
import { ref, reactive } from 'vue';
import go from '@/commons/utils/go.js';
import { couponPage } from '@/http/api/market/index.js';
import { onLoad, onShow, onReachBottom } from '@dcloudio/uni-app';
import { getEmunListLabel, emunList } from '../utils/couponUtils.js';
// 切换类型
function changeType(type) {
couponType.value = type;
resetGetData();
}
// 搜索
function searchHandle() {
resetGetData();
}
function resetGetData() {
tableData.page = 1;
tableData.status = 'loading';
tableData.list = [];
couponPageAjax();
}
// 获取优惠券
const couponType = ref(1);
const tableData = reactive({
query: '',
status: 'loading',
page: 1,
size: 10,
list: []
});
async function couponPageAjax() {
try {
tableData.status = 'loading';
const res = await couponPage({
couponType: couponType.value,
title: tableData.query,
page: tableData.page,
size: tableData.size
});
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.coupon_type;
});
</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>

View File

@@ -3,9 +3,9 @@
<u-form label-position="top" labelWidth="200" :model="form" :rules="rules" ref="formRef">
<view class="card">
<u-form-item label="活动名称" prop="title">
<u-input placeholder="请输入活动名称" v-model="form.title" border="bottom" :customStyle="inputStyle"></u-input>
<u-input placeholder="请输入活动名称" :maxlength="20" v-model="form.title" border="bottom" :customStyle="inputStyle"></u-input>
</u-form-item>
<u-form-item label="可用门店" prop="useShops">
<u-form-item label="可用门店" prop="useShops" v-if="shopInfo.isHeadShop && shopInfo.shopType != 'only'">
<my-shop-select-w v-model:useType="form.useShopType" v-model:selShops="form.useShops"></my-shop-select-w>
</u-form-item>
</view>
@@ -39,7 +39,7 @@
</u-form-item>
<u-form-item label="优先级">
<view class="center">
<u-input placeholder="默认值0" v-model="form.sort"></u-input>
<u-input placeholder="默认值0" :maxlength="8" v-model="form.sort" @change="sortInput"></u-input>
</view>
<view class="tips">
<text class="red-tips">数值越大排序越靠前重复时段下按照排序值最高的折扣使用</text>
@@ -48,7 +48,7 @@
<u-form-item label="限时折扣优先级">
<u-radio-group v-model="form.discountPriority" placement="column">
<u-radio label="优先使用限时折扣价" name="limit-time"></u-radio>
<u-radio label="优先使用会员价/会员折扣" name="vip-price"></u-radio>
<u-radio label="优先使用会员价" name="vip-price"></u-radio>
</u-radio-group>
</u-form-item>
</view>
@@ -63,14 +63,13 @@
</template>
<script setup>
import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';
dayjs.extend(customParseFormat); // 注册插件
import { ref } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { filterNumberInput } from '@/utils/index.js';
import { filterNumberInput, convertTimeFormat } from '@/utils/index.js';
import { limitTimeDiscount } from '@/http/api/market/index.js';
const shopInfo = ref({});
const inputStyle = ref({
paddingLeft: 0
});
@@ -85,11 +84,11 @@ const form = ref({
useShops: [], // 可用门店
validStartTime: '', // 有效期开始时间
validEndTime: '', // 有效期结束时间
useDays: ['周一', '周二', '周三'], // 周一,周二,周三,周四,周五,周六,周日
useDays: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'], // 周一,周二,周三,周四,周五,周六,周日
useTimeType: 'all', // all-全时段custom-指定时段
useStartTime: '', // 可用开始时间
useEndTime: '', // 可用结束时间
useType: ['dine-in', 'take-out'], // 堂食 dine-in 外带 take-out 外卖 take-away 配送 post
useType: ['dine-in'], // 堂食 dine-in 外带 take-out 外卖 take-away 配送 post
discountRate: '', // 折扣% 范围1-99
sort: '', // 数字越小级别越高
discountPriority: 'limit-time', // 折扣优先级 限时折扣优先limit-time/会员价优先vip-price
@@ -213,35 +212,16 @@ function discountRateInput(e) {
}, 50);
}
/**
* 时间格式互转HH:mm → HH:mm:ssHH:mm:ss → HH:mm
* @param {string} timeStr - 输入的时间字符串
* @returns {string} 转换后的时间字符串
*/
const convertTimeFormat = (timeStr) => {
if (!timeStr) return '00:00';
// 正则判断格式
const isHms = /^\d{1,2}:\d{2}:\d{2}$/.test(timeStr); // HH:mm:ss
const isHm = /^\d{1,2}:\d{2}$/.test(timeStr); // HH:mm
if (isHm) {
// HH:mm → 解析后格式化为 HH:mm:ss
return dayjs(timeStr, 'HH:mm').format('HH:mm:ss');
}
if (isHms) {
// HH:mm:ss → 解析后格式化为 HH:mm
return dayjs(timeStr, 'HH:mm:ss').format('HH:mm');
}
// 非法格式兜底
return '00:00';
};
// 排序
function sortInput(e) {
setTimeout(() => {
form.value.sort = filterNumberInput(e, 0);
}, 50);
}
// 提交保存
function submitHandle() {
// console.log('前置form', form.value);
console.log('前置form', form.value);
formRef.value
.validate()
.then(async (res) => {
@@ -254,8 +234,10 @@ function submitHandle() {
data.useDays = form.value.useDays.join(',');
data.useType = form.value.useType.join(',');
data.foods = form.value.foods.join(',');
data.useStartTime = convertTimeFormat(form.value.useStartTime);
data.useEndTime = convertTimeFormat(form.value.useEndTime);
if (form.value.useTimeType == 'custom') {
data.useStartTime = convertTimeFormat(form.value.useStartTime);
data.useEndTime = convertTimeFormat(form.value.useEndTime);
}
uni.showLoading({
title: '提交中...',
@@ -263,7 +245,7 @@ function submitHandle() {
});
await limitTimeDiscount(data);
uni.showToast({
title: '添加成功',
title: '保存成功',
icon: 'none'
});
setTimeout(() => {
@@ -285,7 +267,11 @@ function submitHandle() {
function getLocalLimitDiscount() {
const data = uni.getStorageSync('limitDiscountObj');
if (data.id) {
// uni.setStorageSync('limitDiscountObj', '');
uni.setNavigationBarTitle({
title: '编辑限时折扣'
});
uni.setStorageSync('limitDiscountObj', '');
data.useShops = data.useShops.split(',');
data.useDays = data.useDays.split(',');
data.useType = data.useType.split(',');
@@ -301,6 +287,7 @@ function getLocalLimitDiscount() {
}
onLoad(() => {
shopInfo.value = uni.getStorageSync('shopInfo');
getLocalLimitDiscount();
});
</script>

View File

@@ -11,26 +11,29 @@
<u-tag :type="statusFilter(item.status, 'type')" plain :text="statusFilter(item.status, 'label')"></u-tag>
</view>
</view>
<view class="row">
<!-- <view class="row">
<text class="b">活动名称</text>
<text class="t">{{ item.title }}</text>
</view>
</view> -->
<view class="row">
<text class="b">活动时间</text>
<text class="t">{{ item.updateTime }}</text>
<text class="t">{{ item.validStartTime }}{{ item.validEndTime }}</text>
</view>
<view class="row">
<text class="t">{{ item.useDays }}</text>
</view>
<view class="row">
<text class="t" v-if="item.useTimeType == 'custom'" style="margin-right: 20px">
{{ convertTimeFormat(item.useStartTime) }} - {{ convertTimeFormat(item.useEndTime) }}
</text>
<text class="t">折扣{{ item.discountRate }}%</text>
</view>
<view class="footer">
<view class="btn">
<u-button @click="delHandle(item)">删除</u-button>
<u-button shape="circle" @click="delHandle(item)">删除</u-button>
</view>
<view class="btn">
<u-button type="primary" @click="editorHandle(item)">编辑</u-button>
<u-button shape="circle" type="primary" @click="editorHandle(item)">编辑</u-button>
</view>
</view>
</view>
@@ -45,6 +48,7 @@ import { reactive, ref } from 'vue';
import { onLoad, onShow, onReachBottom } from '@dcloudio/uni-app';
import { limitTimeDiscountPage, limitTimeDiscountDel } from '@/http/api/market/index.js';
import go from '@/commons/utils/go.js';
import { convertTimeFormat } from '@/utils/index.js';
// 去编辑
function editorHandle(item) {
@@ -118,15 +122,21 @@ const tableData = reactive({
// 滚动到底部
onReachBottom(() => {
tableData.page++;
limitTimeDiscountPageAjax();
if (tableData.status != 'nomore') {
tableData.page++;
limitTimeDiscountPageAjax();
}
});
// 获取限时折扣分页
async function limitTimeDiscountPageAjax() {
try {
uni.showLoading({
title: '加载中...',
mask: true
});
const res = await limitTimeDiscountPage({
page: 1,
page: tableData.page,
size: 10,
startTime: '',
endTime: ''
@@ -142,6 +152,9 @@ async function limitTimeDiscountPageAjax() {
} catch (error) {
console.log(error);
}
setTimeout(() => {
uni.hideLoading();
}, 500);
}
onShow(() => {
@@ -159,7 +172,7 @@ page {
</style>
<style scoped lang="scss">
.container {
padding: 0 28upx;
padding: 0 28upx 28upx;
}
.list {
padding: 28upx 0;

View File

@@ -0,0 +1,67 @@
// 优惠券通用的一些方法
export const emunList = {
couponTypes: [{
label: '满减券',
value: 1,
},
{
label: '商品兑换券',
value: 2,
},
{
label: '折扣券',
value: 3,
},
{
label: '第二件半价券',
value: 4,
},
{
label: '消费送券',
value: 5,
},
{
label: '买一送一券',
value: 6,
},
{
label: '固定价格券',
value: 7,
},
{
label: '免配送费券',
value: 8,
}
],
getType: [{
label: '不可自行领取',
value: 'no'
},
{
label: '可领取',
value: 'yes'
}
],
validType: [{
label: '领券后有效期内可用',
value: 'fixed'
},
{
label: '固定有效期范围内可用',
value: 'custom'
}
]
}
/**
* key对应上面emunList属性名value对应属性value
*/
export const getEmunListLabel = (key, value) => {
let obj = emunList[key].find(item => item.value == value)
if (obj) {
return obj.label
} else {
return value
}
}