This commit is contained in:
2025-10-16 21:16:57 +08:00
parent 363630cdb5
commit 9e2fa335aa
13 changed files with 172 additions and 57 deletions

View File

@@ -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>
)}

View File

@@ -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;
}
}
}

View File

@@ -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 {

View File

@@ -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>

View File

@@ -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

View File

@@ -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>