feat: 球局详情管理 未完

This commit is contained in:
2025-09-16 17:30:30 +08:00
parent 1b4c8f9e73
commit 7dea93acde
10 changed files with 480 additions and 210 deletions

View File

@@ -0,0 +1,27 @@
.container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
padding-bottom: 40px;
.button {
width: 100%;
padding: 20px 0;
display: flex;
justify-content: center;
align-items: center;
color: #000;
text-align: center;
font-feature-settings: 'liga' off, 'clig' off;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 600;
line-height: 20px;
&:last-child {
border-top: 8px solid #f5f5f5;
}
}
}

View File

@@ -0,0 +1,145 @@
import React, {
useState,
forwardRef,
useImperativeHandle,
useRef,
} from "react";
import Taro from "@tarojs/taro";
import { View } from "@tarojs/components";
import CommonPopup from "../CommonPopup";
import styles from "./index.module.scss";
import detailService from "@/services/detailService";
import { useUserInfo } from "@/store/userStore";
const CancelPopup = forwardRef((props, ref) => {
const [visible, setVisible] = useState(false);
const onFinish = useRef(null);
useImperativeHandle(ref, () => ({
show: (onAct) => {
onFinish.current = onAct;
setVisible(true);
},
}));
function onClose() {
setVisible(false);
}
return (
<>
<CommonPopup
visible={visible}
showHeader={false}
hideFooter
zIndex={1001}
enableDragToClose={false}
onClose={onClose}
>
<View className={styles.container}></View>
</CommonPopup>
</>
);
});
export default forwardRef(function GameManagePopup(props, ref) {
const [visible, setVisible] = useState(false);
const [detail, setDetail] = useState({});
const onStatusChange = useRef(null);
const cancelRef = useRef(null);
const userInfo = useUserInfo();
useImperativeHandle(ref, () => ({
show: (gameDetail, onChange) => {
onStatusChange.current = onChange;
setDetail(gameDetail);
setVisible(true);
},
}));
function handleEditGame() {
Taro.navigateTo({
url: `/publish_pages/publishBall/index?gameId=${detail.id}`,
});
onClose()
}
const handleRepubGame = handleEditGame;
async function handleCancelGame() {
cancelRef.current.show(async (result) => {
if (result) {
try {
const res = await detailService.disbandGame({
game_id: detail.id,
settle_reason: result,
});
if (res.code === 0) {
Taro.showToast({ title: "活动取消成功" });
onStatusChange.current?.(true);
}
} catch (e) {
Taro.showToast({ title: e.message, icon: "error" });
} finally {
onClose();
}
}
});
}
async function handleQuitGame() {
try {
const res = await detailService.organizerQuit({
game_id: detail.id,
quit_reason: "组织者主动退出",
});
if (res.code === 0) {
Taro.showToast({ title: "活动退出成功" });
onStatusChange.current?.(true);
}
} catch (e) {
Taro.showToast({ title: e.message, icon: "error" });
} finally {
onClose();
}
}
function onClose() {
setVisible(false);
}
const hasJoin = (detail.participants || []).some(item => item.user.id === userInfo.id)
return (
<>
<CommonPopup
visible={visible}
showHeader={false}
hideFooter
zIndex={1001}
enableDragToClose={false}
onClose={onClose}
>
<View className={styles.container}>
<View className={styles.button} onClick={handleEditGame}>
</View>
<View className={styles.button} onClick={handleRepubGame}>
</View>
<View className={styles.button} onClick={handleCancelGame}>
</View>
{!hasJoin && (
<View className={styles.button} onClick={handleQuitGame}>
退
</View>
)}
<View className={styles.button} onClick={onClose}>
</View>
</View>
</CommonPopup>
<CancelPopup ref={cancelRef} />
</>
);
});

View File

@@ -91,7 +91,7 @@ const NTRPEvaluatePopup = (props: NTRPEvaluatePopupProps, ref) => {
<Button onClick={handleEvaluate}></Button> <Button onClick={handleEvaluate}></Button>
</View> </View>
</CommonPopup> </CommonPopup>
{showEntry && props.children} {showEntry ? props.children : ''}
</> </>
); );
}; };

View File

