新增部分优惠券页面

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

219
App.vue
View File

@ -3,59 +3,54 @@
App.vue本身不是页面这里不能编写视图元素也就是没有<template>
-->
<script setup>
import { onLaunch } from '@dcloudio/uni-app';
import { getVersion } from '@/http/api/index.js'
import appConfig from '@/config/appConfig.js';
import { provide,onMounted } from 'vue';
import WebsocketUtil from '@/commons/utils/websocket.js'
const websocketUtil = new WebsocketUtil(appConfig.wss, 5000); // WebSocket
provide('websocketUtil', websocketUtil); //
onMounted(() => {
import { onLaunch } from '@dcloudio/uni-app';
import { getVersion } from '@/http/api/index.js';
import appConfig from '@/config/appConfig.js';
import { provide, onMounted } from 'vue';
import WebsocketUtil from '@/commons/utils/websocket.js';
const websocketUtil = new WebsocketUtil(appConfig.wss, 5000); // WebSocket
provide('websocketUtil', websocketUtil); //
onMounted(() => {});
onLaunch(() => {
// console.log console.info
// if (uni.getSystemInfoSync().platform !== "devtools") {
// console.log = () => {};
// console.info = () => {};
// }
let that = this;
uni.hideTabBar();
// #ifdef MP-WEIXIN
const updateManager = wx.getUpdateManager(); //
updateManager.onCheckForUpdate(function (res) {
//
});
onLaunch(() => {
// console.log console.info
// if (uni.getSystemInfoSync().platform !== "devtools") {
// console.log = () => {};
// console.info = () => {};
// }
let that = this
uni.hideTabBar()
// #ifdef MP-WEIXIN
const updateManager = wx.getUpdateManager() //
updateManager.onCheckForUpdate(function(res) {
//
})
updateManager.onUpdateReady(function() {
// applyUpdate
updateManager.applyUpdate()
updateManager.onUpdateReady(function () {
// applyUpdate
updateManager.applyUpdate();
});
updateManager.onUpdateFailed(function () {
//
});
// #endif
// console.log("getSystemSetting==",uni.getSystemInfoSync())
// console.log("getSystemSetting==",uni.getSystemSetting())
})
updateManager.onUpdateFailed(function() {
//
})
// #endif
// console.log("getSystemSetting==",uni.getSystemInfoSync())
// console.log("getSystemSetting==",uni.getSystemSetting())
//#ifdef APP-PLUS
//
plus.runtime.getProperty(plus.runtime.appid, widgetInfo => {
//
console.log("widgetInfo==",widgetInfo)
let type = uni.getSystemInfoSync().platform == 'ios' ? 2 : 1
getVersion({source:'manager_app',type: type}).then(res => {
console.log("selectNewApp==",res)
console.log("version===",res.url && widgetInfo.version < res.version)
//#ifdef APP-PLUS
//
plus.runtime.getProperty(plus.runtime.appid, (widgetInfo) => {
//
console.log('widgetInfo==', widgetInfo);
let type = uni.getSystemInfoSync().platform == 'ios' ? 2 : 1;
getVersion({ source: 'manager_app', type: type })
.then((res) => {
console.log('selectNewApp==', res);
console.log('version===', 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 = "https://short-video.hnsiyao.cn/app/sy-duanju.apk";
console.log(downloadLink)
console.log(downloadLink);
// let androidLink = res.androidWgtUrl;
// let iosLink = res.iosWgtUrl;
let ready = false;
@ -66,37 +61,39 @@ App.vue本身不是页面这里不能编写视图元素也就是没有<tem
title: '发现新版本',
confirmText: '立即更新',
content: res.message,
success: res => {
success: (res) => {
if (res.confirm) {
uni.showLoading('下载中...');
if (uni.getSystemInfoSync().platform == 'android') {
uni.downloadFile({
url: downloadLink,
success: downloadResult => {
success: (downloadResult) => {
if (downloadResult.statusCode === 200) {
plus.io.resolveLocalFileSystemURL(downloadResult.tempFilePath, entry => {
entry.getParent(_oldFile=>{
entry.moveTo(_oldFile,'.apk',newFilePath=>{
console.log('newFilePath',newFilePath.fullPath)
plus.runtime.install(newFilePath.fullPath, { force: false },
d => {
console .log( 'install success...' );
plus.runtime .restart();
plus.io.resolveLocalFileSystemURL(downloadResult.tempFilePath, (entry) => {
entry.getParent((_oldFile) => {
entry.moveTo(_oldFile, '.apk', (newFilePath) => {
console.log('newFilePath', newFilePath.fullPath);
plus.runtime.install(
newFilePath.fullPath,
{ force: false },
(d) => {
console.log('install success...');
plus.runtime.restart();
},
e => {
console.log(e)
console .error( 'install fail...' );
(e) => {
console.log(e);
console.error('install fail...');
}
);
})
})
})
});
});
});
}
}
});
}
if (uni.getSystemInfoSync().platform == 'ios') {
plus.runtime.openURL(downloadLink, function( res) {});
plus.runtime.openURL(downloadLink, function (res) {});
}
} else if (res.cancel) {
console.log('取消');
@ -109,38 +106,39 @@ App.vue本身不是页面这里不能编写视图元素也就是没有<tem
confirmText: '立即更新',
cancelText: '下次更新',
content: res.message,
success: res => {
success: (res) => {
if (res.confirm) {
uni.showLoading('下载中...');
if (uni.getSystemInfoSync().platform == 'android') {
uni.downloadFile({
url: downloadLink,
success: downloadResult => {
success: (downloadResult) => {
if (downloadResult.statusCode == 200) {
plus.io.resolveLocalFileSystemURL(downloadResult.tempFilePath, entry => {
entry.getParent(_oldFile=>{
entry.moveTo(_oldFile,'.apk',newFilePath=>{
console.log('newFilePath',newFilePath.fullPath)
plus.runtime.install(newFilePath.fullPath, { force: false },
d => {
console.log('install success...');
plus.runtime.restart();
},
e => {
console.log(e)
console.error('install fail...');
}
);
})
})
})
plus.io.resolveLocalFileSystemURL(downloadResult.tempFilePath, (entry) => {
entry.getParent((_oldFile) => {
entry.moveTo(_oldFile, '.apk', (newFilePath) => {
console.log('newFilePath', newFilePath.fullPath);
plus.runtime.install(
newFilePath.fullPath,
{ force: false },
(d) => {
console.log('install success...');
plus.runtime.restart();
},
(e) => {
console.log(e);
console.error('install fail...');
}
);
});
});
});
}
}
});
}
if (uni.getSystemInfoSync().platform == 'ios') {
plus.runtime.openURL(downloadLink, function( res) {});
plus.runtime.openURL(downloadLink, function (res) {});
}
} else if (res.cancel) {
console.log('取消');
@ -149,24 +147,51 @@ App.vue本身不是页面这里不能编写视图元素也就是没有<tem
});
}
}
}).catch((res)=>{
console.log(res)
})
});
// #endif
.catch((res) => {
console.log(res);
});
});
// #endif
});
</script>
<style lang="scss">
@import "uview-plus/index.scss";
@import 'uview-plus/index.scss';
/** 每个页面公共css */
@import '@/commons/style/global.scss';
@import '@/commons/style/common.scss';
/** 每个页面公共css */
@import '@/commons/style/global.scss';
@import '@/commons/style/common.scss';
/** uni 组件样式覆盖 */
@import '@/commons/style/uni-overwrite.scss';
/** uni 组件样式覆盖 */
@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>

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: {
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() {
confirmSelectGoods();
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 {
const res = await getProductList();
res.forEach((item, index) => {
console.log('modelValue.value===', modelValue.value);
console.log('index===', item.id.includes(modelValue.value));
// console.log('modelValue.value===', modelValue.value);
// console.log('index===', item.id.includes(modelValue.value));
if (modelValue.value.includes(item.id)) {
item.selected = true;
} else {
@ -226,6 +222,13 @@ onMounted(async () => {
font-size: 28upx;
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
});
}
/**
* 限时折扣-分页
* @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">
<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
}
}

View File

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

View File

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

View File

@ -1,3 +1,7 @@
import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';
dayjs.extend(customParseFormat); // 注册插件
/**
* 过滤输入只允许数字和最多两位小数
* @param {string} value - 输入框当前值
@ -42,3 +46,29 @@ export function filterNumberInput(value, isIntegerOnly = false) {
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';
};