Sfoglia il codice sorgente

添加创建星灵界面

lalalashen 3 mesi fa
parent
commit
553d13ab4a
3 ha cambiato i file con 781 aggiunte e 0 eliminazioni
  1. 5 0
      pages.json
  2. 501 0
      pages/my/myStar.scss
  3. 275 0
      pages/my/myStar.vue

+ 5 - 0
pages.json

@@ -243,6 +243,11 @@
 			"style": {
 				"navigationBarTitleText": "音乐制作详情"
 			}
+		}, {
+			"path": "pages/my/myStar",
+			"style": {
+				"navigationBarTitleText": "我的星灵"
+			}
 		}
 	],
 	"globalStyle": {

+ 501 - 0
pages/my/myStar.scss

@@ -0,0 +1,501 @@
+.star-container {
+	width: 100%;
+	min-height: 100vh;
+	background-color: #f5f5f5;
+	
+	.loading-area {
+		position: fixed;
+		top: 0;
+		left: 0;
+		right: 0;
+		bottom: 0;
+		display: flex;
+		flex-direction: column;
+		justify-content: center;
+		align-items: center;
+		background: rgba(255,255,255,0.9);
+		
+		.loading-wrapper {
+			width: 400rpx;
+			height: 400rpx;
+			position: relative;
+			
+			.center-circle {
+				position: absolute;
+				top: 50%;
+				left: 50%;
+				width: 100rpx;
+				height: 100rpx;
+				margin: -50rpx 0 0 -50rpx;
+				background: #1E90FF;
+				border-radius: 50%;
+				animation: rotate 2s linear infinite;
+				
+				&::after {
+					content: '';
+					position: absolute;
+					top: 8rpx;
+					left: 8rpx;
+					right: 8rpx;
+					bottom: 8rpx;
+					background: #fff;
+					border-radius: 50%;
+					opacity: 0.3;
+				}
+			}
+			
+			.orbit-balls {
+				width: 100%;
+				height: 100%;
+				position: absolute;
+				animation: rotate 2s linear infinite;
+				
+				.ball {
+					position: absolute;
+					width: 100%;
+					height: 100%;
+					left: 0;
+					top: 0;
+					
+					.ball-item {
+						position: absolute;
+						width: 20rpx;
+						height: 20rpx;
+						background: var(--color);
+						border-radius: 50%;
+						top: 0;
+						left: 50%;
+						margin-left: -10rpx;
+						animation: moveBall 3s ease-in infinite;
+						animation-delay: var(--delay);
+					}
+				}
+			}
+		}
+		
+		.loading-text {
+			margin-top: 40rpx;
+			font-size: 28rpx;
+			color: #666;
+		}
+	}
+	
+	.star-content {
+		width: 100%;
+		padding: 20rpx;
+	}
+	
+	.gender-popup {
+		position: fixed;
+		top: 0;
+		left: 0;
+		right: 0;
+		bottom: 0;
+		background: rgba(0, 0, 0, 0.5);
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		z-index: 1000;
+		
+		.popup-content {
+			width: 600rpx;
+			background: #FFFFFF;
+			border-radius: 24rpx;
+			padding: 40rpx;
+			
+			.popup-title {
+				font-size: 36rpx;
+				color: #333;
+				text-align: center;
+				font-weight: 500;
+				margin-bottom: 40rpx;
+			}
+			
+			.gender-cards {
+				display: flex;
+				justify-content: space-between;
+				margin-bottom: 40rpx;
+				
+				.gender-card {
+					width: 240rpx;
+					height: 280rpx;
+					border-radius: 16rpx;
+					border: 2rpx solid #EEEEEE;
+					display: flex;
+					flex-direction: column;
+					align-items: center;
+					justify-content: center;
+					position: relative;
+					transition: all 0.3s;
+					
+					image {
+						width: 160rpx;
+						height: 160rpx;
+						margin-bottom: 20rpx;
+					}
+					
+					text {
+						font-size: 28rpx;
+						color: #333;
+					}
+					
+					.check-icon {
+						position: absolute;
+						top: 16rpx;
+						right: 16rpx;
+						width: 40rpx;
+						height: 40rpx;
+					}
+					
+					&.selected {
+						border-color: #1E90FF;
+						background: rgba(30, 144, 255, 0.05);
+					}
+				}
+			}
+			
+			.confirm-btn {
+				height: 88rpx;
+				background: #9C27B0;
+				border-radius: 44rpx;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				color: #FFFFFF;
+				font-size: 32rpx;
+				font-weight: 500;
+				
+				&:active {
+					opacity: 0.8;
+				}
+			}
+		}
+	}
+	
+	.character-page {
+		width: 100%;
+		min-height: 100vh;
+		background-color: #f5f5f5;
+		display: flex;
+		flex-direction: column;
+		position: relative;
+		
+		.character-container {
+			flex: 1;
+			display: flex;
+			justify-content: center;
+			align-items: center;
+			padding: 40rpx;
+			margin-bottom: 120rpx; // 为底部按钮留出空间
+			
+			.character-image {
+				width: 100%;
+				height: 800rpx; // 调整角色图片高度
+				object-fit: contain;
+			}
+		}
+		
+		.bottom-button {
+			position: fixed;
+			bottom: 40rpx;
+			left: 40rpx;
+			right: 40rpx;
+			height: 98rpx;
+			background: #333333;
+			border-radius: 49rpx;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			color: #FFFFFF;
+			font-size: 32rpx;
+			font-weight: 500;
+			box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
+			transition: all 0.2s ease;
+			
+			&:active {
+				opacity: 0.95;
+				transform: scale(0.98);
+			}
+		}
+	}
+}
+
+@keyframes rotate {
+	from {
+		transform: rotate(0deg);
+	}
+	to {
+		transform: rotate(-360deg);
+	}
+}
+
+@keyframes moveBall {
+	0% {
+		transform: translateY(0) scale(1);
+		opacity: 1;
+	}
+	98% {
+		transform: translateY(180rpx) scale(0.1);
+		opacity: 0.2;
+	}
+	99% {
+		transform: translateY(180rpx) scale(0.01);
+		opacity: 0;
+	}
+	100% {
+		transform: translateY(0) scale(1);
+		opacity: 0;
+	}
+}
+
+.form-page {
+	width: 100%;
+	min-height: 100vh;
+	background-color: #ffffff;
+	padding: 30rpx;
+	box-sizing: border-box;
+	
+	.form-group {
+		margin-bottom: 40rpx;
+		
+		.label {
+			display: flex;
+			align-items: center;
+			margin-bottom: 16rpx;
+			font-size: 28rpx;
+			color: #333;
+			
+			.required {
+				color: #ff4d4f;
+				margin-right: 8rpx;
+				
+				&.error {
+					animation: shake 0.5s ease-in-out;
+				}
+			}
+		}
+		
+		.input {
+			width: 100%;
+			height: 88rpx;
+			background: #f5f5f5;
+			border-radius: 12rpx;
+			padding: 0 24rpx;
+			font-size: 28rpx;
+			
+			&.error {
+				border: 2rpx solid #ff4d4f;
+			}
+		}
+		
+		.gender-options {
+			display: flex;
+			gap: 20rpx;
+			
+			.gender-option {
+				flex: 1;
+				height: 80rpx;
+				background: #f5f5f5;
+				border-radius: 40rpx;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				font-size: 28rpx;
+				color: #666;
+				transition: all 0.3s;
+				
+				&.selected {
+					background: #333;
+					color: #fff;
+				}
+			}
+		}
+		
+		.textarea-container {
+			position: relative;
+			
+			.textarea {
+				width: 100%;
+				height: 240rpx;
+				background: #f5f5f5;
+				border-radius: 12rpx;
+				padding: 24rpx;
+				font-size: 28rpx;
+				
+				&.error {
+					border: 2rpx solid #ff4d4f;
+				}
+			}
+			
+			.word-count {
+				position: absolute;
+				right: 24rpx;
+				bottom: 24rpx;
+				font-size: 24rpx;
+				color: #999;
+			}
+		}
+		
+		.tags-scroll {
+			width: 100%;
+			white-space: nowrap;
+			
+			.tags-container {
+				display: inline-flex;
+				padding: 20rpx 0;
+				gap: 20rpx;
+				
+				.tag {
+					padding: 16rpx 32rpx;
+					background: #f5f5f5;
+					border-radius: 32rpx;
+					font-size: 26rpx;
+					color: #666;
+					transition: all 0.3s;
+					
+					&.selected {
+						background: #333;
+						color: #fff;
+					}
+				}
+			}
+		}
+	}
+	
+	.submit-button {
+		position: fixed;
+		bottom: 40rpx;
+		left: 40rpx;
+		right: 40rpx;
+		height: 98rpx;
+		background: #333333;
+		border-radius: 49rpx;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		color: #FFFFFF;
+		font-size: 32rpx;
+		font-weight: 500;
+		transition: all 0.2s ease;
+		
+		&:active {
+			opacity: 0.95;
+			transform: scale(0.98);
+		}
+	}
+}
+
+@keyframes shake {
+	0%, 100% { transform: translateX(0); }
+	25% { transform: translateX(-5rpx); }
+	75% { transform: translateX(5rpx); }
+}
+
+.character-info {
+	width: 100%;
+	min-height: 100vh;
+	background-color: #ffffff;
+	position: relative;
+	padding-bottom: 120rpx;
+	
+	.info-container {
+		padding: 30rpx;
+		
+		.character-portrait {
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			margin-bottom: 40rpx;
+			
+			.portrait-image {
+				width: 100%;
+				height: 600rpx;
+				object-fit: contain;
+			}
+			
+			.character-name {
+				font-size: 40rpx;
+				font-weight: 600;
+				color: #333;
+				margin-top: 20rpx;
+			}
+		}
+		
+		.info-section {
+			background: #f8f8f8;
+			border-radius: 20rpx;
+			padding: 30rpx;
+			
+			.section-title {
+				font-size: 32rpx;
+				font-weight: 500;
+				color: #333;
+				margin-bottom: 20rpx;
+				position: relative;
+				padding-left: 20rpx;
+				
+				&::before {
+					content: '';
+					position: absolute;
+					left: 0;
+					top: 50%;
+					transform: translateY(-50%);
+					width: 6rpx;
+					height: 28rpx;
+					background: #9C27B0;
+					border-radius: 3rpx;
+				}
+			}
+			
+			.description-box {
+				background: #ffffff;
+				border-radius: 16rpx;
+				padding: 24rpx;
+				margin-bottom: 30rpx;
+				
+				.description-text {
+					font-size: 28rpx;
+					color: #666;
+					line-height: 1.6;
+				}
+			}
+			
+			.tags-box {
+				display: flex;
+				flex-wrap: wrap;
+				gap: 16rpx;
+				
+				.tag-item {
+					padding: 12rpx 24rpx;
+					background: #f0f0f0;
+					border-radius: 28rpx;
+					font-size: 24rpx;
+					color: #666;
+				}
+			}
+		}
+	}
+	
+	.join-button {
+		position: fixed;
+		bottom: 40rpx;
+		left: 40rpx;
+		right: 40rpx;
+		height: 98rpx;
+		background: linear-gradient(to right, #9C27B0, #7B1FA2);
+		border-radius: 49rpx;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		color: #FFFFFF;
+		font-size: 32rpx;
+		font-weight: 500;
+		box-shadow: 0 4rpx 12rpx rgba(156, 39, 176, 0.3);
+		transition: all 0.2s ease;
+		
+		&:active {
+			transform: scale(0.98);
+			opacity: 0.95;
+		}
+	}
+}

+ 275 - 0
pages/my/myStar.vue

@@ -0,0 +1,275 @@
+<template>
+	<view class="star-container">
+		<!-- 性别选择弹窗 -->
+		<view class="gender-popup" v-if="!selectedGender">
+			<view class="popup-content">
+				<view class="popup-title">请选择性别</view>
+				
+				<view class="gender-cards">
+					<view class="gender-card" 
+						:class="{'selected': tempGender === 'male'}"
+						@tap="selectGender('male')">
+						<image src="/static/gender/male.png" mode="aspectFit"></image>
+						<text>男生</text>
+						<image v-if="tempGender === 'male'" 
+							class="check-icon" 
+							src="/static/gender/check.png" 
+							mode="aspectFit">
+						</image>
+					</view>
+					
+					<view class="gender-card"
+						:class="{'selected': tempGender === 'female'}"
+						@tap="selectGender('female')">
+						<image src="/static/gender/female.png" mode="aspectFit"></image>
+						<text>女生</text>
+						<image v-if="tempGender === 'female'" 
+							class="check-icon" 
+							src="/static/gender/check.png" 
+							mode="aspectFit">
+						</image>
+					</view>
+				</view>
+				
+				<view class="confirm-btn" @tap="confirmGender">
+					创建星灵
+				</view>
+			</view>
+		</view>
+		
+		<!-- 加载动画区域 -->
+		<view class="loading-area" v-if="isLoading">
+			<view class="loading-wrapper">
+				<!-- 中心蓝色旋转圆 -->
+				<view class="center-circle"></view>
+				
+				<!-- 外围16个小球 -->
+				<view class="orbit-balls">
+					<view class="ball" v-for="(item,index) in 16" :key="index" 
+						:style="{
+							transform: `rotate(${index * 22.5}deg)`,
+							'--delay': `${index * 0.2}s`,
+							'--color': ballColors[index % 8]
+						}">
+						<view class="ball-item"></view>
+					</view>
+				</view>
+			</view>
+			<text class="loading-text">正在加载...</text>
+		</view>
+		
+		<!-- 角色信息展示页面 -->
+		<view class="character-info" v-else-if="showInfo">
+			<view class="info-container">
+				<!-- 角色立绘区域 -->
+				<view class="character-portrait">
+					<image 
+						:src="selectedGender === 'male' ? '/static/character/male-full.png' : '/static/character/female-full.png'"
+						mode="aspectFit"
+						class="portrait-image"
+					></image>
+					<text class="character-name">{{formData.nickname}}</text>
+				</view>
+				
+				<!-- 角色信息板块 -->
+				<view class="info-section">
+					<view class="section-title">关于Ta</view>
+					
+					<!-- 人物简介 -->
+					<view class="description-box">
+						<text class="description-text">{{formData.description}}</text>
+					</view>
+					
+					<!-- 标签展示 -->
+					<view class="tags-box">
+						<view class="tag-item" v-for="tag in formData.tags" :key="tag">
+							{{tag}}
+						</view>
+					</view>
+				</view>
+			</view>
+			
+			<!-- 底部按钮 -->
+			<view class="join-button" @tap="handleJoin">
+				入驻星球
+			</view>
+		</view>
+		
+		<!-- 表单页面 -->
+		<view class="form-page" v-else-if="showForm">
+			<form @submit="submitForm">
+				<view class="form-group">
+					<view class="label">
+						<text class="required">*</text>
+						<text>昵称</text>
+					</view>
+					<input 
+						class="input" 
+						v-model="formData.nickname"
+						placeholder="给星灵取个名字"
+						:class="{'error': showError && !formData.nickname}"
+					/>
+				</view>
+				
+				<view class="form-group">
+					<view class="label">性别</view>
+					<view class="gender-options">
+						<view 
+							class="gender-option" 
+							:class="{'selected': formData.gender === gender}"
+							v-for="gender in ['男', '女', '其他']" 
+							:key="gender"
+							@tap="formData.gender = gender"
+						>
+							{{gender}}
+						</view>
+					</view>
+				</view>
+				
+				<view class="form-group">
+					<view class="label">
+						<text class="required">*</text>
+						<text>人物简介</text>
+					</view>
+					<view class="textarea-container">
+						<textarea 
+							class="textarea" 
+							v-model="formData.description"
+							placeholder="填写这个角色的人物介绍,例如性格、身份、背景与历程..."
+							:maxlength="255"
+							:class="{'error': showError && !formData.description}"
+						/>
+						<text class="word-count">{{formData.description.length}}/255</text>
+					</view>
+				</view>
+				
+				<view class="form-group">
+					<view class="label">人物标签</view>
+					<scroll-view 
+						class="tags-scroll" 
+						scroll-x="true" 
+						show-scrollbar="false"
+					>
+						<view class="tags-container">
+							<view 
+								class="tag" 
+								:class="{'selected': formData.tags.includes(tag)}"
+								v-for="tag in predefinedTags" 
+								:key="tag"
+								@tap="toggleTag(tag)"
+							>
+								{{tag}}
+							</view>
+						</view>
+					</scroll-view>
+				</view>
+			</form>
+			
+			<view class="submit-button" @tap="handleSubmit">
+				确定并提交
+			</view>
+		</view>
+		
+		<!-- 角色展示页面 -->
+		<view class="character-page" v-else-if="selectedGender">
+			<view class="character-container">
+				<image 
+					:src="selectedGender === 'male' ? '/static/character/male-full.png' : '/static/character/female-full.png'"
+					mode="aspectFit"
+					class="character-image"
+				></image>
+			</view>
+			<view class="bottom-button" @tap="goToSetProfile">
+				设置星灵简介
+			</view>
+		</view>
+		
+		<!-- 收藏内容区域 -->
+		<view class="star-content" v-else>
+			<view class="star-list">
+				<!-- 这里放收藏列表内容 -->
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import tabbarView from "@/components/tabbar/tabbar.vue"
+	
+	export default {
+		components: {
+			tabbarView
+		},
+		data() {
+			return {
+				isLoading: false,
+				selectedGender: null,
+				tempGender: null,
+				tabbars: [],
+				ballColors: [
+					'#FF6B6B', // 红色
+					'#4ECDC4', // 青色
+					'#45B7D1', // 蓝色
+					'#96CEB4', // 绿色
+					'#FFEEAD', // 黄色
+					'#D4A5A5', // 粉色
+					'#9A8194', // 紫色
+					'#FF9F1C'  // 橙色
+				],
+				showForm: false,
+				showError: false,
+				formData: {
+					nickname: '',
+					gender: '其他',
+					description: '',
+					tags: []
+				},
+				predefinedTags: ['高冷', 'INTJ', '爱吃瘦果', '傲娇', '理性', '感性', '文艺', '二次元'],
+				showInfo: false,
+			}
+		},
+		methods: {
+			selectGender(gender) {
+				this.tempGender = gender;
+			},
+			confirmGender() {
+				if (!this.tempGender) return;
+				this.selectedGender = this.tempGender;
+				this.isLoading = true;
+				
+				// 模拟加载过程
+				setTimeout(() => {
+					this.isLoading = false;
+				}, 4000);
+			},
+			goToSetProfile() {
+				this.showForm = true;
+			},
+			toggleTag(tag) {
+				const index = this.formData.tags.indexOf(tag);
+				if (index > -1) {
+					this.formData.tags.splice(index, 1);
+				} else {
+					this.formData.tags.push(tag);
+				}
+			},
+			handleSubmit() {
+				// if (!this.formData.nickname || !this.formData.description) {
+				// 	this.showError = true;
+				// 	return;
+				// }
+				
+				this.showForm = false;
+				this.showInfo = true;
+			},
+			handleJoin() {
+				console.log('入驻星球');
+				// 处理入驻逻辑
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	@import './myStar.scss';
+</style>