完成兑奖页面逻辑

This commit is contained in:
Andy Leong 2024-01-17 17:13:45 +08:00
parent 27b1eab2ce
commit 3291088bca
48 changed files with 372 additions and 178 deletions

View File

@ -1,4 +1,4 @@
VITE_MODE = test
VITE_MODE = fat
VITE_HOST = https://test.szxgl.cn
VITE_CDN = https://test.szxgl.cn
VITE_FOLDER = /vite

View File

@ -5,8 +5,8 @@
"type": "module",
"scripts": {
"dev": "vite",
"test": "vite --mode test",
"build:test": "vite build --mode test",
"fat": "vite --mode fat",
"build:fat": "vite build --mode fat",
"build:prod": "vite build --mode production",
"preview": "vite preview"
},

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -33,3 +33,12 @@ export function draw(data, authorization) {
authorization
);
}
// 兑奖
export function exchangePrize(data, authorization) {
return http.post("/h5/activity/exchangePrize",
data,
true,
authorization
);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 352 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 432 B

After

Width:  |  Height:  |  Size: 373 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 790 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 961 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 461 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 975 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 952 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 375 KiB

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 256 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 952 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 352 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

View File

@ -1,7 +1,6 @@
<script setup>
import { Toast } from "vant";
import gsap from "gsap";
import { debounceTap } from "@/plugins";
import Preloader from "@/plugins/Preloader";
import { loadImg, pageImg } from "@/data/imgList";
import { getMyPrize } from '@/api'
@ -120,18 +119,22 @@ onMounted(() => {
.clock-box {
@include pos(125px, 125px, 313px, 299px);
@include bg_pos("load/clock-bg.png");
.clock-circle {
@include pos(13px, 13px, 57px, 55px);
@include bg_pos("load/clock-circle.png");
}
.clock-s {
@include pos(125px, 125px, 0px, 0px);
@include bg_pos("load/clock-second.png");
}
.clock-m {
@include pos(125px, 125px, 0px, 0px);
@include bg_pos("load/clock-minute.png");
}
.clock-h {
@include pos(125px, 125px, 0px, 0px);
@include bg_pos("load/clock-hour.png");
@ -145,6 +148,7 @@ onMounted(() => {
border-color: #e17c4d;
border-radius: 20px;
overflow: hidden;
.bar {
@include box(10%, 38px);
border-radius: 20px;
@ -174,5 +178,4 @@ onMounted(() => {
background-color: aliceblue;
}
}
}
</style>
}</style>

View File

@ -118,7 +118,10 @@ const showResult = (event) => {
const prevePage = (event) => {
let e = event.target;
debounceTap(e, () => {
// gsap.to(".prev-btn", { duration: 0.5, x: "-=20px", autoAlpha: 0 });
if (currentId.value == 1) {
gsap.to(".prev-btn", { duration: 0.5, x: "-=20px", autoAlpha: 0 });
}
if (currentId.value >= 11) {
resultBtnAni.reverse();
gsap.set(".answer", { pointerEvents: "initial" });
@ -134,23 +137,25 @@ const prevePage = (event) => {
//
const questionEntry = gsap.timeline({
paused: true,
onStart: () => {
gsap.set(".answer-box", { pointerEvents: "none" });
},
// onStart: () => {
// gsap.to('.question-bg', { backgroundPosition: '0px 0px' })
// },
onComplete: () => {
if (currentId.value != 0) {
gsap.to(".prev-btn", { duration: 0.5, x: "+=20px", autoAlpha: 1 });
}
// if (currentId.value != 0) {
// gsap.to(".prev-btn", { duration: 0.5, x: "+=20px", autoAlpha: 1 });
// }
gsap.set(".answer-box", { pointerEvents: "initial" });
},
});
const questionOut = gsap.timeline({
paused: true,
onStart: () => {
// gsap.to('.question-bg', { backgroundPosition: '0px 840px' })
gsap.set(".answer-box", { pointerEvents: "none" });
},
onComplete: () => {
gsap.set(".answer-box", { pointerEvents: "initial" });
},
});
@ -177,9 +182,22 @@ onMounted(() => {
autoAlpha: 0,
duration: 2,
ease: "slow(0.7,0.7,false)",
onStart: () => {
gsap.to('.question-bg', {
backgroundPosition: '0px 0px',
duration: 1,
ease: "slow(0.7,0.7,false)",
})
},
onComplete: () => {
gsap.set(".answer-box", { pointerEvents: "initial" });
if (currentId.value != 0) {
gsap.to(".prev-btn", { duration: 0.5, x: "+=20px", autoAlpha: 1 });
}
}
},
0.5
);
).to('.answer-0', { duration: 1, y: '-=10px', repeat: -1, yoyo: true }).to('.answer-1', { duration: 1, y: '+=10px', repeat: -1, yoyo: true })
questionEntry.play();
questionOut
@ -192,6 +210,13 @@ onMounted(() => {
autoAlpha: 0,
duration: 1.5,
ease: "slow(0.7,0.7,false)",
onStart: () => {
gsap.to('.question-bg', {
backgroundPosition: '0px 835px',
duration: 0.75,
ease: "slow(0.7,0.7,false)",
})
},
})
.to(
".answer-1",
@ -204,15 +229,15 @@ onMounted(() => {
},
1.5
)
.to(
".question-bg",
{
duration: 3,
ease: "slow(0.7,0.7,false)",
background: `linear-gradient(95deg, #f6d365, #fda085)`,
},
1.5
);
// .to(
// ".question-bg",
// {
// duration: 3,
// ease: "slow(0.7,0.7,false)",
// background: `linear-gradient(95deg, #f6d365, #fda085)`,
// },
// 1.5
// );
});
</script>
@ -228,16 +253,9 @@ onMounted(() => {
</div>
</div>
<div class="answer-box">
<div
class="answer"
v-for="(item, index) in questionList[currentId].answer"
:class="'answer-' + index"
:key="index"
>
<div
class="answer-bg"
:class="activeId == item.aid ? 'active' : ''"
></div>
<div class="answer" v-for="(item, index) in questionList[currentId].answer" :class="'answer-' + index"
:key="index">
<div class="answer-bg" :class="activeId == item.aid ? 'active' : ''"></div>
<div class="answer-text">
<div class="content-before"></div>
<div class="content-after"></div>
@ -263,7 +281,7 @@ onMounted(() => {
overflow: hidden;
.question-bg {
@include pos(750px, 100%, 0px, 50%);
@include pos(750px, 4500px, 0px, 50%);
transform: translateY(-50%);
background: linear-gradient(135deg, #f6d365, #fda085);
}

View File

@ -18,6 +18,7 @@ const bgPic = computed(() => {
const mbti = ref(userStore.MBTI);
console.log("mbti", mbti.value);
const changBg = (event, number) => {
@ -27,7 +28,7 @@ const changBg = (event, number) => {
debounceTap(
e,
() => {
console.log("bgId", bgId.value);
// console.log("bgId", bgId.value);
},
0.3
);
@ -36,15 +37,25 @@ const changBg = (event, number) => {
const createPoster = (event) => {
let e = event.target
debounceTap(e, () => {
let saveImg = posterCreate(
{ width: 750, height: 1450 },
//
posterCreate(
{ width: 750, height: 1450 }, //
//
[
new URL(`@/assets/images/result/bg-2.jpg`, import.meta.url).href,
new URL(`@/assets/images/qa/question.png`, import.meta.url).href,
new URL(`@/assets/images/qa/showResult-btn.png`, import.meta.url).href
{
src: new URL(`@/assets/images/result/bg-2.jpg`, import.meta.url).href,
pos: { w: 750, h: 1624, x: 0, y: 0 }
},
{
src: new URL(`@/assets/images/qa/question.png`, import.meta.url).href,
pos: { w: 250, h: 1624, x: 0, y: 0 }
},
{
src: new URL(`@/assets/images/qa/showResult-btn.png`, import.meta.url).href,
pos: { w: 250, h: 124, x: 0, y: 0 }
},
]
)
console.log('saveImg', saveImg);
}, 0.4)
}
</script>
@ -65,6 +76,7 @@ const createPoster = (event) => {
<div style="width: 500px;height: 700px;">
<img class="pic" src="" alt="" srcset="">
</div>
<img id="poster" alt="" srcset="">
</div>
</div>
</template>

171
src/page/Cash/App.vue Normal file
View File

@ -0,0 +1,171 @@
<script setup>
import { Toast, Icon } from 'vant'
import gsap from "gsap";
import { authorize, getUserInfo, exchangePrize } from '@/api'
import { getQueryString, debounceTap } from "@/plugins";
const Authorization = ref('')
const hasPrize = ref(false)
const received = ref(true)
const money = ref('9.99')
onMounted(() => {
let code = getQueryString('code')
let dev = import.meta.env.VITE_MODE
if (dev != 'dev') {
if (code) {
getUserInfo({ code: code }).then(
res => {
if (res.code == 0) {
console.log('我的信息:', res.data);
Authorization.value = res.data.authorization
exchangePrize({}, Authorization.value).then(
res => {
console.log('兑换结果:', res);
}
)
} else {
authorize({ scopeType: 1 }).then(
res => {
if (res.code == 0) {
console.log('重定向地址:', res.data);
location.replace(res.data)
}
//
Toast.fail({
message: res.msg,
duration: 0,
forbidClick: true
})
}
)
}
}
)
} else {
authorize({ scopeType: 1 }).then(
res => {
if (res.code == 0) {
console.log('重定向地址:', res.data);
location.replace(res.data)
}
//
Toast.fail({
message: res.msg,
duration: 0,
forbidClick: true
})
}
)
}
}
gsap.from('.CashPage', { duration: 0.5, autoAlpha: 0 })
})
const go = (event) => {
let e = event.target
debounceTap(e, () => {
console.log(1);
let url = import.meta.env.VITE_HOST + import.meta.env.VITE_FOLDER + '/index.html'
window.location.replace(url)
}, 0.5)
}
</script>
<template>
<div class="CashPage" @touchmove.prevent>
<div class="cash-container" v-if="hasPrize">
<!-- 正常领奖 -->
<div class="cashed-success" v-if="!received">
<div class="money">¥{{ money }}</div>
</div>
<!-- 已经领过奖 -->
<div class="cashed-worng" v-else></div>
</div>
<!-- 暂无中奖记录 -->
<div v-else class="no-prize">
<div class="icon">
<Icon size="40" name="info-o" color="#fda085" />
</div>
<div class="text">暂无中奖记录</div>
<div class="btn" @click="go($event)">前往参与活动</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.CashPage {
@include pos(100%, 100%, 0px, 0px);
background: linear-gradient(135deg, #f6d365, #fda085);
overflow: hidden;
@include flexCen();
.cashed-success {
@include pos(750px, 1624px, 0px, 50%);
transform: translateY(-50%);
@include bg_pos("cash/lucky_bg.jpg");
.money {
@include pos(750px, 200px, 0px, 650px);
// background-color: rgba($color: #000000, $alpha: .7);
display: flex;
justify-content: center;
align-items: center;
font-size: 100px;
font-weight: 700;
color: #fda085;
letter-spacing: 2px;
}
}
.cashed-worng {
@include pos(750px, 1624px, 0px, 50%);
transform: translateY(-50%);
@include bg_pos("cash/received.jpg");
}
.no-prize {
@include box(600px, 400px);
border-radius: 20px;
background-color: aliceblue;
@include flexCen();
box-shadow: 5px 5px 10px #bebebe,
-5px -5px 10px #ffffff;
.icon {
height: 100px;
}
.text {
font-size: 28px;
letter-spacing: 1px;
}
.btn {
@include box(280px, 80px);
background: linear-gradient(135deg, #f6d365, #fda085);
display: flex;
justify-content: center;
align-items: center;
border-radius: 50px;
font-size: 30px;
color: #fff;
margin-top: 50px;
box-shadow: 20px 20px 60px #bebebe,
-20px -20px 60px #ffffff;
}
}
}
</style>

View File

@ -1,14 +1,12 @@
import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from "pinia"
// import h5plugin from '@/plugins';
import { wxShare } from '@/plugins/wxshare';
import { wxShare } from '@/plugins/wxshare'
import 'vant/lib/index.css';
const app = createApp(App)
// 定义引入图片地址的全局方法
app.config.globalProperties.imgUrl = (url) => {
return new URL(`./assets/images/${url}`, import.meta.url).href
}
// 初始化我的方法
// app.config.globalProperties.myPlugin = h5plugin
@ -19,6 +17,6 @@ wxShare({
link: '/index.html',
})
app.use(createPinia())
app.mount('#app')
console.log('Mode:', import.meta.env.VITE_MODE);

View File

@ -82,6 +82,9 @@ onMounted(() => {
let code = getQueryString('code')
console.log('code:', code);
let dev = import.meta.env.VITE_MODE
if (dev != 'dev') {
if (code) {
getUserInfo({ code: code }).then(
res => {
@ -166,6 +169,11 @@ onMounted(() => {
}
)
}
} else {
showLoad.value = true
}
});

View File

@ -1,13 +0,0 @@
<template>
<div class="SharePage">share</div>
</template>
<script setup>
</script>
<style lang="scss" scoped>
.SharePage {
@include fixed();
@include flexCen();
}
</style>

View File

@ -1,6 +1,7 @@
// 常用的方法
import gsap from 'gsap'
import { Howl, Howler } from 'howler';
import { Toast } from 'vant';
import { createVNode, render } from 'vue'
@ -433,10 +434,16 @@ export function mostValue(arr) {
// 海报生成
export function posterCreate(option, imageArr) {
let posterUrl = ''
const { width, height } = option
Toast.loading({
message: '海报生成中',
duration: 0,
forbidClick: true
})
let mycanvas = document.createElement('canvas'), // 创建一个canvas画布元素
ctx = mycanvas.getContext('2d');
let mycanvas = document.createElement('canvas') // 创建一个canvas画布元素
let ctx = mycanvas.getContext('2d')
mycanvas.width = width; //设置canvas的宽
mycanvas.height = height; //设置canvas的高
@ -449,46 +456,28 @@ export function posterCreate(option, imageArr) {
img.onload = () => {
resolve(img)
};
img.src = item;
img.src = item.src;
});
loader_p.push(_p);
})
// imageArr.forEach((ev, index) => {
// const _p = new Promise(resolve => {
// const img = new Image();
// img.crossOrigin = 'Anonymous'
// img.onload = () => {
// resolve(img)
// };
// img.src = ev;
// });
// loader_p.push(_p);
// });
//Promise的.all方法当所有预加载的图像加载好的回调函数
Promise.all(loader_p)
.then(img_Arr => {
const poster = img_Arr[0]; //声明一个对象替代刚刚加载的资源
console.log('======开始绘制海报======)');
console.log('daihui:', img_Arr);
// 画海报
ctx.drawImage(poster, 0, 0, mycanvas.width, mycanvas.height); //原生canvas的绘制图片方法直接百度搜索 `js drawImage`查看方法的参数
// 画签文
// ctx.fillStyle = '#524426'; //原生canvas的绘制文字方法,属性类似css确定好文字颜色、粗细、字号、字体、对齐方式
// ctx.font = 'bold 28px arial'; // normal bold
// ctx.textAlign = 'start'; //type2
// ctx.rotate(-8 * Math.PI / 180);
// ctx.fillText('@' + this.userName, 40, this.tHeight); //绘制文字
.then(imgList => {
console.log('海报数组:', imgList);
imgList.map((item, index) => {
console.log('item', imageArr[index].pos);
ctx.drawImage(item, imageArr[index].pos.x, imageArr[index].pos.y, imageArr[index].pos.w, imageArr[index].pos.h); //原生canvas的绘制图片方法直接百度搜索 `js drawImage`查看方法的参数
})
//海报绘制完 ,转成图片对象
return mycanvas.toDataURL('image/jpeg', 1);
})
.then(baseURL => {
//返回的图片地址就是最后海报的地址可以放在DOM显示
console.log('海报生成完毕 that.posterIsInit', baseURL);
// let img = document.querySelector('#pic')
// img.src = baseURL
// return baseURL
let posterImg = document.querySelector('#poster')
posterImg.src = baseURL
setTimeout(() => Toast.success({ message: '已成功' }), 500)
})
return posterUrl
}

View File

@ -38,9 +38,9 @@ export default defineConfig(({ command, mode }) => {
}
},
{
filename: 'share',
entry: '/src/page/Share/main.js',
template: 'share.html',
filename: 'cash',
entry: '/src/page/Cash/main.js',
template: 'cash.html',
injectOptions: {
data: {
title: '分享页',
@ -61,7 +61,7 @@ export default defineConfig(({ command, mode }) => {
verbose: true, // 默认即可
disable: false, //开启压缩(不禁用),默认即可
deleteOriginFile: false, //删除源文件
threshold: 10240, //压缩前最小文件大小
threshold: 10240, //压缩前最小文件大小:10k
algorithm: 'gzip', //压缩算法
ext: '.gz', //文件类型
})
@ -115,7 +115,7 @@ export default defineConfig(({ command, mode }) => {
},
},
// 公共基础路径构建生产环境时自动载入cdn路径
base: mode == 'production' ? env.VITE_CDN + env.VITE_FOLDER + '/' : './',
base: './',
// 打包配置
build: {
assetsPublicPath: './',
@ -125,8 +125,8 @@ export default defineConfig(({ command, mode }) => {
terserOptions: {
compress: {
//生产环境时移除打印日志
drop_console: mode == 'production' ? true : false,
drop_debugger: mode == 'production' ? true : false,
// drop_console: mode == 'production' ? true : false,
// drop_debugger: mode == 'production' ? true : false,
},
},