完成积分锁客模块

This commit is contained in:
gyq
2025-12-12 10:32:42 +08:00
parent 214026e859
commit f954bbd145
8 changed files with 399 additions and 21 deletions

View File

@@ -54,6 +54,7 @@ const numValue = computed(() => {
num = 0;
return num;
}
return num;
});
const emits = defineEmits(['confirm', 'cancel']);

View File

@@ -119,3 +119,27 @@ export function goodsRecordRejectRefund(data) {
data
})
}
/**
* 积分:获取用户所有门店下积分列表
* @param {Object} data
*/
export function pointUserPage(data) {
return request({
url: `${MARKET_URL}/admin/points/userPage`,
method: "GET",
data
})
}
/**
* 积分:积分详情
* @param {Object} data
*/
export function pointUserRecord(data) {
return request({
url: `${MARKET_URL}/admin/points/userRecord`,
method: "GET",
data
})
}

View File

@@ -15,7 +15,7 @@
<image class="img" :src="item.goodsImageUrl" mode="aspectFill"></image>
</view>
<view class="icon border" v-if="includesString(item.goodsCategory, '优惠券')">
<couponIcon :item="item.couponInfo" typeKey="couponType" />
<couponIcon :item="item.couponInfo" typeKey="couponType" v-if="item.couponInfo" />
</view>
<view class="info-wrap">
<text class="name">{{ item.goodsName }}</text>

View File

