diff --git a/src/components/GameManagePopup/index.module.scss b/src/components/GameManagePopup/index.module.scss
new file mode 100644
index 0000000..24fe1dc
--- /dev/null
+++ b/src/components/GameManagePopup/index.module.scss
@@ -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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/components/GameManagePopup/index.tsx b/src/components/GameManagePopup/index.tsx
new file mode 100644
index 0000000..12e6f34
--- /dev/null
+++ b/src/components/GameManagePopup/index.tsx
@@ -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 (
+ <>
+
+
+
+ >
+ );
+});
+
+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 (
+ <>
+
+
+
+ 编辑活动
+
+
+ 重新发布
+
+
+ 取消活动
+
+ {!hasJoin && (
+
+ 退出活动
+
+ )}
+
+ 取消
+
+
+
+
+ >
+ );
+});
diff --git a/src/components/NTRPEvaluatePopup/index.tsx b/src/components/NTRPEvaluatePopup/index.tsx
index 724f678..2f9caa8 100644
--- a/src/components/NTRPEvaluatePopup/index.tsx
+++ b/src/components/NTRPEvaluatePopup/index.tsx
@@ -91,7 +91,7 @@ const NTRPEvaluatePopup = (props: NTRPEvaluatePopupProps, ref) => {
- {showEntry && props.children}
+ {showEntry ? props.children : ''}
>
);
};
diff --git a/src/components/UploadCover/upload-source-popup.scss b/src/components/UploadCover/upload-source-popup.scss
index 999c934..bb8fbcd 100644
--- a/src/components/UploadCover/upload-source-popup.scss
+++ b/src/components/UploadCover/upload-source-popup.scss
@@ -31,7 +31,8 @@
}
.upload-popup-scroll-view {
- max-height: calc(100vh - 260px);
+ // max-height: calc(100vh - 260px);
+ height: 440px;
overflow-y: auto;
.upload-popup-image-list {
@@ -124,7 +125,7 @@
display: flex;
width: 100%;
height: 62px;
- padding: 8px 10px 10px 10px;
+ padding: 8px 10px 50px 10px;
box-sizing: border-box;
justify-content: center;
align-items: flex-start;
diff --git a/src/components/UploadCover/upload-source-popup.tsx b/src/components/UploadCover/upload-source-popup.tsx
index ddd4004..8a832c0 100644
--- a/src/components/UploadCover/upload-source-popup.tsx
+++ b/src/components/UploadCover/upload-source-popup.tsx
@@ -121,6 +121,7 @@ export default forwardRef(function UploadImage(props: UploadImageProps, ref) {
{images.length > 0 ? (
diff --git a/src/components/index.ts b/src/components/index.ts
index abc1c4a..44bc01e 100644
--- a/src/components/index.ts
+++ b/src/components/index.ts
@@ -17,6 +17,7 @@ import withAuth from "./Auth";
import { CustomPicker, PopupPicker } from "./Picker";
import NTRPEvaluatePopup from "./NTRPEvaluatePopup";
import RefundPopup from "./refundPopup";
+import GameManagePopup from './GameManagePopup'
export {
ActivityTypeSwitch,
@@ -39,4 +40,5 @@ export {
PopupPicker,
NTRPEvaluatePopup,
RefundPopup,
+ GameManagePopup,
};
diff --git a/src/game_pages/detail/index.scss b/src/game_pages/detail/index.scss
index da114ba..d851af7 100644
--- a/src/game_pages/detail/index.scss
+++ b/src/game_pages/detail/index.scss
@@ -807,7 +807,7 @@
}
&-organizer-recommend-games {
- padding: 24px 15px 0;
+ padding: 24px 15px 10px;
.organizer-title {
overflow: hidden;
@@ -1122,27 +1122,47 @@
}
}
- &-join-game {
+ .detail-main-action {
display: flex;
align-items: center;
height: 52px;
width: auto;
- padding: 2px 6px;
+ // padding: 2px 6px;
box-sizing: border-box;
justify-content: center;
gap: 12px;
flex: 1 0 0;
border-radius: 16px;
- border: 1px solid rgba(0, 0, 0, 0.06);
+ // border: 1px solid rgba(0, 0, 0, 0.06);
background: #fff;
+ overflow: hidden;
- &-price {
- font-family: "PoetsenOne";
- font-size: 28px;
- font-weight: 400;
- line-height: 24px; /* 114.286% */
- letter-spacing: -0.56px;
- color: #000;
+ .sticky-bottom-bar-join-game {
+ margin-left: auto;
+ width: 151px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ &-price {
+ font-family: "PoetsenOne";
+ font-size: 28px;
+ font-weight: 400;
+ line-height: 24px; /* 114.286% */
+ letter-spacing: -0.56px;
+ color: #000;
+ }
+ }
+
+ .game_manage {
+ width: 100px;
+ margin-left: auto;
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: #000;
+ color: #fff;
}
}
}
diff --git a/src/game_pages/detail/index.tsx b/src/game_pages/detail/index.tsx
index 29bc5bf..af9597c 100644
--- a/src/game_pages/detail/index.tsx
+++ b/src/game_pages/detail/index.tsx
@@ -16,7 +16,12 @@ import Taro, {
import dayjs from "dayjs";
import "dayjs/locale/zh-cn";
// 导入API服务
-import { CommonPopup, withAuth, NTRPEvaluatePopup } from "@/components";
+import {
+ CommonPopup,
+ withAuth,
+ NTRPEvaluatePopup,
+ GameManagePopup,
+} from "@/components";
import {
EvaluateType,
SceneType,
@@ -210,7 +215,7 @@ const SharePopup = forwardRef(
);
- },
+ }
);
function navto(url) {
@@ -219,20 +224,18 @@ function navto(url) {
});
}
+function toast(message) {
+ Taro.showToast({ title: message, icon: "none" });
+}
+
// 底部操作栏
function StickyButton(props) {
- const { handleShare, handleJoinGame, detail } = props;
+ const { handleShare, handleJoinGame, detail, onStatusChange } = props;
const ntrpRef = useRef(null);
- // const userInfo = useUserInfo();
- // const { id } = userInfo;
- const {
- id,
- publisher_id,
- match_status,
- price,
- user_action_status,
- end_time,
- } = detail || {};
+ const { id, price, user_action_status, end_time, is_organizer } =
+ detail || {};
+
+ const gameManageRef = useRef();
function handleSelfEvaluate() {
// TODO: 打开自评弹窗
@@ -240,13 +243,14 @@ function StickyButton(props) {
}
function generateTextAndAction(
- user_action_status: null | { [key: string]: boolean },
+ user_action_status: null | { [key: string]: boolean }
): undefined | { text: string | React.FC; action: () => void } {
if (!user_action_status) {
return;
}
+ const displayPrice = is_organizer ? 0 : price;
// user_action_status.can_assess = true;
- user_action_status.can_join = true;
+ // user_action_status.can_join = true;
const {
can_assess,
can_join,
@@ -260,27 +264,27 @@ function StickyButton(props) {
dayjs(end_time).isBefore(dayjs())
) {
return {
- text: "球局已结束,查看其他球局",
- action: navto.bind(null, "/game_pages/list/index"),
+ text: "活动已结束",
+ action: () => toast("活动已结束"),
};
}
if (waiting_start) {
return {
- text: "等待开始, 查看更多球局",
- action: navto.bind(null, "/game_pages/list/index"),
+ text: () => ¥{displayPrice} 已加入,
+ action: () => toast("已加入"),
};
} else if (is_substituting) {
return {
- text: "候补中,查看其他球局",
- action: navto.bind(null, "/game_pages/list/index"),
+ text: () => ¥{displayPrice} 已加入候补,
+ action: () => toast("已加入候补"),
};
} else if (can_pay) {
return {
- text: "继续支付",
+ text: () => ¥{price} 继续支付,
action: async () => {
const res = await OrderService.getUnpaidOrder(id);
if (res.code === 0) {
- Taro.navigateTo({
+ navto({
url: `/order_pages/orderDetail/index?id=${res.data.order_info.order_id}`,
});
}
@@ -288,21 +292,13 @@ function StickyButton(props) {
};
} else if (can_substitute) {
return {
- text: "立即候补",
+ text: () => ¥{displayPrice} 我要候补,
action: handleJoinGame,
};
} else if (can_join) {
return {
text: () => {
- return (
- <>
- 🎾
- 立即加入
-
- ¥ {price}
-
- >
- );
+ return ¥{displayPrice} 立即加入;
},
action: handleJoinGame,
};
@@ -315,7 +311,7 @@ function StickyButton(props) {
scene={SceneType.DETAIL}
displayCondition={DisplayConditionType.AUTO}
>
- NTRP自评
+ ¥{displayPrice} 立即加入
),
action: handleSelfEvaluate,
@@ -341,36 +337,49 @@ function StickyButton(props) {
};
}
- // const role = Number(publisher_id) === id ? "ownner" : "visitor";
-
return (
-
-
-
-
- 分享
+ <>
+
+
+
+
+ 分享
+
+
+ {
+ Taro.showToast({ title: "To be continued", icon: "none" });
+ }}
+ >
+
+ 32
+
-
- {
- Taro.showToast({ title: "To be continued", icon: "none" });
- }}
- >
-
- 32
+
+
+
+
+ {is_organizer && (
+ {
+ gameManageRef.current.show(detail, onStatusChange);
+ }}
+ >
+ 管理
+
+ )}
-
-
-
-
+
+ >
);
}
@@ -612,10 +621,11 @@ function VenueInfo(props) {
}
function genNTRPRequirementText(min, max) {
+ console.log(min, max, "ntrp");
if (min && max && min !== max) {
return `${min} - ${max} 之间`;
- } else if (max === 1) {
- return "没有要求";
+ } else if (max === "1") {
+ return "无要求";
} else if (max) {
return `${max} 以上`;
}
@@ -675,10 +685,9 @@ function Participants(props) {
user_action_status;
const showApplicationEntry =
[can_pay, can_substitute, is_substituting, waiting_start].every(
- (item) => !item,
+ (item) => !item
) && can_join;
const leftCount = max_participants - participant_count;
- const organizer_id = Number(detail.publisher_id);
return (
@@ -694,7 +703,6 @@ function Participants(props) {
className="participants-list-application"
onClick={() => {
handleJoinGame();
- // Taro.showToast({ title: "To be continued", icon: "none" });
}}
>
{participants.map((participant) => {
const {
+ is_organizer,
user: {
avatar_url,
nickname,
@@ -723,15 +734,17 @@ function Participants(props) {
id: participant_user_id,
},
} = participant;
- const role =
- participant_user_id === organizer_id ? "组织者" : "参与者";
+ const role = is_organizer ? "组织者" : "参与者";
return (
{nickname || "未知"}
@@ -813,7 +826,12 @@ function genRecommendGames(games, location, avatar) {
avatar,
applications: max_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,
};
});
@@ -862,9 +880,9 @@ function OrganizerInfo(props) {
};
function handleViewGame(gameId) {
- Taro.navigateTo({
- url: `/game_pages/detail/index?id=${gameId}&from=current`
- })
+ navto({
+ url: `/game_pages/detail/index?id=${gameId}&from=current`,
+ });
}
return (
@@ -875,7 +893,12 @@ function OrganizerInfo(props) {
{/* organizer avatar and name */}
-
+
{nickname}
@@ -914,66 +937,79 @@ function OrganizerInfo(props) {
{/* recommend games by organizer */}
-
-
- TA的更多活动
-
-
-
-
- {recommendGames.map((game, index) => (
-
- {/* game title */}
-
- {game.title}
-
-
- {/* game time and range */}
-
- {game.time}
- {game.timeLength}
-
- {/* game location、vunue、distance */}
-
- {game.venue}
- ·
- {game.venueType}
- ·
- {game.distance}
-
- {/* organizer avatar、applications、level requirements、play type */}
-
- { e.stopPropagation(); handleViewUserInfo(id) }}
- />
-
-
-
- 报名人数 {game.checkedApplications}/{game.applications}
-
-
-
- {game.levelRequirements}
-
-
- {game.playType}
+ {recommendGames.length > 0 && (
+
+
+ TA的更多活动
+
+
+
+
+ {recommendGames.map((game, index) => (
+
+ {/* game title */}
+
+ {game.title}
+
+
+ {/* game time and range */}
+
+ {game.time}
+ {game.timeLength}
+
+ {/* game location、vunue、distance */}
+
+ {game.venue}
+ ·
+ {game.venueType}
+ ·
+ {game.distance}
+
+ {/* organizer avatar、applications、level requirements、play type */}
+
+ {
+ e.stopPropagation();
+ handleViewUserInfo(id);
+ }}
+ />
+
+
+
+ 报名人数 {game.checkedApplications}/
+ {game.applications}
+
+
+
+ {game.levelRequirements}
+
+
+ {game.playType}
+
-
- ))}
-
-
-
+ ))}
+
+
+
+ )}
);
}
@@ -987,6 +1023,9 @@ function Index() {
const { id, from } = params;
const [userInfo, setUserInfo] = useState({}); // 组织者的userInfo
const { fetchUserInfo } = useUserActions(); // 获取登录用户的userInfo
+ const myInfo = useUserInfo();
+
+ const isMyOwn = userInfo.id === myInfo.id;
const sharePopupRef = useRef(null);
@@ -1031,7 +1070,6 @@ function Index() {
async function fetchUserInfoById(user_id) {
const userDetailInfo = await LoginService.getUserInfoById(user_id);
if (userDetailInfo.code === 0) {
- // console.log(userDetailInfo.data);
setUserInfo(userDetailInfo.data);
}
}
@@ -1040,12 +1078,26 @@ function Index() {
sharePopupRef.current.show();
}
- const handleJoinGame = () => {
- Taro.navigateTo({
+ const handleJoinGame = async () => {
+ if (isMyOwn) {
+ const res = await DetailService.organizerJoin(Number(id));
+ if (res.code === 0) {
+ toast("加入成功");
+ fetchDetail();
+ }
+ return;
+ }
+ navto({
url: `/order_pages/orderDetail/index?gameId=${id}`,
});
};
+ function onStatusChange(result) {
+ if (result) {
+ fetchDetail();
+ }
+ }
+
function handleBack() {
const pages = Taro.getCurrentPages();
if (pages.length <= 1) {
@@ -1058,9 +1110,9 @@ function Index() {
}
function handleViewUserInfo(userId) {
- Taro.navigateTo({
- url: `/user_pages/other/index?userid=${userId}`
- })
+ navto({
+ url: `/user_pages/other/index?userid=${userId}`,
+ });
}
console.log("detail", detail);
@@ -1093,7 +1145,11 @@ function Index() {
{/* content */}
{/* avatar and tags */}
-
+
{/* title */}
{detail.title}
@@ -1105,7 +1161,11 @@ function Index() {
{/* gameplay requirements */}
{/* participants */}
-
+
{/* supplemental notes */}
{/* organizer and recommend games by organizer */}
@@ -1121,6 +1181,7 @@ function Index() {
handleShare={handleShare}
handleJoinGame={handleJoinGame}
detail={detail}
+ onStatusChange={onStatusChange}
/>
{/* share popup */}
({DayOfWeekMap.get(dayofWeek)})
- {startTime.format('ah')}点
+ {startTime.format("ah")}点
{gameLength}
>
);
@@ -59,7 +59,7 @@ function generateTimeMsg(game_info) {
const OrderList = () => {
const [list, setList] = useState([]);
const [total, setTotal] = useState(0);
- const refundRef = useRef(null)
+ const refundRef = useRef(null);
const end = list.length * PAGESIZE >= total;
@@ -78,7 +78,7 @@ const OrderList = () => {
setTotal(res.data.count);
setList((prev) => {
const newList = [...prev];
- const index = page - 1
+ const index = page - 1;
newList.splice(
index,
clear ? newList.length - index : 1,
@@ -121,53 +121,49 @@ const OrderList = () => {
}
async function handleDeleteOrder(item) {
- const { id: order_id } = item
+ const { id: order_id } = item;
// TODO:删除订单,刷新这一页,然后后面的全清除掉
const onCancel = () => {
- Dialog.close("cancelOrder");
- };
- const onConfirm = async () => {
- try {
- const deleteRes = await orderService.deleteOrder({
- order_id,
- });
- if (deleteRes.code !== 0) {
- throw new Error(deleteRes.message);
- }
- getOrders(item.page);
- Taro.showToast({
- title: "删除成功",
- icon: "none",
- })
- } catch (e) {
- Taro.showToast({
- title: e.message,
- icon: "error",
- });
- } finally {
- Dialog.close("cancelOrder");
+ Dialog.close("cancelOrder");
+ };
+ const onConfirm = async () => {
+ try {
+ const deleteRes = await orderService.deleteOrder({
+ order_id,
+ });
+ if (deleteRes.code !== 0) {
+ throw new Error(deleteRes.message);
}
- };
+ getOrders(item.page);
+ Taro.showToast({
+ title: "删除成功",
+ icon: "none",
+ });
+ } catch (e) {
+ Taro.showToast({
+ title: e.message,
+ icon: "error",
+ });
+ } finally {
+ Dialog.close("cancelOrder");
+ }
+ };
Dialog.open("cancelOrder", {
title: "确定删除订单吗?",
content: "删除订单后,您将无法恢复订单。请确认是否继续取消?",
- footer: (
-
-
-
-
- ),
- onConfirm,
- onCancel,
- })
+ footer: (
+
+
+
+
+ ),
+ onConfirm,
+ onCancel,
+ });
}
async function handleCancelOrder(item) {
@@ -188,7 +184,7 @@ const OrderList = () => {
Taro.showToast({
title: "取消成功",
icon: "none",
- })
+ });
} catch (e) {
Taro.showToast({
title: e.message,
@@ -206,11 +202,7 @@ const OrderList = () => {
-
@@ -220,13 +212,13 @@ const OrderList = () => {
});
}
- function handleQuit (item) {
+ function handleQuit(item) {
if (refundRef.current) {
refundRef.current.show(item, (result) => {
if (result) {
- getOrders(item.page)
+ getOrders(item.page);
}
- })
+ });
}
}
@@ -249,7 +241,9 @@ const OrderList = () => {
>
{/* */}
{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 {
game_info: {
diff --git a/src/services/detailService.ts b/src/services/detailService.ts
index 8d03adf..2b8cf62 100644
--- a/src/services/detailService.ts
+++ b/src/services/detailService.ts
@@ -92,10 +92,8 @@ export interface UpdateLocationRes {
city: string;
district: string;
}
-
-// 发布球局类
class GameDetailService {
- // 用户登录
+ // 查询球局详情
async getDetail(id: number): Promise> {
return httpService.post(
"/games/detail",
@@ -114,6 +112,27 @@ class GameDetailService {
showLoading: true,
});
}
+
+ // 组织者加入球局
+ async organizerJoin(game_id: number): Promise> {
+ return httpService.post("/games/organizer_join", { game_id }, {
+ showLoading: true,
+ });
+ }
+
+ // 组织者退出球局
+ async organizerQuit(req: { game_id: number, quit_reason: string }): Promise> {
+ return httpService.post("/games/organizer_quit", req, {
+ showLoading: true,
+ });
+ }
+
+ // 组织者解散球局
+ async disbandGame(req: { game_id: number, settle_reason: string }): Promise> {
+ return httpService.post("/games/settle_game", req, {
+ showLoading: true,
+ });
+ }
}
// 导出认证服务实例