新增部分优惠券页面

This commit is contained in:
gyq 2025-11-20 10:27:08 +08:00
parent 805236dc5d
commit f74364a253
13 changed files with 887 additions and 368 deletions

135
App.vue
View File

@ -4,58 +4,53 @@ App.vue本身不是页面这里不能编写视图元素也就是没有<tem
--> -->
<script setup> <script setup>
import { onLaunch } from '@dcloudio/uni-app'; import { onLaunch } from '@dcloudio/uni-app';
import { getVersion } from '@/http/api/index.js' import { getVersion } from '@/http/api/index.js';
import appConfig from '@/config/appConfig.js'; import appConfig from '@/config/appConfig.js';
import { provide, onMounted } from 'vue'; import { provide, onMounted } from 'vue';
import WebsocketUtil from '@/commons/utils/websocket.js' import WebsocketUtil from '@/commons/utils/websocket.js';
const websocketUtil = new WebsocketUtil(appConfig.wss, 5000); // WebSocket const websocketUtil = new WebsocketUtil(appConfig.wss, 5000); // WebSocket
provide('websocketUtil', websocketUtil); // provide('websocketUtil', websocketUtil); //
onMounted(() => { onMounted(() => {});
});
onLaunch(() => { onLaunch(() => {
// console.log console.info // console.log console.info
// if (uni.getSystemInfoSync().platform !== "devtools") { // if (uni.getSystemInfoSync().platform !== "devtools") {
// console.log = () => {}; // console.log = () => {};
// console.info = () => {}; // console.info = () => {};
// } // }
let that = this let that = this;
uni.hideTabBar() uni.hideTabBar();
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
const updateManager = wx.getUpdateManager() // const updateManager = wx.getUpdateManager(); //
updateManager.onCheckForUpdate(function (res) { updateManager.onCheckForUpdate(function (res) {
// //
}) });
updateManager.onUpdateReady(function () { updateManager.onUpdateReady(function () {
// applyUpdate // applyUpdate
updateManager.applyUpdate() updateManager.applyUpdate();
});
})
updateManager.onUpdateFailed(function () { updateManager.onUpdateFailed(function () {
// //
}) });
// #endif // #endif
// console.log("getSystemSetting==",uni.getSystemInfoSync()) // console.log("getSystemSetting==",uni.getSystemInfoSync())
// console.log("getSystemSetting==",uni.getSystemSetting()) // console.log("getSystemSetting==",uni.getSystemSetting())
//#ifdef APP-PLUS //#ifdef APP-PLUS
// //
plus.runtime.getProperty(plus.runtime.appid, widgetInfo => { plus.runtime.getProperty(plus.runtime.appid, (widgetInfo) => {
// //
console.log("widgetInfo==",widgetInfo) console.log('widgetInfo==', widgetInfo);
let type = uni.getSystemInfoSync().platform == 'ios' ? 2 : 1 let type = uni.getSystemInfoSync().platform == 'ios' ? 2 : 1;
getVersion({source:'manager_app',type: type}).then(res => { getVersion({ source: 'manager_app', type: type })
console.log("selectNewApp==",res) .then((res) => {
console.log("version===",res.url && widgetInfo.version < res.version) console.log('selectNewApp==', res);
console.log('version===', res.url && widgetInfo.version < res.version);
if (res.url && widgetInfo.version < res.version) { if (res.url && widgetInfo.version < res.version) {
console.log("version===222") console.log('version===222');
let downloadLink = res.url; let downloadLink = res.url;
// let downloadLink = "https://short-video.hnsiyao.cn/app/sy-duanju.apk"; // let downloadLink = "https://short-video.hnsiyao.cn/app/sy-duanju.apk";
console.log(downloadLink) console.log(downloadLink);
// let androidLink = res.androidWgtUrl; // let androidLink = res.androidWgtUrl;
// let iosLink = res.iosWgtUrl; // let iosLink = res.iosWgtUrl;
let ready = false; let ready = false;
@ -66,31 +61,33 @@ App.vue本身不是页面这里不能编写视图元素也就是没有<tem
title: '发现新版本', title: '发现新版本',
confirmText: '立即更新', confirmText: '立即更新',
content: res.message, content: res.message,
success: res => { success: (res) => {
if (res.confirm) { if (res.confirm) {
uni.showLoading('下载中...'); uni.showLoading('下载中...');
if (uni.getSystemInfoSync().platform == 'android') { if (uni.getSystemInfoSync().platform == 'android') {
uni.downloadFile({ uni.downloadFile({
url: downloadLink, url: downloadLink,
success: downloadResult => { success: (downloadResult) => {
if (downloadResult.statusCode === 200) { if (downloadResult.statusCode === 200) {
plus.io.resolveLocalFileSystemURL(downloadResult.tempFilePath, entry => { plus.io.resolveLocalFileSystemURL(downloadResult.tempFilePath, (entry) => {
entry.getParent(_oldFile=>{ entry.getParent((_oldFile) => {
entry.moveTo(_oldFile,'.apk',newFilePath=>{ entry.moveTo(_oldFile, '.apk', (newFilePath) => {
console.log('newFilePath',newFilePath.fullPath) console.log('newFilePath', newFilePath.fullPath);
plus.runtime.install(newFilePath.fullPath, { force: false }, plus.runtime.install(
d => { newFilePath.fullPath,
{ force: false },
(d) => {
console.log('install success...'); console.log('install success...');
plus.runtime.restart(); plus.runtime.restart();
}, },
e => { (e) => {
console.log(e) console.log(e);
console.error('install fail...'); console.error('install fail...');
} }
); );
}) });
}) });
}) });
} }
} }
}); });
@ -109,32 +106,33 @@ App.vue本身不是页面这里不能编写视图元素也就是没有<tem
confirmText: '立即更新', confirmText: '立即更新',
cancelText: '下次更新', cancelText: '下次更新',
content: res.message, content: res.message,
success: res => { success: (res) => {
if (res.confirm) { if (res.confirm) {
uni.showLoading('下载中...'); uni.showLoading('下载中...');
if (uni.getSystemInfoSync().platform == 'android') { if (uni.getSystemInfoSync().platform == 'android') {
uni.downloadFile({ uni.downloadFile({
url: downloadLink, url: downloadLink,
success: downloadResult => { success: (downloadResult) => {
if (downloadResult.statusCode == 200) { if (downloadResult.statusCode == 200) {
plus.io.resolveLocalFileSystemURL(downloadResult.tempFilePath, entry => { plus.io.resolveLocalFileSystemURL(downloadResult.tempFilePath, (entry) => {
entry.getParent(_oldFile=>{ entry.getParent((_oldFile) => {
entry.moveTo(_oldFile,'.apk',newFilePath=>{ entry.moveTo(_oldFile, '.apk', (newFilePath) => {
console.log('newFilePath',newFilePath.fullPath) console.log('newFilePath', newFilePath.fullPath);
plus.runtime.install(newFilePath.fullPath, { force: false }, plus.runtime.install(
d => { newFilePath.fullPath,
{ force: false },
(d) => {
console.log('install success...'); console.log('install success...');
plus.runtime.restart(); plus.runtime.restart();
}, },
e => { (e) => {
console.log(e) console.log(e);
console.error('install fail...'); console.error('install fail...');
} }
); );
}) });
}) });
}) });
} }
} }
}); });
@ -149,18 +147,18 @@ App.vue本身不是页面这里不能编写视图元素也就是没有<tem
}); });
} }
} }
}).catch((res)=>{
console.log(res)
}) })
.catch((res) => {
console.log(res);
});
}); });
// #endif // #endif
}); });
</script> </script>
<style lang="scss"> <style lang="scss">
@import "uview-plus/index.scss"; @import 'uview-plus/index.scss';
/** 每个页面公共css */ /** 每个页面公共css */
@import '@/commons/style/global.scss'; @import '@/commons/style/global.scss';
@ -169,4 +167,31 @@ App.vue本身不是页面这里不能编写视图元素也就是没有<tem
/** uni 组件样式覆盖 */ /** uni 组件样式覆盖 */
@import '@/commons/style/uni-overwrite.scss'; @import '@/commons/style/uni-overwrite.scss';
//
.my-coupon-item-list {
padding-bottom: 28upx;
.my-coupon-item-item {
&:not(:first-child) {
margin-top: 28upx;
}
.my-coupon-item-row-wrap {
.row {
display: flex;
&:not(:first-child) {
margin-top: 12upx;
}
.title {
width: 200upx;
font-size: 28upx;
color: #666;
}
.info {
flex: 1;
font-size: 28upx;
color: #333;
}
}
}
}
}
</style> </style>

View File

@ -0,0 +1,110 @@
<!-- 优惠券item -->
<template>
<view class="item">
<view class="header">
<text class="title">{{ item.title }}</text>
<text class="id">ID:83713</text>
</view>
<view class="content">
<slot></slot>
</view>
<view class="total-info">
<view class="item">
<text class="info">{{ item.giveNum }}</text>
<text class="title">总发放</text>
</view>
<view class="item">
<text class="info">{{ item.giftNum }}</text>
<text class="title">已领取</text>
</view>
<view class="item">
<text class="info">{{ item.useNum }}</text>
<text class="title">已使用</text>
</view>
<view class="item">
<text class="info">
<template v-if="item.giveNum == -10086">无限</template>
<template v-else>{{ item.leftNum }}</template>
</text>
<text class="title">剩余</text>
</view>
</view>
<view class="footer-wrap">
<view class="btn">
<u-button shape="circle">删除</u-button>
</view>
<view class="btn">
<u-button shape="circle" type="primary">编辑</u-button>
</view>
</view>
</view>
</template>
<script setup>
const props = defineProps({
item: {
type: Object,
default: {}
}
});
</script>
<style scoped lang="scss">
.item {
background-color: #fff;
border-radius: 20upx;
padding: 28upx;
.header {
display: flex;
justify-content: space-between;
.title {
font-size: 32upx;
color: #333;
}
.id {
font-size: 24upx;
color: #999;
background-color: #f8f8f8;
display: flex;
align-items: center;
justify-content: center;
padding: 0 8upx;
border-radius: 4upx;
}
}
.content {
margin-top: 28upx;
padding: 20upx;
background-color: #f8f8f8;
border-radius: 12upx;
}
.total-info {
display: flex;
.item {
flex: 1;
display: flex;
gap: 12upx;
align-items: center;
justify-content: center;
flex-direction: column;
.info {
font-weight: bold;
font-size: 28upx;
color: #333;
}
.title {
font-size: 24upx;
color: #999;
}
}
}
.footer-wrap {
display: flex;
justify-content: flex-end;
gap: 28upx;
.btn {
width: 200upx;
}
}
}
</style>

View File

@ -25,7 +25,7 @@ const props = defineProps({
}, },
shape: { shape: {
type: String, type: String,
default: 'squre' // squre circle default: 'circle' // squre circle
} }
}); });

View File

@ -141,10 +141,6 @@ function updateSelectGoods() {
} }
// //
const foods = defineModel('foods', {
type: [Array, String],
default: []
});
function confirmHandle() { function confirmHandle() {
confirmSelectGoods(); confirmSelectGoods();
popupShow.value = false; popupShow.value = false;
@ -162,7 +158,7 @@ function confirmSelectGoods() {
}); });
}); });
foods.value = selectGoodsCount.value.map((item) => item.id); modelValue.value = selectGoodsCount.value.map((item) => item.id);
} }
// //
@ -170,8 +166,8 @@ async function getProductListAjax() {
try { try {
const res = await getProductList(); const res = await getProductList();
res.forEach((item, index) => { res.forEach((item, index) => {
console.log('modelValue.value===', modelValue.value); // console.log('modelValue.value===', modelValue.value);
console.log('index===', item.id.includes(modelValue.value)); // console.log('index===', item.id.includes(modelValue.value));
if (modelValue.value.includes(item.id)) { if (modelValue.value.includes(item.id)) {
item.selected = true; item.selected = true;
} else { } else {
@ -226,6 +222,13 @@ onMounted(async () => {
font-size: 28upx; font-size: 28upx;
color: #999; color: #999;
} }
.t {
display: block;
max-width: 400upx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
} }
} }
} }

View File

@ -36,3 +36,15 @@ export function limitTimeDiscount(data) {
data data
}); });
} }
/**
* 限时折扣-分页
* @param {Object} params
*/
export function couponPage(params) {
return request({
url: `${urlType}/admin/coupon/page`,
method: "GET",
params
});
}

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"> <u-form label-position="top" labelWidth="200" :model="form" :rules="rules" ref="formRef">
<view class="card"> <view class="card">
<u-form-item label="活动名称" prop="title"> <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>
<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> <my-shop-select-w v-model:useType="form.useShopType" v-model:selShops="form.useShops"></my-shop-select-w>
</u-form-item> </u-form-item>
</view> </view>
@ -39,7 +39,7 @@
</u-form-item> </u-form-item>
<u-form-item label="优先级"> <u-form-item label="优先级">
<view class="center"> <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>
<view class="tips"> <view class="tips">
<text class="red-tips">数值越大排序越靠前重复时段下按照排序值最高的折扣使用</text> <text class="red-tips">数值越大排序越靠前重复时段下按照排序值最高的折扣使用</text>
@ -48,7 +48,7 @@
<u-form-item label="限时折扣优先级"> <u-form-item label="限时折扣优先级">
<u-radio-group v-model="form.discountPriority" placement="column"> <u-radio-group v-model="form.discountPriority" placement="column">
<u-radio label="优先使用限时折扣价" name="limit-time"></u-radio> <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-radio-group>
</u-form-item> </u-form-item>
</view> </view>
@ -63,14 +63,13 @@
</template> </template>
<script setup> <script setup>
import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';
dayjs.extend(customParseFormat); //
import { ref } from 'vue'; import { ref } from 'vue';
import { onLoad } from '@dcloudio/uni-app'; 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'; import { limitTimeDiscount } from '@/http/api/market/index.js';
const shopInfo = ref({});
const inputStyle = ref({ const inputStyle = ref({
paddingLeft: 0 paddingLeft: 0
}); });
@ -85,11 +84,11 @@ const form = ref({
useShops: [], // useShops: [], //
validStartTime: '', // validStartTime: '', //
validEndTime: '', // validEndTime: '', //
useDays: ['周一', '周二', '周三'], // ,,,,,, useDays: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'], // ,,,,,,
useTimeType: 'all', // all-custom- useTimeType: 'all', // all-custom-
useStartTime: '', // useStartTime: '', //
useEndTime: '', // 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 discountRate: '', // % 1-99
sort: '', // sort: '', //
discountPriority: 'limit-time', // limit-time/vip-price discountPriority: 'limit-time', // limit-time/vip-price
@ -213,35 +212,16 @@ function discountRateInput(e) {
}, 50); }, 50);
} }
/** //
* 时间格式互转HH:mm HH:mm:ssHH:mm:ss HH:mm function sortInput(e) {
* @param {string} timeStr - 输入的时间字符串 setTimeout(() => {
* @returns {string} 转换后的时间字符串 form.value.sort = filterNumberInput(e, 0);
*/ }, 50);
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 submitHandle() { function submitHandle() {
// console.log('form', form.value); console.log('前置form', form.value);
formRef.value formRef.value
.validate() .validate()
.then(async (res) => { .then(async (res) => {
@ -254,8 +234,10 @@ function submitHandle() {
data.useDays = form.value.useDays.join(','); data.useDays = form.value.useDays.join(',');
data.useType = form.value.useType.join(','); data.useType = form.value.useType.join(',');
data.foods = form.value.foods.join(','); data.foods = form.value.foods.join(',');
if (form.value.useTimeType == 'custom') {
data.useStartTime = convertTimeFormat(form.value.useStartTime); data.useStartTime = convertTimeFormat(form.value.useStartTime);
data.useEndTime = convertTimeFormat(form.value.useEndTime); data.useEndTime = convertTimeFormat(form.value.useEndTime);
}
uni.showLoading({ uni.showLoading({
title: '提交中...', title: '提交中...',
@ -263,7 +245,7 @@ function submitHandle() {
}); });
await limitTimeDiscount(data); await limitTimeDiscount(data);
uni.showToast({ uni.showToast({
title: '添加成功', title: '保存成功',
icon: 'none' icon: 'none'
}); });
setTimeout(() => { setTimeout(() => {
@ -285,7 +267,11 @@ function submitHandle() {
function getLocalLimitDiscount() { function getLocalLimitDiscount() {
const data = uni.getStorageSync('limitDiscountObj'); const data = uni.getStorageSync('limitDiscountObj');
if (data.id) { if (data.id) {
// uni.setStorageSync('limitDiscountObj', ''); uni.setNavigationBarTitle({
title: '编辑限时折扣'
});
uni.setStorageSync('limitDiscountObj', '');
data.useShops = data.useShops.split(','); data.useShops = data.useShops.split(',');
data.useDays = data.useDays.split(','); data.useDays = data.useDays.split(',');
data.useType = data.useType.split(','); data.useType = data.useType.split(',');
@ -301,6 +287,7 @@ function getLocalLimitDiscount() {
} }
onLoad(() => { onLoad(() => {
shopInfo.value = uni.getStorageSync('shopInfo');
getLocalLimitDiscount(); getLocalLimitDiscount();
}); });
</script> </script>

View File

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

View File

@ -636,7 +636,8 @@
"pageId": "PAGES_MARKET_DISTRIBUTION_INDEX", "pageId": "PAGES_MARKET_DISTRIBUTION_INDEX",
"path": "distribution/index", "path": "distribution/index",
"style": { "style": {
"navigationBarTitleText": "分销"} "navigationBarTitleText": "分销"
}
}, },
{ {
"pageId": "PAGES_LIMIT_DISCOUNT_ADD", "pageId": "PAGES_LIMIT_DISCOUNT_ADD",
@ -644,6 +645,20 @@
"style": { "style": {
"navigationBarTitleText": "添加限时折扣" "navigationBarTitleText": "添加限时折扣"
} }
},
{
"pageId": "PAGES_EXCHANGE_COUPON",
"path": "exchangeCoupon/index",
"style": {
"navigationBarTitleText": "商品兑换券"
}
},
{
"pageId": "PAGES_ADD_COUPON",
"path": "addCoupon/index",
"style": {
"navigationBarTitleText": "添加优惠券"
}
} }
] ]
}, },

View File

@ -5,12 +5,7 @@
<text class="t">{{ item.label }}</text> <text class="t">{{ item.label }}</text>
</view> </view>
<view class="menu-wrap"> <view class="menu-wrap">
<view <view class="item" v-for="(val, i) in item.menus" :key="i" @click="go.to(val.pageUrl, val.query)">
class="item"
v-for="(val, i) in item.menus"
:key="i"
@click="go.to(val.pageUrl)"
>
<image :src="val.icon" mode="aspectFit" class="icon"></image> <image :src="val.icon" mode="aspectFit" class="icon"></image>
<view class="info"> <view class="info">
<view class="title"> <view class="title">
@ -27,125 +22,139 @@
</template> </template>
<script setup> <script setup>
import { ref, computed } from "vue"; import { ref, computed } from 'vue';
import go from "@/commons/utils/go.js"; import go from '@/commons/utils/go.js';
import { useMenusStore } from "@/store/menus.js"; import { useMenusStore } from '@/store/menus.js';
const menusStore = useMenusStore(); const menusStore = useMenusStore();
const menuList = ref([ const menuList = ref([
{ {
label: "营销", label: '营销',
menus: [ menus: [
{ {
title: "霸王餐", title: '霸王餐',
icon: "", icon: '',
intro: "设置充值消费的N倍当前订单立即免单", intro: '设置充值消费的N倍当前订单立即免单',
pageUrl: "PAGES_BWC", pageUrl: 'PAGES_BWC'
}, },
{ {
title: "积分锁客", title: '积分锁客',
icon: "", icon: '',
pageUrl: "", pageUrl: '',
intro: "设置充值消费的N倍当前订单立即免单", intro: '设置充值消费的N倍当前订单立即免单'
}, },
{ {
title: "弹窗广告", title: '弹窗广告',
icon: "", icon: '',
pageUrl: "PAGES_ORDER_INDEX", pageUrl: 'PAGES_ORDER_INDEX',
intro: "设置弹窗广告", intro: '设置弹窗广告'
}, },
{ {
title: "超级会员", title: '超级会员',
icon: "", icon: '',
pageUrl: "PAGES_ORDER_INDEX", pageUrl: 'PAGES_ORDER_INDEX',
intro: "用户会员管理设置", intro: '用户会员管理设置'
}, },
{ {
title: "新客立减", title: '新客立减',
icon: "", icon: '',
pageUrl: "PAGES_ORDER_INDEX", pageUrl: 'PAGES_ORDER_INDEX',
intro: "首单下单减免金额", intro: '首单下单减免金额'
}, },
{ {
title: "智慧充值", title: '智慧充值',
icon: "", icon: '',
pageUrl: "PAGES_ORDER_INDEX", pageUrl: 'PAGES_ORDER_INDEX',
intro: "允许客户充值并使用余额支付", intro: '允许客户充值并使用余额支付'
}, },
{ {
title: "分销", title: '分销',
icon: "", icon: '',
pageUrl: "PAGES_MARKET_DISTRIBUTION_INDEX", pageUrl: 'PAGES_MARKET_DISTRIBUTION_INDEX',
intro: "用户成为业务员,可促进消费", intro: '用户成为业务员,可促进消费'
}, },
{ {
title: "消费返现", title: '消费返现',
icon: "", icon: '',
pageUrl: "PAGES_MARKET_CONSUME_CASHBACK", pageUrl: 'PAGES_MARKET_CONSUME_CASHBACK',
intro: "用户下单后返现一定的金额到余额,可促进复购", intro: '用户下单后返现一定的金额到余额,可促进复购'
}, },
{ {
title: "私域引流", title: '私域引流',
icon: "", icon: '',
pageUrl: "PAGES_MARKET_DRAINAGE_CONFIG", pageUrl: 'PAGES_MARKET_DRAINAGE_CONFIG',
intro: "可设置用户下单成功后的群二维码", intro: '可设置用户下单成功后的群二维码'
}, },
{ {
title: "满减活动", title: '满减活动',
icon: "", icon: '',
pageUrl: "PAGES_MARKET_DISCOUNT_ACTIVITY", pageUrl: 'PAGES_MARKET_DISCOUNT_ACTIVITY',
intro: "达到指定支付金额享受减价", intro: '达到指定支付金额享受减价'
}, },
{ {
title: "生日有礼", title: '生日有礼',
icon: "", icon: '',
pageUrl: "", pageUrl: '',
intro: "用户生日管理设置", intro: '用户生日管理设置'
}, },
{ {
title: "点餐智能推荐", title: '点餐智能推荐',
icon: "", icon: '',
pageUrl: "", pageUrl: '',
intro: "进入点单页X秒未点自动推荐商品此推荐设置启用即生效", intro: '进入点单页X秒未点自动推荐商品此推荐设置启用即生效'
}, },
{ {
title: "超值券包", title: '超值券包',
icon: "", icon: '',
pageUrl: "", pageUrl: '',
intro: "下单加购", intro: '下单加购'
}, },
{ {
title: "套餐推广", title: '套餐推广',
icon: "", icon: '',
pageUrl: "", pageUrl: '',
intro: "下单通过用户邀请好友减免金额的方式裂变宣传套餐加购", intro: '下单通过用户邀请好友减免金额的方式裂变宣传套餐加购'
}, },
{ {
title: "充值兑换码", title: '充值兑换码',
icon: "", icon: '',
pageUrl: "", pageUrl: '',
intro: "兑换码直充余额,可当作礼品赠送", intro: '兑换码直充余额,可当作礼品赠送'
}, },
{ {
title: "券兑换码", title: '券兑换码',
icon: "", icon: '',
pageUrl: "", pageUrl: '',
intro: "可添加多券组合兑换", intro: '可添加多券组合兑换'
}, },
{ {
icon: "xszk", icon: 'xszk',
pageUrl: "PAGES_LIMIT_DISCOUNT", pageUrl: 'PAGES_LIMIT_DISCOUNT',
title: "限时折扣", title: '限时折扣',
intro: "批量设置商品折扣", intro: '批量设置商品折扣'
}, },
{ {
icon: "xszk", icon: 'xszk',
pageUrl: "PAGES_LIMIT_DISCOUNT", pageUrl: 'PAGES_LIMIT_DISCOUNT',
title: "商品拼团", title: '商品拼团',
intro: "拼团", intro: '拼团'
}, }
], ]
}, },
{
label: '优惠券',
menus: [
{
icon: 'spdhq',
pageUrl: 'PAGES_EXCHANGE_COUPON',
title: '商品兑换券',
intro: '批量设置商品折扣',
query: {
coupon_type: 2
}
}
]
}
]); ]);
console.log(menusStore.adminPages); console.log(menusStore.adminPages);
@ -155,10 +164,8 @@ const computedMenus = computed(() => {
// }); // });
return menuList.value.map((v) => { return menuList.value.map((v) => {
v.menus = v.menus.filter((menu) => { v.menus = v.menus.filter((menu) => {
const hasPermission = menusStore.adminPages.find( const hasPermission = menusStore.adminPages.find((navItem) => navItem.title == menu.title);
(navItem) => navItem.title == menu.title console.log('hasPermission', hasPermission);
);
console.log("hasPermission", hasPermission);
if (hasPermission) { if (hasPermission) {
menu.icon = hasPermission.miniIcon; menu.icon = hasPermission.miniIcon;
console.log(menu); console.log(menu);
@ -178,10 +185,10 @@ page {
</style> </style>
<style scoped lang="scss"> <style scoped lang="scss">
.container { .container {
padding: 28upx; padding: 0 28upx;
.row { .row {
.header { .header {
padding-bottom: 28upx; padding: 28upx 0;
.t { .t {
font-size: 32upx; font-size: 32upx;
font-weight: bold; font-weight: bold;

View File

@ -1,3 +1,7 @@
import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';
dayjs.extend(customParseFormat); // 注册插件
/** /**
* 过滤输入只允许数字和最多两位小数 * 过滤输入只允许数字和最多两位小数
* @param {string} value - 输入框当前值 * @param {string} value - 输入框当前值
@ -42,3 +46,29 @@ export function filterNumberInput(value, isIntegerOnly = false) {
return filtered; return filtered;
} }
/**
* 时间格式互转HH:mm HH:mm:ssHH:mm:ss HH:mm
* @param {string} timeStr - 输入的时间字符串
* @returns {string} 转换后的时间字符串
*/
export 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';
};