修改 列表 时间格式化问题
This commit is contained in:
@@ -2,12 +2,14 @@ import { View, Text, Image } from "@tarojs/components";
|
||||
import Taro from "@tarojs/taro";
|
||||
import img from "../../config/images";
|
||||
import { ListCardProps } from "../../../types/list/types";
|
||||
import { formatGameTime, calculateDuration } from "@/utils/timeUtils";
|
||||
import "./index.scss";
|
||||
|
||||
const ListCard: React.FC<ListCardProps> = ({
|
||||
id,
|
||||
title,
|
||||
start_time,
|
||||
end_time,
|
||||
location,
|
||||
distance_km,
|
||||
current_players,
|
||||
@@ -112,7 +114,11 @@ const ListCard: React.FC<ListCardProps> = ({
|
||||
|
||||
{/* 时间信息 */}
|
||||
<View className="date-time">
|
||||
<Text>{start_time}</Text>
|
||||
<Text>{formatGameTime(start_time)}</Text>
|
||||
{/* 时长 如 2小时 */}
|
||||
{end_time && (
|
||||
<Text> {calculateDuration(start_time, end_time)}</Text>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* 地点,室内外,距离 */}
|
||||
|
||||
@@ -8,24 +8,16 @@ const LoginPage: React.FC = () => {
|
||||
const [is_loading, set_is_loading] = useState(false);
|
||||
const [agree_terms, set_agree_terms] = useState(false);
|
||||
const [show_terms_layer, set_show_terms_layer] = useState(false);
|
||||
const [pending_login_type, set_pending_login_type] = useState<'wechat' | 'phone' | null>(null); // 记录待执行的登录类型
|
||||
const [pending_phone_event, set_pending_phone_event] = useState<any>(null); // 记录微信登录的事件数据
|
||||
const { params: { redirect } } = useRouter();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 微信授权登录
|
||||
const handle_wechat_login = async (e: any) => {
|
||||
if (!agree_terms) {
|
||||
set_show_terms_layer(true);
|
||||
Taro.showToast({
|
||||
title: '请先同意用户协议',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 执行微信登录的核心逻辑
|
||||
const execute_wechat_login = async (e: any) => {
|
||||
// 检查是否获取到手机号
|
||||
if (!e.detail || !e.detail.code) {
|
||||
Taro.showToast({
|
||||
@@ -68,9 +60,12 @@ const LoginPage: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 手机号验证码登录
|
||||
const handle_phone_login = async () => {
|
||||
// 微信授权登录
|
||||
const handle_wechat_login = async (e: any) => {
|
||||
if (!agree_terms) {
|
||||
// 记录待执行的登录类型和事件数据
|
||||
set_pending_login_type('wechat');
|
||||
set_pending_phone_event(e);
|
||||
set_show_terms_layer(true);
|
||||
Taro.showToast({
|
||||
title: '请先同意用户协议',
|
||||
@@ -80,16 +75,54 @@ const LoginPage: React.FC = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果已同意条款,直接执行登录
|
||||
await execute_wechat_login(e);
|
||||
};
|
||||
|
||||
// 执行手机号登录的核心逻辑
|
||||
const execute_phone_login = () => {
|
||||
// 跳转到验证码页面
|
||||
Taro.navigateTo({
|
||||
url: `/login_pages/verification/index?redirect=${redirect}`
|
||||
});
|
||||
};
|
||||
|
||||
// 同意协议并关闭浮层
|
||||
// 手机号验证码登录
|
||||
const handle_phone_login = async () => {
|
||||
if (!agree_terms) {
|
||||
// 记录待执行的登录类型
|
||||
set_pending_login_type('phone');
|
||||
set_show_terms_layer(true);
|
||||
Taro.showToast({
|
||||
title: '请先同意用户协议',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果已同意条款,直接执行登录
|
||||
execute_phone_login();
|
||||
};
|
||||
|
||||
// 同意协议并关闭浮层,继续执行未完成的登录
|
||||
const handle_agree_terms = () => {
|
||||
set_agree_terms(true);
|
||||
set_show_terms_layer(false);
|
||||
|
||||
// 根据待执行的登录类型,继续执行登录
|
||||
if (pending_login_type === 'wechat' && pending_phone_event) {
|
||||
// 继续执行微信登录
|
||||
execute_wechat_login(pending_phone_event);
|
||||
// 清空待执行状态
|
||||
set_pending_login_type(null);
|
||||
set_pending_phone_event(null);
|
||||
} else if (pending_login_type === 'phone') {
|
||||
// 继续执行手机号登录
|
||||
execute_phone_login();
|
||||
// 清空待执行状态
|
||||
set_pending_login_type(null);
|
||||
}
|
||||
};
|
||||
|
||||
// 切换协议同意状态(复选框用)
|
||||
|
||||
@@ -10,8 +10,10 @@ import {
|
||||
import "./index.scss";
|
||||
|
||||
const VerificationPage: React.FC = () => {
|
||||
const [phone, setPhone] = useState("");
|
||||
const [verification_code, setVerificationCode] = useState("");
|
||||
const [phone, setPhone] = useState(""); // 存储纯数字的手机号
|
||||
const [display_phone, setDisplayPhone] = useState(""); // 显示带空格的手机号
|
||||
const [verification_code, setVerificationCode] = useState(""); // 存储纯数字的验证码
|
||||
const [display_code, setDisplayCode] = useState(""); // 显示带空格的验证码
|
||||
const [countdown, setCountdown] = useState(0);
|
||||
const [can_send_code, setCanSendCode] = useState(true);
|
||||
const [is_loading, setIsLoading] = useState(false);
|
||||
@@ -23,6 +25,62 @@ const VerificationPage: React.FC = () => {
|
||||
params: { redirect },
|
||||
} = useRouter();
|
||||
|
||||
// 格式化手机号为 3-4-4 格式
|
||||
const formatPhone = (value: string): string => {
|
||||
// 移除所有非数字字符
|
||||
const numbers = value.replace(/\D/g, "");
|
||||
|
||||
// 按 3-4-4 格式添加空格
|
||||
if (numbers.length <= 3) {
|
||||
return numbers;
|
||||
} else if (numbers.length <= 7) {
|
||||
return `${numbers.slice(0, 3)} ${numbers.slice(3)}`;
|
||||
} else {
|
||||
return `${numbers.slice(0, 3)} ${numbers.slice(3, 7)} ${numbers.slice(7, 11)}`;
|
||||
}
|
||||
};
|
||||
|
||||
// 格式化验证码为 3-3 格式
|
||||
const formatCode = (value: string): string => {
|
||||
// 移除所有非数字字符
|
||||
const numbers = value.replace(/\D/g, "");
|
||||
|
||||
// 按 3-3 格式添加空格
|
||||
if (numbers.length <= 3) {
|
||||
return numbers;
|
||||
} else {
|
||||
return `${numbers.slice(0, 3)} ${numbers.slice(3, 6)}`;
|
||||
}
|
||||
};
|
||||
|
||||
// 处理手机号输入
|
||||
const handlePhoneInput = (e) => {
|
||||
const inputValue = e.detail.value;
|
||||
// 移除所有非数字字符
|
||||
const numbers = inputValue.replace(/\D/g, "");
|
||||
// 限制最多11位
|
||||
const limitedNumbers = numbers.slice(0, 11);
|
||||
|
||||
// 保存纯数字版本用于提交
|
||||
setPhone(limitedNumbers);
|
||||
// 保存格式化版本用于显示
|
||||
setDisplayPhone(formatPhone(limitedNumbers));
|
||||
};
|
||||
|
||||
// 处理验证码输入
|
||||
const handleCodeInput = (e) => {
|
||||
const inputValue = e.detail.value;
|
||||
// 移除所有非数字字符
|
||||
const numbers = inputValue.replace(/\D/g, "");
|
||||
// 限制最多6位
|
||||
const limitedNumbers = numbers.slice(0, 6);
|
||||
|
||||
// 保存纯数字版本用于提交
|
||||
setVerificationCode(limitedNumbers);
|
||||
// 保存格式化版本用于显示
|
||||
setDisplayCode(formatCode(limitedNumbers));
|
||||
};
|
||||
|
||||
// 计算登录按钮是否应该启用
|
||||
const can_login =
|
||||
phone.length === 11 && verification_code.length === 6 && !is_loading;
|
||||
@@ -69,6 +127,7 @@ const VerificationPage: React.FC = () => {
|
||||
setCodeInputFocus(true);
|
||||
// 清空验证码,让用户重新输入
|
||||
setVerificationCode("");
|
||||
setDisplayCode("");
|
||||
console.log("设置验证码输入框聚焦");
|
||||
}, 500); // 延迟500ms确保Toast显示完成后再聚焦
|
||||
} else {
|
||||
@@ -232,12 +291,12 @@ const VerificationPage: React.FC = () => {
|
||||
<View className="input_container">
|
||||
<Input
|
||||
className="phone_input"
|
||||
type="number"
|
||||
type="text"
|
||||
placeholder="输入中国内地手机号"
|
||||
placeholderClass="input_placeholder"
|
||||
value={phone}
|
||||
onInput={(e) => setPhone(e.detail.value)}
|
||||
maxlength={11}
|
||||
value={display_phone}
|
||||
onInput={handlePhoneInput}
|
||||
maxlength={13}
|
||||
/>
|
||||
<View className="char_count">
|
||||
<Text
|
||||
@@ -262,11 +321,11 @@ const VerificationPage: React.FC = () => {
|
||||
placeholderClass="input_placeholder"
|
||||
placeholderStyle="color:#999999;"
|
||||
focus={code_input_focus}
|
||||
value={verification_code}
|
||||
onInput={(e) => setVerificationCode(e.detail.value)}
|
||||
value={display_code}
|
||||
onInput={handleCodeInput}
|
||||
onFocus={() => setCodeInputFocus(true)}
|
||||
onBlur={() => setCodeInputFocus(false)}
|
||||
maxlength={6}
|
||||
maxlength={7}
|
||||
/>
|
||||
<View className="char_count">
|
||||
<Text
|
||||
|
||||
@@ -139,10 +139,10 @@ export const formatRelativeTime = (timeStr: string): string => {
|
||||
*/
|
||||
export const formatShortRelativeTime = (timeStr: string): string => {
|
||||
if (!timeStr) return "";
|
||||
|
||||
|
||||
const date = new Date(timeStr);
|
||||
const now = new Date();
|
||||
|
||||
|
||||
// 获取日期部分(年-月-日),忽略时间
|
||||
const getDateString = (d: Date) => {
|
||||
const year = d.getFullYear();
|
||||
@@ -150,10 +150,10 @@ export const formatShortRelativeTime = (timeStr: string): string => {
|
||||
const day = d.getDate();
|
||||
return `${year}-${month.toString().padStart(2, '0')}-${day.toString().padStart(2, '0')}`;
|
||||
};
|
||||
|
||||
|
||||
const dateStr = getDateString(date);
|
||||
const nowStr = getDateString(now);
|
||||
|
||||
|
||||
// 计算日期差
|
||||
const dateObj = new Date(dateStr);
|
||||
const nowObj = new Date(nowStr);
|
||||
@@ -165,7 +165,7 @@ export const formatShortRelativeTime = (timeStr: string): string => {
|
||||
const diff = now.getTime() - date.getTime();
|
||||
const minutes = Math.floor(diff / (1000 * 60));
|
||||
const hours = Math.floor(diff / (1000 * 60 * 60));
|
||||
|
||||
|
||||
if (minutes < 1) {
|
||||
return "刚刚";
|
||||
} else if (minutes < 60) {
|
||||
@@ -182,4 +182,114 @@ export const formatShortRelativeTime = (timeStr: string): string => {
|
||||
const day = date.getDate();
|
||||
return `${month}月${day}日`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化球局时间显示(例如:明天(周五)下午5点)
|
||||
* @param timeStr 时间字符串
|
||||
* @returns 格式化后的时间字符串
|
||||
*/
|
||||
export const formatGameTime = (timeStr: string): string => {
|
||||
if (!timeStr) return "";
|
||||
|
||||
const date = new Date(timeStr);
|
||||
const now = new Date();
|
||||
|
||||
// 获取星期几
|
||||
const weekDays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
|
||||
const weekDay = weekDays[date.getDay()];
|
||||
|
||||
// 获取小时和分钟
|
||||
const hours = date.getHours();
|
||||
const minutes = date.getMinutes();
|
||||
|
||||
// 判断上午/下午/晚上
|
||||
let period = '';
|
||||
let displayHour = hours;
|
||||
|
||||
if (hours >= 0 && hours < 6) {
|
||||
period = '凌晨';
|
||||
} else if (hours >= 6 && hours < 12) {
|
||||
period = '上午';
|
||||
} else if (hours >= 12 && hours < 18) {
|
||||
period = '下午';
|
||||
displayHour = hours === 12 ? 12 : hours - 12;
|
||||
} else {
|
||||
period = '晚上';
|
||||
displayHour = hours - 12;
|
||||
}
|
||||
|
||||
// 格式化时间部分
|
||||
const timeStr2 = minutes === 0 ? `${displayHour}点` : `${displayHour}点${minutes}分`;
|
||||
|
||||
// 获取日期部分(年-月-日),忽略时间
|
||||
const getDateString = (d: Date) => {
|
||||
const year = d.getFullYear();
|
||||
const month = d.getMonth() + 1;
|
||||
const day = d.getDate();
|
||||
return `${year}-${month.toString().padStart(2, '0')}-${day.toString().padStart(2, '0')}`;
|
||||
};
|
||||
|
||||
const dateStr = getDateString(date);
|
||||
const nowStr = getDateString(now);
|
||||
|
||||
// 计算日期差
|
||||
const dateObj = new Date(dateStr);
|
||||
const nowObj = new Date(nowStr);
|
||||
const diffTime = dateObj.getTime() - nowObj.getTime();
|
||||
const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24));
|
||||
|
||||
// 根据日期差返回不同格式
|
||||
if (diffDays === 0) {
|
||||
// 今天
|
||||
return `今天(${weekDay})${period}${timeStr2}`;
|
||||
} else if (diffDays === 1) {
|
||||
// 明天
|
||||
return `明天(${weekDay})${period}${timeStr2}`;
|
||||
} else if (diffDays === 2) {
|
||||
// 后天
|
||||
return `后天(${weekDay})${period}${timeStr2}`;
|
||||
} else if (diffDays > 2 && diffDays <= 7) {
|
||||
// 一周内
|
||||
return `${weekDay}${period}${timeStr2}`;
|
||||
} else {
|
||||
// 超过一周,显示具体日期
|
||||
const month = date.getMonth() + 1;
|
||||
const day = date.getDate();
|
||||
return `${month}月${day}日(${weekDay})${period}${timeStr2}`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算时长(结束时间 - 开始时间)
|
||||
* @param startTime 开始时间字符串
|
||||
* @param endTime 结束时间字符串
|
||||
* @returns 格式化后的时长字符串(如:2小时、1.5小时、30分钟)
|
||||
*/
|
||||
export const calculateDuration = (startTime: string, endTime: string): string => {
|
||||
if (!startTime || !endTime) return "";
|
||||
|
||||
const start = new Date(startTime);
|
||||
const end = new Date(endTime);
|
||||
|
||||
// 计算时间差(毫秒)
|
||||
const diffMs = end.getTime() - start.getTime();
|
||||
|
||||
// 转换为分钟
|
||||
const diffMinutes = Math.floor(diffMs / (1000 * 60));
|
||||
|
||||
// 转换为小时
|
||||
const hours = Math.floor(diffMinutes / 60);
|
||||
const minutes = diffMinutes % 60;
|
||||
|
||||
// 格式化输出
|
||||
if (hours > 0 && minutes > 0) {
|
||||
return `${hours}.5小时`;
|
||||
} else if (hours > 0) {
|
||||
return `${hours}小时`;
|
||||
} else if (minutes > 0) {
|
||||
return `${minutes}分钟`;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -207,6 +207,7 @@ export interface ListCardProps {
|
||||
id: string | number,
|
||||
title: string,
|
||||
start_time: string,
|
||||
end_time?: string, // 结束时间
|
||||
location: string,
|
||||
distance_km: number,
|
||||
current_players: number,
|
||||
|
||||
Reference in New Issue
Block a user