diff --git a/src/components/NTRPEvaluatePopup/index.tsx b/src/components/NTRPEvaluatePopup/index.tsx index ed3bec4..6c7c53a 100644 --- a/src/components/NTRPEvaluatePopup/index.tsx +++ b/src/components/NTRPEvaluatePopup/index.tsx @@ -104,7 +104,12 @@ const NTRPEvaluatePopup = (props: NTRPEvaluatePopupProps, ref) => { async function getNtrp() { const res = await evaluateService.getLastResult(); if (res.code === 0 && res.data.has_ntrp_level) { - setNtrp(res.data.user_ntrp_level); + const match = res.data.user_ntrp_level.match(/-?\d+(\.\d+)?/); + if (!match) { + setNtrp(""); + return; + } + setNtrp(match[0] as string); } else { setNtrp(""); } @@ -128,7 +133,7 @@ const NTRPEvaluatePopup = (props: NTRPEvaluatePopupProps, ref) => { title: "NTRP水平修改成功", icon: "none", }); - evaCallback.next(true); + evaCallback.next({ flag: true, score: String(ntrp) }); handleClose(); } diff --git a/src/components/NTRPTestEntryCard/index.tsx b/src/components/NTRPTestEntryCard/index.tsx index 4471f18..e433ab6 100644 --- a/src/components/NTRPTestEntryCard/index.tsx +++ b/src/components/NTRPTestEntryCard/index.tsx @@ -1,8 +1,9 @@ -import React, { useEffect } from "react"; +import React, { useState, useEffect, useCallback, memo } from "react"; import { View, Image, Text } from "@tarojs/components"; import Taro from "@tarojs/taro"; import { useUserInfo, useUserActions } from "@/store/userStore"; // import { getCurrentFullPath } from "@/utils"; +import evaluateService, { StageType } from "@/services/evaluateService"; import DocCopy from "@/static/ntrp/ntrp_doc_copy.svg"; import ArrowRight from "@/static/ntrp/ntrp_arrow_right_color.svg"; import { @@ -16,54 +17,96 @@ function NTRPTestEntryCard(props: { type: EvaluateScene; evaluateCallback?: EvaluateCallback; }) { + const [testFlag, setTestFlag] = useState(false); const { type, evaluateCallback } = props; const userInfo = useUserInfo(); const { setCallback } = useEvaluate(); - // const { fetchUserInfo } = useUserActions() + const { fetchUserInfo } = useUserActions(); - // useEffect(() => { - // fetchUserInfo() - // }, []) + console.log(userInfo); - function handleTest() { - switch (type) { - case (EvaluateScene.list, EvaluateScene.share): - setCallback({ - type, - next: () => { - Taro.redirectTo({ url: "/main_pages/index" }); - }, - onCancel: () => { - Taro.redirectTo({ url: "/main_pages/index" }); - }, - }); - case (EvaluateScene.detail, EvaluateScene.publish): - setCallback(evaluateCallback as EvaluateCallback); - case (EvaluateScene.user, EvaluateScene.userEdit): - setCallback({ - type, - next: () => { - Taro.redirectTo({ url: "/main_pages/index" }); - }, - onCancel: () => { - Taro.redirectTo({ url: "/user_pages/myself/index" }); - }, - }); - default: - setCallback({ - type, - next: () => { - Taro.redirectTo({ url: "/main_pages/index" }); - }, - onCancel: () => { - Taro.redirectTo({ url: "/main_pages/index" }); - }, - }); + useEffect(() => { + if (!userInfo.id) { + fetchUserInfo(); } - Taro.redirectTo({ - url: `/other_pages/ntrp-evaluate/index?stage=test`, + evaluateService.getLastResult().then((res) => { + setTestFlag(res.code === 0 && res.data.has_ntrp_level); }); - } + }, [userInfo.id]); + + const handleTest = useCallback( + function () { + switch (type) { + case EvaluateScene.list: + setCallback({ + type, + next: () => { + Taro.redirectTo({ url: "/game_pages/list/index" }); + }, + onCancel: () => { + // Taro.redirectTo({ url: "/game_pages/list/index" }); + Taro.navigateBack(); + }, + }); + break; + case EvaluateScene.share: + setCallback({ + type, + next: () => { + Taro.redirectTo({ url: "/main_pages/index" }); + }, + onCancel: () => { + Taro.redirectTo({ url: "/main_pages/index" }); + }, + }); + break; + case EvaluateScene.detail: + case EvaluateScene.publish: + setCallback(evaluateCallback as EvaluateCallback); + break; + case EvaluateScene.user: + setCallback({ + type, + next: () => { + Taro.redirectTo({ url: "/main_pages/index" }); + }, + onCancel: () => { + // Taro.redirectTo({ url: "/user_pages/myself/index" }); + Taro.navigateBack(); + }, + }); + break; + case EvaluateScene.userEdit: + setCallback({ + type, + next: () => { + Taro.redirectTo({ url: "/game_pages/list/index" }); + }, + onCancel: () => { + // Taro.redirectTo({ url: "/user_pages/edit/index" }); + Taro.navigateBack(); + }, + }); + break; + default: + setCallback({ + type, + next: () => { + Taro.redirectTo({ url: "/main_pages/index" }); + }, + onCancel: () => { + Taro.redirectTo({ url: "/main_pages/index" }); + }, + }); + } + Taro.navigateTo({ + url: `/other_pages/ntrp-evaluate/index?stage=${ + testFlag ? StageType.INTRO : StageType.TEST + }`, + }); + }, + [setCallback] + ); return type === EvaluateScene.list ? ( @@ -131,4 +174,5 @@ function NTRPTestEntryCard(props: { ); } -export default NTRPTestEntryCard; +export default memo(NTRPTestEntryCard); +// export default NTRPTestEntryCard; diff --git a/src/components/PublishMenu/PublishMenu.tsx b/src/components/PublishMenu/PublishMenu.tsx index ecddbf7..6f60789 100644 --- a/src/components/PublishMenu/PublishMenu.tsx +++ b/src/components/PublishMenu/PublishMenu.tsx @@ -22,7 +22,7 @@ export interface PublishMenuProps { const PublishMenu: React.FC = (props) => { const { onVisibleChange } = props; const [isVisible, setIsVisible] = useState(false); - + // 使用 useEffect 监听 isVisible 变化,确保所有情况都能触发回调 useEffect(() => { onVisibleChange?.(isVisible); @@ -55,7 +55,7 @@ const PublishMenu: React.FC = (props) => { if (!userInfo.ntrp_level) { ntrpRef.current.show({ type: EvaluateScene.publish, - next: (flag) => { + next: ({ flag }) => { if (flag) { handleMenuClick(type); } else if (type === "ai") { diff --git a/src/container/listContainer/index.tsx b/src/container/listContainer/index.tsx index 6d1439c..cdcf4cf 100644 --- a/src/container/listContainer/index.tsx +++ b/src/container/listContainer/index.tsx @@ -8,7 +8,7 @@ import { setStorage, getStorage } from "@/store/storage"; import { NTRPTestEntryCard } from "@/components"; import { EvaluateScene } from "@/store/evaluateStore"; import "./index.scss"; -import { useRef, useEffect, useState } from "react"; +import { useRef, useEffect, useState, useMemo } from "react"; const ListContainer = (props) => { const { @@ -26,6 +26,7 @@ const ListContainer = (props) => { style, collapse = false, defaultShowNum, + evaluateFlag, } = props; const timerRef = useRef(null); const loadingStartTimeRef = useRef(null); @@ -47,19 +48,17 @@ const ListContainer = (props) => { }); useEffect(() => { - setShowNumber( - () => { - return defaultShowNum === undefined ? data?.length : defaultShowNum - - }) - }, [data]) + setShowNumber(() => { + return defaultShowNum === undefined ? data?.length : defaultShowNum; + }); + }, [data]); // 控制骨架屏显示逻辑 useEffect(() => { if (loading) { // 开始加载时记录时间 loadingStartTimeRef.current = Date.now(); - + // 延迟 300ms 后再显示骨架屏 skeletonTimerRef.current = setTimeout(() => { setShowSkeleton(true); @@ -102,6 +101,7 @@ const ListContainer = (props) => { // 对于没有ntrp等级的用户每个月展示一次, 插在第三个位置 function insertEvaluateCard(list) { + if (!evaluateFlag) return list; if (!list || list.length === 0) { return list; } @@ -122,6 +122,11 @@ const ListContainer = (props) => { return [item1, item2, item3, { type: "evaluateCard" }, ...rest]; } + const memoizedList = useMemo( + () => insertEvaluateCard(data), + [evaluateFlag, data, userInfo.ntrp_level] + ); + // 渲染列表 const renderList = (list) => { // 请求数据为空 @@ -137,12 +142,12 @@ const ListContainer = (props) => { ); } - showNumber !== undefined && (list = list.slice(0, showNumber)) + showNumber !== undefined && (list = list.slice(0, showNumber)); // 渲染数据 return ( <> - {insertEvaluateCard(list).map((match, index) => { + {memoizedList.map((match, index) => { if (match.type === "evaluateCard") { return ( @@ -164,20 +169,33 @@ const ListContainer = (props) => { {renderList(recommendList)} */} {/* 到底了 */} - {collapse ? - data?.length > defaultShowNum ? - data?.length > showNumber ? - { setShowNumber(data?.length) }}> + {collapse ? ( + data?.length > defaultShowNum ? ( + data?.length > showNumber ? ( + { + setShowNumber(data?.length); + }} + > 更多球局 - : - { setShowNumber(defaultShowNum) }}> + + ) : ( + { + setShowNumber(defaultShowNum); + }} + > 收起 - : - null - : data?.length > 0 && 到底了} + ) + ) : null + ) : ( + data?.length > 0 && 到底了 + )} ); }; diff --git a/src/game_pages/detail/components/GameInfo/index.tsx b/src/game_pages/detail/components/GameInfo/index.tsx index cf2b7c4..fba6529 100644 --- a/src/game_pages/detail/components/GameInfo/index.tsx +++ b/src/game_pages/detail/components/GameInfo/index.tsx @@ -204,6 +204,9 @@ export default function GameInfo(props) { // hide business msg showLocation theme="dark" + enableScroll={false} + enableZoom={false} + onTap={openMap} /> )} diff --git a/src/game_pages/detail/components/GamePlayAndReq/index.tsx b/src/game_pages/detail/components/GamePlayAndReq/index.tsx index ae81fe2..c2f456d 100644 --- a/src/game_pages/detail/components/GamePlayAndReq/index.tsx +++ b/src/game_pages/detail/components/GamePlayAndReq/index.tsx @@ -1,5 +1,5 @@ import { View, Text } from "@tarojs/components"; -import { genNTRPRequirementText } from "../../utils/helper"; +import { genNTRPRequirementText } from "@/utils/helper"; import styles from "./index.module.scss"; // 玩法要求 diff --git a/src/game_pages/detail/components/OrganizerInfo/index.tsx b/src/game_pages/detail/components/OrganizerInfo/index.tsx index 37861ca..408d673 100644 --- a/src/game_pages/detail/components/OrganizerInfo/index.tsx +++ b/src/game_pages/detail/components/OrganizerInfo/index.tsx @@ -6,7 +6,7 @@ import { calculateDistance } from "@/utils"; import { useUserInfo } from "@/store/userStore"; import * as LoginService from "@/services/loginService"; import img from "@/config/images"; -import { navto } from "../../utils/helper"; +import { navto } from "@/utils/helper"; import styles from "./index.module.scss"; function genRecommendGames(games, location, avatar) { diff --git a/src/game_pages/detail/components/SharePopup/index.tsx b/src/game_pages/detail/components/SharePopup/index.tsx index 3a5f698..8fefc8f 100644 --- a/src/game_pages/detail/components/SharePopup/index.tsx +++ b/src/game_pages/detail/components/SharePopup/index.tsx @@ -12,7 +12,7 @@ import WechatLogo from "@/static/detail/wechat_icon.svg"; // import WechatTimeline from "@/static/detail/wechat_timeline.svg"; import LinkIcon from "@/static/detail/link.svg"; import CrossIcon from "@/static/detail/cross.svg"; -import { genNTRPRequirementText, navto } from "../../utils/helper"; +import { genNTRPRequirementText, navto } from "@/utils/helper"; import { DayOfWeekMap } from "../../config"; import styles from "./index.module.scss"; diff --git a/src/game_pages/detail/components/StickyBottom/index.module.scss b/src/game_pages/detail/components/StickyBottom/index.module.scss index adcf285..9d2f356 100644 --- a/src/game_pages/detail/components/StickyBottom/index.module.scss +++ b/src/game_pages/detail/components/StickyBottom/index.module.scss @@ -88,7 +88,7 @@ &.disabled > .sticky-bottom-bar-join-game { background: #b4b4b4; color: rgba(60, 60, 67, 0.6); - pointer-events: none; + // pointer-events: none; } .sticky-bottom-bar-join-game { @@ -147,6 +147,7 @@ font-feature-settings: "liga" off, "clig" off; font-family: "DingTalk JinBuTi"; // font-style: italic; + font-style: normal; font-size: 18px; font-weight: 400; line-height: 20px; diff --git a/src/game_pages/detail/components/StickyBottom/index.tsx b/src/game_pages/detail/components/StickyBottom/index.tsx index 17e8711..0f232be 100644 --- a/src/game_pages/detail/components/StickyBottom/index.tsx +++ b/src/game_pages/detail/components/StickyBottom/index.tsx @@ -9,7 +9,7 @@ import { MATCH_STATUS, IsSubstituteSupported } from "@/services/detailService"; import { GameManagePopup, NTRPEvaluatePopup } from "@/components"; import img from "@/config/images"; import RMB_ICON from "@/static/detail/rmb.svg"; -import { toast, navto } from "../../utils/helper"; +import { toast, navto } from "@/utils/helper"; import styles from "./index.module.scss"; function isFull(counts) { @@ -36,6 +36,34 @@ function isFull(counts) { return false; } +function matchNtrpRequestment( + target?: string, + min?: string, + max?: string +): boolean { + // 目标值为空或 undefined + if (!target?.trim()) return true; + + // 提取目标值中的第一个数字 + const match = target.match(/-?\d+(\.\d+)?/); + if (!match) return true; + + const value = parseFloat(match[0]); + const minNum = min !== undefined ? parseFloat(min) : undefined; + const maxNum = max !== undefined ? parseFloat(max) : undefined; + + // min 和 max 都未定义 → 直接通过 + if (minNum === undefined && maxNum === undefined) return true; + + // min = max 或只有一边 undefined → 参考值判断,包含端点 + if (minNum === undefined || maxNum === undefined || minNum === maxNum) { + return value >= (minNum ?? maxNum!); + } + + // 正常区间判断,包含端点 + return value >= minNum && value <= maxNum; +} + // 底部操作栏 export default function StickyButton(props) { const { @@ -45,6 +73,7 @@ export default function StickyButton(props) { onStatusChange, handleAddComment, getCommentCount, + currentUserInfo, } = props; const [commentCount, setCommentCount] = useState(0); const ntrpRef = useRef<{ @@ -58,14 +87,28 @@ export default function StickyButton(props) { start_time, end_time, is_organizer, + skill_level_max, + skill_level_min, } = detail || {}; + const { ntrp_level } = currentUserInfo || {}; + + const matchNtrpReq = matchNtrpRequestment( + ntrp_level, + skill_level_min, + skill_level_max + ); + const gameManageRef = useRef(); function handleSelfEvaluate() { ntrpRef?.current?.show({ type: EvaluateScene.detail, - next: (flag) => { + next: ({ flag, score }) => { + if (!matchNtrpRequestment(score, skill_level_min, skill_level_max)) { + toast("您当前不符合此球局NTRP水平要求,去看看其他活动吧~"); + return; + } if (flag) { Taro.navigateTo({ url: `/order_pages/orderDetail/index?gameId=${id}`, @@ -123,31 +166,31 @@ export default function StickyButton(props) { return { text: "活动已取消", available: false, - // action: () => toast("活动已取消"), + action: () => toast("活动已取消,去看看其他活动吧~"), }; } else if (MATCH_STATUS.FINISHED === match_status) { return { text: "活动已结束", available: false, - // action: () => toast("活动已取消"), + action: () => toast("活动已结束,去看看其他活动吧~"), }; } else if (dayjs(end_time).isBefore(dayjs())) { return { text: "活动已结束", available: false, - // action: () => toast("活动已结束"), + action: () => toast("活动已结束,去看看其他活动吧~"), }; } else if (dayjs(start_time).isBefore(dayjs())) { return { text: "活动已开始", available: false, - // action: () => toast("活动已开始"), + action: () => toast("活动已开始,去看看其他活动吧~"), }; } else if (isFull(detail)) { return { text: "活动已满员", available: false, - // action: () => toast("活动已满员"), + action: () => toast("活动已满员,去看看其他活动吧~"), }; } if (waiting_start) { @@ -159,7 +202,7 @@ export default function StickyButton(props) { 已加入 ), - action: () => toast("已加入"), + action: () => toast("您已参与了本次活动"), }; } else if (is_substituting) { return { @@ -170,7 +213,7 @@ export default function StickyButton(props) { 已加入候补 ), - action: () => toast("已加入候补"), + action: () => toast("您已加入候补,候补失败会全额退款~"), }; } else if (can_pay) { return { @@ -190,6 +233,19 @@ export default function StickyButton(props) { } }, }; + } else if (!matchNtrpReq) { + return { + text: () => ( + <> + + {displayPrice} + 立即加入 + + ), + available: false, + action: () => + toast("您当前不符合此球局NTRP水平要求,去看看其他活动吧~"), + }; } else if (can_substitute) { return { text: () => ( diff --git a/src/game_pages/detail/components/SupplementalNotes/index.tsx b/src/game_pages/detail/components/SupplementalNotes/index.tsx index 08bcdf9..480dc9b 100644 --- a/src/game_pages/detail/components/SupplementalNotes/index.tsx +++ b/src/game_pages/detail/components/SupplementalNotes/index.tsx @@ -1,6 +1,6 @@ import { Text, View } from "@tarojs/components"; import styles from "./index.module.scss"; -import { insertDotInTags } from "../../utils/helper"; +import { insertDotInTags } from "@/utils/helper"; export default function SupplementalNotes(props) { const { diff --git a/src/game_pages/detail/components/VenueInfo/index.tsx b/src/game_pages/detail/components/VenueInfo/index.tsx index 2cb8533..9316002 100644 --- a/src/game_pages/detail/components/VenueInfo/index.tsx +++ b/src/game_pages/detail/components/VenueInfo/index.tsx @@ -4,7 +4,7 @@ import Taro from "@tarojs/taro"; import { CommonPopup } from "@/components"; import img from "@/config/images"; import styles from "./index.module.scss"; -import { insertDotInTags } from "../../utils/helper"; +import { insertDotInTags } from "@/utils/helper"; // 场馆信息 export default function VenueInfo(props) { diff --git a/src/game_pages/detail/index.module.scss b/src/game_pages/detail/index.module.scss index 6185373..f3de38b 100644 --- a/src/game_pages/detail/index.module.scss +++ b/src/game_pages/detail/index.module.scss @@ -1,8 +1,7 @@ .detail-page { width: 100%; height: 100%; - // background-color: #FAFAFA; - // padding-bottom: env(safe-area-inset-bottom); + position: relative; .custom-navbar { height: 56px; /* 通常与原生导航栏高度一致 */ @@ -11,43 +10,55 @@ justify-content: center; // background-color: #fff; color: #000; - padding-top: 44px; /* 适配状态栏 */ - position: sticky; + // padding-top: 44px; /* 适配状态栏 */ + position: fixed; + width: 100%; top: 0; + box-sizing: border-box; z-index: 100; overflow: hidden; - background-color: rgba(0, 0, 0, 0.2); + border-bottom: 1px solid transparent; + transition: background 0.25s ease, backdrop-filter 0.25s ease; + + &.glass { + background: rgba(0, 0, 0, 0.2); + box-shadow: 0 0 4px 0 rgba(255, 255, 255, 0.25) inset; + backdrop-filter: blur(6px); + border-color: rgba(0, 0, 0, 0.1); + } } .detail-navigator { - height: 30px; + height: 40px; width: 80px; border-radius: 15px; position: absolute; left: 12px; - border: 1px solid #888; + // border: 1px solid #888; box-sizing: border-box; color: #fff; display: flex; align-items: center; - background: rgba(0, 0, 0, 0.1); + // background: rgba(0, 0, 0, 0.1); - .detail-navigator-back { - border-right: 1px solid #444; - } + // .detail-navigator-back { + // border-right: 1px solid #444; + // } .detail-navigator-back, .detail-navigator-icon { - height: 20px; - width: 50%; + height: 100%; + width: 100%; display: flex; - justify-content: center; + justify-content: flex-start; + align-items: center; & > .detail-navigator-back-icon { - width: 20px; - height: 20px; + width: 16px; + height: 16px; color: #fff; + margin-left: 8px; } & > .detail-navigator-logo-icon { diff --git a/src/game_pages/detail/index.tsx b/src/game_pages/detail/index.tsx index c948f02..a1656c5 100644 --- a/src/game_pages/detail/index.tsx +++ b/src/game_pages/detail/index.tsx @@ -1,6 +1,8 @@ import { useState, useEffect, useRef } from "react"; -import { View, Text, Image } from "@tarojs/components"; +import { View, Text, Image, ScrollView } from "@tarojs/components"; import Taro, { useRouter, useDidShow } from "@tarojs/taro"; +import classnames from "classnames"; +import { throttle } from "@tarojs/runtime"; // 导入API服务 import { withAuth, Comments } from "@/components"; import DetailService from "@/services/detailService"; @@ -18,9 +20,9 @@ import Participants from "./components/Participants"; import SupplementalNotes from "./components/SupplementalNotes"; import OrganizerInfo from "./components/OrganizerInfo"; import SharePopup from "./components/SharePopup"; -import { navto, toast } from "./utils/helper"; +import { navto, toast } from "@/utils/helper"; import ArrowLeft from "@/static/detail/icon-arrow-left.svg"; -import Logo from "@/static/detail/icon-logo-go.svg"; +// import Logo from "@/static/detail/icon-logo-go.svg"; import styles from "./index.module.scss"; function Index() { @@ -35,7 +37,7 @@ function Index() { const myInfo = useUserInfo(); const { statusNavbarHeightInfo } = useGlobalState(); - const { statusBarHeight, navBarHeight } = statusNavbarHeightInfo; + const { statusBarHeight, navBarHeight, totalHeight } = statusNavbarHeightInfo; const isMyOwn = userInfo.id === myInfo.id; @@ -150,14 +152,33 @@ function Index() { ? { backgroundImage: `url(${detail?.image_list?.[0]})` } : {}; + const [glass, setGlass] = useState(false); + + const onScroll = throttle((e) => { + const top = e.detail.scrollTop; + setGlass(top > 20); + }, 16); + return ( - + { + setGlass(false); + }} + enhanced + showScrollbar={false} + > {/* custom navbar */} - @@ -170,14 +191,14 @@ function Index() { src={ArrowLeft} /> - + {/* - + */} - + {/* swiper */} @@ -238,6 +259,7 @@ function Index() { getCommentCount={ commentRef.current && commentRef.current.getCommentCount } + currentUserInfo={myInfo} /> {/* share popup */} - + ); } diff --git a/src/game_pages/detail/utils/helper.ts b/src/game_pages/detail/utils/helper.ts deleted file mode 100644 index cf7998e..0000000 --- a/src/game_pages/detail/utils/helper.ts +++ /dev/null @@ -1,28 +0,0 @@ -import Taro from "@tarojs/taro"; - -export function navto(url) { - Taro.navigateTo({ - url: url, - }); -} - -export function toast(message) { - Taro.showToast({ title: message, icon: "none" }); -} - -// 将·作为连接符插入到标签文本之间 -export function insertDotInTags(tags: string[]) { - if (!tags) return []; - return tags.join("-·-").split("-"); -} - -export function genNTRPRequirementText(min, max) { - if (min && max && min !== max) { - return `${min} - ${max} 之间`; - } else if (max === "1") { - return "无要求"; - } else if (max) { - return `${max} 以上`; - } - return "-"; -} \ No newline at end of file diff --git a/src/game_pages/list/index.tsx b/src/game_pages/list/index.tsx index 502ff3a..1acc70e 100644 --- a/src/game_pages/list/index.tsx +++ b/src/game_pages/list/index.tsx @@ -66,7 +66,7 @@ const ListPage = () => { const scrollViewRef = useRef(null); // ScrollView 的 ref const scrollTimeoutRef = useRef(null); const lastScrollTopRef = useRef(0); - const scrollDirectionRef = useRef<'up' | 'down' | null>(null); + const scrollDirectionRef = useRef<"up" | "down" | null>(null); const lastScrollTimeRef = useRef(Date.now()); const loadingMoreRef = useRef(false); // 防止重复加载更多 const scrollStartPositionRef = useRef(0); // 记录开始滚动的位置 @@ -74,45 +74,54 @@ const ListPage = () => { const [scrollTop, setScrollTop] = useState(0); // 控制 ScrollView 滚动位置 // 动态控制 GuideBar 的 z-index - const [guideBarZIndex, setGuideBarZIndex] = useState<'low' | 'high'>('high'); + const [guideBarZIndex, setGuideBarZIndex] = useState<"low" | "high">("high"); const [isPublishMenuVisible, setIsPublishMenuVisible] = useState(false); const [isDistanceFilterVisible, setIsDistanceFilterVisible] = useState(false); const [isCityPickerVisible, setIsCityPickerVisible] = useState(false); - + // 处理 PublishMenu 显示/隐藏 const handlePublishMenuVisibleChange = useCallback((visible: boolean) => { setIsPublishMenuVisible(visible); }, []); - + // 处理 DistanceQuickFilter 显示/隐藏 const handleDistanceFilterVisibleChange = useCallback((visible: boolean) => { setIsDistanceFilterVisible(visible); }, []); - + // 处理 CityPicker 显示/隐藏 const handleCityPickerVisibleChange = useCallback((visible: boolean) => { setIsCityPickerVisible(visible); }, []); - + // 滚动到顶部的方法 const scrollToTop = useCallback(() => { // 使用一个唯一值触发 scrollTop 更新,确保每次都能滚动到顶部 - setScrollTop(prev => prev === 0 ? 0.1 : 0); + setScrollTop((prev) => (prev === 0 ? 0.1 : 0)); }, []); - + // 监听所有弹窗和菜单的状态,动态调整 GuideBar 的 z-index useEffect(() => { if (isPublishMenuVisible) { // PublishMenu 展开时,GuideBar 保持高层级 - setGuideBarZIndex('high'); - } else if (isShowFilterPopup || isDistanceFilterVisible || isCityPickerVisible) { + setGuideBarZIndex("high"); + } else if ( + isShowFilterPopup || + isDistanceFilterVisible || + isCityPickerVisible + ) { // 任何筛选组件或选择器展开时,GuideBar 降低层级 - setGuideBarZIndex('low'); + setGuideBarZIndex("low"); } else { // 都关闭时,GuideBar 保持高层级 - setGuideBarZIndex('high'); + setGuideBarZIndex("high"); } - }, [isShowFilterPopup, isPublishMenuVisible, isDistanceFilterVisible, isCityPickerVisible]); + }, [ + isShowFilterPopup, + isPublishMenuVisible, + isDistanceFilterVisible, + isCityPickerVisible, + ]); // ScrollView 滚动处理函数 const handleScrollViewScroll = useCallback( @@ -133,28 +142,34 @@ const ListPage = () => { if (Math.abs(scrollDiff) > 15) { if (scrollDiff > 0) { // 方向改变时,记录新的起始位置 - if (newDirection !== 'up') { + if (newDirection !== "up") { scrollStartPositionRef.current = lastScrollTop; } - newDirection = 'up'; + newDirection = "up"; } else { // 方向改变时,记录新的起始位置 - if (newDirection !== 'down') { + if (newDirection !== "down") { scrollStartPositionRef.current = lastScrollTop; } - newDirection = 'down'; + newDirection = "down"; } scrollDirectionRef.current = newDirection; } // 计算从开始滚动到现在的累计距离 - const totalScrollDistance = Math.abs(currentScrollTop - scrollStartPositionRef.current); + const totalScrollDistance = Math.abs( + currentScrollTop - scrollStartPositionRef.current + ); // 滚动阈值 const positionThreshold = 120; // 需要滚动到距离顶部120px const distanceThreshold = 80; // 需要连续滚动80px才触发 - if (newDirection === 'up' && currentScrollTop > positionThreshold && totalScrollDistance > distanceThreshold) { + if ( + newDirection === "up" && + currentScrollTop > positionThreshold && + totalScrollDistance > distanceThreshold + ) { // 上滑超过阈值,且连续滚动距离足够,隐藏搜索框 if (showSearchBar || !isShowInputCustomerNavBar) { setShowSearchBar(false); @@ -164,7 +179,10 @@ const ListPage = () => { // 重置起始位置 scrollStartPositionRef.current = currentScrollTop; } - } else if ((newDirection === 'down' && totalScrollDistance > distanceThreshold) || currentScrollTop <= positionThreshold) { + } else if ( + (newDirection === "down" && totalScrollDistance > distanceThreshold) || + currentScrollTop <= positionThreshold + ) { // 下滑且连续滚动距离足够,或者回到顶部附近,显示搜索框 if (!showSearchBar || isShowInputCustomerNavBar) { setShowSearchBar(true); @@ -296,7 +314,7 @@ const ListPage = () => { updateFilterOptions(params); }; - const handleSearchChange = () => { }; + const handleSearchChange = () => {}; // 距离筛选 const handleDistanceOrQuickChange = (name, value) => { @@ -433,7 +451,6 @@ const ListPage = () => { return ( <> - {/* 自定义导航 */} { {/* 固定在顶部的搜索框和筛选 */} {/* 搜索框 - 可隐藏 */} - + 0} @@ -507,7 +528,11 @@ const ListPage = () => { lowerThreshold={100} onScrollToLower={async () => { // 防止重复调用,检查 loading 状态和是否正在加载更多 - if (!loading && !loadingMoreRef.current && listPageState?.isHasMoreData) { + if ( + !loading && + !loadingMoreRef.current && + listPageState?.isHasMoreData + ) { loadingMoreRef.current = true; try { await loadMoreMatches(); @@ -529,14 +554,19 @@ const ListPage = () => { error={error} reload={refreshMatches} loadMoreMatches={loadMoreMatches} + evaluateFlag /> )} - diff --git a/src/game_pages/sharePoster/index.tsx b/src/game_pages/sharePoster/index.tsx index d53fb0f..1933994 100644 --- a/src/game_pages/sharePoster/index.tsx +++ b/src/game_pages/sharePoster/index.tsx @@ -13,7 +13,7 @@ import WechatLogo from "@/static/detail/wechat_icon.svg"; import WechatTimeline from "@/static/detail/wechat_timeline.svg"; import { useUserActions } from "@/store/userStore"; import { DayOfWeekMap } from "../detail/config"; -import { genNTRPRequirementText } from "@/game_pages/detail/utils/helper"; +import { genNTRPRequirementText } from "@/utils/helper"; import styles from "./index.module.scss"; function SharePoster(props) { diff --git a/src/main_pages/components/ListPageContent.tsx b/src/main_pages/components/ListPageContent.tsx index d0fc120..dd0a10a 100644 --- a/src/main_pages/components/ListPageContent.tsx +++ b/src/main_pages/components/ListPageContent.tsx @@ -36,9 +36,10 @@ const ListPageContent: React.FC = ({ }) => { const store = useListStore() || {}; const { fetchUserInfo } = useUserActions(); - const { statusNavbarHeightInfo, getCurrentLocationInfo } = useGlobalState() || {}; + const { statusNavbarHeightInfo, getCurrentLocationInfo } = + useGlobalState() || {}; const { totalHeight = 98 } = statusNavbarHeightInfo || {}; - + const { listPageState, loading, @@ -77,7 +78,7 @@ const ListPageContent: React.FC = ({ const scrollViewRef = useRef(null); const scrollTimeoutRef = useRef(null); const lastScrollTopRef = useRef(0); - const scrollDirectionRef = useRef<'up' | 'down' | null>(null); + const scrollDirectionRef = useRef<"up" | "down" | null>(null); const lastScrollTimeRef = useRef(Date.now()); const loadingMoreRef = useRef(false); const scrollStartPositionRef = useRef(0); @@ -86,17 +87,20 @@ const ListPageContent: React.FC = ({ const [refreshing, setRefreshing] = useState(false); // 处理距离筛选显示/隐藏 - const handleDistanceFilterVisibleChange = useCallback((visible: boolean) => { - onDistanceFilterVisibleChange?.(visible); - onNavStateChange?.({ isDistanceFilterVisible: visible }); - }, [onDistanceFilterVisibleChange, onNavStateChange]); + const handleDistanceFilterVisibleChange = useCallback( + (visible: boolean) => { + onDistanceFilterVisibleChange?.(visible); + onNavStateChange?.({ isDistanceFilterVisible: visible }); + }, + [onDistanceFilterVisibleChange, onNavStateChange] + ); // 处理城市选择器显示/隐藏(由主容器统一管理,通过 onNavStateChange 通知) // 注意:CustomerNavBar 的 onCityPickerVisibleChange 由主容器直接处理 // 滚动到顶部(用于 ScrollView 内部滚动) const scrollToTopInternal = useCallback(() => { - setScrollTop(prev => prev === 0 ? 0.1 : 0); + setScrollTop((prev) => (prev === 0 ? 0.1 : 0)); }, []); // 监听外部滚动触发 @@ -120,24 +124,30 @@ const ListPageContent: React.FC = ({ let newDirection = scrollDirectionRef.current; if (Math.abs(scrollDiff) > 15) { if (scrollDiff > 0) { - if (newDirection !== 'up') { + if (newDirection !== "up") { scrollStartPositionRef.current = lastScrollTop; } - newDirection = 'up'; + newDirection = "up"; } else { - if (newDirection !== 'down') { + if (newDirection !== "down") { scrollStartPositionRef.current = lastScrollTop; } - newDirection = 'down'; + newDirection = "down"; } scrollDirectionRef.current = newDirection; } - const totalScrollDistance = Math.abs(currentScrollTop - scrollStartPositionRef.current); + const totalScrollDistance = Math.abs( + currentScrollTop - scrollStartPositionRef.current + ); const positionThreshold = 120; const distanceThreshold = 80; - if (newDirection === 'up' && currentScrollTop > positionThreshold && totalScrollDistance > distanceThreshold) { + if ( + newDirection === "up" && + currentScrollTop > positionThreshold && + totalScrollDistance > distanceThreshold + ) { if (showSearchBar || !isShowInputCustomerNavBar) { setShowSearchBar(false); updateListPageState({ @@ -146,7 +156,10 @@ const ListPageContent: React.FC = ({ onNavStateChange?.({ isShowInputCustomerNavBar: true }); scrollStartPositionRef.current = currentScrollTop; } - } else if ((newDirection === 'down' && totalScrollDistance > distanceThreshold) || currentScrollTop <= positionThreshold) { + } else if ( + (newDirection === "down" && totalScrollDistance > distanceThreshold) || + currentScrollTop <= positionThreshold + ) { if (!showSearchBar || isShowInputCustomerNavBar) { setShowSearchBar(true); updateListPageState({ @@ -160,7 +173,12 @@ const ListPageContent: React.FC = ({ lastScrollTopRef.current = currentScrollTop; lastScrollTimeRef.current = currentTime; }, - [showSearchBar, isShowInputCustomerNavBar, updateListPageState, onNavStateChange] + [ + showSearchBar, + isShowInputCustomerNavBar, + updateListPageState, + onNavStateChange, + ] ); useEffect(() => { @@ -253,7 +271,7 @@ const ListPageContent: React.FC = ({ updateFilterOptions(params); }; - const handleSearchChange = () => { }; + const handleSearchChange = () => {}; const handleDistanceOrQuickChange = (name, value) => { updateDistanceQuickFilter({ @@ -341,7 +359,11 @@ const ListPageContent: React.FC = ({ )} - + 0} @@ -378,7 +400,11 @@ const ListPageContent: React.FC = ({ onRefresherRefresh={handleRefresh} lowerThreshold={100} onScrollToLower={async () => { - if (!loading && !loadingMoreRef.current && listPageState?.isHasMoreData) { + if ( + !loading && + !loadingMoreRef.current && + listPageState?.isHasMoreData + ) { loadingMoreRef.current = true; try { await loadMoreMatches(); @@ -399,6 +425,7 @@ const ListPageContent: React.FC = ({ error={error} reload={refreshMatches} loadMoreMatches={loadMoreMatches} + evaluateFlag /> @@ -409,4 +436,3 @@ const ListPageContent: React.FC = ({ }; export default ListPageContent; - diff --git a/src/main_pages/components/MyselfPageContent.tsx b/src/main_pages/components/MyselfPageContent.tsx index 0cc724c..3e52662 100644 --- a/src/main_pages/components/MyselfPageContent.tsx +++ b/src/main_pages/components/MyselfPageContent.tsx @@ -16,7 +16,7 @@ const MyselfPageContent: React.FC = () => { const pickerOption = usePickerOption(); const { statusNavbarHeightInfo } = useGlobalState() || {}; const { totalHeight = 98 } = statusNavbarHeightInfo || {}; - + const instance = (Taro as any).getCurrentInstance(); const user_id = instance.router?.params?.userid || ""; const is_current_user = !user_id; @@ -26,7 +26,9 @@ const MyselfPageContent: React.FC = () => { const [ended_game_records, setEndedGameRecords] = useState([]); const [loading] = useState(false); const [is_following, setIsFollowing] = useState(false); - const [active_tab, setActiveTab] = useState<"hosted" | "participated">("hosted"); + const [active_tab, setActiveTab] = useState<"hosted" | "participated">( + "hosted" + ); useEffect(() => { pickerOption.getCities(); @@ -66,7 +68,7 @@ const MyselfPageContent: React.FC = () => { const load_game_data = async () => { try { - if (!user_info || !('id' in user_info)) { + if (!user_info || !("id" in user_info)) { return; } let games_data; @@ -136,7 +138,10 @@ const MyselfPageContent: React.FC = () => { return ( - + { }; export default MyselfPageContent; - diff --git a/src/order_pages/orderDetail/index.tsx b/src/order_pages/orderDetail/index.tsx index 2a93571..42b0653 100644 --- a/src/order_pages/orderDetail/index.tsx +++ b/src/order_pages/orderDetail/index.tsx @@ -400,15 +400,49 @@ function OrderMsg(props) { }, { title: "报名人电话", - content: registrant_phone, + // content: registrant_phone, + content: registrant_phone ? ( + { + Taro.makePhoneCall({ phoneNumber: registrant_phone }); + }} + > + {registrant_phone} + + ) : ( + "-" + ), }, { title: "组织人微信号", - content: wechat_contact, + content: wechat_contact || "-", }, { title: "组织人电话", - content: wechat_contact, + // content: wechat_contact, + content: wechat_contact ? ( + { + Taro.makePhoneCall({ phoneNumber: wechat_contact }); + }} + > + {wechat_contact} + + ) : ( + "-" + ), }, { title: "费用", diff --git a/src/order_pages/orderList/index.module.scss b/src/order_pages/orderList/index.module.scss index 1a4d4f0..417a694 100644 --- a/src/order_pages/orderList/index.module.scss +++ b/src/order_pages/orderList/index.module.scss @@ -10,7 +10,7 @@ } .container { - padding: 100px 12px 40px; + padding: 100px 0 40px; background-color: #fafafa; height: 100vh; width: 100%; @@ -24,7 +24,7 @@ height: 100%; width: 100%; position: relative; - background-color: #fff; + background-color: #fafafa; // .bg { // position: absolute; @@ -48,12 +48,13 @@ font-style: normal; font-weight: 500; line-height: 18px; - background-color: #f9f9f9; + // background-color: #f9f9f9; } } .orderItem { - width: 100%; + // width: calc(100% - 3px); + margin: 0 12px; // height: 222px; background-color: #fff; border-radius: 12px; diff --git a/src/order_pages/orderList/index.tsx b/src/order_pages/orderList/index.tsx index ca6b15d..89baf9f 100644 --- a/src/order_pages/orderList/index.tsx +++ b/src/order_pages/orderList/index.tsx @@ -17,7 +17,7 @@ import { withAuth, RefundPopup, GeneralNavbar } from "@/components"; import { payOrder, generateOrderActions } from "@/utils"; import emptyContent from "@/static/emptyStatus/publish-empty.png"; import CustomerIcon from "@/static/order/customer.svg"; -import { insertDotInTags } from "@/game_pages/detail/utils/helper"; +import { insertDotInTags, genNTRPRequirementText } from "@/utils/helper"; import styles from "./index.module.scss"; dayjs.locale("zh-cn"); @@ -363,11 +363,7 @@ const OrderList = () => { {max_players} - {skill_level_max !== skill_level_min - ? `${skill_level_min || "-"} 至 ${skill_level_max || "-"}` - : skill_level_min === 1 - ? "无要求" - : `${skill_level_min} 以上`} + {genNTRPRequirementText(skill_level_min, skill_level_max)} {play_type} diff --git a/src/other_pages/ntrp-evaluate/index.tsx b/src/other_pages/ntrp-evaluate/index.tsx index 7a68aed..249ce0a 100644 --- a/src/other_pages/ntrp-evaluate/index.tsx +++ b/src/other_pages/ntrp-evaluate/index.tsx @@ -8,6 +8,7 @@ import evaluateService, { LastTimeTestResult, Question, TestResultData, + StageType, } from "@/services/evaluateService"; import { useUserInfo, useUserActions } from "@/store/userStore"; import { useEvaluate, EvaluateScene } from "@/store/evaluateStore"; @@ -24,12 +25,6 @@ import DownloadIcon from "@/static/ntrp/ntrp_download.svg"; import ReTestIcon from "@/static/ntrp/ntrp_re-action.svg"; import styles from "./index.module.scss"; -enum StageType { - INTRO = "intro", - TEST = "test", - RESULT = "result", -} - const sourceTypeToTextMap = new Map([ [EvaluateScene.detail, "继续加入球局"], [EvaluateScene.publish, "继续发布球局"], @@ -174,20 +169,17 @@ function Intro() { } function handleNext(type) { - setCallback({ - type: EvaluateScene.share, - next: () => { - Taro.redirectTo({ url: "/main_pages/index" }); - }, - onCancel: () => { - Taro.redirectTo({ url: "/main_pages/index" }); - // if (userInfo.id) { - // Taro.redirectTo({ url: "/game_pages/list/index" }); - // } else { - // Taro.exitMiniProgram(); - // } - }, - }); + if (!id) { + setCallback({ + type: EvaluateScene.share, + next: () => { + Taro.redirectTo({ url: "/main_pages/index" }); + }, + onCancel: () => { + Taro.redirectTo({ url: "/main_pages/index" }); + }, + }); + } Taro.redirectTo({ url: `/other_pages/ntrp-evaluate/index?stage=${type}${ type === StageType.RESULT ? `&id=${id}` : "" @@ -497,7 +489,7 @@ function Result() { async function handleGoon() { if (type) { - next(); + next({ flag: false, score: result?.ntrp_level as string }); await delay(1500); clear(); } else { diff --git a/src/publish_pages/publishBall/index.tsx b/src/publish_pages/publishBall/index.tsx index 3340cad..ff0854f 100644 --- a/src/publish_pages/publishBall/index.tsx +++ b/src/publish_pages/publishBall/index.tsx @@ -1,82 +1,93 @@ -import React, { useState, useEffect, useRef } from 'react' -import { View, Text, Button, Image } from '@tarojs/components' -import { Checkbox } from '@nutui/nutui-react-taro' -import dayjs from 'dayjs' -import Taro from '@tarojs/taro' -import { type ActivityType } from '../../components/ActivityTypeSwitch' -import CommonDialog from '../../components/CommonDialog' -import { withAuth } from '@/components' -import PublishForm from './publishForm' -import { FormFieldConfig, publishBallFormSchema } from '../../config/formSchema/publishBallFormSchema'; -import { PublishBallFormData } from '../../../types/publishBall'; -import PublishService from '@/services/publishService'; -import { getNextHourTime, getEndTime, delay } from '@/utils'; -import { useGlobalState } from "@/store/global" -import GeneralNavbar from "@/components/GeneralNavbar" -import images from '@/config/images' -import { useUserInfo } from '@/store/userStore' -import styles from './index.module.scss' -import { usePublishBallData } from '@/store/publishBallStore' -import { useKeyboardHeight } from '@/store/keyboardStore' +import React, { useState, useEffect, useRef } from "react"; +import { View, Text, Button, Image } from "@tarojs/components"; +import { Checkbox } from "@nutui/nutui-react-taro"; +import dayjs from "dayjs"; +import Taro from "@tarojs/taro"; +import { type ActivityType } from "../../components/ActivityTypeSwitch"; +import CommonDialog from "../../components/CommonDialog"; +import { withAuth } from "@/components"; +import PublishForm from "./publishForm"; +import { + FormFieldConfig, + publishBallFormSchema, +} from "../../config/formSchema/publishBallFormSchema"; +import { PublishBallFormData } from "../../../types/publishBall"; +import PublishService from "@/services/publishService"; +import { getNextHourTime, getEndTime, delay } from "@/utils"; +import { useGlobalState } from "@/store/global"; +import GeneralNavbar from "@/components/GeneralNavbar"; +import images from "@/config/images"; +import { useUserInfo } from "@/store/userStore"; +import styles from "./index.module.scss"; +import { usePublishBallData } from "@/store/publishBallStore"; +import { useKeyboardHeight } from "@/store/keyboardStore"; import DetailService from "@/services/detailService"; const defaultFormData: PublishBallFormData = { - title: '', + title: "", image_list: [], timeRange: { start_time: getNextHourTime(), - end_time: getEndTime(getNextHourTime()) + end_time: getEndTime(getNextHourTime()), }, activityInfo: { - play_type: '不限', - price: '', + play_type: "不限", + price: "", venue_id: null, - location_name: '', - location: '', - latitude: '', - longitude: '', - court_type: '', - court_surface: '', + location_name: "", + location: "", + latitude: "", + longitude: "", + court_type: "", + court_surface: "", venue_description_tag: [], - venue_description: '', + venue_description: "", venue_image_list: [], }, players: { min: 1, max: 1, - organizer_joined: true + organizer_joined: true, }, skill_level: [1.0, 5.0], descriptionInfo: { - description: '', + description: "", description_tag: [], }, is_substitute_supported: true, wechat: { is_wechat_contact: true, - wechat_contact: '', - default_wechat_contact: '' - } - -} + wechat_contact: "", + default_wechat_contact: "", + }, +}; const PublishBall: React.FC = () => { - const [activityType, setActivityType] = useState('individual') - const [isSubmitDisabled, setIsSubmitDisabled] = useState(false) + const [activityType, setActivityType] = useState("individual"); + const [isSubmitDisabled, setIsSubmitDisabled] = useState(false); const userInfo = useUserInfo(); - const publishAiData = usePublishBallData() + const publishAiData = usePublishBallData(); const { statusNavbarHeightInfo } = useGlobalState(); // 使用全局键盘状态 - const { keyboardHeight, isKeyboardVisible, addListener, initializeKeyboardListener } = useKeyboardHeight() + const { + keyboardHeight, + isKeyboardVisible, + addListener, + initializeKeyboardListener, + } = useKeyboardHeight(); // 获取页面参数并设置导航标题 - const [optionsConfig, setOptionsConfig] = useState(publishBallFormSchema) - console.log(userInfo, 'userInfo'); - const [formData, setFormData] = useState([defaultFormData]) - const [checked, setChecked] = useState(true) - const [titleBar, setTitleBar] = useState('发布球局') + const [optionsConfig, setOptionsConfig] = useState( + publishBallFormSchema + ); + console.log(userInfo, "userInfo"); + const [formData, setFormData] = useState([ + defaultFormData, + ]); + const [checked, setChecked] = useState(true); + const [titleBar, setTitleBar] = useState("发布球局"); // 控制是否响应全局键盘(由具体输入框 focus/blur 控制) - const [shouldReactToKeyboard, setShouldReactToKeyboard] = useState(false) + const [shouldReactToKeyboard, setShouldReactToKeyboard] = useState(false); // 删除确认弹窗状态 const [deleteConfirm, setDeleteConfirm] = useState<{ @@ -84,113 +95,129 @@ const PublishBall: React.FC = () => { index: number; }>({ visible: false, - index: -1 - }) + index: -1, + }); // 更新表单数据 - const updateFormData = (key: keyof PublishBallFormData, value: any, index: number) => { - console.log(key, value, index, 'key, value, index'); - setFormData(prev => { - const newData = [...prev] - newData[index] = { ...newData[index], [key]: value } - console.log(newData, 'newData'); - return newData - }) - } - - + const updateFormData = ( + key: keyof PublishBallFormData, + value: any, + index: number + ) => { + console.log(key, value, index, "key, value, index"); + setFormData((prev) => { + const newData = [...prev]; + newData[index] = { ...newData[index], [key]: value }; + console.log(newData, "newData"); + return newData; + }); + }; // 检查相邻两组数据是否相同 const checkAdjacentDataSame = (formDataArray: PublishBallFormData[]) => { - if (formDataArray.length < 2) return false + if (formDataArray.length < 2) return false; - const lastIndex = formDataArray.length - 1 - const secondLastIndex = formDataArray.length - 2 + const lastIndex = formDataArray.length - 1; + const secondLastIndex = formDataArray.length - 2; - const lastData = formDataArray[lastIndex] - const secondLastData = formDataArray[secondLastIndex] + const lastData = formDataArray[lastIndex]; + const secondLastData = formDataArray[secondLastIndex]; // 比较关键字段是否相同 - return (JSON.stringify(lastData) === JSON.stringify(secondLastData)) - } + return JSON.stringify(lastData) === JSON.stringify(secondLastData); + }; const handleAdd = () => { // 检查最后两组数据是否相同 if (checkAdjacentDataSame(formData)) { Taro.showToast({ - title: '信息不可与前序场完全一致', - icon: 'none' - }) - return + title: "信息不可与前序场完全一致", + icon: "none", + }); + return; } - const newStartTime = getNextHourTime() - setFormData(prev => [...prev, { - ...defaultFormData, - title: '', - timeRange: { - start_time: newStartTime, - end_time: getEndTime(newStartTime) - } - }]) - } - + const newStartTime = getNextHourTime(); + setFormData((prev) => [ + ...prev, + { + ...defaultFormData, + title: "", + timeRange: { + start_time: newStartTime, + end_time: getEndTime(newStartTime), + }, + }, + ]); + }; // 复制上一场数据 const handleCopyPrevious = (index: number) => { if (index > 0) { - setFormData(prev => { - const newData = [...prev] - newData[index] = { ...newData[index - 1] } - return newData - }) + setFormData((prev) => { + const newData = [...prev]; + newData[index] = { ...newData[index - 1] }; + return newData; + }); Taro.showToast({ - title: '复制上一场填入', - icon: 'success' - }) + title: "复制上一场填入", + icon: "success", + }); } - } + }; // 删除确认弹窗 const showDeleteConfirm = (index: number) => { setDeleteConfirm({ visible: true, - index - }) - } + index, + }); + }; // 关闭删除确认弹窗 const closeDeleteConfirm = () => { setDeleteConfirm({ visible: false, - index: -1 - }) - } + index: -1, + }); + }; // 确认删除 const confirmDelete = () => { if (deleteConfirm.index >= 0) { - setFormData(prev => prev.filter((_, index) => index !== deleteConfirm.index)) - closeDeleteConfirm() + setFormData((prev) => + prev.filter((_, index) => index !== deleteConfirm.index) + ); + closeDeleteConfirm(); Taro.showToast({ - title: '已删除该场次', - icon: 'success' - }) + title: "已删除该场次", + icon: "success", + }); } - } + }; - const validateFormData = (formData: PublishBallFormData, isOnSubmit: boolean = false) => { - const { activityInfo, title, timeRange, image_list, players, current_players } = formData; + const validateFormData = ( + formData: PublishBallFormData, + isOnSubmit: boolean = false + ) => { + const { + activityInfo, + title, + timeRange, + image_list, + players, + current_players, + } = formData; const { play_type, price, location_name } = activityInfo; - const { max } = players; - if (!image_list?.length && activityType === 'group') { + const { max } = players; + if (!image_list?.length && activityType === "group") { if (!isOnSubmit) { Taro.showToast({ title: `请上传活动封面`, - icon: 'none' - }) + icon: "none", + }); } - return false + return false; } // 判断图片是否上传完成 if (image_list?.length > 0) { @@ -209,117 +236,135 @@ const PublishBall: React.FC = () => { if (!isOnSubmit) { Taro.showToast({ title: `请输入活动标题`, - icon: 'none' - }) + icon: "none", + }); } - return false + return false; } - if (!price || (typeof price === 'number' && price <= 0) || (typeof price === 'string' && !price.trim())) { + if ( + !price || + (typeof price === "number" && price <= 0) || + (typeof price === "string" && !price.trim()) + ) { if (!isOnSubmit) { Taro.showToast({ title: `请输入费用`, - icon: 'none' - }) + icon: "none", + }); } - return false + return false; } if (!play_type || !play_type.trim()) { if (!isOnSubmit) { Taro.showToast({ title: `请选择玩法类型`, - icon: 'none' - }) + icon: "none", + }); } - return false + return false; } if (!location_name || !location_name.trim()) { if (!isOnSubmit) { Taro.showToast({ title: `请选择场地`, - icon: 'none' - }) + icon: "none", + }); } - return false + return false; } // 时间范围校验:结束时间需晚于开始时间,且至少间隔30分钟(支持跨天) if (timeRange?.start_time && timeRange?.end_time) { - const start = dayjs(timeRange.start_time) - const end = dayjs(timeRange.end_time) - const currentTime = dayjs() + const start = dayjs(timeRange.start_time); + const end = dayjs(timeRange.end_time); + const currentTime = dayjs(); if (!end.isAfter(start)) { if (!isOnSubmit) { Taro.showToast({ title: `结束时间需晚于开始时间`, - icon: 'none' - }) + icon: "none", + }); } - return false + return false; } - if (end.isBefore(start.add(30, 'minute'))) { + if (end.isBefore(start.add(30, "minute"))) { if (!isOnSubmit) { Taro.showToast({ title: `时间间隔至少30分钟`, - icon: 'none' - }) + icon: "none", + }); } - return false + return false; } if (start.isBefore(currentTime)) { if (!isOnSubmit) { Taro.showToast({ title: `开始时间需晚于当前时间`, - icon: 'none' - }) + icon: "none", + }); } - return false + return false; } if (end.isBefore(currentTime)) { if (!isOnSubmit) { Taro.showToast({ title: `结束时间需晚于当前时间`, - icon: 'none' - }) + icon: "none", + }); } - return false + return false; } } - if (current_players && (current_players > max)) { + if (current_players && current_players > max) { if (!isOnSubmit) { Taro.showToast({ title: `最大人数不能小于当前参与人数${current_players}`, - icon: 'none' - }) + icon: "none", + }); } - return false + return false; } - return true - } + return true; + }; const validateOnSubmit = () => { - const isValid = activityType === 'individual' ? validateFormData(formData[0], true) : formData.every(item => validateFormData(item, true)) + const isValid = + activityType === "individual" + ? validateFormData(formData[0], true) + : formData.every((item) => validateFormData(item, true)); if (!isValid) { - return false + return false; } - return true - } + return true; + }; const getParams = () => { - const currentInstance = Taro.getCurrentInstance() - const params = currentInstance.router?.params - return params - } + const currentInstance = Taro.getCurrentInstance(); + const params = currentInstance.router?.params; + return params; + }; // 提交表单 const handleSubmit = async () => { // 基础验证 - console.log(formData, 'formData'); - const params = getParams() + console.log(formData, "formData"); + const params = getParams(); const { republish } = params || {}; - if (activityType === 'individual') { - const isValid = validateFormData(formData[0]) + if (activityType === "individual") { + const isValid = validateFormData(formData[0]); if (!isValid) { - return + return; } - const { activityInfo, descriptionInfo,is_substitute_supported, timeRange, players, skill_level, image_list, wechat, id, ...rest } = formData[0]; + const { + activityInfo, + descriptionInfo, + is_substitute_supported, + timeRange, + players, + skill_level, + image_list, + wechat, + id, + ...rest + } = formData[0]; const { min, max, organizer_joined } = players; const options = { ...rest, @@ -331,50 +376,69 @@ const PublishBall: React.FC = () => { organizer_joined: organizer_joined === true ? 1 : 0, skill_level_min: skill_level[0], skill_level_max: skill_level[1], - image_list: image_list.map(item => item.url), + image_list: image_list.map((item) => item.url), is_wechat_contact: wechat.is_wechat_contact ? 1 : 0, wechat_contact: wechat.wechat_contact || wechat.default_wechat_contact, - is_substitute_supported: is_substitute_supported ? '1' : '0', - ...(republish === '0' ? { id } : {}), - } - const res = republish === '0' ? await PublishService.gamesUpdate(options) : await PublishService.createPersonal(options); - const successText = republish === '0' ? '更新成功' : '发布成功'; + is_substitute_supported: is_substitute_supported ? "1" : "0", + ...(republish === "0" ? { id } : {}), + }; + const res = + republish === "0" + ? await PublishService.gamesUpdate(options) + : await PublishService.createPersonal(options); + const successText = republish === "0" ? "更新成功" : "发布成功"; if (res.code === 0 && res.data) { Taro.showToast({ title: successText, - icon: 'success' - }) - delay(1000) + icon: "success", + }); + delay(1000); // 如果是个人球局,则跳转到详情页,并自动分享 // 如果是畅打,则跳转第一个球局详情页,并自动分享 @刘杰 const id = (res as any).data?.id; - Taro.navigateTo({ - // @ts-expect-error: id - url: `/game_pages/detail/index?id=${id || 1}&from=publish&autoShare=1` - }) + // 如果是编辑,就返回,否则就是新发布 + if (republish === "0") { + Taro.navigateBack(); + } else { + Taro.navigateTo({ + // @ts-expect-error: id + url: `/game_pages/detail/index?id=${ + id || 1 + }&from=publish&autoShare=1`, + }); + } } else { Taro.showToast({ title: res.message, - icon: 'none' - }) + icon: "none", + }); } } - if (activityType === 'group') { - const isValid = formData.every(item => validateFormData(item)) + if (activityType === "group") { + const isValid = formData.every((item) => validateFormData(item)); if (!isValid) { - return + return; } if (checkAdjacentDataSame(formData)) { Taro.showToast({ - title: '信息不可与前序场完全一致', - icon: 'none' - }) - return + title: "信息不可与前序场完全一致", + icon: "none", + }); + return; } const options = formData.map((item) => { - const { activityInfo, descriptionInfo, timeRange, players, skill_level, is_substitute_supported, id, ...rest } = item; + const { + activityInfo, + descriptionInfo, + timeRange, + players, + skill_level, + is_substitute_supported, + id, + ...rest + } = item; const { min, max, organizer_joined } = players; - return { + return { ...rest, ...activityInfo, ...descriptionInfo, @@ -384,267 +448,362 @@ const PublishBall: React.FC = () => { organizer_joined: organizer_joined === true ? 1 : 0, skill_level_min: skill_level[0], skill_level_max: skill_level[1], - is_substitute_supported: is_substitute_supported ? '1' : '0', - image_list: item.image_list.map(img => img.url), - ...(republish === '0' ? { id } : {}), - } - }) - const successText = republish === '0' ? '更新成功' : '发布成功'; - const res = republish === '0' ? await PublishService.gamesUpdate(options[0]) : await PublishService.create_play_pmoothlys({rows: options}); + is_substitute_supported: is_substitute_supported ? "1" : "0", + image_list: item.image_list.map((img) => img.url), + ...(republish === "0" ? { id } : {}), + }; + }); + const successText = republish === "0" ? "更新成功" : "发布成功"; + const res = + republish === "0" + ? await PublishService.gamesUpdate(options[0]) + : await PublishService.create_play_pmoothlys({ rows: options }); if (res.code === 0 && res.data) { Taro.showToast({ title: successText, - icon: 'success' - }) - delay(1000) + icon: "success", + }); + delay(1000); // 如果是个人球局,则跳转到详情页,并自动分享 // 如果是畅打,则跳转第一个球局详情页,并自动分享 @刘杰 - const id = republish === '0' ? (res as any).data?.id : (res as any).data?.[0]?.id; + const id = + republish === "0" + ? (res as any).data?.id + : (res as any).data?.[0]?.id; Taro.navigateTo({ - // @ts-expect-error: id - url: `/game_pages/detail/index?id=${id || 1}&from=publish&autoShare=1` - }) + // @ts-expect-error: id + url: `/game_pages/detail/index?id=${ + id || 1 + }&from=publish&autoShare=1`, + }); } else { Taro.showToast({ title: res.message, - icon: 'none' - }) + icon: "none", + }); } } - } + }; - const mergeWithDefault = (data: any, isDetail: boolean = false): PublishBallFormData => { + const mergeWithDefault = ( + data: any, + isDetail: boolean = false + ): PublishBallFormData => { // ai导入与详情数据处理 - const { start_time, end_time, play_type, price, venue_id, location_name, location, latitude, - longitude, court_type, court_surface, venue_description_tag, venue_description, venue_image_list, - description, description_tag, max_players, min_players, skill_level_max, skill_level_min, - venueDtl, wechat_contact, image_list, id: publish_id, is_wechat_contact, - is_substitute_supported, title, current_players, organizer_joined - } = data; - const level_max = skill_level_max ? Number(skill_level_max) : 5.0; - const level_min = skill_level_min ? Number(skill_level_min) : 1.0; - const userPhone = wechat_contact || (userInfo as any)?.phone || '' - let activityInfo = {}; - if (venueDtl) { - const { latitude, longitude,venue_type, surface_type, facilities, name, id } = venueDtl; - activityInfo = { - latitude, - longitude, - court_type: venue_type, - court_surface: surface_type, - venue_description: facilities, - location_name: name, - venue_id: id - } - } - if (isDetail) { - activityInfo = { - venue_id, - location_name, - location, - latitude, - longitude, - court_type, - court_surface, - venue_description_tag, - venue_description, - venue_image_list - } - } - return { - ...defaultFormData, - title, - ...(is_substitute_supported === '0' ? { is_substitute_supported: false } : {}), - ...(publish_id ? { id: publish_id } : {}), - timeRange: { - ...defaultFormData.timeRange, - start_time, - end_time, - }, - activityInfo: { - ...defaultFormData.activityInfo, - ...(play_type ? { play_type } : {}), - ...((price) ? { price } : {}), - ...activityInfo - }, - descriptionInfo: { - ...defaultFormData.descriptionInfo, - ...(description ? { description } : {}), - ...(description_tag ? { description_tag } : {}), - }, - ...(level_max && level_min ? { skill_level: [level_min, level_max] } : {}), - ...(max_players && min_players ? { players: { min: min_players, max: max_players, organizer_joined: organizer_joined === 0 ? false : true } } : {}), - wechat: { ...defaultFormData.wechat, default_wechat_contact: userPhone, is_wechat_contact: is_wechat_contact === 0 ? false : true}, - image_list: image_list?.map(item => ({ url: item, id: item })) || [], - ...(current_players ? { current_players } : {}), - - } + const { + start_time, + end_time, + play_type, + price, + venue_id, + location_name, + location, + latitude, + longitude, + court_type, + court_surface, + venue_description_tag, + venue_description, + venue_image_list, + description, + description_tag, + max_players, + min_players, + skill_level_max, + skill_level_min, + venueDtl, + wechat_contact, + image_list, + id: publish_id, + is_wechat_contact, + is_substitute_supported, + title, + current_players, + organizer_joined, + } = data; + const level_max = skill_level_max ? Number(skill_level_max) : 5.0; + const level_min = skill_level_min ? Number(skill_level_min) : 1.0; + const userPhone = wechat_contact || (userInfo as any)?.phone || ""; + let activityInfo = {}; + if (venueDtl) { + const { + latitude, + longitude, + venue_type, + surface_type, + facilities, + name, + id, + } = venueDtl; + activityInfo = { + latitude, + longitude, + court_type: venue_type, + court_surface: surface_type, + venue_description: facilities, + location_name: name, + venue_id: id, + }; } + if (isDetail) { + activityInfo = { + venue_id, + location_name, + location, + latitude, + longitude, + court_type, + court_surface, + venue_description_tag, + venue_description, + venue_image_list, + }; + } + return { + ...defaultFormData, + title, + ...(is_substitute_supported === "0" + ? { is_substitute_supported: false } + : {}), + ...(publish_id ? { id: publish_id } : {}), + timeRange: { + ...defaultFormData.timeRange, + start_time, + end_time, + }, + activityInfo: { + ...defaultFormData.activityInfo, + ...(play_type ? { play_type } : {}), + ...(price ? { price } : {}), + ...activityInfo, + }, + descriptionInfo: { + ...defaultFormData.descriptionInfo, + ...(description ? { description } : {}), + ...(description_tag ? { description_tag } : {}), + }, + ...(level_max && level_min + ? { skill_level: [level_min, level_max] } + : {}), + ...(max_players && min_players + ? { + players: { + min: min_players, + max: max_players, + organizer_joined: organizer_joined === 0 ? false : true, + }, + } + : {}), + wechat: { + ...defaultFormData.wechat, + default_wechat_contact: userPhone, + is_wechat_contact: is_wechat_contact === 0 ? false : true, + }, + image_list: image_list?.map((item) => ({ url: item, id: item })) || [], + ...(current_players ? { current_players } : {}), + }; + }; - const formatConfig = () => { + const formatConfig = () => { const newFormSchema = publishBallFormSchema.reduce((acc, item) => { - if (item.prop === 'wechat') { - return acc + if (item.prop === "wechat") { + return acc; } - if (item.prop === 'image_list') { + if (item.prop === "image_list") { if (item.props) { - item.props.source = ['album', 'history'] + item.props.source = ["album", "history"]; } } - if (item.prop === 'players') { + if (item.prop === "players") { if (item.props) { - item.props.max = 100 + item.props.max = 100; } } - acc.push(item) - return acc - }, [] as FormFieldConfig[]) - setOptionsConfig(newFormSchema) - } + acc.push(item); + return acc; + }, [] as FormFieldConfig[]); + setOptionsConfig(newFormSchema); + }; const initFormData = () => { - const params = getParams() - const userPhone = (userInfo as any)?.phone || '' + const params = getParams(); + const userPhone = (userInfo as any)?.phone || ""; if (params?.type) { - const type = params.type as ActivityType - if (type === 'individual' || type === 'group') { - setActivityType(type) - if (type === 'group') { - formatConfig() - setFormData([defaultFormData]) - setTitleBar('发布畅打活动') + const type = params.type as ActivityType; + if (type === "individual" || type === "group") { + setActivityType(type); + if (type === "group") { + formatConfig(); + setFormData([defaultFormData]); + setTitleBar("发布畅打活动"); } else { - setTitleBar('发布球局') - setFormData([{...defaultFormData, wechat: { ...defaultFormData.wechat, default_wechat_contact: userPhone } }]) + setTitleBar("发布球局"); + setFormData([ + { + ...defaultFormData, + wechat: { + ...defaultFormData.wechat, + default_wechat_contact: userPhone, + }, + }, + ]); } - } else if (type === 'ai') { + } else if (type === "ai") { // 从 Store 注入 AI 生成的表单 JSON - if (publishAiData && Array.isArray(publishAiData) && publishAiData.length > 0) { + if ( + publishAiData && + Array.isArray(publishAiData) && + publishAiData.length > 0 + ) { Taro.showToast({ - title: '智能识别成功,请完善剩余信息', - icon: 'none' - }) - const merged = publishAiData.map(item => mergeWithDefault(item)) - setFormData(merged.length ? merged : [defaultFormData]) + title: "智能识别成功,请完善剩余信息", + icon: "none", + }); + const merged = publishAiData.map((item) => mergeWithDefault(item)); + setFormData(merged.length ? merged : [defaultFormData]); if (merged.length === 1) { - setTitleBar('发布球局') - setActivityType('individual') + setTitleBar("发布球局"); + setActivityType("individual"); } else { - formatConfig() - setTitleBar('发布畅打活动') - setActivityType('group') + formatConfig(); + setTitleBar("发布畅打活动"); + setActivityType("group"); } } else { - setFormData([defaultFormData]) - setTitleBar('发布球局') - setActivityType('individual') + setFormData([defaultFormData]); + setTitleBar("发布球局"); + setActivityType("individual"); } } } if (params?.gameId) { - getGameDetail(params.gameId) + getGameDetail(params.gameId); } - } - - + }; const getGameDetail = async (gameId) => { if (!gameId) return; try { const res = await DetailService.getDetail(Number(gameId)); if (res.code === 0) { - const merged = mergeWithDefault(res.data, true) - setFormData([merged]) - if (res.data.game_type === '个人球局') { - setTitleBar('发布球局') - setActivityType('individual') + const merged = mergeWithDefault(res.data, true); + setFormData([merged]); + if (res.data.game_type === "个人球局") { + setTitleBar("发布球局"); + setActivityType("individual"); } else { - setTitleBar('发布畅打活动') - setActivityType('group') + setTitleBar("发布畅打活动"); + setActivityType("group"); } } } catch (e) { - Taro.showToast({ + Taro.showToast({ title: e.message, - icon: 'none' - }) + icon: "none", + }); } }; const onCheckedChange = (checked: boolean) => { - setChecked(checked) - } + setChecked(checked); + }; useEffect(() => { - const isValid = validateOnSubmit() + const isValid = validateOnSubmit(); if (!isValid) { - setIsSubmitDisabled(true) + setIsSubmitDisabled(true); } else { - setIsSubmitDisabled(false) + setIsSubmitDisabled(false); } - console.log(formData, 'formData'); - }, [formData]) + console.log(formData, "formData"); + }, [formData]); useEffect(() => { - initFormData() - }, []) + initFormData(); + }, []); -// 使用全局键盘状态监听 -useEffect(() => { - // 初始化全局键盘监听器 - initializeKeyboardListener() + // 使用全局键盘状态监听 + useEffect(() => { + // 初始化全局键盘监听器 + initializeKeyboardListener(); - // 添加本地监听器 - const removeListener = addListener((height, visible) => { - console.log('PublishBall 收到键盘变化:', height, visible) - // 这里只记录或用于其他逻辑,布局是否响应交由 shouldReactToKeyboard 决定 - }) + // 添加本地监听器 + const removeListener = addListener((height, visible) => { + console.log("PublishBall 收到键盘变化:", height, visible); + // 这里只记录或用于其他逻辑,布局是否响应交由 shouldReactToKeyboard 决定 + }); - return () => { - removeListener() - } -}, [initializeKeyboardListener, addListener]) + return () => { + removeListener(); + }; + }, [initializeKeyboardListener, addListener]); const handleAnyInputFocus = (item: FormFieldConfig, e: any) => { - const { prop } = item - if (prop === 'descriptionInfo') { - setShouldReactToKeyboard(true) + const { prop } = item; + if (prop === "descriptionInfo") { + setShouldReactToKeyboard(true); } - } + }; const handleAnyInputBlur = () => { - setShouldReactToKeyboard(false) - } + setShouldReactToKeyboard(false); + }; return ( - - - - {/* 活动类型切换 */} - {/* + + + + {/* 活动类型切换 */} + {/* */} - - { - formData.map((item, index) => ( + + {formData.map((item, index) => ( {/* 场次标题行 */} - {activityType === 'group' && index > 0 && ( - - - 第{index + 1}场 - 0 && ( + + + 第{index + 1}场 + showDeleteConfirm(index)} > - - + - - + {index > 0 && ( handleCopyPrevious(index)} > 复制上一场 @@ -661,57 +820,65 @@ useEffect(() => { onAnyInputBlur={handleAnyInputBlur} /> - )) - } - { - activityType === 'group' && ( - - + ))} + {activityType === "group" && ( + + 再添加一场 - ) - } - + )} + - {/* 删除确认弹窗 */} - - {/* 完成按钮 */} - - - { - activityType === 'individual' && ( - + {/* 删除确认弹窗 */} + + {/* 完成按钮 */} + + + {activityType === "individual" && ( + 点击确定发布约球,即表示已经同意条款 - Taro.navigateTo({url: '/publish_pages/footballRules/index'})}>《约球规则》 + + Taro.navigateTo({ url: "/publish_pages/footballRules/index" }) + } + > + 《约球规则》 + - ) - } - { - activityType === 'group' && ( - + )} + {activityType === "group" && ( + 已认证 徐汇爱打球官方球场,请严格遵守签约协议 - ) - } + )} + - - ) -} + ); +}; -export default withAuth(PublishBall) +export default withAuth(PublishBall); diff --git a/src/services/evaluateService.ts b/src/services/evaluateService.ts index 60ca1fd..178577b 100644 --- a/src/services/evaluateService.ts +++ b/src/services/evaluateService.ts @@ -1,6 +1,12 @@ import httpService from "./httpService"; import type { ApiResponse } from "./httpService"; +export enum StageType { + INTRO = "intro", + TEST = "test", + RESULT = "result", +} + // 单个选项类型 interface Option { text: string; diff --git a/src/store/evaluateStore.ts b/src/store/evaluateStore.ts index eb49ac9..b08e264 100644 --- a/src/store/evaluateStore.ts +++ b/src/store/evaluateStore.ts @@ -10,18 +10,25 @@ export enum EvaluateScene { } export interface EvaluateCallback { - type: EvaluateScene | '' - next: (flag?: boolean) => void, - onCancel: () => void, + type: EvaluateScene | ""; + // flag是用来区分跳转ntrp测试后的操作和直接修改ntrp水平成功后的操作 + // score是用在加入球局前判断是否满足球局要求的返回值,限定为必传 + // next有两个地方调用:ntrp结果页handleGoon、ntrp弹窗(NTRPEvaluatePopup)直接修改点击保存按钮时 + next: ({ flag, score }: { flag?: boolean; score: string }) => void; + onCancel: () => void; } export interface EvaluateCallbackType extends EvaluateCallback { - setCallback: (options: { type: EvaluateScene | '', next: () => void, onCancel: () => void }) => void, - clear: () => void, + setCallback: (options: { + type: EvaluateScene | ""; + next: ({ flag, score }: { flag?: boolean; score: string }) => void; + onCancel: () => void; + }) => void; + clear: () => void; } export const useEvaluateCallback = create()((set) => ({ - type: '', + type: "", next: () => { }, onCancel: () => { }, setCallback: ({ type, next, onCancel }) => { @@ -29,15 +36,18 @@ export const useEvaluateCallback = create()((set) => ({ type, next, onCancel, - }) + }); + }, + clear: () => { + set({ type: "", next: () => { }, onCancel: () => { } }); }, - clear: () => { set({ type: '', next: () => { }, onCancel: () => { } }) } })); -export const useEvaluate = () => useEvaluateCallback(({ type, next, onCancel, setCallback, clear }) => ({ - type, - next, - onCancel, - setCallback, - clear, -})) +export const useEvaluate = () => + useEvaluateCallback(({ type, next, onCancel, setCallback, clear }) => ({ + type, + next, + onCancel, + setCallback, + clear, + })); diff --git a/src/utils/helper.ts b/src/utils/helper.ts index a223ad3..6e3df48 100644 --- a/src/utils/helper.ts +++ b/src/utils/helper.ts @@ -23,4 +23,35 @@ export const sceneRedirectLogic = (options, defaultPage: string) => { } catch (e) { console.error(e); } -}; \ No newline at end of file +}; + +export function navto(url) { + Taro.navigateTo({ + url: url, + }); +} + +export function toast(message) { + Taro.showToast({ title: message, icon: "none" }); +} + +// 将·作为连接符插入到标签文本之间 +export function insertDotInTags(tags: string[]) { + if (!tags) return []; + return tags.join("-·-").split("-"); +} + +function formatNtrpDisplay(val) { + return Number(val).toFixed(1) +} + +export function genNTRPRequirementText(min, max) { + if (min && max && min !== max) { + return `${formatNtrpDisplay(min)} - ${formatNtrpDisplay(max)} 之间`; + } else if (max === "1") { + return "无要求"; + } else if (max) { + return `${formatNtrpDisplay(max)} 以上`; + } + return "-"; +} \ No newline at end of file diff --git a/types/ntrp-evaluate.ts b/types/ntrp-evaluate.ts new file mode 100644 index 0000000..2f9dbab --- /dev/null +++ b/types/ntrp-evaluate.ts @@ -0,0 +1,5 @@ +export enum StageType { + INTRO = "intro", + TEST = "test", + RESULT = "result", +} \ No newline at end of file