1
This commit is contained in:
178
src/components/EditModal/EditModal.scss
Normal file
178
src/components/EditModal/EditModal.scss
Normal file
@@ -0,0 +1,178 @@
|
||||
// 编辑弹窗组件样式
|
||||
.edit_modal_overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.edit_modal_container {
|
||||
width: 100%;
|
||||
background: #FAFAFA;
|
||||
border-radius: 20px 20px 0px 0px;
|
||||
animation: slideUp 0.3s ease-out;
|
||||
}
|
||||
|
||||
@keyframes slideUp {
|
||||
from {
|
||||
transform: translateY(100%);
|
||||
}
|
||||
to {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
// 标题栏
|
||||
.modal_header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 16px;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
|
||||
|
||||
.modal_title {
|
||||
font-family: 'PingFang SC';
|
||||
font-weight: 600;
|
||||
font-size: 22px;
|
||||
line-height: 1.27em;
|
||||
color: #000000;
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.close_button {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #FFFFFF;
|
||||
border: 1px solid rgba(0, 0, 0, 0.06);
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
box-shadow: 0px 4px 36px 0px rgba(0, 0, 0, 0.06);
|
||||
|
||||
.close_icon {
|
||||
position: relative;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
|
||||
.close_line {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 10px;
|
||||
height: 2px;
|
||||
background: #000000;
|
||||
transform: translate(-50%, -50%) rotate(45deg);
|
||||
|
||||
&:nth-child(2) {
|
||||
transform: translate(-50%, -50%) rotate(-45deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 内容区域
|
||||
.modal_content {
|
||||
padding: 0px 16px 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
|
||||
.input_container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
background: #FFFFFF;
|
||||
border: 1px solid rgba(0, 0, 0, 0.06);
|
||||
border-radius: 12px;
|
||||
padding: 10px 16px;
|
||||
box-shadow: 0px 4px 36px 0px rgba(0, 0, 0, 0.06);
|
||||
min-height: 120px;
|
||||
|
||||
.text_input {
|
||||
flex: 1;
|
||||
font-family: 'PingFang SC';
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 1.71em;
|
||||
color: #000000;
|
||||
border: none;
|
||||
background: transparent;
|
||||
outline: none;
|
||||
resize: none;
|
||||
min-height: 80px;
|
||||
|
||||
&::placeholder {
|
||||
color: rgba(60, 60, 67, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
.char_count {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
|
||||
.count_text {
|
||||
font-family: 'PingFang SC';
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 1.71em;
|
||||
color: rgba(60, 60, 67, 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.validation_message {
|
||||
padding: 0px 8px;
|
||||
|
||||
.validation_text {
|
||||
font-family: 'PingFang SC';
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
line-height: 1.5em;
|
||||
color: rgba(60, 60, 67, 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 底部按钮
|
||||
.modal_footer {
|
||||
padding: 8px 10px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
|
||||
.save_button {
|
||||
flex: 1;
|
||||
height: 52px;
|
||||
background: #000000;
|
||||
border: 1px solid rgba(0, 0, 0, 0.06);
|
||||
border-radius: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
box-shadow: 0px 8px 64px 0px rgba(0, 0, 0, 0.1);
|
||||
backdrop-filter: blur(32px);
|
||||
|
||||
.save_text {
|
||||
font-family: 'PingFang SC';
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
line-height: 1.4em;
|
||||
color: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
}
|
||||
}
|
||||
119
src/components/EditModal/index.tsx
Normal file
119
src/components/EditModal/index.tsx
Normal file
@@ -0,0 +1,119 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { View, Text, Textarea, Button } from '@tarojs/components';
|
||||
import Taro from '@tarojs/taro';
|
||||
import './EditModal.scss';
|
||||
|
||||
interface EditModalProps {
|
||||
visible: boolean;
|
||||
title: string;
|
||||
placeholder: string;
|
||||
initialValue: string;
|
||||
maxLength: number;
|
||||
onSave: (value: string) => void;
|
||||
onCancel: () => void;
|
||||
validationMessage?: string;
|
||||
}
|
||||
|
||||
const EditModal: React.FC<EditModalProps> = ({
|
||||
visible,
|
||||
title,
|
||||
placeholder,
|
||||
initialValue,
|
||||
maxLength,
|
||||
onSave,
|
||||
onCancel,
|
||||
validationMessage
|
||||
}) => {
|
||||
const [value, setValue] = useState(initialValue);
|
||||
const [isValid, setIsValid] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
setValue(initialValue);
|
||||
}
|
||||
}, [visible, initialValue]);
|
||||
|
||||
const handle_input_change = (e: any) => {
|
||||
const new_value = e.detail.value;
|
||||
setValue(new_value);
|
||||
|
||||
// 验证输入
|
||||
const valid = new_value.length >= 2 && new_value.length <= maxLength;
|
||||
setIsValid(valid);
|
||||
};
|
||||
|
||||
const handle_save = () => {
|
||||
if (!isValid) {
|
||||
Taro.showToast({
|
||||
title: validationMessage || `请填写 2-${maxLength} 个字符`,
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
onSave(value);
|
||||
};
|
||||
|
||||
const handle_cancel = () => {
|
||||
setValue(initialValue);
|
||||
onCancel();
|
||||
};
|
||||
|
||||
if (!visible) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<View className="edit_modal_overlay">
|
||||
<View className="edit_modal_container">
|
||||
{/* 标题栏 */}
|
||||
<View className="modal_header">
|
||||
<Text className="modal_title">{title}</Text>
|
||||
<View className="close_button" onClick={handle_cancel}>
|
||||
<View className="close_icon">
|
||||
<View className="close_line"></View>
|
||||
<View className="close_line"></View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 内容区域 */}
|
||||
<View className="modal_content">
|
||||
{/* 文本输入区域 */}
|
||||
<View className="input_container">
|
||||
<Textarea
|
||||
className="text_input"
|
||||
value={value}
|
||||
placeholder={placeholder}
|
||||
maxlength={maxLength}
|
||||
onInput={handle_input_change}
|
||||
autoFocus={true}
|
||||
/>
|
||||
<View className="char_count">
|
||||
<Text className="count_text">{value.length}/{maxLength}</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 验证提示 */}
|
||||
{!isValid && (
|
||||
<View className="validation_message">
|
||||
<Text className="validation_text">
|
||||
{validationMessage || `请填写 2-${maxLength} 个字符`}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* 底部按钮 */}
|
||||
<View className="modal_footer">
|
||||
<View className="save_button" onClick={handle_save}>
|
||||
<Text className="save_text">保存</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default EditModal;
|
||||
@@ -14,6 +14,7 @@ import CalendarCard, { DialogCalendarCard } from './CalendarCard'
|
||||
import CommonDialog from './CommonDialog'
|
||||
import PublishMenu from './PublishMenu/PublishMenu'
|
||||
import UploadCover from './UploadCover'
|
||||
import EditModal from './EditModal/index'
|
||||
|
||||
export {
|
||||
ActivityTypeSwitch,
|
||||
@@ -31,6 +32,7 @@ import UploadCover from './UploadCover'
|
||||
DialogCalendarCard,
|
||||
CommonDialog,
|
||||
PublishMenu,
|
||||
UploadCover
|
||||
UploadCover,
|
||||
EditModal
|
||||
}
|
||||
|
||||
|
||||
@@ -7,17 +7,75 @@
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
// 导航栏
|
||||
.navbar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
height: 98px;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
backdrop-filter: blur(10px);
|
||||
border-radius: 44px 44px 0px 0px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 21px 16px 0px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.navbar_left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
cursor: pointer;
|
||||
|
||||
.back_icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar_title {
|
||||
font-family: 'PingFang SC';
|
||||
font-weight: 600;
|
||||
font-size: 17px;
|
||||
line-height: 1.4em;
|
||||
color: #000000;
|
||||
text-align: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.navbar_right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
cursor: pointer;
|
||||
|
||||
.save_text {
|
||||
font-family: 'PingFang SC';
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
line-height: 1.4em;
|
||||
color: #000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 主要内容区域
|
||||
.main_content {
|
||||
position: relative;
|
||||
z-index: 5;
|
||||
flex: 1;
|
||||
margin-top: 0;
|
||||
margin-top: 98px;
|
||||
box-sizing: border-box;
|
||||
overflow-y: auto;
|
||||
padding: 15px;
|
||||
|
||||
|
||||
padding: 0px 16px;
|
||||
padding-bottom: 48px;
|
||||
|
||||
// 头像编辑区域
|
||||
.avatar_section {
|
||||
@@ -25,103 +83,133 @@
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 30px;
|
||||
margin-bottom: 48px;
|
||||
margin-top: 98px;
|
||||
|
||||
.avatar_container {
|
||||
position: relative;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
box-shadow: 0px 8px 20px 0px rgba(0, 0, 0, 0.12);
|
||||
|
||||
|
||||
|
||||
.avatar {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
object-fit: cover;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
box-shadow: 0px 8px 20px 0px rgba(0, 0, 0, 0.12), 0px 0px 1px 0px rgba(0, 0, 0, 0.2);
|
||||
border: 0.5px solid rgba(255, 255, 255, 0.65);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.avatar_overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
right: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background: #000000;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
border: 0.5px solid rgba(0, 0, 0, 0.06);
|
||||
z-index: 10;
|
||||
|
||||
.upload_icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .avatar_overlay {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar_tip {
|
||||
font-family: 'PingFang SC';
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 1.4em;
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
// 表单区域
|
||||
.form_section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
margin-bottom: 48px;
|
||||
box-shadow: 0px 4px 36px 0px rgba(0, 0, 0, 0.06);
|
||||
|
||||
.form_group {
|
||||
background: #FFFFFF;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
|
||||
&:not(:first-child) {
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.form_item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 10px 12px;
|
||||
min-height: 44px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.form_label {
|
||||
font-family: 'PingFang SC';
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
line-height: 1.4em;
|
||||
color: #000000;
|
||||
.item_left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex: 1;
|
||||
|
||||
.item_icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.form_input {
|
||||
padding: 12px 16px;
|
||||
background: #FFFFFF;
|
||||
border: 1px solid rgba(0, 0, 0, 0.12);
|
||||
border-radius: 12px;
|
||||
.item_label {
|
||||
font-family: 'PingFang SC';
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
line-height: 1.4em;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
line-height: 1.71em;
|
||||
color: #000000;
|
||||
}
|
||||
}
|
||||
|
||||
.item_right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex: 1;
|
||||
justify-content: flex-end;
|
||||
|
||||
.item_input {
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
font-family: 'PingFang SC';
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
line-height: 1.71em;
|
||||
color: #000000;
|
||||
border: none;
|
||||
background: transparent;
|
||||
outline: none;
|
||||
|
||||
&::placeholder {
|
||||
color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
.form_textarea {
|
||||
padding: 12px 16px;
|
||||
background: #FFFFFF;
|
||||
border: 1px solid rgba(0, 0, 0, 0.12);
|
||||
border-radius: 12px;
|
||||
.item_value {
|
||||
font-family: 'PingFang SC';
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
line-height: 1.5em;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
line-height: 1.71em;
|
||||
color: #000000;
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
.bio_textarea {
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
font-family: 'PingFang SC';
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
line-height: 1.71em;
|
||||
color: #000000;
|
||||
border: none;
|
||||
background: transparent;
|
||||
outline: none;
|
||||
min-height: 20px;
|
||||
resize: none;
|
||||
|
||||
&::placeholder {
|
||||
@@ -129,91 +217,63 @@
|
||||
}
|
||||
}
|
||||
|
||||
.char_count {
|
||||
font-family: 'PingFang SC';
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
line-height: 1.4em;
|
||||
color: rgba(0, 0, 0, 0.4);
|
||||
text-align: right;
|
||||
.arrow_icon {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
opacity: 0.2;
|
||||
}
|
||||
}
|
||||
|
||||
// NTRP等级选择器
|
||||
.level_selector {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
.divider {
|
||||
position: absolute;
|
||||
left: 36px;
|
||||
right: 12px;
|
||||
height: 0.5px;
|
||||
background: rgba(0, 0, 0, 0.06);
|
||||
border-radius: 99px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.level_item {
|
||||
padding: 8px 16px;
|
||||
// 退出登录区域
|
||||
.logout_section {
|
||||
margin-top: 16px;
|
||||
|
||||
.logout_button {
|
||||
background: #FFFFFF;
|
||||
border: 1px solid rgba(0, 0, 0, 0.12);
|
||||
border-radius: 20px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&.selected {
|
||||
background: #000000;
|
||||
border-color: #000000;
|
||||
|
||||
.level_text {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
.level_text {
|
||||
font-family: 'PingFang SC';
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
line-height: 1.4em;
|
||||
color: #000000;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: #000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 性别选择器
|
||||
.gender_selector {
|
||||
border: 1px solid rgba(0, 0, 0, 0.06);
|
||||
border-radius: 16px;
|
||||
padding: 2px 6px;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
|
||||
.gender_item {
|
||||
flex: 1;
|
||||
padding: 12px 16px;
|
||||
background: #FFFFFF;
|
||||
border: 1px solid rgba(0, 0, 0, 0.12);
|
||||
border-radius: 12px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
text-align: center;
|
||||
min-height: 48px;
|
||||
|
||||
&.selected {
|
||||
background: #000000;
|
||||
border-color: #000000;
|
||||
|
||||
.gender_text {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
.gender_text {
|
||||
.logout_text {
|
||||
font-family: 'PingFang SC';
|
||||
font-weight: 500;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
line-height: 1.4em;
|
||||
color: #000000;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: #000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 加载状态
|
||||
.loading_container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 200px;
|
||||
|
||||
.loading_text {
|
||||
font-family: 'PingFang SC';
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
line-height: 1.4em;
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { View, Text, Image, ScrollView, Button, Input, Textarea } from '@tarojs/components';
|
||||
import { View, Text, Image, ScrollView, Input } from '@tarojs/components';
|
||||
import Taro from '@tarojs/taro';
|
||||
import './index.scss';
|
||||
import { UserInfo } from '@/components/UserInfo';
|
||||
import { UserService } from '@/services/userService';
|
||||
import { EditModal } from '@/components';
|
||||
|
||||
const EditProfilePage: React.FC = () => {
|
||||
// 用户信息状态
|
||||
@@ -33,14 +34,19 @@ const EditProfilePage: React.FC = () => {
|
||||
bio: '',
|
||||
location: '',
|
||||
occupation: '',
|
||||
ntrp_level: 'NTRP 3.0',
|
||||
ntrp_level: '4.0',
|
||||
phone: '',
|
||||
gender: ''
|
||||
gender: '',
|
||||
birthday: '2000-01-01'
|
||||
});
|
||||
|
||||
// 加载状态
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
// 编辑弹窗状态
|
||||
const [edit_modal_visible, setEditModalVisible] = useState(false);
|
||||
const [editing_field, setEditingField] = useState<string>('');
|
||||
|
||||
// 页面加载时初始化数据
|
||||
useEffect(() => {
|
||||
load_user_info();
|
||||
@@ -57,9 +63,10 @@ const EditProfilePage: React.FC = () => {
|
||||
bio: user_data.bio,
|
||||
location: user_data.location,
|
||||
occupation: user_data.occupation,
|
||||
ntrp_level: user_data.ntrp_level,
|
||||
ntrp_level: user_data.ntrp_level.replace('NTRP ', ''),
|
||||
phone: user_data.phone || '',
|
||||
gender: user_data.gender || ''
|
||||
gender: user_data.gender || '',
|
||||
birthday: '2000-01-01' // 默认生日,实际应该从用户数据获取
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('加载用户信息失败:', error);
|
||||
@@ -110,40 +117,45 @@ const EditProfilePage: React.FC = () => {
|
||||
});
|
||||
};
|
||||
|
||||
// 处理保存
|
||||
const handle_save = async () => {
|
||||
// 验证表单
|
||||
if (!form_data.nickname.trim()) {
|
||||
Taro.showToast({
|
||||
title: '请输入昵称',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await UserService.save_user_info(form_data);
|
||||
Taro.showToast({
|
||||
title: '保存成功',
|
||||
icon: 'success'
|
||||
});
|
||||
Taro.navigateBack();
|
||||
} catch (error) {
|
||||
console.error('保存失败:', error);
|
||||
Taro.showToast({
|
||||
title: '保存失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
// 处理编辑弹窗
|
||||
const handle_open_edit_modal = (field: string) => {
|
||||
setEditingField(field);
|
||||
setEditModalVisible(true);
|
||||
};
|
||||
|
||||
// 处理返回
|
||||
const handle_back = () => {
|
||||
Taro.navigateBack();
|
||||
const handle_edit_modal_save = (value: string) => {
|
||||
setFormData(prev => ({ ...prev, [editing_field]: value }));
|
||||
setEditModalVisible(false);
|
||||
setEditingField('');
|
||||
};
|
||||
|
||||
const handle_edit_modal_cancel = () => {
|
||||
setEditModalVisible(false);
|
||||
setEditingField('');
|
||||
};
|
||||
|
||||
// 处理退出登录
|
||||
const handle_logout = () => {
|
||||
Taro.showModal({
|
||||
title: '确认退出',
|
||||
content: '确定要退出登录吗?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
// 清除用户数据
|
||||
Taro.removeStorageSync('user_token');
|
||||
Taro.removeStorageSync('user_info');
|
||||
Taro.reLaunch({
|
||||
url: '/pages/login/index/index'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<View className="edit_profile_page">
|
||||
{/* 导航栏 */}
|
||||
|
||||
{/* 主要内容 */}
|
||||
<ScrollView className="main_content" scrollY>
|
||||
{loading ? (
|
||||
@@ -152,7 +164,6 @@ const EditProfilePage: React.FC = () => {
|
||||
</View>
|
||||
) : (
|
||||
<>
|
||||
|
||||
{/* 头像编辑区域 */}
|
||||
<View className="avatar_section">
|
||||
<View className="avatar_container" onClick={handle_avatar_upload}>
|
||||
@@ -160,112 +171,165 @@ const EditProfilePage: React.FC = () => {
|
||||
<View className="avatar_overlay">
|
||||
<Image
|
||||
className="upload_icon"
|
||||
src={require('../../../static/userinfo/icon_upload.svg')}
|
||||
src={require('../../../static/userInfo/edit2.svg')}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<Text className="avatar_tip">点击更换头像</Text>
|
||||
|
||||
|
||||
</View>
|
||||
|
||||
{/* 基本信息编辑 */}
|
||||
<View className="form_section">
|
||||
{/* 昵称 */}
|
||||
{/* 名字 */}
|
||||
<View className="form_group">
|
||||
<View className="form_item">
|
||||
<Text className="form_label">昵称</Text>
|
||||
<View className="item_left">
|
||||
<Image className="item_icon" src={require('../../../static/userInfo/user1.svg')} />
|
||||
<Text className="item_label">名字</Text>
|
||||
</View>
|
||||
<View className="item_right">
|
||||
<Input
|
||||
className="form_input"
|
||||
className="item_input"
|
||||
value={form_data.nickname}
|
||||
placeholder="请输入昵称"
|
||||
placeholder="188的王晨"
|
||||
onInput={(e) => handle_input_change('nickname', e.detail.value)}
|
||||
/>
|
||||
<Image className="arrow_icon" src={require('../../../static/list/icon-list-right-arrow.svg')} />
|
||||
</View>
|
||||
|
||||
{/* 个人简介 */}
|
||||
<View className="form_item">
|
||||
<Text className="form_label">个人简介</Text>
|
||||
<Textarea
|
||||
className="form_textarea"
|
||||
value={form_data.bio}
|
||||
placeholder="介绍一下自己吧..."
|
||||
maxlength={200}
|
||||
onInput={(e) => handle_input_change('bio', e.detail.value)}
|
||||
/>
|
||||
<Text className="char_count">{form_data.bio.length}/200</Text>
|
||||
</View>
|
||||
|
||||
{/* 所在地区 */}
|
||||
<View className="form_item">
|
||||
<Text className="form_label">所在地区</Text>
|
||||
<Input
|
||||
className="form_input"
|
||||
value={form_data.location}
|
||||
placeholder="请输入所在地区"
|
||||
onInput={(e) => handle_input_change('location', e.detail.value)}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* 职业 */}
|
||||
<View className="form_item">
|
||||
<Text className="form_label">职业</Text>
|
||||
<Input
|
||||
className="form_input"
|
||||
value={form_data.occupation}
|
||||
placeholder="请输入职业"
|
||||
onInput={(e) => handle_input_change('occupation', e.detail.value)}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* 手机号 */}
|
||||
<View className="form_item">
|
||||
<Text className="form_label">手机号</Text>
|
||||
<Input
|
||||
className="form_input"
|
||||
value={form_data.phone}
|
||||
placeholder="请输入手机号"
|
||||
type="number"
|
||||
maxlength={11}
|
||||
onInput={(e) => handle_input_change('phone', e.detail.value)}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* NTRP等级 */}
|
||||
<View className="form_item">
|
||||
<Text className="form_label">NTRP等级</Text>
|
||||
<View className="level_selector">
|
||||
{['1.0', '1.5', '2.0', '2.5', '3.0', '3.5', '4.0', '4.5', '5.0'].map((level) => (
|
||||
<View
|
||||
key={level}
|
||||
className={`level_item ${form_data.ntrp_level.includes(level) ? 'selected' : ''}`}
|
||||
onClick={() => handle_input_change('ntrp_level', `NTRP ${level}`)}
|
||||
>
|
||||
<Text className="level_text">{level}</Text>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
<View className="divider"></View>
|
||||
</View>
|
||||
|
||||
{/* 性别 */}
|
||||
<View className="form_group">
|
||||
<View className="form_item">
|
||||
<Text className="form_label">性别</Text>
|
||||
<View className="gender_selector">
|
||||
<View
|
||||
className={`gender_item ${form_data.gender === '男' ? 'selected' : ''}`}
|
||||
onClick={() => handle_input_change('gender', '男')}
|
||||
>
|
||||
<Text className="gender_text">男</Text>
|
||||
<View className="item_left">
|
||||
<Image className="item_icon" src={require('../../../static/userInfo/user2.svg')} />
|
||||
<Text className="item_label">性别</Text>
|
||||
</View>
|
||||
<View
|
||||
className={`gender_item ${form_data.gender === '女' ? 'selected' : ''}`}
|
||||
onClick={() => handle_input_change('gender', '女')}
|
||||
>
|
||||
<Text className="gender_text">女</Text>
|
||||
<View className="item_right">
|
||||
<Text className="item_value">{form_data.gender || '男'}</Text>
|
||||
<Image className="arrow_icon" src={require('../../../static/list/icon-list-right-arrow.svg')} />
|
||||
</View>
|
||||
</View>
|
||||
<View className="divider"></View>
|
||||
</View>
|
||||
|
||||
{/* 生日 */}
|
||||
<View className="form_group">
|
||||
<View className="form_item">
|
||||
<View className="item_left">
|
||||
<Image className="item_icon" src={require('../../../static/userInfo/tennis.svg')} />
|
||||
<Text className="item_label">生日</Text>
|
||||
</View>
|
||||
<View className="item_right">
|
||||
<Text className="item_value">{form_data.birthday}</Text>
|
||||
<Image className="arrow_icon" src={require('../../../static/list/icon-list-right-arrow.svg')} />
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 简介编辑 */}
|
||||
<View className="form_section">
|
||||
<View className="form_group">
|
||||
<View className="form_item" onClick={() => handle_open_edit_modal('bio')}>
|
||||
<View className="item_left">
|
||||
<Image className="item_icon" src={require('../../../static/userInfo/message.svg')} />
|
||||
<Text className="item_label">简介</Text>
|
||||
</View>
|
||||
<View className="item_right">
|
||||
<Text className="item_value">
|
||||
{form_data.bio || '介绍一下自己'}
|
||||
</Text>
|
||||
<Image className="arrow_icon" src={require('../../../static/list/icon-list-right-arrow.svg')} />
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 地区、NTRP水平、职业 */}
|
||||
<View className="form_section">
|
||||
<View className="form_group">
|
||||
{/* 地区 */}
|
||||
<View className="form_item">
|
||||
<View className="item_left">
|
||||
<Image className="item_icon" src={require('../../../static/userInfo/location.svg')} />
|
||||
<Text className="item_label">地区</Text>
|
||||
</View>
|
||||
<View className="item_right">
|
||||
<Text className="item_value">{form_data.location || '上海 黄浦'}</Text>
|
||||
<Image className="arrow_icon" src={require('../../../static/list/icon-list-right-arrow.svg')} />
|
||||
</View>
|
||||
</View>
|
||||
<View className="divider"></View>
|
||||
|
||||
{/* NTRP水平 */}
|
||||
<View className="form_item">
|
||||
<View className="item_left">
|
||||
<Image className="item_icon" src={require('../../../static/userInfo/tennis.svg')} />
|
||||
<Text className="item_label">NTRP 水平</Text>
|
||||
</View>
|
||||
<View className="item_right">
|
||||
<Text className="item_value">{form_data.ntrp_level}</Text>
|
||||
<Image className="arrow_icon" src={require('../../../static/list/icon-list-right-arrow.svg')} />
|
||||
</View>
|
||||
</View>
|
||||
<View className="divider"></View>
|
||||
|
||||
{/* 职业 */}
|
||||
<View className="form_item">
|
||||
<View className="item_left">
|
||||
<Image className="item_icon" src={require('../../../static/userInfo/sc.svg')} />
|
||||
<Text className="item_label">职业</Text>
|
||||
</View>
|
||||
<View className="item_right">
|
||||
<Text className="item_value">{form_data.occupation || '互联网'}</Text>
|
||||
<Image className="arrow_icon" src={require('../../../static/list/icon-list-right-arrow.svg')} />
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 手机号 */}
|
||||
<View className="form_section">
|
||||
<View className="form_group">
|
||||
<View className="form_item">
|
||||
<View className="item_left">
|
||||
<Image className="item_icon" src={require('../../../static/userInfo/message.svg')} />
|
||||
<Text className="item_label">手机</Text>
|
||||
</View>
|
||||
<View className="item_right">
|
||||
<Text className="item_value">{form_data.phone || '+86 130 1234 1234'}</Text>
|
||||
<Image className="arrow_icon" src={require('../../../static/list/icon-list-right-arrow.svg')} />
|
||||
</View>
|
||||
</View>
|
||||
<View className="divider"></View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 退出登录 */}
|
||||
<View className="logout_section">
|
||||
<View className="logout_button" onClick={handle_logout}>
|
||||
<Text className="logout_text">退出登录</Text>
|
||||
</View>
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
</ScrollView>
|
||||
|
||||
{/* 编辑弹窗 */}
|
||||
<EditModal
|
||||
visible={edit_modal_visible}
|
||||
title="编辑简介"
|
||||
placeholder="介绍一下你的喜好,或者训练习惯"
|
||||
initialValue={form_data[editing_field as keyof typeof form_data] || ''}
|
||||
maxLength={100}
|
||||
onSave={handle_edit_modal_save}
|
||||
onCancel={handle_edit_modal_cancel}
|
||||
validationMessage="请填写 2-100 个字符"
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -353,7 +353,7 @@ export const refresh_login_status = async (): Promise<boolean> => {
|
||||
// 获取用户详细信息
|
||||
export const fetchUserProfile = async (): Promise<ApiResponse<UserInfoType>> => {
|
||||
try {
|
||||
const response = await httpService.post('api/user/detail');
|
||||
const response = await httpService.post('user/detail');
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error('获取用户信息失败:', error);
|
||||
|
||||
7
src/static/userInfo/edit2.svg
Normal file
7
src/static/userInfo/edit2.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14.6666 8.00001C14.6666 7.63181 14.3681 7.33334 13.9999 7.33334C13.6317 7.33334 13.3333 7.63181 13.3333 8.00001H14.6666ZM7.99992 2.66668C8.36812 2.66668 8.66659 2.3682 8.66659 2.00001C8.66659 1.63182 8.36812 1.33334 7.99992 1.33334V2.66668ZM12.9999 13.3333H2.99992V14.6667H12.9999V13.3333ZM2.66659 13V3.00001H1.33325V13H2.66659ZM13.3333 8.00001V13H14.6666V8.00001H13.3333ZM2.99992 2.66668H7.99992V1.33334H2.99992V2.66668ZM2.99992 13.3333C2.81583 13.3333 2.66659 13.1841 2.66659 13H1.33325C1.33325 13.9205 2.07944 14.6667 2.99992 14.6667V13.3333ZM12.9999 14.6667C13.9204 14.6667 14.6666 13.9205 14.6666 13H13.3333C13.3333 13.1841 13.184 13.3333 12.9999 13.3333V14.6667ZM2.66659 3.00001C2.66659 2.81592 2.81582 2.66668 2.99992 2.66668V1.33334C2.07945 1.33334 1.33325 2.07953 1.33325 3.00001H2.66659Z" fill="white"/>
|
||||
<path d="M2 11.6667L5.56437 8.39933C5.81297 8.17143 6.19263 8.16509 6.4487 8.38459L10.6667 12" stroke="white" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M9.33325 10.3333L10.9244 8.74218C11.159 8.50762 11.5304 8.48122 11.7958 8.68028L13.9999 10.3333" stroke="white" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M10 4H14" stroke="white" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M12 2V6" stroke="white" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
Reference in New Issue
Block a user