topfans/frontend/pages/profile/selectRole.vue

616 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<LoginBackground :show-logo="true">
<!-- 内容区域 -->
<view class="select-role-content">
<!-- 玩偶头像从卡片顶部伸出 -->
<view class="character-head-wrapper">
<image
class="character-head"
src="/static/login/portal/register-avatar.png"
mode="aspectFit"
></image>
</view>
<!-- 玻璃拟态卡片 -->
<view class="glass-card">
<view class="nav-back" @tap="goBack">
<text class="nav-back-icon"></text>
</view>
<!-- 标题选择明星 -->
<view class="card-title-wrapper">
<text class="card-title">选择明星</text>
</view>
<!-- 未选中输入框 + 候选列表 -->
<template v-if="!selectedStar">
<view class="input-outer">
<view class="input-inner">
<input
class="star-input"
type="text"
v-model="searchText"
placeholder="请输入TA的名称"
placeholder-class="star-input-placeholder"
:adjust-position="true"
disabled
/>
</view>
</view>
<view class="card-divider"></view>
<view class="next-btn-wrapper">
<view class="next-btn" @tap="handleConfirm">
<text class="next-btn-text">确定</text>
</view>
</view>
</template>
<!-- 已选中:两张照片 + 按钮组 -->
<template v-else>
<view class="selected-photos">
<view class="photo-card photo-card-left">
<image
class="photo-img"
:src="selectedStar.image"
mode="aspectFill"
></image>
</view>
<view class="photo-card photo-card-right">
<image
class="photo-img"
:src="selectedStar.imageRight || selectedStar.image"
mode="aspectFill"
></image>
</view>
</view>
<view class="card-divider"></view>
<view class="actions-row">
<view class="action-btn reset-btn" @tap="resetSelection">
<text class="action-btn-text">重新选择</text>
</view>
<view class="action-btn confirm-btn" @tap="handleNext">
<text class="action-btn-text">下一步</text>
</view>
</view>
</template>
</view>
</view>
<!-- 通用确认弹窗 -->
<ConfirmModal
:visible="confirmModal.visible"
:title="confirmModal.title"
:content="confirmModal.content"
:confirmText="confirmModal.confirmText"
:cancelText="confirmModal.cancelText"
:showCancel="confirmModal.showCancel"
@confirm="onConfirmModal"
@cancel="onCancelModal"
/>
</LoginBackground>
</template>
<script setup>
import { ref, computed } from "vue";
import { useStore } from "vuex";
import LoginBackground from "@/components/LoginBackground.vue";
import ConfirmModal from "@/components/ConfirmModal.vue";
const props = defineProps({
isWelcome: {
type: Boolean,
default: false,
},
});
const emit = defineEmits(["confirm"]);
const store = useStore();
// 响应式数据
const searchText = ref("张艺兴");
const selectedStar = ref(null);
// 通用确认弹窗状态
const confirmModal = ref({
visible: false,
title: "",
content: "",
confirmText: "确认",
cancelText: "取消",
showCancel: true,
confirmCallback: null,
});
// 弹窗确认回调
const onConfirmModal = () => {
if (confirmModal.value.confirmCallback) {
confirmModal.value.confirmCallback({ confirm: true });
}
confirmModal.value.visible = false;
};
// 弹窗取消回调
const onCancelModal = () => {
if (confirmModal.value.confirmCallback) {
confirmModal.value.confirmCallback({ confirm: false });
}
confirmModal.value.visible = false;
};
// 显示通用确认弹窗
const showConfirmModal = (options) => {
confirmModal.value = {
visible: true,
title: options.title || "",
content: options.content || "",
confirmText: options.confirmText || "确认",
cancelText: options.cancelText || "取消",
showCancel: options.showCancel !== false,
confirmCallback: options.success || null,
};
};
const goBack = () => {
uni.navigateBack();
};
// 选择明星
const selectStar = (star) => {
selectedStar.value = star;
searchText.value = star.nameCn;
};
// 重新选择
const resetSelection = () => {
selectedStar.value = null;
// searchText.value = "";
};
// 确认选择明星(从输入框内容自动匹配)
const handleConfirm = () => {
const query = searchText.value.trim();
if (!query) {
uni.showToast({ title: "请输入明星名称", icon: "none" });
return;
}
// 简单匹配:把输入内容包装成一个临时 selectedStar
selectedStar.value = {
id: Date.now(),
star_id: 87,
nameCn: query,
nameEn: "",
image: "/static/login/portal/selectrole-photo1.png",
imageRight: "/static/login/portal/selectrole-photo2.png",
};
};
// 下一步
const handleNext = async () => {
let targetStar = selectedStar.value;
if (!targetStar) {
const match = stars.value.find(
(s) =>
s.nameCn === searchText.value.trim() ||
s.nameEn.toLowerCase() === searchText.value.trim().toLowerCase(),
);
if (match) {
targetStar = match;
}
}
if (!targetStar) {
uni.showToast({ title: "请先选择一位明星", icon: "none" });
return;
}
if (props.isWelcome) {
emit("confirm", targetStar);
return;
}
try {
const mobile = uni.getStorageSync("temp_register_mobile");
const password = uni.getStorageSync("temp_register_password");
const nickname = uni.getStorageSync("temp_register_nickname");
const verify_token = uni.getStorageSync("temp_register_verify_token") || "";
const avatar_url = uni.getStorageSync("temp_register_avatar_url") || "https://top-fans-test.oss-cn-shanghai.aliyuncs.com/avatar/13/87/character.png";
const star_id = targetStar.star_id;
console.log("注册信息:", { mobile, password, nickname, star_id, avatar_url });
if (!mobile || !password || !nickname || !star_id) {
uni.showToast({ title: "注册信息不完整,请重新注册", icon: "none" });
uni.removeStorageSync("temp_register_mobile");
uni.removeStorageSync("temp_register_password");
uni.removeStorageSync("temp_register_nickname");
uni.removeStorageSync("temp_register_verify_token");
uni.removeStorageSync("temp_register_avatar_url");
setTimeout(() => {
uni.reLaunch({ url: "/pages/register/register" });
}, 1500);
return;
}
uni.showLoading({ title: "注册中...", mask: true });
await store.dispatch("user/register", {
mobile,
password,
star_id,
nickname,
verify_token,
avatar_url,
});
uni.hideLoading();
uni.removeStorageSync("temp_register_mobile");
uni.removeStorageSync("temp_register_password");
uni.removeStorageSync("temp_register_nickname");
uni.removeStorageSync("temp_register_verify_token");
uni.removeStorageSync("temp_register_avatar_url");
uni.setStorageSync("is_new_user", true);
// 注册成功后首次进入 square触发 TopfansWelcome 显示
uni.setStorageSync("needs_welcome", true);
uni.reLaunch({ url: "/pages/square/square" });
} catch (error) {
uni.hideLoading();
if (
error.code === 3 ||
(error.message &&
(error.message.includes("昵称") || error.message.includes("已存在")))
) {
showConfirmModal({
title: "昵称已存在",
content: "该昵称已被使用,请返回修改昵称",
showCancel: true,
confirmText: "返回修改",
cancelText: "取消",
success: (res) => {
if (res.confirm) {
uni.navigateBack();
}
},
});
} else {
uni.showToast({
title: (error && error.message) || "注册失败,请重试",
icon: "none",
duration: 2000,
});
}
}
};
</script>
<style scoped>
.select-role-content {
position: relative;
z-index: 10;
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
/* 玩偶头像(从卡片顶部伸出) */
.character-head-wrapper {
width: 296rpx;
height: 274rpx;
margin-top: 130rpx;
z-index: 11;
filter: drop-shadow(1rpx 2rpx 98rpx rgba(0, 0, 0, 0.94));
}
.character-head {
width: 100%;
height: 100%;
}
/* 玻璃拟态卡片 */
.glass-card {
width: 710rpx;
margin-top: -104rpx;
padding: 30rpx 104rpx 30rpx;
box-sizing: border-box;
border-radius: 56rpx;
border: 1px solid rgba(255, 255, 255, 0.15);
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(64rpx);
-webkit-backdrop-filter: blur(64rpx);
box-shadow: 0 0 41rpx rgba(0, 0, 0, 0.31);
display: flex;
flex-direction: column;
align-items: center;
z-index: 12;
}
.nav-back {
width: 80rpx;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
left: 32rpx;
}
.nav-back-icon {
font-size: 48rpx;
font-weight: bold;
color: #fff;
}
/* 标题胶囊:选择明星 */
.card-title-wrapper {
position: relative;
width: 324rpx;
height: 84rpx;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 56rpx;
background:
linear-gradient(240deg, #cdaffa 9.77%, rgba(205, 175, 250, 0) 62.44%),
linear-gradient(108deg, #f7cbbf 13.91%, rgba(247, 203, 191, 0) 51.34%),
linear-gradient(297deg, #81a9f8 31.28%, rgba(129, 169, 248, 0) 90.74%),
linear-gradient(80deg, #69f4e9 39.86%, rgba(164, 252, 245, 0) 66.88%);
border-radius: 84rpx;
}
.card-title {
position: relative;
z-index: 1;
font-size: 44rpx;
color: #fff9e7;
text-shadow: -2rpx 2rpx 8rpx rgba(0, 0, 0, 0.84);
font-family: "Abhaya Libre Medium", sans-serif;
}
/* 输入框外层(带渐变描边感) */
.input-outer {
width: 508rpx;
height: 74rpx;
border-radius: 58rpx;
background: linear-gradient(
90deg,
rgba(255, 222, 8, 0.06) 0%,
rgba(252, 100, 102, 0.12) 50%,
rgba(244, 88, 104, 0.12) 100%
);
box-shadow: 2rpx 2rpx 8rpx rgba(242, 21, 21, 0.47);
padding: 4rpx;
box-sizing: border-box;
display: flex;
align-items: center;
margin: 136rpx 0;
}
.input-inner {
width: 100%;
height: 60rpx;
border-radius: 58rpx;
background: rgba(255, 255, 255, 0.65);
display: flex;
align-items: center;
padding: 0 32rpx;
box-sizing: border-box;
}
.star-input {
width: 100%;
height: 100%;
font-size: 30rpx;
color: #333;
background: transparent;
}
.star-input-placeholder {
color: #565656;
font-size: 30rpx;
font-family: "Abhaya Libre Medium", sans-serif;
}
/* 候选明星列表 */
.suggestion-list {
width: 508rpx;
margin: 24rpx auto 0 auto;
max-height: 360rpx;
overflow-y: auto;
}
.suggestion-item {
display: flex;
align-items: center;
padding: 16rpx 20rpx;
border-radius: 24rpx;
background: rgba(255, 255, 255, 0.45);
margin-bottom: 12rpx;
transition: background 0.2s ease;
}
.suggestion-item.is-selected {
background: rgba(255, 255, 255, 0.85);
box-shadow: 0 0 12rpx rgba(252, 100, 102, 0.4);
}
.suggestion-avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
flex-shrink: 0;
background: #eee;
}
.suggestion-info {
flex: 1;
margin-left: 20rpx;
display: flex;
flex-direction: column;
}
.suggestion-name-cn {
font-size: 30rpx;
font-weight: 600;
color: #222;
line-height: 1.2;
}
.suggestion-name-en {
font-size: 24rpx;
color: #777;
margin-top: 6rpx;
}
.suggestion-check {
width: 40rpx;
height: 40rpx;
border-radius: 50%;
background: linear-gradient(135deg, #ffde08, #fc6466);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.suggestion-check-icon {
color: #fff;
font-size: 24rpx;
font-weight: bold;
}
/* 分隔线 */
.card-divider {
width: 612rpx;
height: 4rpx;
background: rgba(255, 255, 255, 0.3);
border-radius: 100rpx;
margin: 28rpx 0 24rpx;
}
/* 下一步按钮 */
.next-btn-wrapper {
width: 100%;
display: flex;
justify-content: center;
padding: 64rpx 0;
}
.next-btn {
width: 270rpx;
height: 90rpx;
border-radius: 58rpx;
background: linear-gradient(
90deg,
rgba(255, 222, 8, 0.28) 0%,
rgba(252, 100, 102, 0.58) 50%,
rgba(244, 88, 104, 0.58) 100%
);
box-shadow: 2rpx 2rpx 8rpx rgba(242, 21, 21, 0.47);
display: flex;
align-items: center;
justify-content: center;
transition: transform 0.2s ease;
}
.next-btn:active {
transform: scale(0.96);
}
.next-btn-text {
font-size: 40rpx;
font-weight: 500;
color: #fff9e7;
letter-spacing: 6rpx;
text-shadow: -1rpx 1rpx 8rpx rgba(0, 0, 0, 0.84);
}
/* 已选中:两张照片 */
.selected-photos {
position: relative;
width: 510rpx;
height: 480rpx;
margin: 24rpx auto 0;
display: flex;
align-items: center;
justify-content: center;
gap: 30rpx;
}
.photo-card {
position: relative;
width: 280rpx;
height: 420rpx;
border-radius: 18rpx;
overflow: hidden;
box-shadow: 0 4rpx 28rpx rgba(113, 13, 13, 0.97);
}
.photo-card-left {
transform: rotate(-5deg) scale(0.96);
margin-right: -50rpx;
}
.photo-card-right {
transform: rotate(6deg);
margin-left: -50rpx;
margin-top: 24rpx;
}
.photo-img {
width: 100%;
height: 100%;
border-radius: inherit;
}
/* 按钮组:重新选择 + 下一步 */
.actions-row {
width: 510rpx;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 36rpx;
gap: 24rpx;
}
.action-btn {
flex: 1;
height: 90rpx;
border-radius: 58rpx;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 4rpx 4rpx 8rpx 0 rgba(242, 21, 21, 0.47);
}
.reset-btn {
background: linear-gradient(
90deg,
rgba(255, 222, 8, 0.1) 0%,
rgba(252, 100, 102, 0.2) 64%,
rgba(244, 88, 104, 0.2) 100%
);
}
.confirm-btn {
background: linear-gradient(
90deg,
rgba(255, 222, 8, 0.28) 0%,
rgba(252, 100, 102, 0.58) 64%,
rgba(244, 88, 104, 0.58) 100%
);
}
.action-btn-text {
font-size: 36rpx;
color: #fff9e7;
text-shadow: -2rpx 2rpx 8rpx rgba(0, 0, 0, 0.84);
font-family: "Abhaya Libre Medium", sans-serif;
}
</style>