feat: 生成分享图

This commit is contained in:
2025-10-15 11:20:36 +08:00
parent 56fd71f266
commit 77e50731a3
30 changed files with 2756 additions and 2641 deletions

View File

@@ -0,0 +1,253 @@
import { useEffect, useRef, useState } from "react";
import Taro from "@tarojs/taro";
import classnames from "classnames";
import dayjs from "dayjs";
import { Text, View, Image } from "@tarojs/components";
import OrderService from "@/services/orderService";
import { EvaluateCallback, EvaluateScene } from "@/store/evaluateStore";
import { MATCH_STATUS, IsSubstituteSupported } from "@/services/detailService";
import { GameManagePopup, NTRPEvaluatePopup } from "@/components";
import img from "@/config/images";
import { toast, navto } from "../../utils/helper";
import styles from "./index.module.scss";
function isFull(counts) {
const {
max_players,
current_players,
max_substitute_players,
current_substitute_count,
is_substitute_supported,
} = counts;
if (max_players === current_players) {
return true;
} else if (is_substitute_supported === IsSubstituteSupported.SUPPORT) {
return max_substitute_players === current_substitute_count;
}
return false;
}
// 底部操作栏
export default function StickyButton(props) {
const {
handleShare,
handleJoinGame,
detail,
onStatusChange,
handleAddComment,
getCommentCount,
} = props;
const [commentCount, setCommentCount] = useState(0);
const ntrpRef = useRef<{
show: (evaluateCallback: EvaluateCallback) => void;
}>({ show: () => {} });
const {
id,
price,
user_action_status,
match_status,
start_time,
end_time,
is_organizer,
} = detail || {};
const gameManageRef = useRef();
function handleSelfEvaluate() {
ntrpRef?.current?.show({
type: EvaluateScene.detail,
next: (flag) => {
if (flag) {
Taro.navigateTo({
url: `/order_pages/orderDetail/index?gameId=${id}`,
});
return;
}
Taro.redirectTo({ url: `/order_pages/orderDetail/index?gameId=${id}` });
},
onCancel: () => {
// Taro.redirectTo({ url: `/game_pages/detail/index?id=${id}` });
Taro.navigateBack();
},
});
}
useEffect(() => {
getCommentCount?.((count) => {
setCommentCount(count);
});
}, [getCommentCount]);
function generateTextAndAction(
user_action_status: null | { [key: string]: boolean }
):
| undefined
| { text: string | React.FC; action?: () => void; available?: boolean } {
if (!user_action_status) {
return;
}
const displayPrice = is_organizer ? 0 : price;
// user_action_status.can_assess = true;
// user_action_status.can_join = false;
// console.log(user_action_status, "user_action");
const {
can_assess,
can_join,
can_substitute,
can_pay,
is_substituting,
waiting_start,
} = user_action_status || {};
if (MATCH_STATUS.CANCELED === match_status) {
return {
text: "活动已取消",
available: false,
// action: () => toast("活动已取消"),
};
} else if (dayjs(end_time).isBefore(dayjs())) {
return {
text: "活动已结束",
available: false,
// action: () => toast("活动已结束"),
};
} else if (dayjs(start_time).isBefore(dayjs())) {
return {
text: "活动已开始",
available: false,
// action: () => toast("活动已开始"),
};
} else if (isFull(detail)) {
return {
text: "活动已满员",
available: false,
// action: () => toast("活动已满员"),
};
}
if (waiting_start) {
return {
text: () => <Text>¥{displayPrice} </Text>,
action: () => toast("已加入"),
};
} else if (is_substituting) {
return {
text: () => <Text>¥{displayPrice} </Text>,
action: () => toast("已加入候补"),
};
} else if (can_pay) {
return {
text: () => <Text>¥{price} </Text>,
action: async () => {
const res = await OrderService.getUnpaidOrder(id);
if (res.code === 0) {
navto(
`/order_pages/orderDetail/index?id=${res.data.order_info.order_id}`
);
}
},
};
} else if (can_substitute) {
return {
text: () => <Text>¥{displayPrice} </Text>,
action: handleJoinGame,
};
} else if (can_join) {
return {
text: () => {
return <Text>¥{displayPrice} </Text>;
},
action: handleJoinGame,
};
} else if (can_assess) {
return {
text: () => <Text>¥{displayPrice} </Text>,
action: handleSelfEvaluate,
};
}
return {
text: "球局无法加入",
available: false,
};
}
if (!user_action_status) {
return "";
}
const {
text,
available = true,
action = () => {},
} = generateTextAndAction(user_action_status)!;
let ActionText: React.FC | string = text;
if (typeof ActionText === "string") {
ActionText = () => {
return <Text>{text as string}</Text>;
};
}
return (
<>
<View className={styles["sticky-bottom-bar"]}>
<View className={styles["sticky-bottom-bar-share-and-comment"]}>
<View
className={styles["sticky-bottom-bar-share"]}
onClick={() => handleShare()}
>
<Image
className={styles["sticky-bottom-bar-share-icon"]}
src={img.ICON_DETAIL_SHARE}
/>
<Text className={styles["sticky-bottom-bar-share-text"]}></Text>
</View>
<View
className={styles["sticky-bottom-bar-share-and-comment-separator"]}
/>
<View
className={styles["sticky-bottom-bar-comment"]}
onClick={() => {
// Taro.showToast({ title: "To be continued", icon: "none" });
handleAddComment();
}}
>
<Image
className={styles["sticky-bottom-bar-comment-icon"]}
src={img.ICON_DETAIL_COMMENT_DARK}
/>
<Text className={styles["sticky-bottom-bar-comment-text"]}>
{commentCount > 0 ? commentCount : "评论"}
</Text>
</View>
</View>
<View
className={classnames(
styles["detail-main-action"],
available ? "" : styles.disabled
)}
>
<View
style={is_organizer ? {} : { margin: "auto" }}
className={styles["sticky-bottom-bar-join-game"]}
onClick={action}
>
<ActionText />
</View>
{is_organizer && (
<View
className={styles.game_manage}
onClick={() => {
gameManageRef.current.show(detail, onStatusChange);
}}
>
</View>
)}
</View>
</View>
<GameManagePopup ref={gameManageRef} />
<NTRPEvaluatePopup type={EvaluateScene.detail} ref={ntrpRef} showGuide />
</>
);
}