@@ -0,0 +1,586 @@
< template >
< view class = "avatar-detail-page" : style = "{ paddingTop: navBarHeight + 'px' }" >
<!-- Custom Navbar -- >
< view
class = "nav-bar"
: style = "{
height: navBarHeight + 'px',
paddingTop: statusBarHeight + 'px',
}"
>
< view class = "nav-content" >
< view class = "back" @tap ="goBack" > ‹ < / view >
< text class = "nav-title" > 新春头像详情 < / text >
< / view >
< / view >
< view class = "content-wrap" >
<!-- User Info -- >
< view class = "user-info-section" v-if = "detailData" >
< image
: src = "detailData.from?.avatar || defaultAvatar"
class = "user-avatar"
mode = "aspectFill"
/ >
< view class = "user-text" >
< view class = "name-row" >
< text class = "nickname" > { {
detailData . from ? . nickname || "神秘用户"
} } < / text >
< view class = "tag" > 马年专属 < / view >
< / view >
< text class = "action-text" > 换上了新春头像 < / text >
< / view >
< / view >
<!-- Main Image Card -- >
< view class = "main-card" >
< view class = "card-inner" >
< image
v-if = "detailData?.imageUrl"
:src = "detailData.imageUrl"
class = "generated-avatar"
mode = "aspectFill"
@tap ="previewImage"
/ >
< view class = "loading-box" v-else >
< text > 加载中 ... < / text >
< / view >
<!-- Decorative Elements -- >
< view class = "decor-tag" > 🐰 < / view >
< view class = "card-footer-text" >
< text class = "icon" > 🌸 < / text > 2026 丙午马年限定
< / view >
< / view >
< / view >
<!-- Action Buttons -- >
< view class = "action-group" >
< button class = "btn primary-btn" @tap ="goToMake" >
< text class = "icon" > 🎨 < / text > 我也要领同款制作
< / button >
< button class = "btn secondary-btn" @tap ="saveImage" >
< text class = "icon" > 📥 < / text > 保存到相册
< / button >
< / view >
<!-- Recommended Frames -- >
< view class = "section recommended-section" >
< view class = "section-header" >
< view class = "left" >
< view class = "bar" > < / view >
< text class = "title" > 热门新春头像框 < / text >
< / view >
< text class = "more" @tap ="goToMake" > 查看全部 < / text >
< / view >
< view class = "frame-grid" >
< view
class = "frame-item"
v-for = "(item, index) in frameList"
:key = "index"
@tap ="goToMake"
>
< view class = "frame-img-box" >
< image :src = "item.url" class = "frame-img" mode = "aspectFit" / >
< / view >
< text class = "frame-name" > { { item . name || "新春相框" } } < / text >
< / view >
< / view >
< / view >
<!-- Wallpaper Banner -- >
< 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 >
<!-- Footer -- >
< view class = "page-footer" >
< view class = "footer-line" >
< text class = "line" > < / text >
< text class = "text" > 2026 HAPPY NEW YEAR < / text >
< text class = "line" > < / text >
< / view >
< text class = "footer-sub" > 新春祝福 · 传递温情 < / text >
< / view >
< / view >
< / view >
< / template >
< script setup >
import { ref , onMounted } from "vue" ;
import { onLoad } from "@dcloudio/uni-app" ;
import { getBavBarHeight } from "@/utils/system" ;
import { getAvatarFrameList , getPageDetail } from "@/api/avatar.js" ;
const defaultAvatar =
"https://file.lihailezzc.com/resource/d9b329082b32f8305101f708593a4882.png" ;
const detailData = ref ( null ) ;
const frameList = ref ( [ ] ) ;
const shareToken = ref ( "" ) ;
const navBarHeight = ref ( 64 ) ;
const statusBarHeight = ref ( 20 ) ;
onLoad ( ( options ) => {
if ( options . shareToken ) {
shareToken . value = options . shareToken ;
fetchDetail ( ) ;
}
fetchFrames ( ) ;
} ) ;
onMounted ( ( ) => {
const sysInfo = uni . getSystemInfoSync ( ) ;
statusBarHeight . value = sysInfo . statusBarHeight ;
navBarHeight . value = getBavBarHeight ( ) ;
} ) ;
const goBack = ( ) => {
// Check if can go back, otherwise go home
const pages = getCurrentPages ( ) ;
if ( pages . length > 1 ) {
uni . navigateBack ( ) ;
} else {
uni . switchTab ( { url : "/pages/index/index" } ) ;
}
} ;
const fetchDetail = async ( ) => {
try {
// uni.showLoading({ title: "加载中..." });
const res = await getPageDetail ( shareToken . value ) ;
if ( res ) {
detailData . value = res ;
}
} catch ( e ) {
console . error ( e ) ;
// uni.showToast({ title: "获取详情失败", icon: "none" });
} finally {
// uni.hideLoading();
}
} ;
const fetchFrames = async ( ) => {
try {
const res = await getAvatarFrameList ( 1 ) ;
if ( res ) {
const list = Array . isArray ( res ) ? res : res . list || [ ] ;
frameList . value = list . slice ( 0 , 3 ) ; // Take first 3
}
} catch ( e ) {
console . error ( e ) ;
}
} ;
const previewImage = ( ) => {
if ( detailData . value ? . imageUrl ) {
uni . previewImage ( {
urls : [ detailData . value . imageUrl ] ,
} ) ;
}
} ;
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 = ( ) => {
uni . navigateTo ( {
url : "/pages/avatar/index" ,
} ) ;
} ;
const goToWallpaper = ( ) => {
uni . navigateTo ( {
url : "/pages/wallpaper/index" ,
} ) ;
} ;
< / script >
< style lang = "scss" scoped >
. avatar - detail - page {
min - height : 100 vh ;
background : # fff0f5 ; /* Light Pink Background */
box - sizing : border - box ;
}
. nav - bar {
position : fixed ;
top : 0 ;
left : 0 ;
right : 0 ;
z - index : 100 ;
box - sizing : border - box ;
background : # fff0f5 ;
}
. nav - content {
display : flex ;
align - items : center ;
height : 100 % ;
padding : 0 24 rpx ;
}
. back {
font - size : 50 rpx ;
margin - right : 24 rpx ;
line - height : 1 ;
color : # 333 ;
}
. nav - title {
font - size : 34 rpx ;
font - weight : bold ;
color : # 333 ;
flex : 1 ;
text - align : center ;
margin - right : 50 rpx ; /* Balance back button */
}
. content - scroll {
}
. content - wrap {
padding : 30 rpx 40 rpx 60 rpx ;
}
/* User Info */
. user - info - section {
display : flex ;
align - items : center ;
margin - bottom : 40 rpx ;
}
. user - avatar {
width : 100 rpx ;
height : 100 rpx ;
border - radius : 50 % ;
border : 4 rpx solid # fff ;
margin - right : 24 rpx ;
box - shadow : 0 4 rpx 12 rpx rgba ( 0 , 0 , 0 , 0.05 ) ;
}
. user - text {
flex : 1 ;
}
. name - row {
display : flex ;
align - items : center ;
margin - bottom : 8 rpx ;
}
. nickname {
font - size : 32 rpx ;
font - weight : bold ;
color : # 333 ;
margin - right : 16 rpx ;
}
. tag {
background : # ff3b30 ;
color : # fff ;
font - size : 20 rpx ;
padding : 4 rpx 12 rpx ;
border - radius : 99 rpx ;
}
. action - text {
font - size : 24 rpx ;
color : # 999 ;
}
/* Main Card */
. main - card {
background : linear - gradient ( 180 deg , # ffffff 0 % , # fff5f5 100 % ) ;
border - radius : 40 rpx ;
padding : 24 rpx ;
box - shadow : 0 20 rpx 60 rpx rgba ( 255 , 59 , 48 , 0.15 ) ;
margin - bottom : 60 rpx ;
}
. card - inner {
position : relative ;
background : # fffaf0 ;
border - radius : 30 rpx ;
padding : 60 rpx ;
display : flex ;
flex - direction : column ;
align - items : center ;
}
. generated - avatar {
width : 400 rpx ;
height : 400 rpx ;
border - radius : 20 rpx ;
box - shadow : 0 10 rpx 30 rpx rgba ( 0 , 0 , 0 , 0.1 ) ;
border : 8 rpx solid # d63333 ;
}
. loading - box {
width : 400 rpx ;
height : 400 rpx ;
display : flex ;
align - items : center ;
justify - content : center ;
color : # 999 ;
background : # eee ;
border - radius : 20 rpx ;
}
. decor - tag {
position : absolute ;
top : 30 rpx ;
right : 30 rpx ;
background : # fff ;
width : 80 rpx ;
height : 80 rpx ;
border - radius : 50 % ;
display : flex ;
align - items : center ;
justify - content : center ;
font - size : 40 rpx ;
box - shadow : 0 4 rpx 16 rpx rgba ( 0 , 0 , 0 , 0.08 ) ;
color : # ff3b30 ;
}
. card - footer - text {
margin - top : 40 rpx ;
font - size : 28 rpx ;
color : # d63333 ;
font - weight : bold ;
display : flex ;
align - items : center ;
background : # fff ;
padding : 10 rpx 30 rpx ;
border - radius : 99 rpx ;
box - shadow : 0 4 rpx 10 rpx rgba ( 214 , 51 , 51 , 0.1 ) ;
}
. card - footer - text . icon {
margin - right : 10 rpx ;
}
/* Buttons */
. action - group {
margin - bottom : 60 rpx ;
}
. btn {
height : 100 rpx ;
border - radius : 99 rpx ;
display : flex ;
align - items : center ;
justify - content : center ;
font - size : 32 rpx ;
font - weight : 600 ;
margin - bottom : 30 rpx ;
border : none ;
}
. btn : : after {
border : none ;
}
. primary - btn {
background : # ff3b30 ;
color : # fff ;
box - shadow : 0 10 rpx 20 rpx rgba ( 255 , 59 , 48 , 0.3 ) ;
}
. secondary - btn {
background : # eaeaea ;
color : # 666 ;
}
. btn . icon {
margin - right : 16 rpx ;
font - size : 36 rpx ;
}
/* Recommended Section */
. section {
margin - bottom : 40 rpx ;
}
. section - header {
display : flex ;
justify - content : space - between ;
align - items : center ;
margin - bottom : 30 rpx ;
}
. section - header . left {
display : flex ;
align - items : center ;
}
. section - header . bar {
width : 8 rpx ;
height : 32 rpx ;
background : # ff3b30 ;
border - radius : 4 rpx ;
margin - right : 16 rpx ;
}
. section - header . title {
font - size : 32 rpx ;
font - weight : bold ;
color : # 333 ;
}
. section - header . more {
font - size : 24 rpx ;
color : # 999 ;
}
. frame - grid {
display : flex ;
justify - content : space - between ;
}
. frame - item {
width : 200 rpx ;
display : flex ;
flex - direction : column ;
align - items : center ;
background : # fff ;
border - radius : 24 rpx ;
padding : 20 rpx ;
box - shadow : 0 4 rpx 12 rpx rgba ( 0 , 0 , 0 , 0.03 ) ;
}
. frame - img - box {
width : 140 rpx ;
height : 140 rpx ;
margin - bottom : 16 rpx ;
border - radius : 50 % ;
overflow : hidden ;
background : # f9f9f9 ;
}
. frame - img {
width : 100 % ;
height : 100 % ;
}
. frame - name {
font - size : 24 rpx ;
color : # 333 ;
font - weight : 500 ;
}
/* Wallpaper Banner */
. wallpaper - banner {
background : # fff ;
border - radius : 24 rpx ;
padding : 30 rpx ;
display : flex ;
align - items : center ;
margin - bottom : 60 rpx ;
box - shadow : 0 4 rpx 12 rpx rgba ( 0 , 0 , 0 , 0.03 ) ;
}
. banner - icon {
width : 80 rpx ;
height : 80 rpx ;
background : # fff0f5 ;
border - radius : 20 rpx ;
display : flex ;
align - items : center ;
justify - content : center ;
margin - right : 24 rpx ;
}
. banner - icon text {
font - size : 40 rpx ;
color : # ff3b30 ;
}
. banner - content {
flex : 1 ;
}
. banner - title {
font - size : 30 rpx ;
font - weight : bold ;
color : # 333 ;
display : block ;
margin - bottom : 8 rpx ;
}
. banner - desc {
font - size : 22 rpx ;
color : # 999 ;
}
. banner - arrow {
font - size : 36 rpx ;
color : # ccc ;
}
/* Footer */
. page - footer {
text - align : center ;
padding - bottom : 40 rpx ;
}
. footer - line {
display : flex ;
align - items : center ;
justify - content : center ;
margin - bottom : 16 rpx ;
}
. footer - line . line {
width : 60 rpx ;
height : 2 rpx ;
background : # ccc ;
}
. footer - line . text {
font - size : 20 rpx ;
color : # 999 ;
margin : 0 20 rpx ;
letter - spacing : 2 rpx ;
}
. footer - sub {
font - size : 20 rpx ;
color : # ccc ;
}
< / style >