image:替换图片

This commit is contained in:
zheng020 2026-05-15 21:39:21 +08:00
parent e4ce006de3
commit 6252be4d75
7 changed files with 373 additions and 302 deletions

View File

@ -114,6 +114,19 @@
</view> --> </view> -->
<!-- </view> --> <!-- </view> -->
<!-- 完整链上哈希显示遮罩层 -->
<view v-if="showTxHash" class="txhash-mask" @tap="showTxHash = false">
<view class="txhash-popup" @tap.stop>
<view class="txhash-popup-header">
<text class="txhash-popup-title">链上哈希</text>
<view class="txhash-popup-close" @tap="showTxHash = false">
<image class="close-icon" src="/static/icon/hide.png" mode="aspectFit"></image>
</view>
</view>
<text class="txhash-popup-content" selectable @longpress="copyHash">{{ displayTxHash }}</text>
</view>
</view>
<!-- 链上数据 --> <!-- 链上数据 -->
<view class="chain-section"> <view class="chain-section">
<image class="chain-logo" src="/static/logo/APPLOGO.png" mode="aspectFit"></image> <image class="chain-logo" src="/static/logo/APPLOGO.png" mode="aspectFit"></image>
@ -143,8 +156,7 @@
<view class="chain-row"> <view class="chain-row">
<text class="chain-label">链上哈希</text> <text class="chain-label">链上哈希</text>
<view class="chain-value-wrap"> <view class="chain-value-wrap">
<text class="chain-value chain-hash" @longpress="copyHash">{{ showTxHash ? displayTxHash <text class="chain-value chain-hash" @longpress="copyHash">{{ hiddenTxHash }}</text>
: hiddenTxHash }}</text>
<view class="toggle-btn" @tap="showTxHash = !showTxHash"> <view class="toggle-btn" @tap="showTxHash = !showTxHash">
<image class="toggle-icon" :src="showTxHash ? '/static/icon/show.png' : '/static/icon/hide.png'" mode="aspectFit"></image> <image class="toggle-icon" :src="showTxHash ? '/static/icon/show.png' : '/static/icon/hide.png'" mode="aspectFit"></image>
</view> </view>
@ -1026,6 +1038,62 @@ onUnmounted(() => {
color: rgba(255, 255, 255, 0.75); color: rgba(255, 255, 255, 0.75);
} }
/* 链上哈希遮罩层 */
.txhash-mask {
position: fixed;
left: 0;
right: 0;
bottom: 24rpx;
z-index: 999;
display: flex;
align-items: center;
justify-content: center;
padding: 0 64rpx;
}
.txhash-popup {
border-radius: 24rpx;
padding: 32rpx;
background: url('/static/rank/activity-support-icon/beijingkuang.png') no-repeat center center;
background-size: 105% 120%;
}
.txhash-popup-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24rpx;
}
.txhash-popup-title {
font-size: 32rpx;
font-weight: bold;
color: #fff;
font-family: 'yt', sans-serif;
}
.txhash-popup-close {
padding: 8rpx;
}
.close-icon {
width: 40rpx;
height: 40rpx;
}
.txhash-popup-content {
display: block;
font-size: 26rpx;
color: #fff;
font-family: 'yt', sans-serif;
word-break: break-all;
line-height: 1.6;
background-color: rgba(0, 0, 0, 0.2);
padding: 20rpx;
border-radius: 12rpx;
}
/* 点赞用户列表 */ /* 点赞用户列表 */
.like-users-list { .like-users-list {
display: flex; display: flex;

View File

@ -56,7 +56,8 @@ const navItems = [
name: '铸爱', name: '铸爱',
icon: '/static/icon/castlove.png', icon: '/static/icon/castlove.png',
angle: 90.01, // angle: 90.01, //
path: '/pages/castlove/mall' path: '/pages/castlove/mall',
rotate: '8deg'
}, },
{ {
name: '星城', name: '星城',
@ -107,7 +108,8 @@ const getNavIconStyle = (index) => {
return { return {
'--x': `${x}rpx`, '--x': `${x}rpx`,
'--y': `${y}rpx`, '--y': `${y}rpx`,
'--delay': `${delay}s` '--delay': `${delay}s`,
'--rotate': item.rotate || '0deg'
}; };
}; };
@ -237,6 +239,7 @@ const handleNavClick = (index) => {
transition: transform 0.3s ease, filter 0.3s ease; transition: transform 0.3s ease, filter 0.3s ease;
filter: drop-shadow(0 6rpx 16rpx rgba(0, 0, 0, 0.4)) drop-shadow(0 2rpx 8rpx rgba(0, 0, 0, 0.2)); filter: drop-shadow(0 6rpx 16rpx rgba(0, 0, 0, 0.4)) drop-shadow(0 2rpx 8rpx rgba(0, 0, 0, 0.2));
position: relative; position: relative;
transform: rotate(var(--rotate));
} }
/* 底部倒影效果 */ /* 底部倒影效果 */

View File

@ -2,256 +2,273 @@
<view class="profile-container"> <view class="profile-container">
<!-- 背景图片 - 固定在容器上 --> <!-- 背景图片 - 固定在容器上 -->
<image class="background-image" src="/static/square/squearbj.png" mode="aspectFill"></image> <image class="background-image" src="/static/square/squearbj.png" mode="aspectFill"></image>
<scroll-view class="profile-scroll" scroll-y :show-scrollbar="false" :enable-back-to-top="true"> <scroll-view class="profile-scroll" scroll-y :show-scrollbar="false" :enable-back-to-top="true">
<!-- 上半部分用户信息卡片 --> <!-- 上半部分用户信息卡片 -->
<view class="top-section"> <view class="top-section">
<!-- 蒙层 --> <!-- 蒙层 -->
<view class="background-overlay"></view> <view class="background-overlay"></view>
<!-- Header组件 --> <!-- Header组件 -->
<image class="close-icon-img" src="/static/starbookcontent/tuichu.png" mode="aspectFit" @tap="goBack"></image> <image class="close-icon-img" src="/static/starbookcontent/tuichu.png" mode="aspectFit" @tap="goBack">
</image>
<!-- 用户信息卡片 -->
<view class="user-info-card"> <!-- 用户信息卡片 -->
<!-- 上半部分头像和用户信息左右布局 --> <view class="user-info-card">
<view class="user-main-info"> <!-- 上半部分头像和用户信息左右布局 -->
<view @tap="handleAvatarClick" class="avatar-container"> <view class="user-main-info">
<Avatar :key="avatarKey" :userId="uid" :size="260" :borderWidth="6" :showLevel="true" <view @tap="handleAvatarClick" class="avatar-container">
:level="fanLevel" :avatarUrl="userAvatarUrl" /> <Avatar :key="avatarKey" :userId="uid" :size="260" :borderWidth="6" :showLevel="true"
</view> :level="fanLevel" :avatarUrl="userAvatarUrl" />
<view class="user-text-info">
<!-- 昵称 -->
<view class="info-row">
<text style="font-size: 48rpx;text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.3);" class="info-value">{{ nickname }}</text>
</view> </view>
<!-- DID --> <view class="user-text-info">
<view class="info-row"> <!-- 昵称 -->
<text class="info-label">DID</text> <view class="info-row">
<text class="info-value uid-value">{{ uid }}</text> <text style="font-size: 48rpx;text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.3);"
<view class="info-btn" @tap="copyUid">查看</view> class="info-value">{{ nickname }}</text>
</view> </view>
<!-- 链上地址 --> <!-- DID -->
<view class="info-row"> <view class="info-row">
<text class="info-label">链上地址</text> <text class="info-label">DID</text>
<text class="info-value address-value">{{ displayAddress }}</text> <view class="address-row">
<view class="info-btn" @tap="copyAddress">查看</view> <text class="info-value uid-value">{{ uid }}</text>
</view> <!-- <image class="toggle-icon"
<!-- 手机号 --> :src="showBlockNumber ? '/static/icon/show.png' : '/static/icon/hide.png'"
<view class="info-row"> mode="aspectFit" @tap="copyUid"></image> -->
<text class="info-label">注册手机</text> </view>
<text class="info-value" v-if="displayMobile">{{ displayMobile }}</text> </view>
<text class="info-value" v-else>未绑定</text> <!-- 链上地址 -->
<view class="info-btn" @tap="handleViewMobile">查看</view> <view class="info-row">
<text class="info-label">链上地址</text>
<view class="address-row">
<text class="info-value address-value" @longpress="copyAddress">{{ displayAddress }}</text>
<view class="toggle-btn" @tap="showBlockNumber = !showBlockNumber">
<image class="toggle-icon" :src="showBlockNumber ? '/static/icon/show.png' : '/static/icon/hide.png'" mode="aspectFit"></image>
</view>
</view>
</view>
<!-- 手机号 -->
<view class="info-row">
<text class="info-label">注册手机</text>
<view class="address-row">
<text class="info-value" v-if="mobile">{{ displayMobile }}</text>
<view class="toggle-btn" @tap="toggleMobileDisplay">
<image class="toggle-icon" :src="showMobile ? '/static/icon/show.png' : '/static/icon/hide.png'" mode="aspectFit"></image>
</view>
</view>
</view>
</view> </view>
</view> </view>
</view> </view>
</view> </view>
</view>
<!-- 下半部分白色背景区域 --> <!-- 下半部分白色背景区域 -->
<view class="bottom-section"> <view class="bottom-section">
<view class="content-area"> <view class="content-area">
<!-- 我的资产 --> <!-- 我的资产 -->
<view class="section-bg" style="padding-top: 0;"> <view class="section-bg" style="padding-top: 0;">
<view class="section-title">我的资产</view> <view class="section-title">我的资产</view>
<view class="assets-grid"> <view class="assets-grid">
<view class="asset-card" @tap="handleAssetClick('myWorks')"> <view class="asset-card" @tap="handleAssetClick('myWorks')">
<image class="asset-icon" src="/static/icon/dazi.png" mode="aspectFit"></image> <image class="asset-icon" src="/static/icon/dazi.png" mode="aspectFit"></image>
<text class="asset-text">个人中心</text> <text class="asset-text">个人中心</text>
<!-- <text class="arrow"></text> --> <!-- <text class="arrow"></text> -->
</view> </view>
<view class="asset-card" @tap="handleAssetClick('starbook')"> <view class="asset-card" @tap="handleAssetClick('starbook')">
<image class="asset-icon" src="/static/icon/starbook.png" mode="aspectFit"></image> <image class="asset-icon" src="/static/icon/starbook.png" mode="aspectFit"></image>
<text class="asset-text">我的星册</text> <text class="asset-text">我的星册</text>
<!-- <text class="arrow"></text> --> <!-- <text class="arrow"></text> -->
</view>
</view> </view>
</view> </view>
</view>
<!-- 服务与工具 --> <!-- 服务与工具 -->
<view class="section-bg"> <view class="section-bg">
<view class="section-title">服务与工具</view> <view class="section-title">服务与工具</view>
<view class="service-buttons-container"> <view class="service-buttons-container">
<!-- 新手指引入口 --> <!-- 新手指引入口 -->
<view class="service-button" @tap="handleGuideClick"> <view class="service-button" @tap="handleGuideClick">
<image class="service-icon" src="/static/icon/onboarding.png" mode="aspectFit"></image> <image class="service-icon" src="/static/icon/onboarding.png" mode="aspectFit"></image>
<text class="service-text">新手指引</text> <text class="service-text">新手指引</text>
<text v-if="guideClaimableCount > 0" class="guide-badge">{{ guideClaimableCount }}</text> <text v-if="guideClaimableCount > 0" class="guide-badge">{{ guideClaimableCount
</view> }}</text>
<view class="service-button" @tap="handleChangeNickname"> </view>
<image class="service-icon" src="/static/icon/edit-nickname.png" mode="aspectFit"></image> <view class="service-button" @tap="handleChangeNickname">
<text class="service-text">修改昵称</text> <image class="service-icon" src="/static/icon/edit-nickname.png" mode="aspectFit">
</view> </image>
<view class="service-button" @tap="handleChangePassword"> <text class="service-text">修改昵称</text>
<image class="service-icon" src="/static/icon/edit-password.png" mode="aspectFit"></image> </view>
<text class="service-text">修改密码</text> <view class="service-button" @tap="handleChangePassword">
</view> <image class="service-icon" src="/static/icon/edit-password.png" mode="aspectFit">
<!-- <view class="service-button" @tap="handleSwitchRole"> </image>
<text class="service-text">修改密码</text>
</view>
<!-- <view class="service-button" @tap="handleSwitchRole">
<image class="service-icon" src="/static/icon/switch-account.png" mode="aspectFit"></image> <image class="service-icon" src="/static/icon/switch-account.png" mode="aspectFit"></image>
<text class="service-text">添加身份</text> <text class="service-text">添加身份</text>
</view> --> </view> -->
<view class="service-button" @tap="handleDeleteAccount"> <view class="service-button" @tap="handleDeleteAccount">
<image class="service-icon" src="/static/icon/logout.png" mode="aspectFit"></image> <image class="service-icon" src="/static/icon/logout.png" mode="aspectFit"></image>
<text class="service-text">注销账号</text> <text class="service-text">注销账号</text>
</view>
</view>
</view>
</view>
<!-- 修改昵称弹窗 -->
<view class="nickname-modal" v-if="showNicknameModal" @tap="closeNicknameModal">
<view class="modal-content" @tap.stop>
<view class="modal-title">修改昵称</view>
<input class="modal-input" v-model="newNickname" placeholder="请输入新昵称" maxlength="20" />
<view class="modal-buttons">
<button class="modal-btn-cancel" @tap="closeNicknameModal">取消</button>
<button class="modal-btn-confirm" @tap="confirmChangeNickname">确认</button>
</view>
</view>
</view>
<!-- 修改密码弹窗 -->
<view class="password-modal" v-if="showPasswordModal" @tap="closePasswordModal">
<view class="modal-content" @tap.stop>
<view class="modal-title">修改密码</view>
<!-- 旧密码输入框 -->
<view class="modal-password-wrapper">
<input class="modal-password-input" :type="showOldPassword ? 'text' : 'password'"
v-model="oldPassword" placeholder="请输入旧密码" placeholder-class="input-placeholder" />
<view class="modal-eye-icon" @click="showOldPassword = !showOldPassword">
<text class="eye-text">{{ showOldPassword ? '👁️' : '👁️‍🗨️' }}</text>
</view>
</view>
<!-- 新密码输入框 -->
<view class="modal-password-wrapper">
<input class="modal-password-input" :type="showNewPassword ? 'text' : 'password'"
v-model="newPassword" placeholder="请输入新密码" placeholder-class="input-placeholder" />
<view class="modal-eye-icon" @click="showNewPassword = !showNewPassword">
<text class="eye-text">{{ showNewPassword ? '👁️' : '👁️‍🗨️' }}</text>
</view>
</view>
<view class="modal-buttons">
<button class="modal-btn-cancel" @tap="closePasswordModal">取消</button>
<button class="modal-btn-confirm" @tap="confirmChangePassword">确认</button>
</view>
</view>
</view>
<!-- 添加身份弹窗 -->
<view class="add-identity-modal" v-if="showAddIdentityModal" @tap="closeAddIdentityModal">
<view class="modal-content" @tap.stop>
<view class="modal-title">添加身份</view>
<view class="modal-subtitle">选择您喜欢的明星成为TA的粉丝</view>
<!-- 明星选择列表 -->
<view class="star-list">
<view v-for="star in fanIdentitiesList" :key="star.star_id" class="star-item"
:class="{ 'star-item-selected': selectedStarId === star.star_id }"
@tap="selectStar(star.star_id)">
<view class="star-info">
<text class="star-name">{{ star.name }}</text>
<text class="star-tag" v-if="star.tag">{{ star.tag }}</text>
</view>
<view class="star-radio">
<view v-if="selectedStarId === star.star_id" class="star-radio-checked"></view>
</view> </view>
</view> </view>
</view> </view>
</view>
<!-- 昵称输入框 --> <!-- 修改昵称弹窗 -->
<input class="modal-input" v-model="newIdentityNickname" placeholder="请输入您的新昵称" maxlength="20" /> <view class="nickname-modal" v-if="showNicknameModal" @tap="closeNicknameModal">
<view class="modal-content" @tap.stop>
<view class="modal-buttons"> <view class="modal-title">修改昵称</view>
<button class="modal-btn-cancel" @tap="closeAddIdentityModal">取消</button> <input class="modal-input" v-model="newNickname" placeholder="请输入新昵称" maxlength="20" />
<button class="modal-btn-confirm" @tap="confirmAddIdentity">确认</button> <view class="modal-buttons">
<button class="modal-btn-cancel" @tap="closeNicknameModal">取消</button>
<button class="modal-btn-confirm" @tap="confirmChangeNickname">确认</button>
</view>
</view> </view>
</view> </view>
</view>
<!-- 身份切换下拉列表 --> <!-- 修改密码弹窗 -->
<view class="identity-dropdown-modal" v-if="showIdentityDropdown" @tap="closeIdentityDropdown"> <view class="password-modal" v-if="showPasswordModal" @tap="closePasswordModal">
<view class="identity-dropdown-content" @tap.stop> <view class="modal-content" @tap.stop>
<view class="identity-dropdown-title">切换粉丝身份</view> <view class="modal-title">修改密码</view>
<view class="identity-list"> <!-- 旧密码输入框 -->
<view v-for="identity in myFanIdentities" :key="identity.star_id" class="identity-item" :class="{ <view class="modal-password-wrapper">
'identity-item-active': identity.star_id === currentStarId, <input class="modal-password-input" :type="showOldPassword ? 'text' : 'password'"
'identity-item-disabled': identity.star_id === currentStarId v-model="oldPassword" placeholder="请输入旧密码" placeholder-class="input-placeholder" />
}" @tap="handleSwitchIdentity(identity.star_id)"> <view class="modal-eye-icon" @click="showOldPassword = !showOldPassword">
<view class="identity-info"> <text class="eye-text">{{ showOldPassword ? '👁️' : '👁️‍🗨️' }}</text>
<view class="identity-main"> </view>
<text class="identity-star-name">{{ identity.star_name }}</text> </view>
<text class="identity-star-tag">{{ identity.star_tag }}</text> <!-- 新密码输入框 -->
<view class="modal-password-wrapper">
<input class="modal-password-input" :type="showNewPassword ? 'text' : 'password'"
v-model="newPassword" placeholder="请输入新密码" placeholder-class="input-placeholder" />
<view class="modal-eye-icon" @click="showNewPassword = !showNewPassword">
<text class="eye-text">{{ showNewPassword ? '👁️' : '👁️‍🗨️' }}</text>
</view>
</view>
<view class="modal-buttons">
<button class="modal-btn-cancel" @tap="closePasswordModal">取消</button>
<button class="modal-btn-confirm" @tap="confirmChangePassword">确认</button>
</view>
</view>
</view>
<!-- 添加身份弹窗 -->
<view class="add-identity-modal" v-if="showAddIdentityModal" @tap="closeAddIdentityModal">
<view class="modal-content" @tap.stop>
<view class="modal-title">添加身份</view>
<view class="modal-subtitle">选择您喜欢的明星成为TA的粉丝</view>
<!-- 明星选择列表 -->
<view class="star-list">
<view v-for="star in fanIdentitiesList" :key="star.star_id" class="star-item"
:class="{ 'star-item-selected': selectedStarId === star.star_id }"
@tap="selectStar(star.star_id)">
<view class="star-info">
<text class="star-name">{{ star.name }}</text>
<text class="star-tag" v-if="star.tag">{{ star.tag }}</text>
</view>
<view class="star-radio">
<view v-if="selectedStarId === star.star_id" class="star-radio-checked"></view>
</view> </view>
<text class="identity-nickname">昵称: {{ identity.nickname }}</text>
</view> </view>
<view v-if="identity.star_id === currentStarId" class="identity-current-badge"> </view>
<text class="identity-current-text">当前身份</text>
<!-- 昵称输入框 -->
<input class="modal-input" v-model="newIdentityNickname" placeholder="请输入您的新昵称"
maxlength="20" />
<view class="modal-buttons">
<button class="modal-btn-cancel" @tap="closeAddIdentityModal">取消</button>
<button class="modal-btn-confirm" @tap="confirmAddIdentity">确认</button>
</view>
</view>
</view>
<!-- 身份切换下拉列表 -->
<view class="identity-dropdown-modal" v-if="showIdentityDropdown" @tap="closeIdentityDropdown">
<view class="identity-dropdown-content" @tap.stop>
<view class="identity-dropdown-title">切换粉丝身份</view>
<view class="identity-list">
<view v-for="identity in myFanIdentities" :key="identity.star_id" class="identity-item"
:class="{
'identity-item-active': identity.star_id === currentStarId,
'identity-item-disabled': identity.star_id === currentStarId
}" @tap="handleSwitchIdentity(identity.star_id)">
<view class="identity-info">
<view class="identity-main">
<text class="identity-star-name">{{ identity.star_name }}</text>
<text class="identity-star-tag">{{ identity.star_tag }}</text>
</view>
<text class="identity-nickname">昵称: {{ identity.nickname }}</text>
</view>
<view v-if="identity.star_id === currentStarId" class="identity-current-badge">
<text class="identity-current-text">当前身份</text>
</view>
</view> </view>
</view> </view>
</view> </view>
</view> </view>
<!-- 注销账号确认弹窗 -->
<view class="confirm-modal" v-if="showDeleteAccountModal" @tap="closeDeleteAccountModal">
<view class="modal-content" @tap.stop>
<view class="modal-title">注销账号</view>
<view class="modal-message">注销账号后您的所有数据将被永久删除且无法恢复确定要注销账号吗</view>
<view class="modal-buttons">
<button class="modal-btn-cancel" @tap="closeDeleteAccountModal">取消</button>
<button class="modal-btn-confirm danger" @tap="confirmDeleteAccount">确定注销</button>
</view>
</view>
</view>
<!-- 退出登录确认弹窗 -->
<view class="confirm-modal" v-if="showLogoutModal" @tap="closeLogoutModal">
<view class="modal-content" @tap.stop>
<view class="modal-title">退出登录</view>
<view class="modal-message">确定要退出登录吗</view>
<view class="modal-buttons">
<button class="modal-btn-cancel" @tap="closeLogoutModal">取消</button>
<button class="modal-btn-confirm" @tap="confirmLogout">确定</button>
</view>
</view>
</view>
<!-- 修改头像弹窗 -->
<view class="avatar-modal" v-if="showAvatarModal" @tap="closeAvatarModal">
<view class="modal-content" @tap.stop>
<view class="modal-title">修改头像</view>
<!-- 头像预览 -->
<view class="avatar-preview">
<Avatar :key="avatarKey" :userId="uid" :size="200" :borderWidth="6"
:avatarUrl="userAvatarUrl" />
</view>
<!-- 上传按钮 -->
<button class="upload-avatar-btn" @tap="handleUploadAvatar" :disabled="uploadingAvatar">
{{ uploadingAvatar ? '上传中...' : '上传新头像' }}
</button>
<view class="upload-hint">支持JPGPNG格式大小不超过10MB</view>
<view class="modal-buttons">
<button class="modal-btn-cancel" @tap="closeAvatarModal">取消</button>
</view>
</view>
</view>
</view> </view>
<!-- 注销账号确认弹窗 --> <!-- 退出登录按钮 -->
<view class="confirm-modal" v-if="showDeleteAccountModal" @tap="closeDeleteAccountModal"> <view class="logout-section">
<view class="modal-content" @tap.stop> <button class="logout-button" @tap="handleLogout">退出登录</button>
<view class="modal-title">注销账号</view>
<view class="modal-message">注销账号后您的所有数据将被永久删除且无法恢复确定要注销账号吗</view>
<view class="modal-buttons">
<button class="modal-btn-cancel" @tap="closeDeleteAccountModal">取消</button>
<button class="modal-btn-confirm danger" @tap="confirmDeleteAccount">确定注销</button>
</view>
</view>
</view> </view>
<!-- 退出登录确认弹窗 -->
<view class="confirm-modal" v-if="showLogoutModal" @tap="closeLogoutModal">
<view class="modal-content" @tap.stop>
<view class="modal-title">退出登录</view>
<view class="modal-message">确定要退出登录吗</view>
<view class="modal-buttons">
<button class="modal-btn-cancel" @tap="closeLogoutModal">取消</button>
<button class="modal-btn-confirm" @tap="confirmLogout">确定</button>
</view>
</view>
</view>
<!-- 修改头像弹窗 -->
<view class="avatar-modal" v-if="showAvatarModal" @tap="closeAvatarModal">
<view class="modal-content" @tap.stop>
<view class="modal-title">修改头像</view>
<!-- 头像预览 -->
<view class="avatar-preview">
<Avatar :key="avatarKey" :userId="uid" :size="200" :borderWidth="6"
:avatarUrl="userAvatarUrl" />
</view>
<!-- 上传按钮 -->
<button class="upload-avatar-btn" @tap="handleUploadAvatar" :disabled="uploadingAvatar">
{{ uploadingAvatar ? '上传中...' : '上传新头像' }}
</button>
<view class="upload-hint">支持JPGPNG格式大小不超过10MB</view>
<view class="modal-buttons">
<button class="modal-btn-cancel" @tap="closeAvatarModal">取消</button>
</view>
</view>
</view>
</view>
<!-- 退出登录按钮 -->
<view class="logout-section">
<button class="logout-button" @tap="handleLogout">退出登录</button>
</view>
</scroll-view> </scroll-view>
<!-- 新手引导列表弹窗 --> <!-- 新手引导弹窗 -->
<GuideListModal :visible="showGuideListModal" @start-guide="handleStartGuide" <GuideModal :visible="showGuideModal" @close="showGuideModal = false" @updated="handleGuideUpdated" />
@claim-success="handleClaimSuccess" @close="showGuideListModal = false" />
<!-- 全局引导遮罩 --> <!-- 全局引导遮罩 -->
<GuideOverlay /> <GuideOverlay />
@ -268,7 +285,7 @@ import Avatar from '../components/Avatar.vue';
import { getUserProfileApi, deleteAccountApi, updateNicknameApi, updatePasswordApi, getFanIdentitiesApi, addFanIdentityApi, getMyFanIdentitiesApi, switchFanIdentityApi, getOssSignatureApi, updateAvatarApi } from '@/utils/api'; import { getUserProfileApi, deleteAccountApi, updateNicknameApi, updatePasswordApi, getFanIdentitiesApi, addFanIdentityApi, getMyFanIdentitiesApi, switchFanIdentityApi, getOssSignatureApi, updateAvatarApi } from '@/utils/api';
import { validateNickname } from '@/utils/validator.js'; import { validateNickname } from '@/utils/validator.js';
import { clearAvatarCache } from '@/utils/avatarCache'; import { clearAvatarCache } from '@/utils/avatarCache';
import GuideListModal from '@/components/GuideListModal.vue'; import GuideModal from '@/pages/tasks/GuideModal.vue';
import GuideOverlay from '@/components/GuideOverlay.vue'; import GuideOverlay from '@/components/GuideOverlay.vue';
import { import {
getClaimableRewardCount getClaimableRewardCount
@ -295,8 +312,13 @@ const newPassword = ref('');
const showOldPassword = ref(false); const showOldPassword = ref(false);
// //
const showGuideListModal = ref(false); const showGuideModal = ref(false);
const guideClaimableCount = computed(() => getClaimableRewardCount()); const guideClaimableCount = computed(() => getClaimableRewardCount());
//
const handleGuideUpdated = () => {
console.log('[Profile] Guide updated');
};
const showNewPassword = ref(false); const showNewPassword = ref(false);
// //
@ -325,18 +347,33 @@ const avatarKey = ref(0); // 用于强制刷新Avatar组件
// //
const mobile = ref(''); const mobile = ref('');
// // /
const showBlockNumber = ref(false);
const showMobile = ref(false);
// showMobile
const displayMobile = computed(() => { const displayMobile = computed(() => {
return mobile.value || ''; console.log('displayMobile computed, mobile:', mobile.value, 'showMobile:', showMobile.value);
if (!mobile.value) return '';
// showMobiletruefalse
if (showMobile.value) {
return mobile.value;
}
// 34
const phone = mobile.value;
return phone.length === 11 ? phone.slice(0, 3) + '****' + phone.slice(-4) : phone;
}); });
// //
const displayAddress = computed(() => { const displayAddress = computed(() => {
const address = blockchainAddress.value; const address = blockchainAddress.value;
console.log('displayAddress computed, address:', address, 'showBlockNumber:', showBlockNumber.value);
// //
if (!address) return '0xabcd...123c'; if (!address) return '0xabcd...123c';
// showBlockNumbertruefalse
if (showBlockNumber.value) return address;
if (address.length <= 20) return address; if (address.length <= 20) return address;
// 108 // 44
return address.substring(0, 4) + '...' + address.substring(address.length - 4); return address.substring(0, 4) + '...' + address.substring(address.length - 4);
}); });
@ -392,7 +429,7 @@ const fetchUserInfo = async (forceRefresh = false) => {
fanTag.value = userForCache.fan_identity?.name || ''; fanTag.value = userForCache.fan_identity?.name || '';
blockchainAddress.value = userForCache.blockchain_address || ''; blockchainAddress.value = userForCache.blockchain_address || '';
userAvatarUrl.value = userForCache.avatar_url || ''; userAvatarUrl.value = userForCache.avatar_url || '';
mobile.value = uni.getStorageSync('login_mobile') || ''; mobile.value = userForCache.mobile || uni.getStorageSync('login_mobile') || '';
} }
} catch (error) { } catch (error) {
console.error('获取用户信息失败:', error); console.error('获取用户信息失败:', error);
@ -408,7 +445,7 @@ const fetchUserInfo = async (forceRefresh = false) => {
fanTag.value = cachedUser.fan_identity?.tag || ''; fanTag.value = cachedUser.fan_identity?.tag || '';
blockchainAddress.value = cachedUser.blockchain_address || ''; blockchainAddress.value = cachedUser.blockchain_address || '';
userAvatarUrl.value = cachedUser.avatar_url || ''; userAvatarUrl.value = cachedUser.avatar_url || '';
mobile.value = uni.getStorageSync('login_mobile') || ''; mobile.value = cachedUser.mobile || uni.getStorageSync('login_mobile') || '';
} catch (e) { } catch (e) {
console.error('解析缓存用户信息失败:', e); console.error('解析缓存用户信息失败:', e);
} }
@ -423,6 +460,12 @@ const fetchUserInfo = async (forceRefresh = false) => {
} }
}; };
//
const toggleMobileDisplay = () => {
console.log('toggleMobileDisplay called, showMobile:', showMobile.value);
showMobile.value = !showMobile.value;
};
// UID // UID
const copyUid = () => { const copyUid = () => {
if (!uid.value) { if (!uid.value) {
@ -445,19 +488,6 @@ const handleViewNickname = () => {
}); });
}; };
//
const handleViewMobile = () => {
if (!displayMobile.value) {
uni.showToast({ title: '未绑定手机号', icon: 'none' });
return;
}
uni.setClipboardData({
data: displayMobile.value,
success: () => uni.showToast({ title: '已复制手机号', icon: 'success' }),
fail: () => uni.showToast({ title: '复制失败', icon: 'none' })
});
};
// //
const copyAddress = () => { const copyAddress = () => {
if (!blockchainAddress.value) { if (!blockchainAddress.value) {
@ -917,50 +947,7 @@ const handleDeleteAccount = () => {
// //
const handleGuideClick = () => { const handleGuideClick = () => {
showGuideListModal.value = true; showGuideModal.value = true;
};
//
const handleStartGuide = (params) => {
// { key, fromStep, targetPage } key
const key = typeof params === 'string' ? params : (params?.key || '');
const fromStep = typeof params === 'object' ? (params.fromStep ?? 0) : 0;
const targetPage = typeof params === 'object' ? (params.targetPage || '') : '';
console.log('[Profile] handleStartGuide:', { key, fromStep, targetPage });
showGuideListModal.value = false;
//
if (key === 'square_home') {
// 使 targetPage
const navigateUrl = targetPage || '/pages/square/square';
uni.navigateTo({
url: navigateUrl,
success: () => {
//
setTimeout(() => {
if (fromStep === 0) {
store.dispatch("guide/startGuideFromBeginning", key);
} else {
store.dispatch("guide/resumeGuide", key);
}
}, 500);
}
});
} else {
//
if (fromStep === 0) {
store.dispatch("guide/startGuideFromBeginning", key);
} else {
store.dispatch("guide/resumeGuide", key);
}
}
};
//
const handleClaimSuccess = (reward) => {
console.log("[Profile] 领取奖励成功:", reward);
}; };
// //
@ -1309,12 +1296,12 @@ onShow(() => {
display: none; display: none;
} }
.close-icon-img{ .close-icon-img {
width: 80rpx; width: 80rpx;
height: 80rpx; height: 80rpx;
position: relative; position: relative;
top: 32rpx; top: 32rpx;
left: 32rpx; left: 32rpx;
} }
.user-info-card { .user-info-card {
@ -1335,7 +1322,7 @@ onShow(() => {
align-items: flex-start; align-items: flex-start;
/* gap: 30rpx; */ /* gap: 30rpx; */
margin-bottom: 0; margin-bottom: 0;
} }
.avatar-container { .avatar-container {
@ -1353,8 +1340,8 @@ onShow(() => {
gap: 8rpx; gap: 8rpx;
margin-left: 8rpx; margin-left: 8rpx;
background-image: url(/static/rank/activity-support-icon/beijingkuang.png); background-image: url(/static/rank/activity-support-icon/beijingkuang.png);
background-size: 100% 110%; background-size: 100% 110%;
background-position: center; background-position: center;
padding: 24rpx 24rpx 24rpx 240rpx; padding: 24rpx 24rpx 24rpx 240rpx;
min-width: 356rpx; min-width: 356rpx;
} }
@ -1371,6 +1358,11 @@ onShow(() => {
min-width: 112rpx; min-width: 112rpx;
} }
.address-row {
display: flex;
align-items: center;
}
.info-value { .info-value {
font-size: 24rpx; font-size: 24rpx;
color: #ffffff; color: #ffffff;
@ -1378,15 +1370,18 @@ onShow(() => {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
min-width: 200rpx;
} }
.uid-value { .uid-value {}
max-width: 200rpx;
.toggle-icon {
width: 32rpx;
height: 32rpx;
} }
.address-value { .address-value {}
max-width: 160rpx;
}
.info-btn { .info-btn {
font-size: 20rpx; font-size: 20rpx;
@ -1619,8 +1614,10 @@ onShow(() => {
.logout-section { .logout-section {
padding: 10rpx 30rpx; padding: 10rpx 30rpx;
padding-bottom: calc(40rpx + constant(safe-area-inset-bottom)); /* iOS 11.0 */ padding-bottom: calc(40rpx + constant(safe-area-inset-bottom));
padding-bottom: calc(40rpx + env(safe-area-inset-bottom)); /* iOS 11.2+ */ /* iOS 11.0 */
padding-bottom: calc(40rpx + env(safe-area-inset-bottom));
/* iOS 11.2+ */
display: flex; display: flex;
position: relative; position: relative;
} }
@ -1686,7 +1683,10 @@ onShow(() => {
.modal-content { .modal-content {
width: 80%; width: 80%;
max-width: 600rpx; max-width: 600rpx;
background: #ffffff; /* background: #ffffff; */
background-image: url('/static/starbookcontent/beijing.png');
background-size: cover;
background-position: center bottom;
border-radius: 30rpx; border-radius: 30rpx;
padding: 60rpx 40rpx; padding: 60rpx 40rpx;
box-sizing: border-box; box-sizing: border-box;

View File

@ -17,7 +17,7 @@
<view class="modal-header"> <view class="modal-header">
<!-- 返回按钮 --> <!-- 返回按钮 -->
<view class="back-button" @click="handleClose"> <view class="back-button" @click="handleClose">
<image class="back-icon" src="/static/icon/back.png" mode="aspectFit" /> <image class="back-icon" src="/static/starbookcontent/tuichu.png" mode="aspectFit" />
</view> </view>
<!-- 标题 --> <!-- 标题 -->

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 354 KiB

After

Width:  |  Height:  |  Size: 110 KiB

View File

@ -96,8 +96,8 @@ const actions = {
// 缓存用户信息 // 缓存用户信息
const user = res.data.user const user = res.data.user
// 缓存登录手机号(优先使用后端返回的脱敏手机号) // 缓存登录手机号
const loginMobile = user.mobile_masked || mobile const loginMobile = mobile
uni.setStorageSync('login_mobile', loginMobile) uni.setStorageSync('login_mobile', loginMobile)
uni.setStorageSync('user', JSON.stringify(user)) uni.setStorageSync('user', JSON.stringify(user))
@ -131,8 +131,8 @@ const actions = {
// 缓存用户信息 // 缓存用户信息
const user = res.data.user const user = res.data.user
// 缓存登录手机号(优先使用后端返回的脱敏手机号) // 缓存登录手机号
const loginMobile = user.mobile_masked || mobile const loginMobile = mobile
uni.setStorageSync('login_mobile', loginMobile) uni.setStorageSync('login_mobile', loginMobile)
uni.setStorageSync('user', JSON.stringify(user)) uni.setStorageSync('user', JSON.stringify(user))