feat:积分管理

This commit is contained in:
dzc committed 2026-04-09 17:22:22 +08:00
1 parent a21b3ae4db
commit a45515d934
9 files changed
+419 -14

No files matched your search

+1 -1
View File
@@ -6,7 +6,7 @@
"localRepoPath" : "C:/workcode/vue/biz-mobile-cloud-zax",
"openVueDevtools" : true,
"packageName" : "z",
"playground" : "standard",
"playground" : "custom",
"type" : "uni-app:app-android"
},
{
+1 -1
View File
@@ -20,7 +20,7 @@
<line x1="150" y1="22" x2="150" y2="138" stroke="#ffffff" stroke-width="2" stroke-dasharray="6 10" opacity="0.8"/>
<g fill="#ffffff">
<text x="55" y="92" font-size="64" font-weight="700" text-anchor="middle" dominant-baseline="middle">¥</text>
<text x="205" y="66" font-size="28" font-weight="700" text-anchor="middle" fill="#ffffff">代金券</text>
<text x="205" y="66" font-size="28" font-weight="700" text-anchor="middle" fill="#ffffff">优惠券</text>
<text x="205" y="98" font-size="16" text-anchor="middle" opacity="0.9">COUPON</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

+111 -2
View File
@@ -4,12 +4,14 @@ import { reactive, computed, ref } from "vue"
import { adApi } from "@@/api/index"
import { hooks, router } from "@@/index"
const data = {
}
const state = reactive<any>({
pa: {}
})
const pageRef = ref<any>(null)
const pageHook = hooks.usePage(pageRef, adApi.integralPage, null, "data.records")
const pageHook = hooks.usePage(pageRef, adApi.rewardedIntegralPage, null, "data.records")
const query = (page: number, pagesize: number) => {
pageHook.startPage(page, pagesize, false, state.pa)
}
@@ -21,8 +23,115 @@ const query = (page: number, pagesize: number) => {
<z-paging ref="pageRef" height="100%" :fixed="false" v-model="pageHook.list" :default-page-size="5"
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">
<view class="h-30rpx" />
<view class="record-card" v-for="(v, i) in pageHook.list" :key="i">
<view class="record-main">
<view class="record-title">{{ v.title || '激励视频' }}</view>
<view class="record-time">{{ v.createTime }}</view>
</view>
<view class="record-badge">
<text class="record-add">+{{ v.integralNum }}</text>
<text class="record-unit">积分</text>
<view class="record-shine"></view>
</view>
</view>
</z-paging>
</crud-layout>
</template>
<style scoped></style>
<style scoped>
.record-card {
margin: 0 0 30rpx 0;
padding: 20rpx 22rpx;
display: flex;
align-items: center;
justify-content: space-between;
background: #ffffff;
border-radius: 16rpx;
box-shadow: 0 10rpx 24rpx rgba(0, 0, 0, 0.06);
}
.record-main {
display: flex;
flex-direction: column;
gap: 8rpx;
}
.record-title {
font-size: 28rpx;
font-weight: 600;
color: #333;
}
.record-time {
font-size: 22rpx;
color: #999;
}
.record-badge {
position: relative;
overflow: hidden;
display: inline-flex;
align-items: baseline;
gap: 6rpx;
padding: 10rpx 20rpx;
border-radius: 999rpx;
color: #fff;
background: linear-gradient(90deg, #0094ff 0%, #33b6ff 50%, #0094ff 100%);
background-size: 200% 100%;
animation: promoGradient 2.2s linear infinite;
box-shadow: 0 8rpx 20rpx rgba(0, 148, 255, 0.35);
}
.record-add {
font-size: 28rpx;
font-weight: 700;
}
.record-unit {
font-size: 20rpx;
opacity: 0.9;
}
.record-shine {
position: absolute;
top: 0;
left: -30%;
width: 30%;
height: 100%;
background: rgba(255, 255, 255, 0.35);
transform: skewX(-20deg);
animation: recordShine 2.2s linear infinite;
}
@keyframes promoGradient {
0% {
background-position: 0% 50%;
}
100% {
background-position: 200% 50%;
}
}
@keyframes recordShine {
0% {
left: -30%;
opacity: 0.0;
}
15% {
opacity: 0.6;
}
50% {
left: 130%;
opacity: 0.0;
}
100% {
left: 130%;
opacity: 0.0;
}
}
</style>
+280 -2
View File
@@ -1,10 +1,16 @@
<script setup lang="ts">
import { reactive, computed, ref } from "vue"
import { adApi } from "@@/api/index"
import { serviceEnum } from "@@/constant"
import { displayPrice } from "@@/utils/format-money"
import zTabs from "@@/components/other/z-tabs/z-tabs.vue"
import { hooks, router } from "@@/index"
const { actCouponTypeEnum } = serviceEnum
const data = {
tabs: [
{ id: 1, name: "全部", disabled: false },
@@ -17,7 +23,7 @@ const state = reactive<any>({
})
const pageRef = ref<any>(null)
const pageHook = hooks.usePage(pageRef, null, null, "data.records")
const pageHook = hooks.usePage(pageRef, adApi.rewardedAdCouponPage, null, "data.records")
const query = (page: number, pagesize: number) => {
pageHook.startPage(page, pagesize, false, state.pa)
}
@@ -28,6 +34,9 @@ const doTab = (e: any) => {
pageHook.list = []
pageRef.value.reload(true)
}
const doVisibleQrcode = (v: any) => {
}
</script>
<template>
@@ -40,8 +49,277 @@ const doTab = (e: any) => {
<z-tabs :list="data.tabs" @change="doTab" />
</view>
</template>
<view class="h-30rpx" />
<view class="record-card" v-for="(v, i) in pageHook.list" :key="i">
<view class="coupon-left relative">
<view class="relative">
<image class="size-140rpx rounded-8rpx flex-shrink-0 m-r-10rpx" src="/static/icon/ad/djq.png"
mode="widthFix" />
<view class="absolute left-35rpx font-size-26rpx! line-height-26rpx! color-white"
style="top:50%; transform:translateY(-60%);">
{{ displayPrice(v.faceValue, "", 0) }}
</view>
</view>
<view class="absolute top-0rpx right-80rpx">
<!-- 未使用 -->
<view v-if="v.status == 1"
class="iconfont icon-weishiyong absolute font-size-80rpx! color-blue" />
<!-- 已使用 -->
<view v-if="v.status == 2"
class="iconfont icon-weishiyong1 absolute font-size-80rpx! color-#cccccc" />
<!-- 已过期 -->
<view v-if="v.status == 3"
class="iconfont icon-yiguoqi absolute font-size-80rpx! color-#cccccc" />
<!-- 已作废 -->
<view v-if="v.status == 4"
class="iconfont icon-yizuofei1 absolute font-size-80rpx! color-#cccccc" />
</view>
<view class="info-box">
<view class="price-row">
<view v-if="v.faceValue" class="flex items-center">
<text class="symbol">¥</text>
<text class="amount"> {{ displayPrice(v.faceValue) }}</text>
</view>
<text class="name">{{ v.couponName }}</text>
</view>
<view v-if="v.minPoint" class="condition">
满{{ v.minPoint }}可用
</view>
<view v-else class="condition">优惠券</view>
<view class="scope-text flex-col">
<text>{{ actCouponTypeEnum[v.couponType] }}</text>
<text>在{{ v.validStartTime }}至{{ v.validEndTime }}时间段使用</text>
</view>
</view>
</view>
<!-- 虚线分割与缺口 -->
<view class="split-line">
<view class="circle-top"></view>
<view class="dashed-line"></view>
<view class="circle-bottom"></view>
</view>
<!-- 右侧按钮 -->
<view class="coupon-right">
<view v-if="v.status == 1" class="verify-badge" @tap="doVisibleQrcode(v)">
<text class="verify-text">核销码</text>
<view class="verify-shine"></view>
</view>
<view v-if="v.status == 2" class="action-btn disabled">已使用</view>
<view v-if="v.status == 3" class="action-btn disabled">已过期</view>
<view v-if="v.status == 4" class="action-btn disabled">已作废</view>
</view>
</view>
</z-paging>
</crud-layout>
</template>
<style scoped></style>
<style scoped>
.record-card {
display: flex;
align-items: stretch;
margin-bottom: 20rpx;
border-radius: 16rpx;
overflow: hidden;
position: relative;
box-shadow: 0 4rpx 16rpx rgba(0, 148, 255, 0.08);
}
/* 左侧布局 */
.coupon-left {
flex: 1;
display: flex;
align-items: center;
padding: 24rpx 0 24rpx 24rpx;
background: radial-gradient(circle at right top, transparent 12rpx, #fff 0) top left / 100% 51% no-repeat,
radial-gradient(circle at right bottom, transparent 12rpx, #fff 0) bottom left / 100% 51% no-repeat;
/* 备用背景色,防止渐变失效 */
background-color: #fff;
}
.ribbon {
width: 160rpx;
height: 40rpx;
position: absolute;
left: -40rpx;
top: 20rpx;
transform: rotateZ(-45deg);
text-align: center;
color: #fff;
font-size: 24rpx;
}
.info-box {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
height: 140rpx;
}
.price-row {
display: flex;
align-items: baseline;
color: #0094ff;
}
.symbol {
font-size: 28rpx;
font-weight: 600;
}
.amount {
font-size: 48rpx;
font-weight: bold;
margin: 0 8rpx 0 2rpx;
line-height: 1;
}
.name {
font-size: 28rpx;
color: #333;
font-weight: 600;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 200rpx;
}
.condition {
font-size: 24rpx;
color: #0094ff;
opacity: 0.8;
margin-top: 4rpx;
}
.scope-text {
font-size: 22rpx;
color: #999;
margin-top: auto;
}
/* 中间分割线区域 */
.split-line {
width: 30rpx;
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: #fff;
}
.dashed-line {
width: 0;
height: 80%;
border-left: 2rpx dashed #0094ff44;
}
.circle-top {
position: absolute;
top: 0;
left: 50%;
transform: translate(-50%, -50%);
width: 24rpx;
height: 24rpx;
border-radius: 50%;
background-color: #f5f5f5;
}
.circle-bottom {
position: absolute;
bottom: 0;
left: 50%;
transform: translate(-50%, 50%);
width: 24rpx;
height: 24rpx;
border-radius: 50%;
background-color: #f5f5f5;
}
/* 右侧按钮区 */
.coupon-right {
width: 160rpx;
display: flex;
align-items: center;
justify-content: center;
background: radial-gradient(circle at left top, transparent 12rpx, #fff 0) top left / 100% 51% no-repeat,
radial-gradient(circle at left bottom, transparent 12rpx, #fff 0) bottom left / 100% 51% no-repeat;
background-color: #fff;
}
.action-btn {
background: #0094ff;
color: #fff;
font-size: 26rpx;
padding: 10rpx 24rpx;
border-radius: 30rpx;
font-weight: 500;
&.disabled {
background: #cccccc;
}
}
.verify-badge {
position: relative;
overflow: hidden;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 10rpx 24rpx;
border-radius: 999rpx;
color: #fff;
background: linear-gradient(90deg, #0094ff 0%, #33b6ff 50%, #0094ff 100%);
background-size: 200% 100%;
animation: verifyGradient 2.2s linear infinite;
box-shadow: 0 8rpx 20rpx rgba(0, 148, 255, 0.35);
}
.verify-text {
font-size: 26rpx;
font-weight: 600;
}
.verify-shine {
position: absolute;
top: 0;
left: -30%;
width: 30%;
height: 100%;
background: rgba(255, 255, 255, 0.35);
transform: skewX(-20deg);
animation: verifyShine 2.2s linear infinite;
}
@keyframes verifyGradient {
0% {
background-position: 0% 50%;
}
100% {
background-position: 200% 50%;
}
}
@keyframes verifyShine {
0% {
left: -30%;
opacity: 0.0;
}
15% {
opacity: 0.6;
}
50% {
left: 130%;
opacity: 0.0;
}
100% {
left: 130%;
opacity: 0.0;
}
}
</style>
+4 -3
View File
@@ -108,8 +108,9 @@ const getMakeMoneyTotal = async () => {
<view class="btn-link">观看记录</view>
</view>
<view class="progress-wrap">
<SemiProgress :value="1" :total="state.makeMoneyDetail.todayViewAdLimitNum" color="#0094ff"
trackColor="#e5f3ff" :gapAngle="60" gapPosition="bottom" direction="cw" />
<SemiProgress :value="state.makeMoneyDetail.todayViewAdNum"
:total="state.makeMoneyDetail.todayViewAdLimitNum" color="#0094ff" trackColor="#e5f3ff"
:gapAngle="60" gapPosition="bottom" direction="cw" />
</view>
<view class="stats">
<view class="stat-item">
@@ -383,7 +384,7 @@ const getMakeMoneyTotal = async () => {
align-items: center;
justify-content: space-between;
padding: 16rpx 18rpx;
margin: 8rpx 12rpx;
margin: 8rpx 0;
background: #ffffff;
border-radius: 14rpx;
box-shadow: 0 10rpx 24rpx rgba(0, 0, 0, 0.06);
+2 -2
View File
@@ -7,9 +7,9 @@ export default {
method: "POST",
data,
}),
integralPage: (params: any) =>
rewardedIntegralPage: (params: any) =>
request({
url: "/integrated/ad-record/app/integral-page",
url: "/wallet/integral-transaction/app/rewarded-integral-page",
method: "GET",
params,
}),
+9
View File
@@ -55,6 +55,14 @@ const actCancelStatusEnum = {
"3": "已过期",
}
const actCouponTypeEnum = {
"1": "满减券",
"2": "折扣券",
"3": "立减券",
"4": "兑换券",
}
export default {
hardwareOrderStatusEnum,
hardwareOrderTypeEnum,
@@ -64,4 +72,5 @@ export default {
hardwareRefundStatusEnum,
carTypeEnum,
actCancelStatusEnum,
actCouponTypeEnum,
}
+11 -3
View File
@@ -1,9 +1,9 @@
@font-face {
font-family: "iconfont";
/* Project id 4740692 */
src: url('https://at.alicdn.com/t/c/font_4740692_0xyqsj5qnt1.woff2?t=1775618316107') format('woff2'),
url('https://at.alicdn.com/t/c/font_4740692_0xyqsj5qnt1.woff?t=1775618316107') format('woff'),
url('https://at.alicdn.com/t/c/font_4740692_0xyqsj5qnt1.ttf?t=1775618316107') format('truetype');
src: url('//at.alicdn.com/t/c/font_4740692_0z7oaxadr7kr.woff2?t=1775722113838') format('woff2'),
url('//at.alicdn.com/t/c/font_4740692_0z7oaxadr7kr.woff?t=1775722113838') format('woff'),
url('//at.alicdn.com/t/c/font_4740692_0z7oaxadr7kr.ttf?t=1775722113838') format('truetype');
}
.iconfont {
@@ -14,6 +14,14 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-yizuofei1:before {
content: "\e60d";
}
.icon-yizuofei:before {
content: "\f2d8";
}
.icon-jilu1:before {
content: "\e631";
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB