UI优化
This commit is contained in:
@@ -55,17 +55,17 @@ const CommonPopup: React.FC<CommonPopupProps> = ({
|
||||
|
||||
const handleTouchStart = (e: any) => {
|
||||
if (!enableDragToClose) return
|
||||
|
||||
|
||||
touchStartY.current = e.touches[0].clientY
|
||||
setIsDragging(true)
|
||||
}
|
||||
|
||||
const handleTouchMove = (e: any) => {
|
||||
if (!enableDragToClose || !isDragging) return
|
||||
|
||||
|
||||
const currentY = e.touches[0].clientY
|
||||
const deltaY = currentY - touchStartY.current
|
||||
|
||||
|
||||
// 只允许向下拖动,限制最大拖动距离
|
||||
if (deltaY > 0) {
|
||||
setDragOffset(Math.min(deltaY, 200))
|
||||
@@ -74,14 +74,14 @@ const CommonPopup: React.FC<CommonPopupProps> = ({
|
||||
|
||||
const handleTouchEnd = () => {
|
||||
if (!enableDragToClose || !isDragging) return
|
||||
|
||||
|
||||
setIsDragging(false)
|
||||
|
||||
|
||||
// 如果拖动距离超过阈值,关闭弹窗
|
||||
if (dragOffset > 100) {
|
||||
onClose()
|
||||
}
|
||||
|
||||
|
||||
// 重置拖动偏移
|
||||
setDragOffset(0)
|
||||
}
|
||||
@@ -94,14 +94,14 @@ const CommonPopup: React.FC<CommonPopupProps> = ({
|
||||
closeable={false}
|
||||
onClose={onClose}
|
||||
className={`${styles['common-popup']} ${className ? className : ''}`}
|
||||
style={{
|
||||
zIndex: zIndex ? zIndex : undefined,
|
||||
...style
|
||||
style={{
|
||||
zIndex: zIndex ? zIndex : undefined,
|
||||
...style
|
||||
}}
|
||||
>
|
||||
{enableDragToClose && (
|
||||
<View className={styles['common-popup__drag-handle-container']}>
|
||||
<View
|
||||
<View
|
||||
className={styles['common-popup__drag-handle']}
|
||||
style={{
|
||||
transform: `translateX(-50%) translateY(${dragOffset * 0.3}px)`,
|
||||
@@ -118,6 +118,12 @@ const CommonPopup: React.FC<CommonPopupProps> = ({
|
||||
{showHeader && (
|
||||
<View className={styles['common-popup__header']}>
|
||||
{typeof title === 'string' ? <Text className={styles['common-popup__title']}>{title}</Text> : title}
|
||||
<View className={styles["close_button"]} onClick={onClose}>
|
||||
<View className={styles["close_icon"]}>
|
||||
<View className={styles["close_line"]}></View>
|
||||
<View className={styles["close_line"]}></View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
.common-popup {
|
||||
position: fixed;
|
||||
z-index: 9999 !important;
|
||||
|
||||
.common-popup__drag-handle-container {
|
||||
position: position;
|
||||
}
|
||||
|
||||
.common-popup__drag-handle {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
@@ -22,22 +24,71 @@
|
||||
background-color: #9ca3af;
|
||||
}
|
||||
}
|
||||
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
max-height: calc(100vh - 10px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: theme.$page-background-color;
|
||||
.common-popup__header {
|
||||
padding: 12px 16px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #1f2329;
|
||||
border-bottom: 1px solid #f0f1f5;
|
||||
}
|
||||
|
||||
.common-popup__title {
|
||||
display: inline-block;
|
||||
// .common-popup__header {
|
||||
// padding: 12px 16px;
|
||||
// font-size: 16px;
|
||||
// font-weight: 600;
|
||||
// color: #1f2329;
|
||||
// border-bottom: 1px solid #f0f1f5;
|
||||
// }
|
||||
|
||||
.common-popup__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 16px 20px;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
|
||||
|
||||
.common-popup__title {
|
||||
font-family: 'PingFang SC';
|
||||
font-weight: 600;
|
||||
font-size: 22px;
|
||||
line-height: 1.27em;
|
||||
color: #000000;
|
||||
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: 17px;
|
||||
height: 3px;
|
||||
border-radius: 3px;
|
||||
background: #000000;
|
||||
transform: translate(-50%, -50%) rotate(45deg);
|
||||
|
||||
&:nth-child(2) {
|
||||
transform: translate(-50%, -50%) rotate(-45deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.common-popup__body {
|
||||
@@ -83,4 +134,4 @@
|
||||
border-radius: 12px !important;
|
||||
padding: 4px 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 16px;
|
||||
padding: 16px 20px;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
|
||||
|
||||
.modal_title {
|
||||
@@ -43,7 +43,6 @@
|
||||
font-size: 22px;
|
||||
line-height: 1.27em;
|
||||
color: #000000;
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -68,8 +67,9 @@
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 10px;
|
||||
height: 2px;
|
||||
width: 17px;
|
||||
height: 3px;
|
||||
border-radius: 3px;
|
||||
background: #000000;
|
||||
transform: translate(-50%, -50%) rotate(45deg);
|
||||
|
||||
@@ -176,12 +176,18 @@
|
||||
box-shadow: 0px 8px 64px 0px rgba(0, 0, 0, 0.1);
|
||||
backdrop-filter: blur(32px);
|
||||
|
||||
&.disabled {
|
||||
.save_text {
|
||||
color: rgba(255, 255, 255, 0.3) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.save_text {
|
||||
font-family: 'PingFang SC';
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
line-height: 1.4em;
|
||||
color: rgba(255, 255, 255, 0.3);
|
||||
color: #fff
|
||||
}
|
||||
|
||||
&:active {
|
||||
|
||||
@@ -49,6 +49,8 @@ const EditModal: React.FC<EditModalProps> = ({
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
setValue(initialValue);
|
||||
const valid = initialValue.length >= 2 && initialValue.length <= maxLength;
|
||||
setIsValid(valid);
|
||||
}
|
||||
}, [visible, initialValue]);
|
||||
|
||||
@@ -70,7 +72,6 @@ const EditModal: React.FC<EditModalProps> = ({
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
onSave(value);
|
||||
};
|
||||
|
||||
@@ -85,7 +86,7 @@ const EditModal: React.FC<EditModalProps> = ({
|
||||
|
||||
return (
|
||||
<View className="edit_modal_overlay">
|
||||
<View className="edit_modal_container" style={{ paddingBottom: isKeyboardVisible ? (type === 'nickname' ? `${keyboardHeight + 60}px` : `${keyboardHeight }px`) : undefined }}>
|
||||
<View className="edit_modal_container" style={{ paddingBottom: isKeyboardVisible ? (type === 'nickname' ? `${keyboardHeight + 60}px` : `${keyboardHeight}px`) : undefined }}>
|
||||
{/* 标题栏 */}
|
||||
<View className="modal_header">
|
||||
<Text className="modal_title">{title}</Text>
|
||||
@@ -144,7 +145,7 @@ const EditModal: React.FC<EditModalProps> = ({
|
||||
|
||||
{/* 底部按钮 */}
|
||||
<View className="modal_footer">
|
||||
<View className="save_button" onClick={handle_save}>
|
||||
<View className={`save_button ${!isValid ? "disabled" : ""}`} onClick={handle_save}>
|
||||
<Text className="save_text">保存</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -17,6 +17,9 @@ interface PickerOption {
|
||||
}
|
||||
|
||||
interface PickerProps {
|
||||
title?: string;
|
||||
showHeader?: boolean;
|
||||
confirmText?: string;
|
||||
visible: boolean;
|
||||
setvisible: (visible: boolean) => void;
|
||||
options?: PickerOption[][] | PickerOption[];
|
||||
@@ -29,6 +32,9 @@ interface PickerProps {
|
||||
}
|
||||
|
||||
const PopupPicker = ({
|
||||
confirmText,
|
||||
title,
|
||||
showHeader,
|
||||
visible,
|
||||
setvisible,
|
||||
value = [],
|
||||
@@ -99,11 +105,11 @@ const PopupPicker = ({
|
||||
<CommonPopup
|
||||
visible={visible}
|
||||
onClose={dialogClose}
|
||||
showHeader={false}
|
||||
title={null}
|
||||
showHeader={showHeader || false}
|
||||
title={title || null}
|
||||
hideFooter={false}
|
||||
cancelText="取消"
|
||||
confirmText="完成"
|
||||
confirmText={confirmText || "完成"}
|
||||
onConfirm={handleConfirm}
|
||||
position="bottom"
|
||||
round
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import Taro from "@tarojs/taro";
|
||||
import { View, Text, Image, Button } from "@tarojs/components";
|
||||
import "./index.scss";
|
||||
|
||||
import { EditModal } from "@/components";
|
||||
import { UserService } from "@/services/userService";
|
||||
import { UserService, PickerOption } from "@/services/userService";
|
||||
import { PopupPicker } from "@/components/Picker/index";
|
||||
|
||||
// 用户信息接口
|
||||
@@ -76,6 +76,34 @@ export const UserInfoCard: React.FC<UserInfoCardProps> = ({
|
||||
// 表单状态
|
||||
const [form_data, setFormData] = useState<UserInfo>({ ...user_info });
|
||||
|
||||
// 职业数据
|
||||
const [professions, setProfessions] = useState<PickerOption[]>([]);
|
||||
|
||||
// 城市数据
|
||||
const [cities, setCities] = useState<PickerOption[]>([]);
|
||||
|
||||
// 页面加载时初始化数据
|
||||
useEffect(() => {
|
||||
getProfessions();
|
||||
getCities();
|
||||
}, []);
|
||||
|
||||
const getProfessions = async () => {
|
||||
try {
|
||||
const res = await UserService.getProfessions();
|
||||
setProfessions(res);
|
||||
} catch (e) {
|
||||
console.log("获取职业失败:", e);
|
||||
}
|
||||
};
|
||||
const getCities = async () => {
|
||||
try {
|
||||
const res = await UserService.getCities();
|
||||
setCities(res);
|
||||
} catch (e) {
|
||||
console.log("获取职业失败:", e);
|
||||
}
|
||||
};
|
||||
// 处理编辑弹窗
|
||||
const handle_open_edit_modal = (field: string) => {
|
||||
if (field === "gender") {
|
||||
@@ -416,6 +444,8 @@ export const UserInfoCard: React.FC<UserInfoCardProps> = ({
|
||||
{/* 性别选择弹窗 */}
|
||||
{gender_picker_visible && (
|
||||
<PopupPicker
|
||||
showHeader={true}
|
||||
title="选择性别"
|
||||
options={[
|
||||
[
|
||||
{ text: "男", value: "0" },
|
||||
@@ -432,14 +462,9 @@ export const UserInfoCard: React.FC<UserInfoCardProps> = ({
|
||||
{/* 地区选择弹窗 */}
|
||||
{location_picker_visible && (
|
||||
<PopupPicker
|
||||
options={[
|
||||
[{ text: "中国", value: "中国" }],
|
||||
[{ text: "上海", value: "上海" }],
|
||||
[
|
||||
{ text: "浦东新区", value: "浦东新区" },
|
||||
{ text: "静安区", value: "静安区" },
|
||||
],
|
||||
]}
|
||||
showHeader={true}
|
||||
title="选择地区"
|
||||
options={cities}
|
||||
visible={location_picker_visible}
|
||||
setvisible={setLocationPickerVisible}
|
||||
value={[form_data.country, form_data.province, form_data.city]}
|
||||
@@ -449,6 +474,8 @@ export const UserInfoCard: React.FC<UserInfoCardProps> = ({
|
||||
{/* NTRP水平选择弹窗 */}
|
||||
{ntrp_picker_visible && (
|
||||
<PopupPicker
|
||||
showHeader={true}
|
||||
title="选择 NTRP 自评水平"
|
||||
options={[
|
||||
[
|
||||
{ text: "1.5", value: "1.5" },
|
||||
@@ -471,13 +498,9 @@ export const UserInfoCard: React.FC<UserInfoCardProps> = ({
|
||||
{/* 职业选择弹窗 */}
|
||||
{occupation_picker_visible && (
|
||||
<PopupPicker
|
||||
options={[
|
||||
[{ text: "时尚", value: "时尚" }],
|
||||
[
|
||||
{ text: "美妆博主", value: "美妆博主" },
|
||||
{ text: "设计师", value: "设计师" },
|
||||
],
|
||||
]}
|
||||
showHeader={true}
|
||||
title="选择职业"
|
||||
options={professions}
|
||||
visible={occupation_picker_visible}
|
||||
setvisible={setOccupationPickerVisible}
|
||||
value={[...form_data.occupation.split(" ")]}
|
||||
@@ -621,9 +644,8 @@ export const GameTabs: React.FC<GameTabsProps> = ({
|
||||
<Text className="tab_text">{hosted_text}</Text>
|
||||
</View>
|
||||
<View
|
||||
className={`tab_item ${
|
||||
active_tab === "participated" ? "active" : ""
|
||||
}`}
|
||||
className={`tab_item ${active_tab === "participated" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => on_tab_change("participated")}
|
||||
>
|
||||
<Text className="tab_text">{participated_text}</Text>
|
||||
|
||||
Reference in New Issue
Block a user