feat:商户活动
This commit is contained in:
1 parent
1a7a6ec54d
commit
50b8652a64
6 files changed
+128
-63
No files matched your search
@@ -23,21 +23,28 @@
|
||||
<text class="file-size">{{ formatFileSize(file.size) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<tm-button v-if="noticeId == '1969326082705055746'" class="px-2 my-4" block @click="goGetCoupon">去 领 券</tm-button>
|
||||
<tm-button v-if="actDetail" class="px-2 my-4" block @click="goGetCoupon">去 领 券</tm-button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from "vue"
|
||||
import { onLoad } from "@dcloudio/uni-app"
|
||||
import { noticeApi } from "@/sheep/api"
|
||||
import { actCancel, noticeApi } from "@/sheep/api"
|
||||
|
||||
const noticeId = ref("")
|
||||
const detail = ref<any>({})
|
||||
const actDetail = ref<any>({})
|
||||
|
||||
onLoad(async (option: any) => {
|
||||
const { id } = option
|
||||
if (!id) return uni.showToast({ title: "参数错误", icon: "error" })
|
||||
const { data = {} }: any = await actCancel.getDetailByNoticeId({ id })
|
||||
actDetail.value = data
|
||||
})
|
||||
|
||||
// 临时商户活动的通知公告跳转链接
|
||||
const goGetCoupon = () => {
|
||||
uni.navigateTo({ url: "/pages/merchant/merchant-activity" })
|
||||
uni.navigateTo({ url: `/pages/merchant/merchant-activity?actId=${actDetail.value.id}&mchId=${actDetail.value.mchId}` })
|
||||
}
|
||||
|
||||
const nodes = computed(() => {
|
||||
|
||||
@@ -1,13 +1,35 @@
|
||||
<template>
|
||||
<crud-layout mainIsScroll bg="/static/page/blue-bg.png">
|
||||
<z-paging ref="pageRef" height="100%" :fixed="false" v-model="pageHook.list" :default-page-size="10"
|
||||
safe-area-inset-bottom :loading-more-enabled="true" :show-scrollbar="false" @query="query"
|
||||
:auto-clean-list-when-reload="false" :auto-scroll-to-top-when-reload="false" @scroll="pageHook.scroll">
|
||||
<z-paging
|
||||
ref="pageRef"
|
||||
height="100%"
|
||||
:fixed="false"
|
||||
v-model="pageHook.list"
|
||||
:default-page-size="10"
|
||||
safe-area-inset-bottom
|
||||
:loading-more-enabled="true"
|
||||
:show-scrollbar="false"
|
||||
@query="query"
|
||||
:auto-clean-list-when-reload="false"
|
||||
:auto-scroll-to-top-when-reload="false"
|
||||
@scroll="pageHook.scroll"
|
||||
>
|
||||
<template #top>
|
||||
<tm-input class="mt-2" v-model="params.receiverUserName" type="text" height="72" minHeight="72"
|
||||
fontSize="28" :showClear="true" :focus="false" placeholder="请输入领取人姓名"
|
||||
style="border: 4rpx solid #0779fd; border-radius: 14rpx" :focus-highlight="false" color="#ECF4F9"
|
||||
@clear="inputClear">
|
||||
<tm-input
|
||||
class="mt-2"
|
||||
v-model="params.receiverUserName"
|
||||
type="text"
|
||||
height="72"
|
||||
minHeight="72"
|
||||
fontSize="28"
|
||||
:showClear="true"
|
||||
:focus="false"
|
||||
placeholder="请输入领取人姓名"
|
||||
style="border: 4rpx solid #0779fd; border-radius: 14rpx"
|
||||
:focus-highlight="false"
|
||||
color="#ECF4F9"
|
||||
@clear="inputClear"
|
||||
>
|
||||
<template v-slot:rightIcon>
|
||||
<tm-button class="mr-1 px-3 py-26rpx text-30rpx!" size="xs" @click="search">搜 索</tm-button>
|
||||
</template>
|
||||
@@ -17,18 +39,23 @@
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<view class="card w-full h-400rpx relative activity-card overflow-hidden mb-2 py-2"
|
||||
:style="{ backgroundColor: getActStatus(item.actStatus)?.color }" v-for="(item, index) in pageHook.list"
|
||||
:key="index">
|
||||
<view
|
||||
class="card w-full h-400rpx relative activity-card overflow-hidden mb-2 py-2"
|
||||
:style="{ backgroundColor: getActStatus(item.actStatus)?.color }"
|
||||
v-for="(item, index) in pageHook.list"
|
||||
:key="index"
|
||||
>
|
||||
<view class="ribbon" :style="{ backgroundColor: getActStatus(item.actStatus)?.color }">
|
||||
{{ getActStatus(item.actStatus)?.name }}
|
||||
</view>
|
||||
<view class="text-28 c-#fff text-right px-2">ID {{ item.id }}</view>
|
||||
<view class="flex justify-between font-bold mt-1 px-8">
|
||||
<text class="text-32 c-#FFD941">限时领取</text>
|
||||
<text class="text-30 c-#FFD941 px-1 rounded-full bg-#eeeeee44">2025-09-21~2025-12-20</text>
|
||||
<text class="text-30 c-#FFD941 px-1 rounded-full bg-#eeeeee44">
|
||||
{{ (item.actStartTime?.split(" ")[0] || "") + "~" + (item.actExpireTime?.split(" ")[0] || "") }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="w-4/5 py-2 text-28 c-#fff px-8">店内核销将会自动扣费1元并领取价值89元的速干T恤1件</view>
|
||||
<view class="w-4/5 py-2 text-28 c-#fff px-8">{{ item.actTitlel }}</view>
|
||||
<view class="absolute bottom-100 left-60 text-28 bg-#eeeeee44 c-#fff px-2 rounded-full">限量领取 先领先得</view>
|
||||
<view v-if="item.receiverTime" class="absolute bottom-40 right-20 text-22 c-#fff">
|
||||
<text class="mr-2">领取人 {{ item.receiverUsername }}</text>
|
||||
|
||||
@@ -1,25 +1,31 @@
|
||||
<template>
|
||||
<crud-layout mainIsScroll bg="/static/page/blue-bg.png">
|
||||
<view class="px-2 py-4">
|
||||
<view class="card w-full h-400rpx relative activity-card overflow-hidden">
|
||||
<view v-if="state.actId" class="px-2 py-4">
|
||||
<view class="card rounded-lb-0! rounded-rb-0! w-full h-400rpx relative activity-card overflow-hidden">
|
||||
<view class="ribbon">兑换券</view>
|
||||
<view class="px-8 pt-5 flex justify-between items-center font-bold">
|
||||
<text class="text-32 c-#FF4F3F">限时领取</text>
|
||||
<text class="text-30 c-#FF4F3F px-1 rounded-full bg-#eeeeee44">2025-09-21~2025-12-20</text>
|
||||
<text class="text-30 c-#FF4F3F px-1 rounded-full bg-#eeeeee44">
|
||||
{{ (state.couponDetail.startTime?.split(" ")[0] || "") + "~" + (state.couponDetail.expireTime?.split(" ")[0] || "") }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="w-4/5 px-8 pt-4 text-28 c-#fff">店内核销将会自动扣费1元并领取价值89元的速干T恤1件</view>
|
||||
<view class="absolute bottom-60 left-60 text-28 bg-#eeeeee44 c-#fff px-2 rounded-full">限量领取 先领先得</view>
|
||||
<view class="w-4/5 px-8 pt-4 text-28 c-#fff">{{ state.couponDetail.actTitle }}</view>
|
||||
<view class="absolute bottom-100 left-60 text-40 italic">
|
||||
<text class="color-red mr-2">¥{{ hooks.useMoney(state.couponDetail.activeCancelPrice) }}</text>
|
||||
<text class="text-30 line-through color-red">¥{{ hooks.useMoney(state.couponDetail.activeOrgPrice) }}</text>
|
||||
</view>
|
||||
<view class="absolute bottom-40 left-60 text-28 bg-#eeeeee44 c-#fff px-2 rounded-full">限量领取 先领先得</view>
|
||||
</view>
|
||||
<view v-if="couponInfo?.actStatus == '2'" class="text-center card p-3 sub-text-30">已 核 销</view>
|
||||
<view v-if="state.couponInfo.actStatus == '2'" class="text-center card rounded-lt-0! rounded-rt-0! p-3 sub-text-30">已 核 销</view>
|
||||
<template v-else>
|
||||
<view v-if="!isGet" class="text-center card p-3 sub-text-30" @tap="doGetCoupon">立 即 领 取</view>
|
||||
<view v-if="isGet" class="text-center card p-3 sub-text-30">已 领 取</view>
|
||||
<view v-if="!state.isGet" class="text-center card rounded-lt-0! rounded-rt-0! p-3 sub-text-30" @tap="getCoupon">立 即 领 取</view>
|
||||
<view v-if="state.isGet" class="text-center card rounded-lt-0! rounded-rt-0! p-3 sub-text-30">已 领 取</view>
|
||||
</template>
|
||||
</view>
|
||||
|
||||
<template #main-bottom>
|
||||
<view v-if="isGet" class="text-center">
|
||||
<tm-button class="px-32 m-2" @click="CouponVerification">我的核销码</tm-button>
|
||||
<view v-if="state.isGet" class="text-center">
|
||||
<tm-button class="px-32 m-2" @click="genVerificationCode">我的核销码</tm-button>
|
||||
</view>
|
||||
</template>
|
||||
</crud-layout>
|
||||
@@ -33,31 +39,55 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { actCancel } from "@/sheep/api"
|
||||
import { reactive, ref } from "vue"
|
||||
import { onLoad } from "@dcloudio/uni-app"
|
||||
import { ref } from "vue"
|
||||
import { actCancel } from "@/sheep/api"
|
||||
import uqrcode from "@@/utils/uqrcode"
|
||||
import * as CryptoJS from "crypto-js"
|
||||
import { hooks } from "@/sheep"
|
||||
|
||||
const isGet = ref(false) // 是否已领取
|
||||
const couponInfo = ref<any>({})
|
||||
const state = reactive<any>({
|
||||
actId: "",
|
||||
mchId: "",
|
||||
isGet: false, // 是否已领取
|
||||
couponDetail: {}, // 优惠券详情
|
||||
couponInfo: {}, // 优惠券信息
|
||||
})
|
||||
const showQrCodeDialog = ref(false)
|
||||
|
||||
onLoad(() => {
|
||||
onLoad((option: any) => {
|
||||
const { actId, mchId } = option
|
||||
if (!actId || !mchId) return uni.showToast({ title: "参数错误", icon: "error" })
|
||||
state.actId = actId
|
||||
state.mchId = mchId
|
||||
getCouponDetail()
|
||||
getCouponInfo()
|
||||
})
|
||||
|
||||
// 获取优惠券信息
|
||||
// 获取优惠券详情
|
||||
const getCouponDetail = async () => {
|
||||
try {
|
||||
const { data } = await actCancel.getDetailById({
|
||||
id: state.actId,
|
||||
mchId: state.mchId,
|
||||
})
|
||||
state.couponDetail = data
|
||||
} catch (error: any) {
|
||||
uni.showToast({ title: error, icon: "error" })
|
||||
}
|
||||
}
|
||||
|
||||
// 获取用户的唯一优惠券信息
|
||||
const getCouponInfo = async () => {
|
||||
try {
|
||||
uni.showLoading({ title: "加载中...", mask: true })
|
||||
const { code, data }: any = await actCancel.appFindUnique()
|
||||
if (code != 0) {
|
||||
isGet.value = false
|
||||
const { code, data }: any = await actCancel.appFindUnique({ actId: state.actId })
|
||||
if (!data) {
|
||||
state.isGet = false
|
||||
return
|
||||
}
|
||||
couponInfo.value = data
|
||||
isGet.value = true
|
||||
state.couponInfo = data
|
||||
state.isGet = true
|
||||
} catch (error) {
|
||||
uni.showToast({ title: "加载失败", icon: "none" })
|
||||
} finally {
|
||||
@@ -65,12 +95,16 @@ const getCouponInfo = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 领取兑换券
|
||||
const doGetCoupon = async () => {
|
||||
// 领取券
|
||||
const getCoupon = async () => {
|
||||
try {
|
||||
uni.showLoading({ title: "正在领取...", mask: true })
|
||||
await new Promise((resolve) => setTimeout(resolve, 2_000))
|
||||
const { code, msg }: any = await actCancel.appGet({ receiverUserId: uni.getStorageSync("user_info")?.sysUser?.userId })
|
||||
const { code, msg }: any = await actCancel.appGet({
|
||||
receiverUserId: uni.getStorageSync("user_info")?.sysUser?.userId,
|
||||
actId: state.actId,
|
||||
mchId: state.mchId,
|
||||
})
|
||||
if (code != 0) return uni.showToast({ title: msg || "领取失败", icon: "none", mask: true })
|
||||
uni.showToast({ title: "领取成功", icon: "success" })
|
||||
await getCouponInfo()
|
||||
@@ -81,10 +115,10 @@ const doGetCoupon = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 券核销
|
||||
const CouponVerification = async () => {
|
||||
// 生成核销二维码
|
||||
const genVerificationCode = async () => {
|
||||
showQrCodeDialog.value = true
|
||||
const words = CryptoJS.enc.Utf8.parse(JSON.stringify({ actId: couponInfo.value.id, totalPrice: 1 }))
|
||||
const words = CryptoJS.enc.Utf8.parse(JSON.stringify({ cancelId: state.couponInfo.id }))
|
||||
uqrcode.make({
|
||||
canvasId: "qrcodeId",
|
||||
text: CryptoJS.enc.Base64.stringify(words),
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<view v-if="mchDetail.id" class="card p-20rpx mt-10rpx mx-20rpx">
|
||||
<view class="w-full sub-text-32 truncate">{{ mchDetail.name }}</view>
|
||||
<text class="sub-text-24 c-#0094ff! px-2 bg-#0094ff22 rounded-2 mr-4">营业</text>
|
||||
<text class="second-text-24 truncate mt-1">营业人 {{ mchDetail.contactName }}·{{ mchDetail.contactPhone }}</text>
|
||||
<text class="second-text-24 truncate mt-1">营业人{{ mchDetail.contactName }} · {{ mchDetail.contactPhone }}</text>
|
||||
<view class="second-text-26 mt-1">
|
||||
<image class="w-24rpx h-24rpx mr-1" src="@/static/page/address.svg" />
|
||||
<text>{{ mchDetail.address }}</text>
|
||||
|
||||
+13
-14
@@ -2,10 +2,13 @@
|
||||
<crud-layout mainIsScroll bg="/static/page/blue-bg.png">
|
||||
<template #main-top>
|
||||
<view class="flex items-center py-3 px-5">
|
||||
<image v-if="state.userInfo?.sysUser?.avatar" class="size-100rpx rounded-full"
|
||||
:src="filePath(state.userInfo.sysUser.avatar)" mode="aspectFill" />
|
||||
<image v-else class="w-100rpx h-100rpx rounded-full" src="/static/icon/default-avatar.png"
|
||||
mode="aspectFill" />
|
||||
<image
|
||||
v-if="state.userInfo?.sysUser?.avatar"
|
||||
class="size-100rpx rounded-full"
|
||||
:src="filePath(state.userInfo.sysUser.avatar)"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
<image v-else class="w-100rpx h-100rpx rounded-full" src="/static/icon/default-avatar.png" mode="aspectFill" />
|
||||
<view class="ml-30rpx" v-if="state.userInfo?.sysUser?.userId">
|
||||
<view class="sub-text-30">{{ state.userInfo?.sysUser?.name }}</view>
|
||||
<view class="sub-text-26">ID {{ state.userInfo?.sysUser?.userId }}</view>
|
||||
@@ -18,8 +21,7 @@
|
||||
</template>
|
||||
|
||||
<view class="mt-10rpx rounded-20rpx shadow-main p-30rpx pb-40rpx bg-white">
|
||||
<view class="service_item flex items-center justify-between" v-for="(v, i) in state.menuList" :key="i"
|
||||
@tap="onTabMenu(v)">
|
||||
<view class="service_item flex items-center justify-between" v-for="(v, i) in state.menuList" :key="i" @tap="onTabMenu(v)">
|
||||
<view class="flex-row-center">
|
||||
<image class="size-40rpx" :src="v.icon" mode="aspectFill" />
|
||||
<text class="sub-text-28 m-l-20rpx">{{ v.text }}</text>
|
||||
@@ -29,15 +31,13 @@
|
||||
</view>
|
||||
|
||||
<view v-if="isDevEnv()" class="flex-col-center mt-40rpx mx-30rpx">
|
||||
<view class="w-full text-center sub-text-28 p-y-20rpx rounded-40rpx border-solid border border-#0094ff"
|
||||
@tap="doLogout">
|
||||
<view class="w-full text-center sub-text-28 p-y-20rpx rounded-40rpx border-solid border border-#0094ff" @tap="doLogout">
|
||||
退出登录
|
||||
</view>
|
||||
</view>
|
||||
<view class="h-30rpx" />
|
||||
<view v-if="state.appInfo == APPENV.SH" class="flex-col-center mt-40rpx mx-30rpx">
|
||||
<view class="w-full text-center sub-text-28 p-y-20rpx rounded-40rpx border-solid border border-#0094ff"
|
||||
@tap="doChangeRole">
|
||||
<view class="w-full text-center sub-text-28 p-y-20rpx rounded-40rpx border-solid border border-#0094ff" @tap="doChangeRole">
|
||||
切换角色
|
||||
</view>
|
||||
</view>
|
||||
@@ -50,10 +50,9 @@
|
||||
</view>
|
||||
</crud-layout>
|
||||
|
||||
<tm-modal :show="state.actModalShow" :showCancel="false" title="核销活动兑换券" zIndex="999" @confirm="" @cancel=""
|
||||
@close="">
|
||||
<tm-modal :show="state.actModalShow" :showCancel="false" title="核销活动兑换券" zIndex="999" @confirm="" @cancel="" @close="">
|
||||
<view class="text-center text-28">是否核销该活动兑换券?</view>
|
||||
<view class="text-center text-28">确认核销将会对用户的 消费钱包 扣除 1元 钱</view>
|
||||
<view class="text-center text-28">确认核销将自动对用户的 消费钱包 扣费</view>
|
||||
<template #footer>
|
||||
<view class="w-full flex justify-center gap-6">
|
||||
<tm-button skin="thin" @tap="actModalCancel">取 消</tm-button>
|
||||
@@ -276,7 +275,7 @@ const actModalConfirm = async () => {
|
||||
try {
|
||||
uni.showLoading({ title: "核销中...", mask: true })
|
||||
const { code, msg }: any = await actCancel.appCreateActOrder(state.actVal)
|
||||
if (code != 0) return uni.showToast({ title: msg || "核销失败", icon: "none" })
|
||||
if (code != 0) return uni.showToast({ title: msg || "核销失败", icon: "none", duration: 4000 })
|
||||
uni.showToast({ title: "核销成功", icon: "success" })
|
||||
state.actModalShow = false
|
||||
state.actVal = {}
|
||||
|
||||
@@ -14,9 +14,7 @@ export function useScanCode(actModalShow) {
|
||||
// const testQrCode = "eyJoYXJkRG9vcklkIjoiMTkxMzE1NzA4MDQxODI5NTgwOSIsImNhYmluZXRObyI6IjEifQ==" // 邓本地-测试单门智能柜柜门二维码
|
||||
// const testQrCode = "http://192.168.101.45:8889/h5/#/pages/pay/scanPay?id=1905816751043452930&name=测试新县府超市" // 邓本地-测试环境-新县府超市收款二维码
|
||||
// const testQrCode = "http://192.168.101.45:8889/h5/#/pages/pay/scanPay?hardDoorId=1913157080418295809&cabinetNo=1" // 测试智能柜柜门二维码
|
||||
// const testQrCode = "eyJhY3RJZCI6IjE5NjkyNTAwOTg1MTM4MDUzMTQiLCJ0b3RhbFByaWNlIjoxfQ==" // 测试商户活动核销
|
||||
// const testQrCode = "eyJhY3RJZCI6IjE5NjkzMjQwNjMwNTk4Nzc4OTAiLCJ0b3RhbFByaWNlIjoxfQ==" // 测试商户活动核销
|
||||
const testQrCode = "eyJhY3RJZCI6IjE5NjkzMjU3NDQxNDUzMDk2OTciLCJ0b3RhbFByaWNlIjoxfQ==" // 测试商户活动核销
|
||||
const testQrCode = "eyJjYW5jZWxJZCI6IjE5ODQyNDA4MzM5NDMyMDc5MzcifQ==" // 测试商户活动核销
|
||||
uni.showModal({ content: "开发环境不是浙政钉和诗画环境,扫码仅供测试" })
|
||||
return Promise.resolve(testQrCode)
|
||||
}
|
||||
@@ -70,8 +68,8 @@ export function useScanCode(actModalShow) {
|
||||
try {
|
||||
const decodedJson = JSON.parse(decodedString)
|
||||
// 商户活动优惠券扫码核销
|
||||
if (decodedJson.actId) {
|
||||
actModalShow({ actId: decodedJson.actId, totalPrice: decodedJson.totalPrice })
|
||||
if (decodedJson.cancelId) {
|
||||
actModalShow({ cancelId: decodedJson.cancelId })
|
||||
return
|
||||
}
|
||||
// 商户扫码支付
|
||||
|
||||
Reference in new issue
Block a user