optimize: avatar page share reward

This commit is contained in:
zzc
2026-01-28 08:55:59 +08:00
parent aee386da51
commit 2fa6584e0c
4 changed files with 165 additions and 42 deletions

View File

@@ -117,7 +117,8 @@
import { ref, onMounted } from "vue";
import { onLoad } from "@dcloudio/uni-app";
import { getBavBarHeight } from "@/utils/system";
import { getAvatarFrameList, getPageDetail } from "@/api/avatar.js";
import { getAvatarFrameList } from "@/api/avatar.js";
import { getPageDetail } from "@/api/system.js";
const defaultAvatar =
"https://file.lihailezzc.com/resource/d9b329082b32f8305101f708593a4882.png";
@@ -234,7 +235,7 @@ const goToWallpaper = () => {
<style lang="scss" scoped>
.avatar-detail-page {
min-height: 100vh;
background: #fff0f5; /* Light Pink Background */
background: #ffffff;
box-sizing: border-box;
}
@@ -245,7 +246,7 @@ const goToWallpaper = () => {
right: 0;
z-index: 100;
box-sizing: border-box;
background: #fff0f5;
background: #ffffff;
}
.nav-content {
@@ -271,9 +272,6 @@ const goToWallpaper = () => {
margin-right: 50rpx; /* Balance back button */
}
.content-scroll {
}
.content-wrap {
padding: 30rpx 40rpx 60rpx;
}
@@ -326,16 +324,17 @@ const goToWallpaper = () => {
/* Main Card */
.main-card {
background: linear-gradient(180deg, #ffffff 0%, #fff5f5 100%);
background: #ffffff;
border-radius: 40rpx;
padding: 24rpx;
box-shadow: 0 20rpx 60rpx rgba(255, 59, 48, 0.15);
box-shadow: 0 10rpx 40rpx rgba(0, 0, 0, 0.06);
margin-bottom: 60rpx;
border: 2rpx solid #f5f5f5;
}
.card-inner {
position: relative;
background: #fffaf0;
background: #fff9f9;
border-radius: 30rpx;
padding: 60rpx;
display: flex;
@@ -348,7 +347,7 @@ const goToWallpaper = () => {
height: 400rpx;
border-radius: 20rpx;
box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.1);
border: 8rpx solid #d63333;
border: 8rpx solid #ff3b30;
}
.loading-box {
@@ -358,7 +357,7 @@ const goToWallpaper = () => {
align-items: center;
justify-content: center;
color: #999;
background: #eee;
background: #f0f0f0;
border-radius: 20rpx;
}
@@ -381,14 +380,14 @@ const goToWallpaper = () => {
.card-footer-text {
margin-top: 40rpx;
font-size: 28rpx;
color: #d63333;
color: #ff3b30;
font-weight: bold;
display: flex;
align-items: center;
background: #fff;
padding: 10rpx 30rpx;
border-radius: 99rpx;
box-shadow: 0 4rpx 10rpx rgba(214, 51, 51, 0.1);
box-shadow: 0 4rpx 10rpx rgba(255, 59, 48, 0.1);
}
.card-footer-text .icon {
@@ -423,8 +422,8 @@ const goToWallpaper = () => {
}
.secondary-btn {
background: #eaeaea;
color: #666;
background: #f5f5f5;
color: #333;
}
.btn .icon {
@@ -478,10 +477,9 @@ const goToWallpaper = () => {
display: flex;
flex-direction: column;
align-items: center;
background: #fff;
background: #f8f8f8;
border-radius: 24rpx;
padding: 20rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.03);
}
.frame-img-box {
@@ -490,7 +488,7 @@ const goToWallpaper = () => {
margin-bottom: 16rpx;
border-radius: 50%;
overflow: hidden;
background: #f9f9f9;
background: #fff;
}
.frame-img {
@@ -506,19 +504,18 @@ const goToWallpaper = () => {
/* Wallpaper Banner */
.wallpaper-banner {
background: #fff;
background: #f8f8f8;
border-radius: 24rpx;
padding: 30rpx;
display: flex;
align-items: center;
margin-bottom: 60rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.03);
}
.banner-icon {
width: 80rpx;
height: 80rpx;
background: #fff0f5;
background: #fff;
border-radius: 20rpx;
display: flex;
align-items: center;
@@ -569,18 +566,18 @@ const goToWallpaper = () => {
.footer-line .line {
width: 60rpx;
height: 2rpx;
background: #ccc;
background: #eee;
}
.footer-line .text {
font-size: 20rpx;
color: #999;
color: #ccc;
margin: 0 20rpx;
letter-spacing: 2rpx;
}
.footer-sub {
font-size: 20rpx;
color: #ccc;
color: #ddd;
}
</style>

View File

@@ -107,6 +107,8 @@
</view>
<canvas
type="2d"
id="avatarCanvas"
canvas-id="avatarCanvas"
class="hidden-canvas"
style="width: 600px; height: 600px"
@@ -162,7 +164,13 @@ import {
getAvatarSystemList,
getAvatarFrameList,
getAvatarDecorList,
avatarCreateComplete,
} from "@/api/avatar.js";
import {
saveRecordRequest,
getShareToken,
generateObjectId,
} from "@/utils/common.js";
const userStore = useUserStore();
const loginPopupRef = ref(null);
@@ -313,6 +321,12 @@ const loadMoreAvatars = async () => {
}
};
const createAvatarId = () => {
const id = generateObjectId();
avatarCreateComplete({ id });
return id;
};
const selectMoreAvatar = (url) => {
currentAvatar.value = url;
closeMorePopup();
@@ -417,7 +431,109 @@ const goBack = () => {
uni.navigateBack();
};
const saveByCanvas = async (save = true) => {
return new Promise((resolve, reject) => {
const query = uni.createSelectorQuery();
query
.select("#avatarCanvas")
.fields({ node: true, size: true })
.exec(async (res) => {
if (!res[0] || !res[0].node) {
reject("Canvas not found");
return;
}
const canvas = res[0].node;
const ctx = canvas.getContext("2d");
const loadCanvasImage = (url) => {
return new Promise((resolve, reject) => {
const img = canvas.createImage();
img.onload = () => resolve(img);
img.onerror = (e) => reject(e);
img.src = url;
});
};
// 初始化画布尺寸
const size = 600;
const avatarPath = await loadCanvasImage(currentAvatar.value);
ctx.clearRect(0, 0, size, size);
ctx.drawImage(avatarPath, 0, 0, size, size);
if (selectedFrame.value) {
const framePath = await loadCanvasImage(selectedFrame.value);
ctx.drawImage(framePath, 0, 0, size, size);
}
if (selectedDecor.value) {
const decorPath = await loadCanvasImage(selectedDecor.value);
ctx.save();
// 映射 rpx 坐标到 Canvas 坐标 (假设 1rpx = 1 unit for 600x600 canvas logic)
// Canvas size is 600, Preview is 600rpx. Ratio is 1:1 in logical space.
ctx.translate(decorState.value.x, decorState.value.y);
ctx.rotate((decorState.value.rotate * Math.PI) / 180);
const scale = decorState.value.scale;
// 绘制图片,宽高 240
ctx.drawImage(
decorPath,
-120 * scale,
-120 * scale,
240 * scale,
240 * scale,
);
ctx.restore();
}
uni.canvasToTempFilePath({
canvas: canvas, // Canvas 2D 必须传 canvas 实例
width: 600,
height: 600,
destWidth: 600,
destHeight: 600,
success: (res) => {
if (save) saveImage(res.tempFilePath);
resolve(res.tempFilePath);
},
fail: (err) => reject(err),
});
// ctx.draw(false, () => {
// uni.canvasToTempFilePath({
// canvasId: "avatarCanvas",
// success: (res) => {
// uni.saveImageToPhotosAlbum({
// filePath: res.tempFilePath,
// success: () => {
// uni.showToast({ title: "已保存到相册", icon: "success" });
// },
// });
// },
// });
// });
});
});
};
const saveImage = (path) => {
uni.saveImageToPhotosAlbum({
filePath: path,
success() {
uni.showToast({ title: "已保存到相册" });
},
fail() {
uni.showModal({
title: "提示",
content: "请授权保存到相册",
});
},
});
};
const saveAndUse = async () => {
saveByCanvas();
console.log(111111);
return;
if (!isLoggedIn.value) {
loginPopupRef.value.open();
return;
}
const abilityRes = await abilityCheck("avatar_download");
if (!abilityRes.canUse) {
if (
@@ -437,9 +553,10 @@ const saveAndUse = async () => {
return;
}
// 调用avatarDownloadRecord API记录下载次数
await avatarDownloadRecord({
avatarUrl: currentAvatar.value,
});
// await avatarDownloadRecord({
// avatarUrl: currentAvatar.value,
// });
// saveRecordRequest('', )
const ctx = uni.createCanvasContext("avatarCanvas");
const size = 600;
const avatarPath = await loadImage(currentAvatar.value);
@@ -487,13 +604,16 @@ const share = () => {
};
onShareAppMessage(async () => {
const deviceInfo = getDeviceInfo();
const shareTokenRes = await createShareToken({
targetId: "",
scene: "avatar_download",
...deviceInfo,
});
getRewardByShare();
getShareReward({ scene: "avatar_download" });
if (!isLoggedIn.value) {
const shareTokenRes = await getShareToken("avatar_download_not_login", "");
return {
title: "新春祝福",
path: `/pages/index/index?shareToken=${shareTokenRes.shareToken}`,
};
}
const id = createAvatarId();
const shareTokenRes = await getShareToken("avatar_download", id);
return {
title: "制作我的新春头像",
@@ -503,13 +623,6 @@ onShareAppMessage(async () => {
};
});
const getRewardByShare = async () => {
const res = await getShareReward({ scene: "avatar_download" });
if (res.success) {
uni.showToast({ title: "分享成功,可下载头像" });
}
};
// onShareTimeline(() => {
// return {
// title: "制作我的新春头像",