Compare commits
10 Commits
123d7521d7
...
b06a69bd33
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b06a69bd33 | ||
|
|
71620d6199 | ||
|
|
313435d13f | ||
|
|
54e8581b81 | ||
|
|
b6d4a8074e | ||
|
|
03fa790ca2 | ||
|
|
1aef7f1c7c | ||
|
|
a787280e6f | ||
|
|
bf9930d4e4 | ||
|
|
1af26efe14 |
@@ -30,6 +30,13 @@ export const getCardTemplateContentList = async (page = 1) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getCardMusicList = async () => {
|
||||||
|
return request({
|
||||||
|
url: "/api/blessing/card/music/list",
|
||||||
|
method: "GET",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const getCardTemplateTitleList = async (page = 1) => {
|
export const getCardTemplateTitleList = async (page = 1) => {
|
||||||
return request({
|
return request({
|
||||||
url: "/api/blessing/card/template-title/list?page=" + page,
|
url: "/api/blessing/card/template-title/list?page=" + page,
|
||||||
|
|||||||
@@ -73,3 +73,11 @@ export const getTipsList = async () => {
|
|||||||
method: "get",
|
method: "get",
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const createTracking = async (data) => {
|
||||||
|
return request({
|
||||||
|
url: "/api/common/tracking/create",
|
||||||
|
method: "POST",
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
14
pages.json
14
pages.json
@@ -12,7 +12,7 @@
|
|||||||
{
|
{
|
||||||
"path": "pages/make/index",
|
"path": "pages/make/index",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "讨论",
|
"navigationBarTitleText": "制作祝福卡",
|
||||||
"enablePullDownRefresh": true,
|
"enablePullDownRefresh": true,
|
||||||
"navigationStyle": "custom"
|
"navigationStyle": "custom"
|
||||||
}
|
}
|
||||||
@@ -89,6 +89,14 @@
|
|||||||
"navigationStyle": "custom"
|
"navigationStyle": "custom"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/creation/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "创作中心",
|
||||||
|
"navigationStyle": "custom",
|
||||||
|
"backgroundColor": "#fbfbfb"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "pages/detail/index",
|
"path": "pages/detail/index",
|
||||||
"style": {
|
"style": {
|
||||||
@@ -176,8 +184,8 @@
|
|||||||
"selectedIconPath": "static/images/tabBar/home_s.png"
|
"selectedIconPath": "static/images/tabBar/home_s.png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"text": "定制贺卡",
|
"text": "创作",
|
||||||
"pagePath": "pages/make/index",
|
"pagePath": "pages/creation/index",
|
||||||
"iconPath": "static/images/tabBar/creation.png",
|
"iconPath": "static/images/tabBar/creation.png",
|
||||||
"selectedIconPath": "static/images/tabBar/creation_s.png"
|
"selectedIconPath": "static/images/tabBar/creation_s.png"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ onShareAppMessage(async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
onShareTimeline(async () => {
|
onShareTimeline(async () => {
|
||||||
const token = await getShareToken("avatar_timeline", detailData.value?.id);
|
const token = await getShareToken("avatar_download", detailData.value?.id);
|
||||||
return {
|
return {
|
||||||
title: "快来看看我刚领到的新年专属头像 🎊",
|
title: "快来看看我刚领到的新年专属头像 🎊",
|
||||||
query: `shareToken=${token}`,
|
query: `shareToken=${token}`,
|
||||||
|
|||||||
@@ -99,7 +99,7 @@
|
|||||||
:key="item.id"
|
:key="item.id"
|
||||||
class="grid-item"
|
class="grid-item"
|
||||||
:class="{ active: currentAvatar?.id === item.id }"
|
:class="{ active: currentAvatar?.id === item.id }"
|
||||||
@tap="currentAvatar = item"
|
@tap="toggleAvatar(item)"
|
||||||
>
|
>
|
||||||
<image :src="item.imageUrl" class="grid-img" mode="aspectFill" />
|
<image :src="item.imageUrl" class="grid-img" mode="aspectFill" />
|
||||||
<view v-if="currentAvatar?.id === item.id" class="check">✓</view>
|
<view v-if="currentAvatar?.id === item.id" class="check">✓</view>
|
||||||
@@ -218,6 +218,7 @@ import {
|
|||||||
uploadImage,
|
uploadImage,
|
||||||
saveViewRequest,
|
saveViewRequest,
|
||||||
} from "@/utils/common.js";
|
} from "@/utils/common.js";
|
||||||
|
import { trackRecord } from "@/utils/common.js";
|
||||||
import NavBar from "@/components/NavBar/NavBar.vue";
|
import NavBar from "@/components/NavBar/NavBar.vue";
|
||||||
import LoginPopup from "@/components/LoginPopup/LoginPopup.vue";
|
import LoginPopup from "@/components/LoginPopup/LoginPopup.vue";
|
||||||
|
|
||||||
@@ -376,6 +377,10 @@ onLoad((options) => {
|
|||||||
shareToken.value = options.shareToken;
|
shareToken.value = options.shareToken;
|
||||||
saveViewRequest("avatar_download", options.shareToken);
|
saveViewRequest("avatar_download", options.shareToken);
|
||||||
}
|
}
|
||||||
|
trackRecord({
|
||||||
|
eventName: "avatar_page_visit",
|
||||||
|
eventType: `visit`,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
onReachBottom(() => {
|
onReachBottom(() => {
|
||||||
@@ -386,13 +391,32 @@ onReachBottom(() => {
|
|||||||
} else if (activeTool.value === "decor") {
|
} else if (activeTool.value === "decor") {
|
||||||
loadDecors();
|
loadDecors();
|
||||||
}
|
}
|
||||||
|
trackRecord({
|
||||||
|
eventName: "avatar_load_more",
|
||||||
|
eventType: `load_more`,
|
||||||
|
elementId: activeTool.value,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const goBack = () => {
|
const goBack = () => {
|
||||||
uni.navigateBack();
|
uni.navigateBack();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const toggleAvatar = (avatar) => {
|
||||||
|
currentAvatar.value = avatar;
|
||||||
|
trackRecord({
|
||||||
|
eventName: "avatar_click",
|
||||||
|
eventType: `select`,
|
||||||
|
elementId: avatar?.id || "",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const toggleFrame = (frame) => {
|
const toggleFrame = (frame) => {
|
||||||
|
trackRecord({
|
||||||
|
eventName: "avatar_frame_click",
|
||||||
|
eventType: `select`,
|
||||||
|
elementId: frame?.id || "",
|
||||||
|
});
|
||||||
if (selectedFrame.value === frame) {
|
if (selectedFrame.value === frame) {
|
||||||
selectedFrame.value = null;
|
selectedFrame.value = null;
|
||||||
} else {
|
} else {
|
||||||
@@ -401,6 +425,11 @@ const toggleFrame = (frame) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const toggleDecor = (decor) => {
|
const toggleDecor = (decor) => {
|
||||||
|
trackRecord({
|
||||||
|
eventName: "avatar_decor_click",
|
||||||
|
eventType: `select`,
|
||||||
|
elementId: decor?.id || "",
|
||||||
|
});
|
||||||
if (selectedDecor.value === decor) {
|
if (selectedDecor.value === decor) {
|
||||||
selectedDecor.value = null;
|
selectedDecor.value = null;
|
||||||
} else {
|
} else {
|
||||||
@@ -488,6 +517,7 @@ const handleLogind = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onChooseAlbum = () => {
|
const onChooseAlbum = () => {
|
||||||
|
trackRecord({ eventName: "avatar_choose_album", eventType: "click" });
|
||||||
uni.chooseImage({
|
uni.chooseImage({
|
||||||
count: 1,
|
count: 1,
|
||||||
sizeType: ["original", "compressed"],
|
sizeType: ["original", "compressed"],
|
||||||
@@ -728,16 +758,12 @@ const completeCardInfo = async (id) => {
|
|||||||
return imageUrl;
|
return imageUrl;
|
||||||
};
|
};
|
||||||
|
|
||||||
onShareAppMessage(async () => {
|
onShareAppMessage(async (options) => {
|
||||||
getShareReward({ scene: "avatar_download" });
|
getShareReward({ scene: "avatar_download" });
|
||||||
|
if (options.from === "button") {
|
||||||
if (!isLoggedIn.value) {
|
if (!isLoggedIn.value) {
|
||||||
const shareToken = await getShareToken("avatar_download_not_login", "");
|
loginPopupRef.value.open();
|
||||||
return {
|
return;
|
||||||
title: "新春祝福",
|
|
||||||
path: `/pages/index/index?shareToken=${shareToken}`,
|
|
||||||
imageUrl:
|
|
||||||
"https://file.lihailezzc.com/resource/8dd026d76ef7a63d123b7fd698fb989b.png",
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
uni.showLoading({ title: "分享中...", mask: true });
|
uni.showLoading({ title: "分享中...", mask: true });
|
||||||
const id = createAvatarId();
|
const id = createAvatarId();
|
||||||
@@ -747,11 +773,21 @@ onShareAppMessage(async () => {
|
|||||||
]);
|
]);
|
||||||
uni.hideLoading();
|
uni.hideLoading();
|
||||||
return {
|
return {
|
||||||
title: "我做了一个新头像,真的太好看了",
|
title: "3 秒生成新春专属头像,真的好看😆",
|
||||||
path: `/pages/avatar/detail?shareToken=${shareToken}`,
|
path: `/pages/avatar/detail?shareToken=${shareToken}`,
|
||||||
imageUrl:
|
imageUrl:
|
||||||
imageUrl + "?imageMogr2/thumbnail/!500x400r/gravity/Center/crop/500x400",
|
imageUrl +
|
||||||
|
"?imageMogr2/thumbnail/!500x400r/gravity/Center/crop/500x400",
|
||||||
};
|
};
|
||||||
|
} else {
|
||||||
|
const shareToken = await getShareToken("avatar_download_not_login", "");
|
||||||
|
return {
|
||||||
|
title: "3 秒生成新春专属头像,真的好看😆",
|
||||||
|
path: `/pages/avatar/index?shareToken=${shareToken}`,
|
||||||
|
imageUrl:
|
||||||
|
"https://file.lihailezzc.com/resource/8dd026d76ef7a63d123b7fd698fb989b.png",
|
||||||
|
};
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onShareTimeline(async () => {
|
onShareTimeline(async () => {
|
||||||
|
|||||||
472
pages/creation/index.vue
Normal file
472
pages/creation/index.vue
Normal file
@@ -0,0 +1,472 @@
|
|||||||
|
<template>
|
||||||
|
<view class="creation-page" :style="{ paddingTop: navBarHeight + 'px' }">
|
||||||
|
<!-- 自定义导航栏 -->
|
||||||
|
<view
|
||||||
|
class="custom-nav"
|
||||||
|
:style="{
|
||||||
|
height: navBarHeight + 'px',
|
||||||
|
paddingTop: statusBarHeight + 'px',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<text class="nav-title">创作中心</text>
|
||||||
|
<view class="search-icon" @tap="handleSearch">
|
||||||
|
<uni-icons type="search" size="20" color="#333" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="container">
|
||||||
|
<!-- 今日推荐创作 Banner -->
|
||||||
|
<view class="recommend-banner" @tap="goToMake">
|
||||||
|
<view class="banner-content">
|
||||||
|
<view class="banner-tag">
|
||||||
|
<view class="tag-line"></view>
|
||||||
|
<text>灵感瞬间</text>
|
||||||
|
</view>
|
||||||
|
<view class="banner-title">今日推荐创作</view>
|
||||||
|
<view class="banner-main-title">开启你的第一份<br />新春祝福</view>
|
||||||
|
<view class="go-btn">去制作</view>
|
||||||
|
</view>
|
||||||
|
<image
|
||||||
|
class="banner-decor"
|
||||||
|
src="/static/icon/celebrate.png"
|
||||||
|
mode="aspectFit"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 快捷制作 -->
|
||||||
|
<view class="section">
|
||||||
|
<view class="section-header">
|
||||||
|
<text class="section-title">快捷制作</text>
|
||||||
|
</view>
|
||||||
|
<view class="quick-grid">
|
||||||
|
<view class="quick-item" @tap="handleQuickAction('card')">
|
||||||
|
<view class="icon-box card-bg">
|
||||||
|
<image src="/static/icon/celebrate.png" mode="aspectFit" />
|
||||||
|
</view>
|
||||||
|
<text>新春贺卡</text>
|
||||||
|
</view>
|
||||||
|
<view class="quick-item" @tap="handleQuickAction('fortune')">
|
||||||
|
<view class="icon-box fortune-bg">
|
||||||
|
<image src="/static/icon/yunshi.png" mode="aspectFit" />
|
||||||
|
</view>
|
||||||
|
<text>今日运势</text>
|
||||||
|
</view>
|
||||||
|
<view class="quick-item" @tap="handleQuickAction('avatar')">
|
||||||
|
<view class="icon-box avatar-bg">
|
||||||
|
<image src="/static/icon/guashi.png" mode="aspectFit" />
|
||||||
|
</view>
|
||||||
|
<text>头像挂饰</text>
|
||||||
|
</view>
|
||||||
|
<view class="quick-item" @tap="handleQuickAction('wallpaper')">
|
||||||
|
<view class="icon-box wallpaper-bg">
|
||||||
|
<image src="/static/icon/bizhi.png" mode="aspectFit" />
|
||||||
|
</view>
|
||||||
|
<text>精美壁纸</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 按心情创作 -->
|
||||||
|
<view class="section">
|
||||||
|
<view class="section-header">
|
||||||
|
<text class="section-title">按心情创作</text>
|
||||||
|
</view>
|
||||||
|
<scroll-view scroll-x class="mood-scroll" show-scrollbar="false">
|
||||||
|
<view class="mood-list">
|
||||||
|
<view
|
||||||
|
v-for="(mood, index) in moods"
|
||||||
|
:key="index"
|
||||||
|
class="mood-item"
|
||||||
|
@tap="handleMoodClick(mood)"
|
||||||
|
>
|
||||||
|
<text class="mood-emoji">{{ mood.emoji }}</text>
|
||||||
|
<text class="mood-name">{{ mood.name }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 编辑精选 -->
|
||||||
|
<view class="section">
|
||||||
|
<view class="section-header">
|
||||||
|
<text class="section-title">编辑精选</text>
|
||||||
|
<text class="view-all" @tap="viewAll">查看全部</text>
|
||||||
|
</view>
|
||||||
|
<view class="featured-grid">
|
||||||
|
<view
|
||||||
|
v-for="(item, index) in featuredList"
|
||||||
|
:key="index"
|
||||||
|
class="featured-item"
|
||||||
|
@tap="onCardClick(item)"
|
||||||
|
>
|
||||||
|
<view class="item-cover-wrap">
|
||||||
|
<image
|
||||||
|
:src="item.imageUrl"
|
||||||
|
mode="aspectFill"
|
||||||
|
class="item-cover"
|
||||||
|
/>
|
||||||
|
<view v-if="item.tag" class="item-tag" :class="item.tag">{{
|
||||||
|
item.tagText
|
||||||
|
}}</view>
|
||||||
|
</view>
|
||||||
|
<text class="item-title">{{ item.title }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
import { getBavBarHeight, getStatusBarHeight } from "@/utils/system";
|
||||||
|
import { getRecommendList } from "@/api/system";
|
||||||
|
import { trackRecord } from "@/utils/common.js";
|
||||||
|
|
||||||
|
const navBarHeight = ref(getBavBarHeight());
|
||||||
|
const statusBarHeight = ref(getStatusBarHeight());
|
||||||
|
|
||||||
|
const moods = ref([
|
||||||
|
{ name: "开心", emoji: "🎉" },
|
||||||
|
{ name: "想念", emoji: "💌" },
|
||||||
|
{ name: "加油", emoji: "💪" },
|
||||||
|
{ name: "好运", emoji: "🧧" },
|
||||||
|
{ name: "暴富", emoji: "💰" },
|
||||||
|
]);
|
||||||
|
|
||||||
|
const featuredList = ref([]);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchFeaturedList();
|
||||||
|
trackRecord({
|
||||||
|
eventName: "creation_page_visit",
|
||||||
|
eventType: "visit",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchFeaturedList = async () => {
|
||||||
|
try {
|
||||||
|
const res = await getRecommendList(1);
|
||||||
|
const list = res?.list || [];
|
||||||
|
featuredList.value = list.slice(0, 4).map((item) => ({
|
||||||
|
...item,
|
||||||
|
tag: item.tag === "hot" ? "hot" : item.tag === "new" ? "new" : "",
|
||||||
|
tagText: item.tag === "hot" ? "HOT" : item.tag === "new" ? "NEW" : "",
|
||||||
|
}));
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSearch = () => {
|
||||||
|
uni.showToast({ title: "搜索功能开发中", icon: "none" });
|
||||||
|
};
|
||||||
|
|
||||||
|
const goToMake = () => {
|
||||||
|
uni.navigateTo({ url: "/pages/make/index" });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleQuickAction = (type) => {
|
||||||
|
const map = {
|
||||||
|
card: "/pages/make/index",
|
||||||
|
fortune: "/pages/fortune/index",
|
||||||
|
avatar: "/pages/avatar/index",
|
||||||
|
wallpaper: "/pages/wallpaper/index",
|
||||||
|
};
|
||||||
|
|
||||||
|
uni.navigateTo({ url: map[type] });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMoodClick = (mood) => {
|
||||||
|
uni.showToast({ title: `选择了${mood.name}心情`, icon: "none" });
|
||||||
|
};
|
||||||
|
|
||||||
|
const viewAll = () => {
|
||||||
|
uni.switchTab({ url: "/pages/index/index" });
|
||||||
|
};
|
||||||
|
|
||||||
|
const onCardClick = (card) => {
|
||||||
|
const query = `recommendId=${card.recommendId || ""}&type=${card.type || ""}&imageUrl=${encodeURIComponent(card.imageUrl || "")}`;
|
||||||
|
if (card.type === "card") {
|
||||||
|
uni.setStorageSync("RECOMMEND_CARD_DATA", {
|
||||||
|
recommendId: card.recommendId,
|
||||||
|
imageUrl: card.imageUrl,
|
||||||
|
type: card.type,
|
||||||
|
});
|
||||||
|
uni.navigateTo({ url: "/pages/make/index" });
|
||||||
|
} else {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/avatar/index?${query}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.creation-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
background-color: #fbfbfb;
|
||||||
|
padding-bottom: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-nav {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 100;
|
||||||
|
background-color: #fbfbfb;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 32rpx;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.nav-title {
|
||||||
|
font-size: 36rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-icon {
|
||||||
|
width: 64rpx;
|
||||||
|
height: 64rpx;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
padding: 24rpx 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recommend-banner {
|
||||||
|
height: 320rpx;
|
||||||
|
background: linear-gradient(135deg, #fff5f5 0%, #fff 100%);
|
||||||
|
border-radius: 32rpx;
|
||||||
|
padding: 40rpx;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
box-shadow: 0 8rpx 24rpx rgba(255, 59, 48, 0.05);
|
||||||
|
margin-bottom: 48rpx;
|
||||||
|
|
||||||
|
.banner-content {
|
||||||
|
flex: 1;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-tag {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 12rpx;
|
||||||
|
|
||||||
|
.tag-line {
|
||||||
|
width: 32rpx;
|
||||||
|
height: 4rpx;
|
||||||
|
background: #ff3b30;
|
||||||
|
margin-right: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
text {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #ff3b30;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-title {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-main-title {
|
||||||
|
font-size: 40rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #000;
|
||||||
|
line-height: 1.4;
|
||||||
|
margin-bottom: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.go-btn {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 12rpx 40rpx;
|
||||||
|
background: #ff3b30;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 26rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
border-radius: 32rpx;
|
||||||
|
box-shadow: 0 8rpx 16rpx rgba(255, 59, 48, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-decor {
|
||||||
|
width: 200rpx;
|
||||||
|
height: 200rpx;
|
||||||
|
opacity: 0.1;
|
||||||
|
position: absolute;
|
||||||
|
right: 20rpx;
|
||||||
|
bottom: 20rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.section {
|
||||||
|
margin-bottom: 48rpx;
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 24rpx;
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-all {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #ff3b30;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 24rpx;
|
||||||
|
|
||||||
|
.quick-item {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 24rpx;
|
||||||
|
padding: 32rpx;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.02);
|
||||||
|
|
||||||
|
.icon-box {
|
||||||
|
width: 96rpx;
|
||||||
|
height: 96rpx;
|
||||||
|
border-radius: 24rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
|
||||||
|
image {
|
||||||
|
width: 56rpx;
|
||||||
|
height: 56rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.card-bg {
|
||||||
|
background: #fff1f1;
|
||||||
|
}
|
||||||
|
&.fortune-bg {
|
||||||
|
background: #fff8e6;
|
||||||
|
}
|
||||||
|
&.avatar-bg {
|
||||||
|
background: #f0f7ff;
|
||||||
|
}
|
||||||
|
&.wallpaper-bg {
|
||||||
|
background: #f0fff4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
text {
|
||||||
|
font-size: 26rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mood-scroll {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.mood-list {
|
||||||
|
display: flex;
|
||||||
|
padding: 8rpx 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mood-item {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background: #fff;
|
||||||
|
padding: 16rpx 32rpx;
|
||||||
|
border-radius: 40rpx;
|
||||||
|
margin-right: 20rpx;
|
||||||
|
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.02);
|
||||||
|
|
||||||
|
.mood-emoji {
|
||||||
|
font-size: 32rpx;
|
||||||
|
margin-right: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mood-name {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #333;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.featured-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 24rpx;
|
||||||
|
|
||||||
|
.featured-item {
|
||||||
|
.item-cover-wrap {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 320rpx;
|
||||||
|
border-radius: 24rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
background: #eee;
|
||||||
|
|
||||||
|
.item-cover {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-tag {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
padding: 6rpx 16rpx;
|
||||||
|
font-size: 20rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #fff;
|
||||||
|
border-bottom-left-radius: 16rpx;
|
||||||
|
|
||||||
|
&.hot {
|
||||||
|
background: #ff3b30;
|
||||||
|
}
|
||||||
|
&.new {
|
||||||
|
background: #007aff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-title {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #333;
|
||||||
|
font-weight: 500;
|
||||||
|
padding: 0 8rpx;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -22,6 +22,16 @@
|
|||||||
{{ cardDetail?.festival || "丙午马年" }}
|
{{ cardDetail?.festival || "丙午马年" }}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- Music Control -->
|
||||||
|
<view
|
||||||
|
v-if="cardDetail?.musicUrl"
|
||||||
|
class="music-control"
|
||||||
|
:class="{ playing: isBgmPlaying }"
|
||||||
|
@tap="toggleBgm"
|
||||||
|
>
|
||||||
|
<text class="music-icon">{{ isBgmPlaying ? "🎵" : "🔇" }}</text>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- Card Preview Area -->
|
<!-- Card Preview Area -->
|
||||||
@@ -114,14 +124,50 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from "vue";
|
import { ref, onUnmounted } from "vue";
|
||||||
import { onLoad, onShareAppMessage, onShareTimeline } from "@dcloudio/uni-app";
|
import {
|
||||||
|
onLoad,
|
||||||
|
onHide,
|
||||||
|
onUnload,
|
||||||
|
onShareAppMessage,
|
||||||
|
onShareTimeline,
|
||||||
|
} from "@dcloudio/uni-app";
|
||||||
import { getPageDetail } from "@/api/system.js";
|
import { getPageDetail } from "@/api/system.js";
|
||||||
import { getShareToken, saveViewRequest } from "@/utils/common.js";
|
import { getShareToken, saveViewRequest } from "@/utils/common.js";
|
||||||
import NavBar from "@/components/NavBar/NavBar.vue";
|
import NavBar from "@/components/NavBar/NavBar.vue";
|
||||||
|
|
||||||
const cardId = ref("");
|
const cardId = ref("");
|
||||||
const cardDetail = ref({});
|
const cardDetail = ref({});
|
||||||
|
const isBgmPlaying = ref(false);
|
||||||
|
const innerAudioContext = uni.createInnerAudioContext();
|
||||||
|
|
||||||
|
const initBgm = (url) => {
|
||||||
|
if (!url) return;
|
||||||
|
innerAudioContext.src = url;
|
||||||
|
innerAudioContext.loop = true;
|
||||||
|
innerAudioContext.autoplay = true;
|
||||||
|
innerAudioContext.onPlay(() => {
|
||||||
|
isBgmPlaying.value = true;
|
||||||
|
});
|
||||||
|
innerAudioContext.onPause(() => {
|
||||||
|
isBgmPlaying.value = false;
|
||||||
|
});
|
||||||
|
innerAudioContext.onStop(() => {
|
||||||
|
isBgmPlaying.value = false;
|
||||||
|
});
|
||||||
|
innerAudioContext.onError((res) => {
|
||||||
|
console.error("BGM播放错误:", res);
|
||||||
|
isBgmPlaying.value = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleBgm = () => {
|
||||||
|
if (isBgmPlaying.value) {
|
||||||
|
innerAudioContext.pause();
|
||||||
|
} else {
|
||||||
|
innerAudioContext.play();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onLoad(async (options) => {
|
onLoad(async (options) => {
|
||||||
if (options.shareToken) {
|
if (options.shareToken) {
|
||||||
@@ -129,7 +175,21 @@ onLoad(async (options) => {
|
|||||||
cardId.value = card.id;
|
cardId.value = card.id;
|
||||||
cardDetail.value = card;
|
cardDetail.value = card;
|
||||||
saveViewRequest(options.shareToken, "card_generate", card.id);
|
saveViewRequest(options.shareToken, "card_generate", card.id);
|
||||||
|
|
||||||
|
if (card.musicUrl) {
|
||||||
|
initBgm(card.musicUrl);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onHide(() => {
|
||||||
|
if (isBgmPlaying.value) {
|
||||||
|
innerAudioContext.pause();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnload(() => {
|
||||||
|
innerAudioContext.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
onShareAppMessage(async () => {
|
onShareAppMessage(async () => {
|
||||||
@@ -144,7 +204,7 @@ onShareAppMessage(async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
onShareTimeline(async () => {
|
onShareTimeline(async () => {
|
||||||
const token = await getShareToken("card_timeline", cardDetail.value?.id);
|
const token = await getShareToken("card_generate", cardDetail.value?.id);
|
||||||
return {
|
return {
|
||||||
title: "送你一张精美的新春祝福卡片 🎊",
|
title: "送你一张精美的新春祝福卡片 🎊",
|
||||||
query: `shareToken=${token}`,
|
query: `shareToken=${token}`,
|
||||||
@@ -246,6 +306,39 @@ const goToWallpaper = () => {
|
|||||||
padding: 20rpx 30rpx 60rpx;
|
padding: 20rpx 30rpx 60rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Music Control */
|
||||||
|
.music-control {
|
||||||
|
margin-left: auto;
|
||||||
|
width: 64rpx;
|
||||||
|
height: 64rpx;
|
||||||
|
background: rgba(255, 59, 48, 0.05);
|
||||||
|
border: 2rpx solid rgba(255, 59, 48, 0.1);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&.playing {
|
||||||
|
animation: rotate 3s linear infinite;
|
||||||
|
background: rgba(255, 59, 48, 0.1);
|
||||||
|
border-color: rgba(255, 59, 48, 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.music-icon {
|
||||||
|
font-size: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rotate {
|
||||||
|
from {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* User Header */
|
/* User Header */
|
||||||
.user-header {
|
.user-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ import {
|
|||||||
saveRemoteImageToLocal,
|
saveRemoteImageToLocal,
|
||||||
saveRecordRequest,
|
saveRecordRequest,
|
||||||
saveViewRequest,
|
saveViewRequest,
|
||||||
|
trackRecord,
|
||||||
} from "@/utils/common.js";
|
} from "@/utils/common.js";
|
||||||
import NavBar from "@/components/NavBar/NavBar.vue";
|
import NavBar from "@/components/NavBar/NavBar.vue";
|
||||||
|
|
||||||
@@ -166,6 +167,10 @@ onLoad((options) => {
|
|||||||
shareToken.value = options.shareToken;
|
shareToken.value = options.shareToken;
|
||||||
saveViewRequest(options.shareToken, "fortune_draw");
|
saveViewRequest(options.shareToken, "fortune_draw");
|
||||||
}
|
}
|
||||||
|
trackRecord({
|
||||||
|
eventName: "fortune_page_visit",
|
||||||
|
eventType: `visit`,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
onShow(() => {
|
onShow(() => {
|
||||||
@@ -198,9 +203,6 @@ onShareTimeline(async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const handleLogind = async () => {
|
const handleLogind = async () => {
|
||||||
if (shareToken.value) {
|
|
||||||
console.log(11111111, shareToken.value);
|
|
||||||
}
|
|
||||||
checkDrawStatus();
|
checkDrawStatus();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -89,6 +89,8 @@ import { onLoad } from "@dcloudio/uni-app";
|
|||||||
import { getList } from "@/api/fortune.js";
|
import { getList } from "@/api/fortune.js";
|
||||||
import NavBar from "@/components/NavBar/NavBar.vue";
|
import NavBar from "@/components/NavBar/NavBar.vue";
|
||||||
import { formatDate } from "@/utils/date.js";
|
import { formatDate } from "@/utils/date.js";
|
||||||
|
import { trackRecord } from "@/utils/common.js";
|
||||||
|
|
||||||
// 状态管理
|
// 状态管理
|
||||||
const records = ref([]);
|
const records = ref([]);
|
||||||
const page = ref(1);
|
const page = ref(1);
|
||||||
@@ -160,6 +162,10 @@ const loadData = async () => {
|
|||||||
|
|
||||||
const loadMore = () => {
|
const loadMore = () => {
|
||||||
loadData();
|
loadData();
|
||||||
|
trackRecord({
|
||||||
|
eventName: "fortune_record_page_visit",
|
||||||
|
eventType: `visit`,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const goDetail = (item) => {
|
const goDetail = (item) => {
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ import {
|
|||||||
} from "@dcloudio/uni-app";
|
} from "@dcloudio/uni-app";
|
||||||
import { getBavBarHeight } from "@/utils/system";
|
import { getBavBarHeight } from "@/utils/system";
|
||||||
import { getRecommendList, getRandomGreeting, getTipsList } from "@/api/system";
|
import { getRecommendList, getRandomGreeting, getTipsList } from "@/api/system";
|
||||||
import { getShareToken, saveViewRequest } from "@/utils/common.js";
|
import { getShareToken, saveViewRequest, trackRecord } from "@/utils/common.js";
|
||||||
|
|
||||||
const countdownText = ref("");
|
const countdownText = ref("");
|
||||||
const recommendList = ref([]);
|
const recommendList = ref([]);
|
||||||
@@ -194,7 +194,10 @@ onLoad((options) => {
|
|||||||
// updateCountdown();
|
// updateCountdown();
|
||||||
getRandomGreetingText();
|
getRandomGreetingText();
|
||||||
fetchRecommendList();
|
fetchRecommendList();
|
||||||
|
trackRecord({
|
||||||
|
eventName: "index_page_visit",
|
||||||
|
eventType: `visit`,
|
||||||
|
});
|
||||||
// Daily Inspiration Logic
|
// Daily Inspiration Logic
|
||||||
// const startOfYear = new Date(date.getFullYear(), 0, 0);
|
// const startOfYear = new Date(date.getFullYear(), 0, 0);
|
||||||
// const diff = date - startOfYear;
|
// const diff = date - startOfYear;
|
||||||
@@ -237,6 +240,11 @@ const getRandomGreetingText = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const useGreeting = () => {
|
const useGreeting = () => {
|
||||||
|
trackRecord({
|
||||||
|
eventName: "index_goto_make",
|
||||||
|
eventType: "jump",
|
||||||
|
elementId: dailyGreeting.value,
|
||||||
|
});
|
||||||
uni.setStorageSync("TEMP_BLESSING_TEXT", dailyGreeting.value);
|
uni.setStorageSync("TEMP_BLESSING_TEXT", dailyGreeting.value);
|
||||||
uni.switchTab({
|
uni.switchTab({
|
||||||
url: "/pages/make/index",
|
url: "/pages/make/index",
|
||||||
@@ -345,6 +353,11 @@ const getCtaText = (type) => {
|
|||||||
|
|
||||||
const onCardClick = (card) => {
|
const onCardClick = (card) => {
|
||||||
// 构造传递的数据
|
// 构造传递的数据
|
||||||
|
trackRecord({
|
||||||
|
eventName: "index_recommend_click",
|
||||||
|
eventType: `jump_${card.type}`,
|
||||||
|
elementId: card?.recommendId || "",
|
||||||
|
});
|
||||||
const query = `recommendId=${card.recommendId || ""}&type=${card.type || ""}&imageUrl=${encodeURIComponent(card.imageUrl || "")}`;
|
const query = `recommendId=${card.recommendId || ""}&type=${card.type || ""}&imageUrl=${encodeURIComponent(card.imageUrl || "")}`;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@@ -377,6 +390,11 @@ const onCardClick = (card) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onFeatureTap = (item) => {
|
const onFeatureTap = (item) => {
|
||||||
|
trackRecord({
|
||||||
|
eventName: "index_function_select",
|
||||||
|
eventType: "jump",
|
||||||
|
elementId: item.type,
|
||||||
|
});
|
||||||
if (item.type === "fortune") {
|
if (item.type === "fortune") {
|
||||||
uni.navigateTo({ url: "/pages/fortune/index" });
|
uni.navigateTo({ url: "/pages/fortune/index" });
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="make-page" :style="{ paddingTop: getBavBarHeight() + 'px' }">
|
<view class="make-page">
|
||||||
|
<NavBar title="祝福贺卡" />
|
||||||
<!-- 顶部步骤条 -->
|
<!-- 顶部步骤条 -->
|
||||||
<view class="top-steps">
|
<view class="top-steps">
|
||||||
<view class="step-bar">
|
<view class="step-bar">
|
||||||
@@ -26,6 +27,13 @@
|
|||||||
|
|
||||||
<!-- 预览卡片 -->
|
<!-- 预览卡片 -->
|
||||||
<view class="card-preview">
|
<view class="card-preview">
|
||||||
|
<view
|
||||||
|
class="music-control"
|
||||||
|
@tap.stop="openBgmList"
|
||||||
|
:class="{ playing: isBgmPlaying }"
|
||||||
|
>
|
||||||
|
<text class="music-icon">{{ isBgmPlaying ? "🎵" : "🔇" }}</text>
|
||||||
|
</view>
|
||||||
<view class="premium-tag">
|
<view class="premium-tag">
|
||||||
<uni-icons type="info" size="12" color="#fff"></uni-icons>
|
<uni-icons type="info" size="12" color="#fff"></uni-icons>
|
||||||
<text>分享或保存即可去除水印</text>
|
<text>分享或保存即可去除水印</text>
|
||||||
@@ -55,7 +63,7 @@
|
|||||||
@touchmove.stop="handleBubbleTouchMove"
|
@touchmove.stop="handleBubbleTouchMove"
|
||||||
@touchend.stop="handleBubbleTouchEnd"
|
@touchend.stop="handleBubbleTouchEnd"
|
||||||
:style="{
|
:style="{
|
||||||
marginTop: 230 + bubbleOffsetY + 'rpx',
|
marginTop: 140 + bubbleOffsetY + 'rpx',
|
||||||
maxWidth: bubbleMaxWidth + 80 + 'rpx',
|
maxWidth: bubbleMaxWidth + 80 + 'rpx',
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
@@ -432,20 +440,64 @@
|
|||||||
@logind="handleLogind"
|
@logind="handleLogind"
|
||||||
:share-token="shareToken"
|
:share-token="shareToken"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- Music List Popup -->
|
||||||
|
<uni-popup ref="bgmPopup" type="bottom">
|
||||||
|
<view class="bgm-popup">
|
||||||
|
<view class="bgm-header">
|
||||||
|
<text class="bgm-title">选择背景音乐</text>
|
||||||
|
<view class="bgm-close" @tap="closeBgmList">✕</view>
|
||||||
|
</view>
|
||||||
|
<scroll-view scroll-y class="bgm-scroll">
|
||||||
|
<view
|
||||||
|
v-for="(item, index) in bgms"
|
||||||
|
:key="index"
|
||||||
|
class="bgm-item"
|
||||||
|
:class="{ active: currentBgmIndex === index && isBgmPlaying }"
|
||||||
|
@tap="selectBgm(index)"
|
||||||
|
>
|
||||||
|
<view class="bgm-info">
|
||||||
|
<uni-icons
|
||||||
|
:type="
|
||||||
|
currentBgmIndex === index && isBgmPlaying
|
||||||
|
? 'sound-filled'
|
||||||
|
: 'sound'
|
||||||
|
"
|
||||||
|
size="18"
|
||||||
|
:color="
|
||||||
|
currentBgmIndex === index && isBgmPlaying ? '#ff3b30' : '#333'
|
||||||
|
"
|
||||||
|
></uni-icons>
|
||||||
|
<text class="bgm-name">{{ item.name }}</text>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
v-if="currentBgmIndex === index && isBgmPlaying"
|
||||||
|
class="bgm-playing-icon"
|
||||||
|
>
|
||||||
|
<view class="bar bar1"></view>
|
||||||
|
<view class="bar bar2"></view>
|
||||||
|
<view class="bar bar3"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
<view class="bgm-footer" @tap="turnOffBgm">
|
||||||
|
<text class="turn-off-text">关闭音乐</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</uni-popup>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, watch } from "vue";
|
import { ref, computed, watch } from "vue";
|
||||||
import { getBavBarHeight, getDeviceInfo } from "@/utils/system";
|
|
||||||
import { generateObjectId, getShareToken } from "@/utils/common";
|
import { generateObjectId, getShareToken } from "@/utils/common";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
createCardTmp,
|
createCardTmp,
|
||||||
updateCard,
|
updateCard,
|
||||||
getCardTemplateList,
|
getCardTemplateList,
|
||||||
getCardTemplateContentList,
|
getCardTemplateContentList,
|
||||||
getCardTemplateTitleList,
|
getCardTemplateTitleList,
|
||||||
|
getCardMusicList,
|
||||||
} from "@/api/make";
|
} from "@/api/make";
|
||||||
import { abilityCheck, getShareReward, msgCheckApi } from "@/api/system";
|
import { abilityCheck, getShareReward, msgCheckApi } from "@/api/system";
|
||||||
import {
|
import {
|
||||||
@@ -455,10 +507,13 @@ import {
|
|||||||
onReachBottom,
|
onReachBottom,
|
||||||
onShow,
|
onShow,
|
||||||
onPullDownRefresh,
|
onPullDownRefresh,
|
||||||
|
onUnload,
|
||||||
|
onHide,
|
||||||
} from "@dcloudio/uni-app";
|
} from "@dcloudio/uni-app";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
import LoginPopup from "@/components/LoginPopup/LoginPopup.vue";
|
import LoginPopup from "@/components/LoginPopup/LoginPopup.vue";
|
||||||
import { saveRecordRequest, uploadImage } from "@/utils/common.js";
|
import { saveRecordRequest, uploadImage, trackRecord } from "@/utils/common.js";
|
||||||
|
import NavBar from "@/components/NavBar/NavBar.vue";
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const loginPopupRef = ref(null);
|
const loginPopupRef = ref(null);
|
||||||
@@ -484,6 +539,88 @@ const titleState = ref({
|
|||||||
scale: 1,
|
scale: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const bgms = ref([]);
|
||||||
|
const curBgm = ref(null);
|
||||||
|
const currentBgmIndex = ref(0);
|
||||||
|
const isBgmPlaying = ref(false);
|
||||||
|
const innerAudioContext = uni.createInnerAudioContext();
|
||||||
|
const bgmPopup = ref(null);
|
||||||
|
|
||||||
|
const initBgm = () => {
|
||||||
|
if (bgms.value.length > 0) {
|
||||||
|
playBgm(0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const openBgmList = () => {
|
||||||
|
bgmPopup.value.open();
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeBgmList = () => {
|
||||||
|
bgmPopup.value.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectBgm = (index) => {
|
||||||
|
if (index === currentBgmIndex.value && isBgmPlaying.value) {
|
||||||
|
// 如果点击当前正在播放的,暂停
|
||||||
|
// pauseBgm();
|
||||||
|
// 这里用户可能想重播,或者什么都不做。暂时什么都不做
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
curBgm.value = bgms.value[index];
|
||||||
|
playBgm(index);
|
||||||
|
closeBgmList();
|
||||||
|
};
|
||||||
|
|
||||||
|
const turnOffBgm = () => {
|
||||||
|
stopBgm();
|
||||||
|
currentBgmIndex.value = -1; // -1 表示关闭
|
||||||
|
curBgm.value = null;
|
||||||
|
closeBgmList();
|
||||||
|
uni.showToast({ title: "已关闭音乐", icon: "none" });
|
||||||
|
};
|
||||||
|
|
||||||
|
const playBgm = (index) => {
|
||||||
|
if (index < 0 || index >= bgms.value.length) return;
|
||||||
|
|
||||||
|
// 更新 index
|
||||||
|
currentBgmIndex.value = index;
|
||||||
|
|
||||||
|
innerAudioContext.stop();
|
||||||
|
innerAudioContext.src = bgms.value[index].musicUrl;
|
||||||
|
innerAudioContext.loop = true;
|
||||||
|
innerAudioContext.autoplay = true;
|
||||||
|
innerAudioContext.play();
|
||||||
|
|
||||||
|
// 重新绑定事件(防止丢失)
|
||||||
|
innerAudioContext.onPlay(() => {
|
||||||
|
isBgmPlaying.value = true;
|
||||||
|
});
|
||||||
|
innerAudioContext.onPause(() => {
|
||||||
|
isBgmPlaying.value = false;
|
||||||
|
});
|
||||||
|
innerAudioContext.onStop(() => {
|
||||||
|
isBgmPlaying.value = false;
|
||||||
|
});
|
||||||
|
innerAudioContext.onError((res) => {
|
||||||
|
console.error("BGM Error:", res.errMsg);
|
||||||
|
isBgmPlaying.value = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const stopBgm = () => {
|
||||||
|
innerAudioContext.stop();
|
||||||
|
isBgmPlaying.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
onUnload(() => {
|
||||||
|
innerAudioContext.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
onHide(() => {
|
||||||
|
innerAudioContext.stop();
|
||||||
|
});
|
||||||
|
|
||||||
const titleStyle = computed(() => {
|
const titleStyle = computed(() => {
|
||||||
return {
|
return {
|
||||||
transform: `translate(${titleState.value.offsetX}rpx, ${titleState.value.offsetY}rpx) scale(${titleState.value.scale})`,
|
transform: `translate(${titleState.value.offsetX}rpx, ${titleState.value.offsetY}rpx) scale(${titleState.value.scale})`,
|
||||||
@@ -617,8 +754,8 @@ const handleTitleTouchMove = (e) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const targetName = ref("祝您");
|
const targetName = ref("");
|
||||||
const oldTargetName = ref("祝您");
|
const oldTargetName = ref("");
|
||||||
const signatureName = ref(userStore?.userInfo?.nickName || "xxx");
|
const signatureName = ref(userStore?.userInfo?.nickName || "xxx");
|
||||||
const oldSignatureName = ref(userStore?.userInfo?.nickName || "xxx");
|
const oldSignatureName = ref(userStore?.userInfo?.nickName || "xxx");
|
||||||
|
|
||||||
@@ -744,18 +881,23 @@ onLoad((options) => {
|
|||||||
getTemplateList();
|
getTemplateList();
|
||||||
getTemplateContentList();
|
getTemplateContentList();
|
||||||
getTemplateTitleList();
|
getTemplateTitleList();
|
||||||
|
getMusicList();
|
||||||
if (options.shareToken) {
|
if (options.shareToken) {
|
||||||
shareToken.value = options.shareToken;
|
shareToken.value = options.shareToken;
|
||||||
}
|
}
|
||||||
|
trackRecord({
|
||||||
|
eventName: "make_page_visit",
|
||||||
|
eventType: `visit`,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const syncUserInfo = () => {
|
const syncUserInfo = (force = false) => {
|
||||||
if (isLoggedIn.value) {
|
if (isLoggedIn.value) {
|
||||||
if (signatureName.value === "xxx" || !signatureName.value) {
|
if (signatureName.value === "xxx" || !signatureName.value) {
|
||||||
signatureName.value = userStore.userInfo.nickName;
|
signatureName.value = userStore.userInfo.nickName;
|
||||||
oldSignatureName.value = userStore.userInfo.nickName;
|
oldSignatureName.value = userStore.userInfo.nickName;
|
||||||
}
|
}
|
||||||
if (userAvatar.value === DEFAULT_AVATAR || !userAvatar.value) {
|
if (force || userAvatar.value === DEFAULT_AVATAR || !userAvatar.value) {
|
||||||
userAvatar.value = userStore.userInfo.avatarUrl;
|
userAvatar.value = userStore.userInfo.avatarUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -765,14 +907,14 @@ watch(
|
|||||||
() => userStore.userInfo,
|
() => userStore.userInfo,
|
||||||
(newVal) => {
|
(newVal) => {
|
||||||
if (newVal?.nickName) {
|
if (newVal?.nickName) {
|
||||||
syncUserInfo();
|
syncUserInfo(true);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ deep: true },
|
{ deep: true },
|
||||||
);
|
);
|
||||||
|
|
||||||
onShow(() => {
|
onShow(() => {
|
||||||
syncUserInfo();
|
syncUserInfo(true);
|
||||||
const recommendData = uni.getStorageSync("RECOMMEND_CARD_DATA");
|
const recommendData = uni.getStorageSync("RECOMMEND_CARD_DATA");
|
||||||
if (recommendData) {
|
if (recommendData) {
|
||||||
uni.removeStorageSync("RECOMMEND_CARD_DATA");
|
uni.removeStorageSync("RECOMMEND_CARD_DATA");
|
||||||
@@ -884,6 +1026,27 @@ const getTemplateList = async (isLoadMore = false) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getMusicList = async () => {
|
||||||
|
try {
|
||||||
|
const res = await getCardMusicList();
|
||||||
|
if (res && res.length > 0) {
|
||||||
|
bgms.value = res.map((item) => ({
|
||||||
|
id: item.id,
|
||||||
|
name: item.name,
|
||||||
|
musicUrl: item.musicUrl,
|
||||||
|
// 兼容旧逻辑
|
||||||
|
url: item.musicUrl,
|
||||||
|
}));
|
||||||
|
if (bgms.value.length > 0) {
|
||||||
|
curBgm.value = bgms.value[0];
|
||||||
|
}
|
||||||
|
initBgm();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("加载音乐列表失败:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const getTemplateTitleList = async (isLoadMore = false) => {
|
const getTemplateTitleList = async (isLoadMore = false) => {
|
||||||
if (loadingTitles.value || (!hasMoreTitles.value && isLoadMore)) return;
|
if (loadingTitles.value || (!hasMoreTitles.value && isLoadMore)) return;
|
||||||
|
|
||||||
@@ -994,18 +1157,12 @@ const onPanelScrollToLower = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onShareAppMessage(async (options) => {
|
onShareAppMessage(async (options) => {
|
||||||
if (!isLoggedIn.value) {
|
|
||||||
const shareToken = await getShareToken("card_generate_not_login", "");
|
|
||||||
return {
|
|
||||||
title: "快来制作新春祝福卡片🎉",
|
|
||||||
path: "/pages/make/index?shareToken=" + shareToken,
|
|
||||||
imageUrl:
|
|
||||||
"https://file.lihailezzc.com/resource/8dd026d76ef7a63d123b7fd698fb989b.png",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
getShareReward({ scene: "card_generate" });
|
getShareReward({ scene: "card_generate" });
|
||||||
if (options.from === "button") {
|
if (options.from === "button") {
|
||||||
|
if (!isLoggedIn.value) {
|
||||||
|
loginPopupRef.value.open();
|
||||||
|
return;
|
||||||
|
}
|
||||||
// 1. 确保有 cardId (如果内容有变动,最好是新建)
|
// 1. 确保有 cardId (如果内容有变动,最好是新建)
|
||||||
const id = createCard();
|
const id = createCard();
|
||||||
|
|
||||||
@@ -1039,6 +1196,11 @@ onShareTimeline(async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const selectGreeting = (text) => {
|
const selectGreeting = (text) => {
|
||||||
|
trackRecord({
|
||||||
|
eventName: "card_text_choose",
|
||||||
|
eventType: "click",
|
||||||
|
elementId: text?.id,
|
||||||
|
});
|
||||||
blessingText.value = text;
|
blessingText.value = text;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1065,11 +1227,21 @@ const templates = ref([]);
|
|||||||
const currentTemplate = ref(templates.value[0]);
|
const currentTemplate = ref(templates.value[0]);
|
||||||
|
|
||||||
const applyTemplate = (tpl) => {
|
const applyTemplate = (tpl) => {
|
||||||
|
trackRecord({
|
||||||
|
eventName: "card_tpl_choose",
|
||||||
|
eventType: "click",
|
||||||
|
elementId: tpl?.id,
|
||||||
|
});
|
||||||
currentTemplate.value = tpl;
|
currentTemplate.value = tpl;
|
||||||
closePanel();
|
closePanel();
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectTitle = (title) => {
|
const selectTitle = (title) => {
|
||||||
|
trackRecord({
|
||||||
|
eventName: "card_title_choose",
|
||||||
|
eventType: "click",
|
||||||
|
elementId: title?.id,
|
||||||
|
});
|
||||||
if (currentTitle.value?.id === title?.id) {
|
if (currentTitle.value?.id === title?.id) {
|
||||||
currentTitle.value = null;
|
currentTitle.value = null;
|
||||||
} else {
|
} else {
|
||||||
@@ -1150,6 +1322,7 @@ const shareOrSave = async (id) => {
|
|||||||
blessingFrom: signatureName.value,
|
blessingFrom: signatureName.value,
|
||||||
templateId: currentTemplate.value?.id || "",
|
templateId: currentTemplate.value?.id || "",
|
||||||
titleId: currentTitle?.value?.id || "",
|
titleId: currentTitle?.value?.id || "",
|
||||||
|
musicId: curBgm.value?.id || "",
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2089,4 +2262,157 @@ function drawRoundRect(ctx, x, y, w, h, r, color) {
|
|||||||
left: -9999px;
|
left: -9999px;
|
||||||
top: -9999px;
|
top: -9999px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.music-control {
|
||||||
|
position: absolute;
|
||||||
|
top: 24rpx;
|
||||||
|
left: 24rpx;
|
||||||
|
width: 64rpx;
|
||||||
|
height: 64rpx;
|
||||||
|
background: rgba(0, 0, 0, 0.4);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
z-index: 20;
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.music-control.playing {
|
||||||
|
background: rgba(255, 59, 48, 0.8);
|
||||||
|
border-color: rgba(255, 59, 48, 0.5);
|
||||||
|
animation: music-rotate 4s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes music-rotate {
|
||||||
|
from {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bgm-popup {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 24rpx 24rpx 0 0;
|
||||||
|
padding-bottom: env(safe-area-inset-bottom);
|
||||||
|
max-height: 60vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bgm-header {
|
||||||
|
padding: 30rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
border-bottom: 1rpx solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bgm-title {
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bgm-close {
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: #999;
|
||||||
|
padding: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bgm-scroll {
|
||||||
|
max-height: 500rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bgm-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 30rpx;
|
||||||
|
border-bottom: 1rpx solid #f5f5f5;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bgm-item:active {
|
||||||
|
background: #f9f9f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bgm-item.active {
|
||||||
|
background: #fff5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bgm-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bgm-name {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bgm-item.active .bgm-name {
|
||||||
|
color: #ff3b30;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bgm-playing-icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
gap: 4rpx;
|
||||||
|
height: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar {
|
||||||
|
width: 4rpx;
|
||||||
|
background: #ff3b30;
|
||||||
|
animation: equalize 1s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar1 {
|
||||||
|
animation-delay: 0s;
|
||||||
|
height: 60%;
|
||||||
|
}
|
||||||
|
.bar2 {
|
||||||
|
animation-delay: 0.2s;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.bar3 {
|
||||||
|
animation-delay: 0.4s;
|
||||||
|
height: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes equalize {
|
||||||
|
0% {
|
||||||
|
height: 40%;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
height: 40%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bgm-footer {
|
||||||
|
padding: 30rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-top: 1rpx solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-off-text {
|
||||||
|
color: #666;
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
<view class="status-info">
|
<view class="status-info">
|
||||||
<view class="status-title">当前正在使用</view>
|
<view class="status-title">头像效果预览</view>
|
||||||
<view class="decor-name">
|
<view class="decor-name">
|
||||||
<text class="star-icon">✪</text>
|
<text class="star-icon">✪</text>
|
||||||
<text>{{ currentAvatar.decorName || "金马贺岁挂饰" }}</text>
|
<text>{{ currentAvatar.decorName || "金马贺岁挂饰" }}</text>
|
||||||
@@ -93,6 +93,7 @@ import { onPullDownRefresh, onReachBottom } from "@dcloudio/uni-app";
|
|||||||
import { getMyAvatar, userAvatarChange } from "@/api/mine.js";
|
import { getMyAvatar, userAvatarChange } from "@/api/mine.js";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
import NavBar from "@/components/NavBar/NavBar.vue";
|
import NavBar from "@/components/NavBar/NavBar.vue";
|
||||||
|
import { trackRecord } from "@/utils/common.js";
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const list = ref([]);
|
const list = ref([]);
|
||||||
@@ -115,6 +116,10 @@ const names = [
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchList(true);
|
fetchList(true);
|
||||||
|
trackRecord({
|
||||||
|
eventName: "avatar_record_page_visit",
|
||||||
|
eventType: `visit`,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
onPullDownRefresh(() => {
|
onPullDownRefresh(() => {
|
||||||
@@ -174,6 +179,7 @@ const changeUserAvatar = async (imageUrl) => {
|
|||||||
title: "头像更换成功",
|
title: "头像更换成功",
|
||||||
icon: "success",
|
icon: "success",
|
||||||
});
|
});
|
||||||
|
// userStore.fetchUserInfo();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ import {
|
|||||||
} from "@dcloudio/uni-app";
|
} from "@dcloudio/uni-app";
|
||||||
import { getMyCard } from "@/api/mine.js";
|
import { getMyCard } from "@/api/mine.js";
|
||||||
import NavBar from "@/components/NavBar/NavBar.vue";
|
import NavBar from "@/components/NavBar/NavBar.vue";
|
||||||
import { getShareToken } from "@/utils/common.js";
|
import { getShareToken, trackRecord } from "@/utils/common.js";
|
||||||
|
|
||||||
const list = ref([]);
|
const list = ref([]);
|
||||||
const page = ref(1);
|
const page = ref(1);
|
||||||
@@ -112,6 +112,10 @@ const totalCount = ref(0);
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchList(true);
|
fetchList(true);
|
||||||
|
trackRecord({
|
||||||
|
eventName: "greeting_page_visit",
|
||||||
|
eventType: `visit`,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
onPullDownRefresh(() => {
|
onPullDownRefresh(() => {
|
||||||
@@ -139,7 +143,7 @@ onShareAppMessage(async (options) => {
|
|||||||
} else {
|
} else {
|
||||||
const shareToken = await getShareToken("greeting_page", "");
|
const shareToken = await getShareToken("greeting_page", "");
|
||||||
return {
|
return {
|
||||||
title: "新春祝福",
|
title: "新年好运已送达 🎊|祝福卡·头像·壁纸",
|
||||||
path: `/pages/index/index?shareToken=${shareToken}`,
|
path: `/pages/index/index?shareToken=${shareToken}`,
|
||||||
imageUrl:
|
imageUrl:
|
||||||
"https://file.lihailezzc.com/resource/8dd026d76ef7a63d123b7fd698fb989b.png",
|
"https://file.lihailezzc.com/resource/8dd026d76ef7a63d123b7fd698fb989b.png",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="help-page" >
|
<view class="help-page">
|
||||||
<NavBar title="帮助中心" />
|
<NavBar title="帮助中心" />
|
||||||
|
|
||||||
<!-- Search Bar -->
|
<!-- Search Bar -->
|
||||||
@@ -133,6 +133,14 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import NavBar from "@/components/NavBar/NavBar.vue";
|
import NavBar from "@/components/NavBar/NavBar.vue";
|
||||||
|
import { trackRecord } from "@/utils/common.js";
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
trackRecord({
|
||||||
|
eventName: "help_page_visit",
|
||||||
|
eventType: `visit`,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
const faqList = ref([
|
const faqList = ref([
|
||||||
{
|
{
|
||||||
@@ -157,7 +165,7 @@ const faqList = ref([
|
|||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
q: "如何更换新的头像",
|
q: "如何更换新的头像",
|
||||||
a: "在头像定制页面,首先选择地图是微信头像或者系统头像,左边选择您喜欢的边框样式,右边选择头像挂饰,可移动位置,缩放大小,点击保存即可。",
|
a: "在头像定制页面,首先选择上传头像或系统头像,左边选择您喜欢的边框样式,右边选择头像挂饰,可移动位置,缩放大小,点击保存即可。",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -137,7 +137,7 @@
|
|||||||
import { ref, computed, onMounted } from "vue";
|
import { ref, computed, onMounted } from "vue";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
import { onShareAppMessage } from "@dcloudio/uni-app";
|
import { onShareAppMessage } from "@dcloudio/uni-app";
|
||||||
import { getShareToken } from "@/utils/common";
|
import { getShareToken, trackRecord } from "@/utils/common";
|
||||||
import LoginPopup from "@/components/LoginPopup/LoginPopup.vue";
|
import LoginPopup from "@/components/LoginPopup/LoginPopup.vue";
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
@@ -159,13 +159,17 @@ const userInfo = computed(() => ({
|
|||||||
|
|
||||||
const isLoggedIn = computed(() => !!userStore.userInfo.nickName);
|
const isLoggedIn = computed(() => !!userStore.userInfo.nickName);
|
||||||
|
|
||||||
const isIos = false;
|
const isIos = computed(() => uni.getSystemInfoSync().osName === "ios");
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const sysInfo = uni.getSystemInfoSync();
|
const sysInfo = uni.getSystemInfoSync();
|
||||||
navBarTop.value = sysInfo.statusBarHeight;
|
navBarTop.value = sysInfo.statusBarHeight;
|
||||||
// Assuming standard nav bar height
|
// Assuming standard nav bar height
|
||||||
navBarHeight.value = 44;
|
navBarHeight.value = 44;
|
||||||
|
trackRecord({
|
||||||
|
eventName: "mine_page_visit",
|
||||||
|
eventType: `visit`,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
onShareAppMessage(async () => {
|
onShareAppMessage(async () => {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="wallpaper-page" >
|
<view class="wallpaper-page">
|
||||||
<NavBar title="我的壁纸" />
|
<NavBar title="我的壁纸" />
|
||||||
|
|
||||||
<!-- Header Stats -->
|
<!-- Header Stats -->
|
||||||
@@ -24,7 +24,12 @@
|
|||||||
<!-- List Section -->
|
<!-- List Section -->
|
||||||
<view class="list-section">
|
<view class="list-section">
|
||||||
<view class="list-container">
|
<view class="list-container">
|
||||||
<view v-for="item in list" :key="item.id" class="grid-item" @tap="onPreview(item)">
|
<view
|
||||||
|
v-for="item in list"
|
||||||
|
:key="item.id"
|
||||||
|
class="grid-item"
|
||||||
|
@tap="onPreview(item)"
|
||||||
|
>
|
||||||
<image :src="item.imageUrl" mode="aspectFill" class="wallpaper-img" />
|
<image :src="item.imageUrl" mode="aspectFill" class="wallpaper-img" />
|
||||||
<view class="date-badge">
|
<view class="date-badge">
|
||||||
<text>{{ formatDate(item.createdAt) }}</text>
|
<text>{{ formatDate(item.createdAt) }}</text>
|
||||||
@@ -51,6 +56,7 @@ import { ref, onMounted } from "vue";
|
|||||||
import { onPullDownRefresh, onReachBottom } from "@dcloudio/uni-app";
|
import { onPullDownRefresh, onReachBottom } from "@dcloudio/uni-app";
|
||||||
import { getMyWallpaper } from "@/api/mine.js";
|
import { getMyWallpaper } from "@/api/mine.js";
|
||||||
import NavBar from "@/components/NavBar/NavBar.vue";
|
import NavBar from "@/components/NavBar/NavBar.vue";
|
||||||
|
import { trackRecord } from "@/utils/common.js";
|
||||||
|
|
||||||
const list = ref([]);
|
const list = ref([]);
|
||||||
const page = ref(1);
|
const page = ref(1);
|
||||||
@@ -61,6 +67,10 @@ const totalCount = ref(0);
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchList(true);
|
fetchList(true);
|
||||||
|
trackRecord({
|
||||||
|
eventName: "wallpaper_record_page_visit",
|
||||||
|
eventType: `visit`,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
onPullDownRefresh(() => {
|
onPullDownRefresh(() => {
|
||||||
@@ -125,7 +135,7 @@ const formatDate = (dateStr) => {
|
|||||||
const onPreview = (item) => {
|
const onPreview = (item) => {
|
||||||
uni.previewImage({
|
uni.previewImage({
|
||||||
urls: [item.imageUrl],
|
urls: [item.imageUrl],
|
||||||
current: item.imageUrl
|
current: item.imageUrl,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ onShareAppMessage(async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
onShareTimeline(async () => {
|
onShareTimeline(async () => {
|
||||||
const token = await getShareToken("wallpaper_timeline", detailData.value?.id);
|
const token = await getShareToken("wallpaper_download", detailData.value?.id);
|
||||||
return {
|
return {
|
||||||
title: "快来看看我刚领到的新年精美壁纸 🖼",
|
title: "快来看看我刚领到的新年精美壁纸 🖼",
|
||||||
query: `shareToken=${token}`,
|
query: `shareToken=${token}`,
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ import {
|
|||||||
import { onShareAppMessage, onShareTimeline, onLoad } from "@dcloudio/uni-app";
|
import { onShareAppMessage, onShareTimeline, onLoad } from "@dcloudio/uni-app";
|
||||||
import { getShareReward, abilityCheck } from "@/api/system.js";
|
import { getShareReward, abilityCheck } from "@/api/system.js";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
import { saveViewRequest } from "@/utils/common.js";
|
import { saveViewRequest, trackRecord } from "@/utils/common.js";
|
||||||
import NavBar from "@/components/NavBar/NavBar.vue";
|
import NavBar from "@/components/NavBar/NavBar.vue";
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
@@ -113,7 +113,7 @@ onShareAppMessage(async (options) => {
|
|||||||
if (!isLoggedIn.value) {
|
if (!isLoggedIn.value) {
|
||||||
const shareToken = await getShareToken("wallpaper_download_index", "");
|
const shareToken = await getShareToken("wallpaper_download_index", "");
|
||||||
return {
|
return {
|
||||||
title: "新春祝福",
|
title: "新年好运已送达 🎊|祝福卡·头像·壁纸",
|
||||||
path: `/pages/index/index?shareToken=${shareToken}`,
|
path: `/pages/index/index?shareToken=${shareToken}`,
|
||||||
imageUrl:
|
imageUrl:
|
||||||
"https://file.lihailezzc.com/resource/8dd026d76ef7a63d123b7fd698fb989b.png",
|
"https://file.lihailezzc.com/resource/8dd026d76ef7a63d123b7fd698fb989b.png",
|
||||||
@@ -132,7 +132,7 @@ onShareAppMessage(async (options) => {
|
|||||||
} else {
|
} else {
|
||||||
const shareToken = await getShareToken("wallpaper_download_index", "");
|
const shareToken = await getShareToken("wallpaper_download_index", "");
|
||||||
return {
|
return {
|
||||||
title: "新春祝福",
|
title: "新年好运已送达 🎊|祝福卡·头像·壁纸",
|
||||||
path: `/pages/index/index?shareToken=${shareToken}`,
|
path: `/pages/index/index?shareToken=${shareToken}`,
|
||||||
imageUrl:
|
imageUrl:
|
||||||
"https://file.lihailezzc.com/resource/8dd026d76ef7a63d123b7fd698fb989b.png",
|
"https://file.lihailezzc.com/resource/8dd026d76ef7a63d123b7fd698fb989b.png",
|
||||||
@@ -156,6 +156,10 @@ onLoad((options) => {
|
|||||||
shareToken.value = options.shareToken;
|
shareToken.value = options.shareToken;
|
||||||
saveViewRequest(options.shareToken, "wallpaper_download");
|
saveViewRequest(options.shareToken, "wallpaper_download");
|
||||||
}
|
}
|
||||||
|
trackRecord({
|
||||||
|
eventName: "wallpaper_page_visit",
|
||||||
|
eventType: `visit`,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const getThumbUrl = (url) => {
|
const getThumbUrl = (url) => {
|
||||||
@@ -181,6 +185,11 @@ const switchCategory = (id) => {
|
|||||||
if (currentCategoryId.value === id) return;
|
if (currentCategoryId.value === id) return;
|
||||||
currentCategoryId.value = id;
|
currentCategoryId.value = id;
|
||||||
loadWallpapers(true);
|
loadWallpapers(true);
|
||||||
|
trackRecord({
|
||||||
|
eventName: "wallpaper_category_click",
|
||||||
|
eventType: `select`,
|
||||||
|
elementId: id || "",
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadWallpapers = async (reset = false) => {
|
const loadWallpapers = async (reset = false) => {
|
||||||
@@ -230,14 +239,25 @@ const onRefresh = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const previewImage = (index) => {
|
const previewImage = (index) => {
|
||||||
const urls = wallpapers.value.map((item) => item.url);
|
// const urls = wallpapers.value.map((item) => item.url);
|
||||||
uni.previewImage({
|
// uni.previewImage({
|
||||||
urls,
|
// urls,
|
||||||
current: index,
|
// current: index,
|
||||||
|
// });
|
||||||
|
const item = wallpapers.value[index];
|
||||||
|
trackRecord({
|
||||||
|
eventName: "wallpaper_preview_click",
|
||||||
|
eventType: `select`,
|
||||||
|
elementId: item?.id || "",
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const downloadWallpaper = async (item) => {
|
const downloadWallpaper = async (item) => {
|
||||||
|
trackRecord({
|
||||||
|
eventName: "wallpaper_download_click",
|
||||||
|
eventType: `click`,
|
||||||
|
elementId: item?.id || "",
|
||||||
|
});
|
||||||
if (!isLoggedIn.value) {
|
if (!isLoggedIn.value) {
|
||||||
loginPopupRef.value.open();
|
loginPopupRef.value.open();
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
import { getDeviceInfo } from "@/utils/system";
|
import { getDeviceInfo } from "@/utils/system";
|
||||||
import { saveRecord, viewRecord, createShareToken } from "@/api/system";
|
import {
|
||||||
|
saveRecord,
|
||||||
|
viewRecord,
|
||||||
|
createShareToken,
|
||||||
|
createTracking,
|
||||||
|
} from "@/api/system";
|
||||||
|
|
||||||
export const generateObjectId = (
|
export const generateObjectId = (
|
||||||
m = Math,
|
m = Math,
|
||||||
@@ -101,3 +106,10 @@ export const getShareToken = async (scene, targetId = "") => {
|
|||||||
});
|
});
|
||||||
return shareTokenRes?.shareToken || "";
|
return shareTokenRes?.shareToken || "";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const trackRecord = (event) => {
|
||||||
|
createTracking({
|
||||||
|
...event,
|
||||||
|
page: getCurrentPages().pop()?.route,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// const BASE_URL = "https://api.ai-meng.com";
|
const BASE_URL = "https://api.ai-meng.com";
|
||||||
// const BASE_URL = 'http://127.0.0.1:3999'
|
// const BASE_URL = 'http://127.0.0.1:3999'
|
||||||
const BASE_URL = "http://192.168.1.3:3999";
|
// const BASE_URL = "http://192.168.1.3:3999";
|
||||||
// const BASE_URL = "http://192.168.31.253:3999";
|
// const BASE_URL = "http://192.168.31.253:3999";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
import { getPlatform } from "./system.js";
|
import { getPlatform } from "./system.js";
|
||||||
|
|||||||
@@ -39,6 +39,10 @@ export const getLeftIconLeft = () => {
|
|||||||
// #endif
|
// #endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function getPlatform() {
|
||||||
|
return getPlatformProvider().replace("mp-", "");
|
||||||
|
}
|
||||||
|
|
||||||
export function getPlatformProvider() {
|
export function getPlatformProvider() {
|
||||||
const platform = process.env.UNI_PLATFORM;
|
const platform = process.env.UNI_PLATFORM;
|
||||||
return platform || "mp-weixin";
|
return platform || "mp-weixin";
|
||||||
@@ -55,10 +59,6 @@ export function getPlatformProvider() {
|
|||||||
// return typeof tt !== 'undefined' ? 'toutiao' : 'weixin';
|
// return typeof tt !== 'undefined' ? 'toutiao' : 'weixin';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPlatform() {
|
|
||||||
return getPlatformProvider().replace("mp-", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getDeviceInfo() {
|
export function getDeviceInfo() {
|
||||||
const info = uni.getSystemInfoSync();
|
const info = uni.getSystemInfoSync();
|
||||||
return {
|
return {
|
||||||
|
|||||||
Reference in New Issue
Block a user