@@ -20,7 +20,7 @@
<image class="img" :src="item.goodsImageUrl" mode="aspectFill"></image>
</view>
<view class="icon border" v-if="includesString(item.goodsCategory, '优惠券')">
<couponIcon :item="item.couponInfo" typeKey="couponType" />
<couponIcon :item="item.couponInfo" typeKey="couponType" v-if="item.couponInfo" />
</view>
<view class="info-wrap">
<text class="name">{{ item.pointsGoodsName }}</text>
@@ -176,27 +176,32 @@ function checkoutHandle(item) {
uni.showModal({
title: '注意',
content: `确认要核销吗?`,
success: async (res) => {
try {
success: (res) => {
if (res.confirm) {
checkoutAjax(item.couponCode);
}
}
});
}
// 核销请求
async function checkoutAjax(couponCode) {
try {
uni.showLoading({
title: '核销中...',
mask: true
});
await goodsRecordCkecout(item.couponCode);
await goodsRecordCkecout(couponCode);
goodsRecordPageAjax();
uni.showToast({
title: '已核销',
icon: 'none'
});
}
} catch (error) {
console.log(error);
}
uni.hideLoading();
}
});
}
const refundLoading = ref(false);
const showRefundPopup = ref(false);
@@ -264,7 +269,8 @@ async function goodsRecordPageAjax(page = listData.page) {
defineExpose({
reachBottom,
goodsRecordPageAjax
goodsRecordPageAjax,
checkoutAjax
});
onMounted(() => {

View File

@@ -0,0 +1,147 @@
<template>
<view>
<view class="list">
<view class="item" v-for="item in listData.list" :key="item.id">
<view class="top">
<text class="t">用户ID{{ item.userId }}</text>
</view>
<view class="user-info">
<view class="left">
<u-avatar :src="item.headImg" shape="square" :size="50"></u-avatar>
<view class="info">
<text class="t">{{ item.nickName }}</text>
<text class="t">{{ item.phone }}</text>
</view>
</view>
<view class="right">
<text class="t1">当前积分</text>
<text class="t2">{{ item.pointBalance }}</text>
</view>
</view>
<view class="footer-wrap">
<view class="btn" @click="toDetail(item)">
<u-text type="primary" text="查看明细"></u-text>
</view>
</view>
</view>
</view>
<u-loadmore :status="listData.status"></u-loadmore>
</view>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import { pointUserPage } from '@/http/api/market/point.js';
const listData = reactive({
page: 1,
size: 10,
status: 'loading',
list: []
});
function reachBottom() {
if (listData.status != 'nomore') {
listData.page++;
pointUserPageAjax();
}
}
// 获取用户所有门店下积分列表
async function pointUserPageAjax(page = listData.page) {
try {
const res = await pointUserPage({
page: page,
size: listData.size
});
if (listData.page == 1) {
listData.list = res.records;
} else {
listData.list.push(...res.records);
}
if (res.pageNumber >= res.totalPage) {
listData.status = 'nomore';
}
} catch (error) {
console.log(error);
}
}
// 去积分详情
function toDetail(item) {
uni.navigateTo({
url: `/pageMarket/points/userPointDetail?id=${item.id}&nickName=${item.nickName}&phone=${item.phone}`
});
}
defineExpose({
reachBottom
});
onMounted(() => {
pointUserPageAjax();
});
</script>
<style scoped lang="scss">
.list {
padding-bottom: 28upx;
.item {
background-color: #fff;
border-radius: 20upx;
padding: 28upx;
&:not(:first-child) {
margin-top: 28upx;
}
.top {
display: flex;
align-items: center;
justify-content: space-between;
.t {
font-size: 28upx;
color: #999;
}
}
.user-info {
display: flex;
padding: 28upx 0;
.left {
flex: 1;
display: flex;
.info {
flex: 1;
display: flex;
justify-content: center;
flex-direction: column;
padding-left: 10px;
.t {
font-size: 28upx;
color: #333;
}
}
}
.right {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.t1 {
font-size: 28upx;
color: #666;
}
.t2 {
color: #333;
font-size: 32upx;
font-weight: bold;
}
}
}
.footer-wrap {
display: flex;
justify-content: flex-end;
}
}
}
</style>

View File

@@ -12,6 +12,7 @@
<setting ref="settingRef" name="setting" key="setting" v-if="tabsActive == 0" />
<productPage ref="productPageRef" name="productPage" key="productPage" v-if="tabsActive == 1" />
<record ref="recordRef" name="record" key="record" :top="headHeight + 54" v-if="tabsActive == 2" />
<userRecord ref="userRecordRef" name="userRecord" key="userRecord" v-if="tabsActive == 3" />
</view>
<view class="tab-wrap" :style="{ top: `${headHeight}px` }">
<view class="tab-list">
@@ -22,6 +23,7 @@
</view>
<my-footer-btn type="horizontal" showCancel @confirm="settingRef.submitHandle()" @cancel="backHandle" v-if="tabsActive == 0"></my-footer-btn>
<my-footer-btn confirmText="添加商品" type="horizontal" @confirm="toAddProduct" v-if="tabsActive == 1"></my-footer-btn>
<my-footer-btn confirmText="扫码核销" v-if="tabsActive == 2" @confirm="scanHandle"></my-footer-btn>
</view>
</template>
@@ -31,13 +33,15 @@ import { onLoad, onShow, onReachBottom } from '@dcloudio/uni-app';
import setting from './components/setting.vue';
import productPage from './components/productPage.vue';
import record from './components/record.vue';
import userRecord from './components/userRecord.vue';
const settingRef = ref(null);
const productPageRef = ref(null);
const recordRef = ref(null);
const userRecordRef = ref(null);
const headHeight = ref(0);
const tabsActive = ref(2);
const tabsActive = ref(3);
const tabs = ref([
{
value: 1,
@@ -71,6 +75,16 @@ function toAddProduct() {
});
}
// 扫码核销
function scanHandle() {
uni.scanCode({
success: (res) => {
console.log('扫码核销===', res.result);
recordRef.value.checkoutAjax(res.result);
}
});
}
onReachBottom(() => {
switch (tabsActive.value) {
case 0:
@@ -82,6 +96,7 @@ onReachBottom(() => {
recordRef.value.reachBottom();
break;
case 3:
userRecordRef.value.reachBottom();
break;
default:
break;

View File

@@ -0,0 +1,178 @@
<template>
<view>
<view class="header-wrap">
<view class="item">
<text class="t">用户昵称 {{ listData.nickName }}</text>
</view>
<view class="item">
<text class="t">当前积分 {{ listData.phone }}</text>
</view>
</view>
<view class="list">
<view class="item" v-for="item in listData.list" :key="item.id">
<view class="top">
<text class="t">{{ item.content }}</text>
</view>
<view class="user-info">
<view class="left">
<view class="info">
<text class="t1">{{ item.shopName }}</text>
<text class="t2">{{ item.createTime }}</text>
</view>
</view>
<view class="right">
<text class="t1">{{ item.floatPoints }}</text>
<text class="t2">变动后积分{{ item.balancePoints }}</text>
</view>
</view>
</view>
<u-loadmore :status="listData.status"></u-loadmore>
</view>
</view>
</template>
<script setup>
import { reactive } from 'vue';
import { onLoad, onReachBottom } from '@dcloudio/uni-app';
import { pointUserRecord } from '@/http/api/market/point.js';
const listData = reactive({
nickName: '',
phone: '',
id: '',
page: 1,
size: 10,
status: 'loading',
list: []
});
onReachBottom(() => {
if (listData.status != 'nomore') {
listData.page++;
pointUserRecordAjax();
}
});
// 获取用户所有门店下积分列表
async function pointUserRecordAjax() {
try {
const res = await pointUserRecord({
page: listData.page,
size: listData.size,
id: listData.id
});
if (listData.page == 1) {
listData.list = res.records;
} else {
listData.list.push(...res.records);
}
if (res.pageNumber >= res.totalPage) {
listData.status = 'nomore';
}
} catch (error) {
console.log(error);
}
}
onLoad((options) => {
listData.id = options.id;
listData.nickName = options.nickName;
listData.phone = options.phone;
pointUserRecordAjax();
});
</script>
<style>
page {
background-color: #f8f8f8;
}
</style>
<style scoped lang="scss">
.header-wrap {
width: 100%;
height: 53px;
position: fixed;
top: 0;
left: 0;
z-index: 999;
background-color: #fff;
padding: 0 28upx;
display: flex;
align-items: center;
justify-content: space-between;
.item {
flex: 1;
&:last-child {
display: flex;
justify-content: flex-end;
}
.t {
font-size: 28upx;
color: #333;
}
}
}
.list {
padding: calc(53px + 28upx) 28upx 28upx;
.item {
background-color: #fff;
border-radius: 20upx;
padding: 28upx;
&:not(:first-child) {
margin-top: 28upx;
}
.top {
display: flex;
align-items: center;
justify-content: space-between;
.t {
font-size: 32upx;
color: #333;
}
}
.user-info {
display: flex;
padding: 28upx 0;
.left {
flex: 1;
display: flex;
.info {
flex: 1;
display: flex;
justify-content: center;
flex-direction: column;
.t1 {
font-size: 28upx;
color: #333;
}
.t2 {
font-size: 24upx;
color: #666;
}
}
}
.right {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.t1 {
font-size: 32upx;
color: #333;
font-weight: bold;
}
.t2 {
color: #666;
font-size: 24upx;
}
}
}
.footer-wrap {
display: flex;
justify-content: flex-end;
}
}
}
</style>

View File

@@ -822,6 +822,13 @@
"style": {
"navigationBarTitleText": "添加商品"
}
},
{
"pageId": "PAGES_MARKET_POINTS_USER_POINT_DETAIL",
"path": "points/userPointDetail",
"style": {
"navigationBarTitleText": "查看明细"
}
}
]
},