616 lines
14 KiB
Vue
616 lines
14 KiB
Vue
<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>
|