optimize: avatar page share reward

This commit is contained in:
zzc
2026-01-28 10:35:31 +08:00
parent 4a1cbf1f5a
commit 29498e4994
2 changed files with 79 additions and 59 deletions

View File

@@ -47,7 +47,6 @@
<text>加载中...</text> <text>加载中...</text>
</view> </view>
<!-- Decorative Elements --> <!-- Decorative Elements -->
<view class="decor-tag">🐰</view>
<view class="card-footer-text"> <view class="card-footer-text">
<text class="icon">🌸</text> 2026 丙午马年限定 <text class="icon">🌸</text> 2026 丙午马年限定
</view> </view>
@@ -59,9 +58,6 @@
<button class="btn primary-btn" @tap="goToMake"> <button class="btn primary-btn" @tap="goToMake">
<text class="icon">🎨</text> 我也要领同款制作 <text class="icon">🎨</text> 我也要领同款制作
</button> </button>
<button class="btn secondary-btn" @tap="saveImage">
<text class="icon">📥</text> 保存到相册
</button>
</view> </view>
<!-- Recommended Frames --> <!-- Recommended Frames -->
@@ -94,7 +90,27 @@
<text>🖼</text> <text>🖼</text>
</view> </view>
<view class="banner-content"> <view class="banner-content">
<text class="banner-title">去挑选更多壁纸</text> <text class="banner-title">去挑选新年壁纸</text>
<text class="banner-desc">新年新气象全套皮肤限时领</text>
</view>
<text class="banner-arrow"></text>
</view>
<view class="wallpaper-banner" @tap="goToWallpaper">
<view class="banner-icon">
<text>🖼</text>
</view>
<view class="banner-content">
<text class="banner-title">去挑选新年壁纸</text>
<text class="banner-desc">新年新气象全套皮肤限时领</text>
</view>
<text class="banner-arrow"></text>
</view>
<view class="wallpaper-banner" @tap="goToWallpaper">
<view class="banner-icon">
<text>🖼</text>
</view>
<view class="banner-content">
<text class="banner-title">去挑选新年壁纸</text>
<text class="banner-desc">新年新气象全套皮肤限时领</text> <text class="banner-desc">新年新气象全套皮肤限时领</text>
</view> </view>
<text class="banner-arrow"></text> <text class="banner-arrow"></text>
@@ -188,37 +204,6 @@ const previewImage = () => {
} }
}; };
const saveImage = () => {
if (!detailData.value?.imageUrl) return;
uni.showLoading({ title: "保存中..." });
uni.downloadFile({
url: detailData.value.imageUrl,
success: (res) => {
if (res.statusCode === 200) {
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: () => {
// uni.hideLoading();
uni.showToast({ title: "保存成功", icon: "success" });
},
fail: () => {
// uni.hideLoading();
uni.showToast({ title: "保存失败", icon: "none" });
},
});
} else {
// uni.hideLoading();
uni.showToast({ title: "下载失败", icon: "none" });
}
},
fail: () => {
// uni.hideLoading();
uni.showToast({ title: "下载失败", icon: "none" });
},
});
};
const goToMake = () => { const goToMake = () => {
uni.navigateTo({ uni.navigateTo({
url: "/pages/avatar/index", url: "/pages/avatar/index",

View File

@@ -6,17 +6,21 @@
</view> </view>
<view class="preview-card"> <view class="preview-card">
<view class="preview-square"> <view class="preview-square">
<image class="avatar-img" :src="currentAvatar" mode="aspectFill" /> <image
class="avatar-img"
:src="currentAvatar?.imageUrl"
mode="aspectFill"
/>
<image <image
v-if="selectedFrame" v-if="selectedFrame"
class="frame-img" class="frame-img"
:src="selectedFrame" :src="selectedFrame?.imageUrl"
mode="aspectFill" mode="aspectFill"
/> />
<image <image
v-if="selectedDecor" v-if="selectedDecor"
class="decor-img" class="decor-img"
:src="selectedDecor" :src="selectedDecor?.imageUrl"
mode="aspectFit" mode="aspectFit"
:style="decorStyle" :style="decorStyle"
@touchstart.stop="onTouchStart" @touchstart.stop="onTouchStart"
@@ -58,7 +62,11 @@
:class="{ active: currentAvatar === item }" :class="{ active: currentAvatar === item }"
@tap="currentAvatar = item" @tap="currentAvatar = item"
> >
<image :src="item" class="avatar-thumb" mode="aspectFill" /> <image
:src="item.imageUrl"
class="avatar-thumb"
mode="aspectFill"
/>
<view v-if="currentAvatar === item" class="check"></view> <view v-if="currentAvatar === item" class="check"></view>
</view> </view>
</view> </view>
@@ -88,7 +96,7 @@
:class="{ active: selectedFrame === frame }" :class="{ active: selectedFrame === frame }"
@tap="toggleFrame(frame)" @tap="toggleFrame(frame)"
> >
<image :src="frame" class="grid-img" mode="aspectFill" /> <image :src="frame.imageUrl" class="grid-img" mode="aspectFill" />
<view v-if="selectedFrame === frame" class="check"></view> <view v-if="selectedFrame === frame" class="check"></view>
</view> </view>
</view> </view>
@@ -101,7 +109,7 @@
:class="{ active: selectedDecor === decor }" :class="{ active: selectedDecor === decor }"
@tap="selectedDecor = decor" @tap="selectedDecor = decor"
> >
<image :src="decor" class="grid-img" mode="aspectFit" /> <image :src="decor.imageUrl" class="grid-img" mode="aspectFit" />
<view v-if="selectedDecor === decor" class="check"></view> <view v-if="selectedDecor === decor" class="check"></view>
</view> </view>
</view> </view>
@@ -136,7 +144,7 @@
class="popup-item" class="popup-item"
@tap="selectMoreAvatar(item)" @tap="selectMoreAvatar(item)"
> >
<image :src="item" class="popup-img" mode="aspectFill" /> <image :src="item.imageUrl" class="popup-img" mode="aspectFill" />
</view> </view>
</view> </view>
<view v-if="loading" class="loading-text">加载中...</view> <view v-if="loading" class="loading-text">加载中...</view>
@@ -191,9 +199,9 @@ const decorPage = ref(1);
const decorHasNext = ref(true); const decorHasNext = ref(true);
const decorLoading = ref(false); const decorLoading = ref(false);
const currentAvatar = ref(""); const currentAvatar = ref(null);
const selectedFrame = ref(""); const selectedFrame = ref(null);
const selectedDecor = ref(""); const selectedDecor = ref(null);
const activeTab = ref("frame"); const activeTab = ref("frame");
// More Popup logic // More Popup logic
@@ -210,7 +218,12 @@ const loadFrames = async () => {
const res = await getAvatarFrameList(framePage.value); const res = await getAvatarFrameList(framePage.value);
const list = res?.list || []; const list = res?.list || [];
if (list.length > 0) { if (list.length > 0) {
frames.value.push(...list.map((item) => item.imageUrl)); frames.value.push(
...list.map((item) => ({
id: item.id,
imageUrl: item.imageUrl,
})),
);
framePage.value++; framePage.value++;
} }
if (typeof res.hasNext !== "undefined") { if (typeof res.hasNext !== "undefined") {
@@ -232,7 +245,12 @@ const loadDecors = async () => {
const res = await getAvatarDecorList(decorPage.value); const res = await getAvatarDecorList(decorPage.value);
const list = res?.list || []; const list = res?.list || [];
if (list.length > 0) { if (list.length > 0) {
decors.value.push(...list.map((item) => item.imageUrl)); decors.value.push(
...list.map((item) => ({
id: item.id,
imageUrl: item.imageUrl,
})),
);
decorPage.value++; decorPage.value++;
} }
if (typeof res.hasNext !== "undefined") { if (typeof res.hasNext !== "undefined") {
@@ -253,7 +271,9 @@ const initSystemAvatars = async () => {
const list = res?.list || []; const list = res?.list || [];
if (list.length > 0) { if (list.length > 0) {
// 取前3个展示在首页 // 取前3个展示在首页
systemAvatars.value = list.slice(0, 3).map((item) => item.imageUrl); systemAvatars.value = list
.slice(0, 3)
.map((item) => ({ id: item.id, imageUrl: item.imageUrl }));
// 默认选中第一个 // 默认选中第一个
if (systemAvatars.value.length > 0) { if (systemAvatars.value.length > 0) {
currentAvatar.value = systemAvatars.value[0]; currentAvatar.value = systemAvatars.value[0];
@@ -301,7 +321,10 @@ const loadMoreAvatars = async () => {
const list = res?.list || []; const list = res?.list || [];
if (list.length > 0) { if (list.length > 0) {
const newAvatars = list.map((item) => item.imageUrl); const newAvatars = list.map((item) => ({
id: item.id,
imageUrl: item.imageUrl,
}));
moreAvatars.value.push(...newAvatars); moreAvatars.value.push(...newAvatars);
page.value++; page.value++;
} }
@@ -328,14 +351,14 @@ const createAvatarId = () => {
return id; return id;
}; };
const selectMoreAvatar = (url) => { const selectMoreAvatar = (item) => {
currentAvatar.value = url; currentAvatar.value = item;
closeMorePopup(); closeMorePopup();
}; };
const toggleFrame = (frame) => { const toggleFrame = (frame) => {
if (selectedFrame.value === frame) { if (selectedFrame.value === frame) {
selectedFrame.value = ""; selectedFrame.value = null;
} else { } else {
selectedFrame.value = frame; selectedFrame.value = frame;
} }
@@ -424,7 +447,10 @@ const useWeChatAvatar = () => {
if (!isLoggedIn.value) { if (!isLoggedIn.value) {
loginPopupRef.value.open(); loginPopupRef.value.open();
} else { } else {
currentAvatar.value = userStore.userInfo.avatarUrl; currentAvatar.value = {
id: "wechat_" + Date.now(),
imageUrl: userStore.userInfo.avatarUrl,
};
} }
}; };
@@ -460,15 +486,15 @@ const saveByCanvas = async (save = true) => {
const size = 600; const size = 600;
canvas.width = size; canvas.width = size;
canvas.height = size; canvas.height = size;
const avatarPath = await loadCanvasImage(currentAvatar.value); const avatarPath = await loadCanvasImage(currentAvatar.value.imageUrl);
ctx.clearRect(0, 0, size, size); ctx.clearRect(0, 0, size, size);
ctx.drawImage(avatarPath, 0, 0, size, size); ctx.drawImage(avatarPath, 0, 0, size, size);
if (selectedFrame.value) { if (selectedFrame.value) {
const framePath = await loadCanvasImage(selectedFrame.value); const framePath = await loadCanvasImage(selectedFrame.value.imageUrl);
ctx.drawImage(framePath, 0, 0, size, size); ctx.drawImage(framePath, 0, 0, size, size);
} }
if (selectedDecor.value) { if (selectedDecor.value) {
const decorPath = await loadCanvasImage(selectedDecor.value); const decorPath = await loadCanvasImage(selectedDecor.value.imageUrl);
ctx.save(); ctx.save();
// 映射 rpx 坐标到 Canvas 坐标 (假设 1rpx = 1 unit for 600x600 canvas logic) // 映射 rpx 坐标到 Canvas 坐标 (假设 1rpx = 1 unit for 600x600 canvas logic)
// Canvas size is 600, Preview is 600rpx. Ratio is 1:1 in logical space. // Canvas size is 600, Preview is 600rpx. Ratio is 1:1 in logical space.
@@ -553,7 +579,10 @@ const saveAndUse = async () => {
return; return;
} }
saveByCanvas(); const tempPath = saveByCanvas(true);
const id = createAvatarId();
saveRecordRequest(tempPath, id, "avatar_download");
completeCardInfo(id);
return; return;
// 调用avatarDownloadRecord API记录下载次数 // 调用avatarDownloadRecord API记录下载次数
// await avatarDownloadRecord({ // await avatarDownloadRecord({
@@ -605,7 +634,13 @@ const saveAndUse = async () => {
const completeCardInfo = async (id) => { const completeCardInfo = async (id) => {
const tempPath = await saveByCanvas(false); const tempPath = await saveByCanvas(false);
const imageUrl = await uploadImage(tempPath); const imageUrl = await uploadImage(tempPath);
avatarCreateComplete({ id, imageUrl, avatarId: id }); avatarCreateComplete({
id,
imageUrl,
avatarId: currentAvatar?.value?.id,
decorId: selectedDecor?.value?.id,
frameId: selectedFrame?.value?.id,
});
}; };
onShareAppMessage(async () => { onShareAppMessage(async () => {