@@ -31,7 +31,8 @@
} }
.upload-popup-scroll-view { .upload-popup-scroll-view {
max-height: calc(100vh - 260px); // max-height: calc(100vh - 260px);
height: 440px;
overflow-y: auto; overflow-y: auto;
.upload-popup-image-list { .upload-popup-image-list {
@@ -124,7 +125,7 @@
display: flex; display: flex;
width: 100%; width: 100%;
height: 62px; height: 62px;
padding: 8px 10px 10px 10px; padding: 8px 10px 50px 10px;
box-sizing: border-box; box-sizing: border-box;
justify-content: center; justify-content: center;
align-items: flex-start; align-items: flex-start;

View File

@@ -121,6 +121,7 @@ export default forwardRef(function UploadImage(props: UploadImageProps, ref) {
<ScrollView <ScrollView
scrollY scrollY
className="upload-popup-scroll-view" className="upload-popup-scroll-view"
// style={{ height: images.length / 3 * }}
> >
{images.length > 0 ? ( {images.length > 0 ? (
<View className="upload-popup-image-list"> <View className="upload-popup-image-list">

View File

@@ -17,6 +17,7 @@ import withAuth from "./Auth";
import { CustomPicker, PopupPicker } from "./Picker"; import { CustomPicker, PopupPicker } from "./Picker";
import NTRPEvaluatePopup from "./NTRPEvaluatePopup"; import NTRPEvaluatePopup from "./NTRPEvaluatePopup";
import RefundPopup from "./refundPopup"; import RefundPopup from "./refundPopup";
import GameManagePopup from './GameManagePopup'
export { export {
ActivityTypeSwitch, ActivityTypeSwitch,
@@ -39,4 +40,5 @@ export {
PopupPicker, PopupPicker,
NTRPEvaluatePopup, NTRPEvaluatePopup,
RefundPopup, RefundPopup,
GameManagePopup,
}; };

View File

@@ -807,7 +807,7 @@
} }
&-organizer-recommend-games { &-organizer-recommend-games {
padding: 24px 15px 0; padding: 24px 15px 10px;
.organizer-title { .organizer-title {
overflow: hidden; overflow: hidden;
@@ -1122,19 +1122,27 @@
} }
} }
&-join-game { .detail-main-action {
display: flex; display: flex;
align-items: center; align-items: center;
height: 52px; height: 52px;
width: auto; width: auto;
padding: 2px 6px; // padding: 2px 6px;
box-sizing: border-box; box-sizing: border-box;
justify-content: center; justify-content: center;
gap: 12px; gap: 12px;
flex: 1 0 0; flex: 1 0 0;
border-radius: 16px; border-radius: 16px;
border: 1px solid rgba(0, 0, 0, 0.06); // border: 1px solid rgba(0, 0, 0, 0.06);
background: #fff; background: #fff;
overflow: hidden;
.sticky-bottom-bar-join-game {
margin-left: auto;
width: 151px;
display: flex;
align-items: center;
justify-content: center;
&-price { &-price {
font-family: "PoetsenOne"; font-family: "PoetsenOne";
@@ -1145,6 +1153,18 @@
color: #000; color: #000;
} }
} }
.game_manage {
width: 100px;
margin-left: auto;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: #000;
color: #fff;
}
}
} }
} }
} }

View File

@@ -16,7 +16,12 @@ import Taro, {
import dayjs from "dayjs"; import dayjs from "dayjs";
import "dayjs/locale/zh-cn"; import "dayjs/locale/zh-cn";
// 导入API服务 // 导入API服务
import { CommonPopup, withAuth, NTRPEvaluatePopup } from "@/components"; import {
CommonPopup,
withAuth,
NTRPEvaluatePopup,
GameManagePopup,
} from "@/components";
import { import {
EvaluateType, EvaluateType,
SceneType, SceneType,
@@ -210,7 +215,7 @@ const SharePopup = forwardRef(
</View> </View>
</CommonPopup> </CommonPopup>
); );
}, }
); );
function navto(url) { function navto(url) {
@@ -219,20 +224,18 @@ function navto(url) {
}); });
} }
function toast(message) {
Taro.showToast({ title: message, icon: "none" });
}
// 底部操作栏 // 底部操作栏
function StickyButton(props) { function StickyButton(props) {
const { handleShare, handleJoinGame, detail } = props; const { handleShare, handleJoinGame, detail, onStatusChange } = props;
const ntrpRef = useRef(null); const ntrpRef = useRef(null);
// const userInfo = useUserInfo(); const { id, price, user_action_status, end_time, is_organizer } =
// const { id } = userInfo; detail || {};
const {
id, const gameManageRef = useRef();
publisher_id,
match_status,
price,
user_action_status,
end_time,
} = detail || {};
function handleSelfEvaluate() { function handleSelfEvaluate() {
// TODO: 打开自评弹窗 // TODO: 打开自评弹窗
@@ -240,13 +243,14 @@ function StickyButton(props) {
} }
function generateTextAndAction( function generateTextAndAction(
user_action_status: null | { [key: string]: boolean }, user_action_status: null | { [key: string]: boolean }
): undefined | { text: string | React.FC; action: () => void } { ): undefined | { text: string | React.FC; action: () => void } {
if (!user_action_status) { if (!user_action_status) {
return; return;
} }
const displayPrice = is_organizer ? 0 : price;
// user_action_status.can_assess = true; // user_action_status.can_assess = true;
user_action_status.can_join = true; // user_action_status.can_join = true;
const { const {
can_assess, can_assess,
can_join, can_join,
@@ -260,27 +264,27 @@ function StickyButton(props) {
dayjs(end_time).isBefore(dayjs()) dayjs(end_time).isBefore(dayjs())
) { ) {
return { return {
text: "球局已结束,查看其他球局", text: "活动已结束",
action: navto.bind(null, "/game_pages/list/index"), action: () => toast("活动已结束"),
}; };
} }
if (waiting_start) { if (waiting_start) {
return { return {
text: "等待开始, 查看更多球局", text: () => <Text>¥{displayPrice} </Text>,
action: navto.bind(null, "/game_pages/list/index"), action: () => toast("已加入"),
}; };
} else if (is_substituting) { } else if (is_substituting) {
return { return {
text: "候补中,查看其他球局", text: () => <Text>¥{displayPrice} </Text>,
action: navto.bind(null, "/game_pages/list/index"), action: () => toast("已加入候补"),
}; };
} else if (can_pay) { } else if (can_pay) {
return { return {
text: "继续支付", text: () => <Text>¥{price} </Text>,
action: async () => { action: async () => {
const res = await OrderService.getUnpaidOrder(id); const res = await OrderService.getUnpaidOrder(id);
if (res.code === 0) { if (res.code === 0) {
Taro.navigateTo({ navto({
url: `/order_pages/orderDetail/index?id=${res.data.order_info.order_id}`, url: `/order_pages/orderDetail/index?id=${res.data.order_info.order_id}`,
}); });
} }
@@ -288,21 +292,13 @@ function StickyButton(props) {
}; };
} else if (can_substitute) { } else if (can_substitute) {
return { return {
text: "立即候补", text: () => <Text>¥{displayPrice} </Text>,
action: handleJoinGame, action: handleJoinGame,
}; };
} else if (can_join) { } else if (can_join) {
return { return {
text: () => { text: () => {
return ( return <Text>¥{displayPrice} </Text>;
<>
<Text>🎾</Text>
<Text></Text>
<View className="game-price">
<Text>¥ {price}</Text>
</View>
</>
);
}, },
action: handleJoinGame, action: handleJoinGame,
}; };
@@ -315,7 +311,7 @@ function StickyButton(props) {
scene={SceneType.DETAIL} scene={SceneType.DETAIL}
displayCondition={DisplayConditionType.AUTO} displayCondition={DisplayConditionType.AUTO}
> >
<Text>NTRP自评</Text> <Text>¥{displayPrice} </Text>
</NTRPEvaluatePopup> </NTRPEvaluatePopup>
), ),
action: handleSelfEvaluate, action: handleSelfEvaluate,
@@ -341,9 +337,8 @@ function StickyButton(props) {
}; };
} }
// const role = Number(publisher_id) === id ? "ownner" : "visitor";
return ( return (
<>
<View className="sticky-bottom-bar"> <View className="sticky-bottom-bar">
<View className="sticky-bottom-bar-share-and-comment"> <View className="sticky-bottom-bar-share-and-comment">
<View className="sticky-bottom-bar-share" onClick={handleShare}> <View className="sticky-bottom-bar-share" onClick={handleShare}>
@@ -367,10 +362,24 @@ function StickyButton(props) {
<Text className="sticky-bottom-bar-comment-text">32</Text> <Text className="sticky-bottom-bar-comment-text">32</Text>
</View> </View>
</View> </View>
<View className="detail-main-action">
<View className="sticky-bottom-bar-join-game" onClick={action}> <View className="sticky-bottom-bar-join-game" onClick={action}>
<ActionText /> <ActionText />
</View> </View>
{is_organizer && (
<View
className="game_manage"
onClick={() => {
gameManageRef.current.show(detail, onStatusChange);
}}
>
</View> </View>
)}
</View>
</View>
<GameManagePopup ref={gameManageRef} />
</>
); );
} }
@@ -612,10 +621,11 @@ function VenueInfo(props) {
} }
function genNTRPRequirementText(min, max) { function genNTRPRequirementText(min, max) {
console.log(min, max, "ntrp");
if (min && max && min !== max) { if (min && max && min !== max) {
return `${min} - ${max} 之间`; return `${min} - ${max} 之间`;
} else if (max === 1) { } else if (max === "1") {
return "没有要求"; return "要求";
} else if (max) { } else if (max) {
return `${max} 以上`; return `${max} 以上`;
} }
@@ -675,10 +685,9 @@ function Participants(props) {
user_action_status; user_action_status;
const showApplicationEntry = const showApplicationEntry =
[can_pay, can_substitute, is_substituting, waiting_start].every( [can_pay, can_substitute, is_substituting, waiting_start].every(
(item) => !item, (item) => !item
) && can_join; ) && can_join;
const leftCount = max_participants - participant_count; const leftCount = max_participants - participant_count;
const organizer_id = Number(detail.publisher_id);
return ( return (
<View className="detail-page-content-participants"> <View className="detail-page-content-participants">
<View className="participants-title"> <View className="participants-title">
@@ -694,7 +703,6 @@ function Participants(props) {
className="participants-list-application" className="participants-list-application"
onClick={() => { onClick={() => {
handleJoinGame(); handleJoinGame();
// Taro.showToast({ title: "To be continued", icon: "none" });
}} }}
> >
<Image <Image
@@ -711,11 +719,14 @@ function Participants(props) {
<View <View
className="participants-list-scroll-content" className="participants-list-scroll-content"
style={{ style={{
width: `${participants.length * 103 + (participants.length - 1) * 8}px`, width: `${
participants.length * 103 + (participants.length - 1) * 8
}px`,
}} }}
> >
{participants.map((participant) => { {participants.map((participant) => {
const { const {
is_organizer,
user: { user: {
avatar_url, avatar_url,
nickname, nickname,
@@ -723,15 +734,17 @@ function Participants(props) {
id: participant_user_id, id: participant_user_id,
}, },
} = participant; } = participant;
const role = const role = is_organizer ? "组织者" : "参与者";
participant_user_id === organizer_id ? "组织者" : "参与者";
return ( return (
<View key={participant.id} className="participants-list-item"> <View key={participant.id} className="participants-list-item">
<Image <Image
className="participants-list-item-avatar" className="participants-list-item-avatar"
mode="aspectFill" mode="aspectFill"
src={avatar_url} src={avatar_url}
onClick={handleViewUserInfo.bind(null, participant_user_id)} onClick={handleViewUserInfo.bind(
null,
participant_user_id
)}
/> />
<Text className="participants-list-item-name"> <Text className="participants-list-item-name">
{nickname || "未知"} {nickname || "未知"}
@@ -813,7 +826,12 @@ function genRecommendGames(games, location, avatar) {
avatar, avatar,
applications: max_players, applications: max_players,
checkedApplications: current_players, checkedApplications: current_players,
levelRequirements: skill_level_max !== skill_level_min ? `${skill_level_min || '-'}${skill_level_max || '-'}` : skill_level_min === 1 ? '无要求' : `${skill_level_min}以上`, levelRequirements:
skill_level_max !== skill_level_min
? `${skill_level_min || "-"}${skill_level_max || "-"}`
: skill_level_min === "1"
? "无要求"
: `${skill_level_min}以上`,
playType: play_type, playType: play_type,
}; };
}); });
@@ -862,9 +880,9 @@ function OrganizerInfo(props) {
}; };
function handleViewGame(gameId) { function handleViewGame(gameId) {
Taro.navigateTo({ navto({
url: `/game_pages/detail/index?id=${gameId}&from=current` url: `/game_pages/detail/index?id=${gameId}&from=current`,
}) });
} }
return ( return (
@@ -875,7 +893,12 @@ function OrganizerInfo(props) {
</View> </View>
{/* organizer avatar and name */} {/* organizer avatar and name */}
<View className="organizer-avatar-name"> <View className="organizer-avatar-name">
<Image className="organizer-avatar-name-avatar" src={avatar_url} mode="aspectFill" onClick={handleViewUserInfo.bind(null, id)} /> <Image
className="organizer-avatar-name-avatar"
src={avatar_url}
mode="aspectFill"
onClick={handleViewUserInfo.bind(null, id)}
/>
<View className="organizer-avatar-name-message"> <View className="organizer-avatar-name-message">
<Text className="organizer-avatar-name-message-name">{nickname}</Text> <Text className="organizer-avatar-name-message-name">{nickname}</Text>
<View className="organizer-avatar-name-message-stats"> <View className="organizer-avatar-name-message-stats">
@@ -914,8 +937,12 @@ function OrganizerInfo(props) {
</View> </View>
</View> </View>
{/* recommend games by organizer */} {/* recommend games by organizer */}
{recommendGames.length > 0 && (
<View className="organizer-recommend-games"> <View className="organizer-recommend-games">
<View className="organizer-recommend-games-title" onClick={handleViewUserInfo.bind(null, id)}> <View
className="organizer-recommend-games-title"
onClick={handleViewUserInfo.bind(null, id)}
>
<Text>TA的更多活动</Text> <Text>TA的更多活动</Text>
<Image <Image
className="organizer-recommend-games-title-arrow" className="organizer-recommend-games-title-arrow"
@@ -925,7 +952,11 @@ function OrganizerInfo(props) {
<ScrollView className="recommend-games-list" scrollX> <ScrollView className="recommend-games-list" scrollX>
<View className="recommend-games-list-content"> <View className="recommend-games-list-content">
{recommendGames.map((game, index) => ( {recommendGames.map((game, index) => (
<View key={index} className="recommend-games-list-item" onClick={handleViewGame.bind(null, game.id)}> <View
key={index}
className="recommend-games-list-item"
onClick={handleViewGame.bind(null, game.id)}
>
{/* game title */} {/* game title */}
<View className="recommend-games-list-item-title"> <View className="recommend-games-list-item-title">
<Text>{game.title}</Text> <Text>{game.title}</Text>
@@ -953,12 +984,16 @@ function OrganizerInfo(props) {
className="recommend-games-list-item-addon-avatar" className="recommend-games-list-item-addon-avatar"
mode="aspectFill" mode="aspectFill"
src={game.avatar} src={game.avatar}
onClick={(e) => { e.stopPropagation(); handleViewUserInfo(id) }} onClick={(e) => {
e.stopPropagation();
handleViewUserInfo(id);
}}
/> />
<View className="recommend-games-list-item-addon-message"> <View className="recommend-games-list-item-addon-message">
<View className="recommend-games-list-item-addon-message-applications"> <View className="recommend-games-list-item-addon-message-applications">
<Text> <Text>
{game.checkedApplications}/{game.applications} {game.checkedApplications}/
{game.applications}
</Text> </Text>
</View> </View>
<View className="recommend-games-list-item-addon-message-level-requirements"> <View className="recommend-games-list-item-addon-message-level-requirements">
@@ -974,6 +1009,7 @@ function OrganizerInfo(props) {
</View> </View>
</ScrollView> </ScrollView>
</View> </View>
)}
</View> </View>
); );
} }
@@ -987,6 +1023,9 @@ function Index() {
const { id, from } = params; const { id, from } = params;
const [userInfo, setUserInfo] = useState({}); // 组织者的userInfo const [userInfo, setUserInfo] = useState({}); // 组织者的userInfo
const { fetchUserInfo } = useUserActions(); // 获取登录用户的userInfo const { fetchUserInfo } = useUserActions(); // 获取登录用户的userInfo
const myInfo = useUserInfo();
const isMyOwn = userInfo.id === myInfo.id;
const sharePopupRef = useRef<any>(null); const sharePopupRef = useRef<any>(null);
@@ -1031,7 +1070,6 @@ function Index() {
async function fetchUserInfoById(user_id) { async function fetchUserInfoById(user_id) {
const userDetailInfo = await LoginService.getUserInfoById(user_id); const userDetailInfo = await LoginService.getUserInfoById(user_id);
if (userDetailInfo.code === 0) { if (userDetailInfo.code === 0) {
// console.log(userDetailInfo.data);
setUserInfo(userDetailInfo.data); setUserInfo(userDetailInfo.data);
} }
} }
@@ -1040,12 +1078,26 @@ function Index() {
sharePopupRef.current.show(); sharePopupRef.current.show();
} }
const handleJoinGame = () => { const handleJoinGame = async () => {
Taro.navigateTo({ if (isMyOwn) {
const res = await DetailService.organizerJoin(Number(id));
if (res.code === 0) {
toast("加入成功");
fetchDetail();
}
return;
}
navto({
url: `/order_pages/orderDetail/index?gameId=${id}`, url: `/order_pages/orderDetail/index?gameId=${id}`,
}); });
}; };
function onStatusChange(result) {
if (result) {
fetchDetail();
}
}
function handleBack() { function handleBack() {
const pages = Taro.getCurrentPages(); const pages = Taro.getCurrentPages();
if (pages.length <= 1) { if (pages.length <= 1) {
@@ -1058,9 +1110,9 @@ function Index() {
} }
function handleViewUserInfo(userId) { function handleViewUserInfo(userId) {
Taro.navigateTo({ navto({
url: `/user_pages/other/index?userid=${userId}` url: `/user_pages/other/index?userid=${userId}`,
}) });
} }
console.log("detail", detail); console.log("detail", detail);
@@ -1093,7 +1145,11 @@ function Index() {
{/* content */} {/* content */}
<View className="detail-page-content"> <View className="detail-page-content">
{/* avatar and tags */} {/* avatar and tags */}
<GameTags detail={detail} userInfo={userInfo} handleViewUserInfo={handleViewUserInfo} /> <GameTags
detail={detail}
userInfo={userInfo}
handleViewUserInfo={handleViewUserInfo}
/>
{/* title */} {/* title */}
<View className="detail-page-content-title"> <View className="detail-page-content-title">
<Text className="detail-page-content-title-text">{detail.title}</Text> <Text className="detail-page-content-title-text">{detail.title}</Text>
@@ -1105,7 +1161,11 @@ function Index() {
{/* gameplay requirements */} {/* gameplay requirements */}
<GamePlayAndRequirement detail={detail} /> <GamePlayAndRequirement detail={detail} />
{/* participants */} {/* participants */}
<Participants detail={detail} handleJoinGame={handleJoinGame} handleViewUserInfo={handleViewUserInfo} /> <Participants
detail={detail}
handleJoinGame={handleJoinGame}
handleViewUserInfo={handleViewUserInfo}
/>
{/* supplemental notes */} {/* supplemental notes */}
<SupplementalNotes detail={detail} /> <SupplementalNotes detail={detail} />
{/* organizer and recommend games by organizer */} {/* organizer and recommend games by organizer */}
@@ -1121,6 +1181,7 @@ function Index() {
handleShare={handleShare} handleShare={handleShare}
handleJoinGame={handleJoinGame} handleJoinGame={handleJoinGame}
detail={detail} detail={detail}
onStatusChange={onStatusChange}
/> />
{/* share popup */} {/* share popup */}
<SharePopup <SharePopup

View File

@@ -50,7 +50,7 @@ function generateTimeMsg(game_info) {
: startTime.format("YYYY-MM-DD")} : startTime.format("YYYY-MM-DD")}
</Text> </Text>
<Text>({DayOfWeekMap.get(dayofWeek)})</Text> <Text>({DayOfWeekMap.get(dayofWeek)})</Text>
<Text>{startTime.format('ah')}</Text> <Text>{startTime.format("ah")}</Text>
<Text>{gameLength}</Text> <Text>{gameLength}</Text>
</> </>
); );
@@ -59,7 +59,7 @@ function generateTimeMsg(game_info) {
const OrderList = () => { const OrderList = () => {
const [list, setList] = useState<any[][]>([]); const [list, setList] = useState<any[][]>([]);
const [total, setTotal] = useState(0); const [total, setTotal] = useState(0);
const refundRef = useRef(null) const refundRef = useRef(null);
const end = list.length * PAGESIZE >= total; const end = list.length * PAGESIZE >= total;
@@ -78,7 +78,7 @@ const OrderList = () => {
setTotal(res.data.count); setTotal(res.data.count);
setList((prev) => { setList((prev) => {
const newList = [...prev]; const newList = [...prev];
const index = page - 1 const index = page - 1;
newList.splice( newList.splice(
index, index,
clear ? newList.length - index : 1, clear ? newList.length - index : 1,
@@ -121,7 +121,7 @@ const OrderList = () => {
} }
async function handleDeleteOrder(item) { async function handleDeleteOrder(item) {
const { id: order_id } = item const { id: order_id } = item;
// TODO删除订单,刷新这一页,然后后面的全清除掉 // TODO删除订单,刷新这一页,然后后面的全清除掉
const onCancel = () => { const onCancel = () => {
Dialog.close("cancelOrder"); Dialog.close("cancelOrder");
@@ -138,7 +138,7 @@ const OrderList = () => {
Taro.showToast({ Taro.showToast({
title: "删除成功", title: "删除成功",
icon: "none", icon: "none",
}) });
} catch (e) { } catch (e) {
Taro.showToast({ Taro.showToast({
title: e.message, title: e.message,
@@ -156,18 +156,14 @@ const OrderList = () => {
<Button className={styles.cancel} onClick={onCancel}> <Button className={styles.cancel} onClick={onCancel}>
</Button> </Button>
<Button <Button className={styles.confirm} type="primary" onClick={onConfirm}>
className={styles.confirm}
type="primary"
onClick={onConfirm}
>
</Button> </Button>
</View> </View>
), ),
onConfirm, onConfirm,
onCancel, onCancel,
}) });
} }
async function handleCancelOrder(item) { async function handleCancelOrder(item) {
@@ -188,7 +184,7 @@ const OrderList = () => {
Taro.showToast({ Taro.showToast({
title: "取消成功", title: "取消成功",
icon: "none", icon: "none",
}) });
} catch (e) { } catch (e) {
Taro.showToast({ Taro.showToast({
title: e.message, title: e.message,
@@ -206,11 +202,7 @@ const OrderList = () => {
<Button className={styles.cancel} onClick={onCancel}> <Button className={styles.cancel} onClick={onCancel}>
</Button> </Button>
<Button <Button className={styles.confirm} type="primary" onClick={onConfirm}>
className={styles.confirm}
type="primary"
onClick={onConfirm}
>
</Button> </Button>
</View> </View>
@@ -224,9 +216,9 @@ const OrderList = () => {
if (refundRef.current) { if (refundRef.current) {
refundRef.current.show(item, (result) => { refundRef.current.show(item, (result) => {
if (result) { if (result) {
getOrders(item.page) getOrders(item.page);
} }
}) });
} }
} }
@@ -249,7 +241,9 @@ const OrderList = () => {
> >
{/* <View className={styles.bg} /> */} {/* <View className={styles.bg} /> */}
{list.flat().map((item) => { {list.flat().map((item) => {
const unPay = item.order_status === OrderStatus.PENDING && item.cancel_type === CancelType.NONE; const unPay =
item.order_status === OrderStatus.PENDING &&
item.cancel_type === CancelType.NONE;
const { const {
game_info: { game_info: {

View File

@@ -92,10 +92,8 @@ export interface UpdateLocationRes {
city: string; city: string;
district: string; district: string;
} }
// 发布球局类
class GameDetailService { class GameDetailService {
// 用户登录 // 查询球局详情
async getDetail(id: number): Promise<ApiResponse<GameData>> { async getDetail(id: number): Promise<ApiResponse<GameData>> {
return httpService.post( return httpService.post(
"/games/detail", "/games/detail",
@@ -114,6 +112,27 @@ class GameDetailService {
showLoading: true, showLoading: true,
}); });
} }
// 组织者加入球局
async organizerJoin(game_id: number): Promise<ApiResponse<any>> {
return httpService.post("/games/organizer_join", { game_id }, {
showLoading: true,
});
}
// 组织者退出球局
async organizerQuit(req: { game_id: number, quit_reason: string }): Promise<ApiResponse<any>> {
return httpService.post("/games/organizer_quit", req, {
showLoading: true,
});
}
// 组织者解散球局
async disbandGame(req: { game_id: number, settle_reason: string }): Promise<ApiResponse<any>> {
return httpService.post("/games/settle_game", req, {
showLoading: true,
});
}
} }
// 导出认证服务实例 // 导出认证服务实例