feat: 申请加入、退款政策、支付倒计时、详情页发布者信息展示
This commit is contained in:
@@ -20,9 +20,9 @@
|
||||
|
||||
.specTips {
|
||||
padding-bottom: 20px;
|
||||
color: rgba(60, 60, 67, 0.60);
|
||||
color: rgba(60, 60, 67, 0.6);
|
||||
text-align: center;
|
||||
font-feature-settings: 'liga' off, 'clig' off;
|
||||
font-feature-settings: "liga" off, "clig" off;
|
||||
font-family: "PingFang SC";
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
@@ -42,22 +42,55 @@
|
||||
align-items: center;
|
||||
color: #000;
|
||||
text-align: center;
|
||||
font-feature-settings:
|
||||
"liga" off,
|
||||
"clig" off;
|
||||
font-feature-settings: "liga" off, "clig" off;
|
||||
font-family: "PingFang SC";
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.06);
|
||||
&.pastItem {
|
||||
color: #3c3c43;
|
||||
}
|
||||
|
||||
&.currentItem {
|
||||
position: relative;
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 3px;
|
||||
height: 100%;
|
||||
background: #007aff;
|
||||
z-index: 0;
|
||||
}
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 3px;
|
||||
top: 15px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid;
|
||||
border-width: 3px 0 3px 6px;
|
||||
border-color: transparent transparent transparent #007bff;
|
||||
z-index: 0;
|
||||
}
|
||||
.currentTag {
|
||||
color: #007aff;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
font-family: "pingfang SC";
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-child(1) {
|
||||
color: #000;
|
||||
text-align: center;
|
||||
font-feature-settings:
|
||||
"liga" off,
|
||||
"clig" off;
|
||||
font-feature-settings: "liga" off, "clig" off;
|
||||
font-family: "PingFang SC";
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
@@ -72,6 +105,11 @@
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.time {
|
||||
text-align: left;
|
||||
padding-left: 30px;
|
||||
}
|
||||
|
||||
.rule {
|
||||
border-left: 1px solid rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
@@ -92,7 +130,7 @@
|
||||
.title {
|
||||
color: #000;
|
||||
text-align: center;
|
||||
font-feature-settings: 'liga' off, 'clig' off;
|
||||
font-feature-settings: "liga" off, "clig" off;
|
||||
font-family: "PingFang SC";
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
@@ -117,11 +155,11 @@
|
||||
height: 52px;
|
||||
border-radius: 16px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.06);
|
||||
box-shadow: 0 8px 64px 0 rgba(0, 0, 0, 0.10);
|
||||
box-shadow: 0 8px 64px 0 rgba(0, 0, 0, 0.1);
|
||||
backdrop-filter: blur(16px);
|
||||
color: #fff;
|
||||
background-color: #000;
|
||||
font-feature-settings: 'liga' off, 'clig' off;
|
||||
font-feature-settings: "liga" off, "clig" off;
|
||||
font-family: "PingFang SC";
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
|
||||
@@ -6,6 +6,7 @@ import React, {
|
||||
} from "react";
|
||||
import { View, Text, Button, Image } from "@tarojs/components";
|
||||
import Taro from "@tarojs/taro";
|
||||
import classnames from "classnames";
|
||||
import dayjs from "dayjs";
|
||||
import { CommonPopup } from "@/components";
|
||||
import orderService from "@/services/orderService";
|
||||
@@ -47,18 +48,25 @@ function genRefundNotice(refund_policy) {
|
||||
|
||||
function renderCancelContent(checkOrderInfo) {
|
||||
const { refund_policy = [] } = checkOrderInfo;
|
||||
const current = dayjs();
|
||||
const policyList = [
|
||||
{
|
||||
time: "申请退款时间",
|
||||
rule: "退款规则",
|
||||
},
|
||||
...refund_policy.map((item) => {
|
||||
...refund_policy.map((item, index) => {
|
||||
const isLast = index === refund_policy.length - 1;
|
||||
return {
|
||||
time: item.application_time,
|
||||
rule: item.refund_rule,
|
||||
beforeCurrent: isLast
|
||||
? true
|
||||
: current.isBefore(dayjs(item.deadline_formatted)),
|
||||
};
|
||||
}),
|
||||
];
|
||||
console.log("policyList", policyList);
|
||||
const targetIndex = policyList.findIndex((item) => item.beforeCurrent);
|
||||
const { notice } = genRefundNotice(refund_policy);
|
||||
return (
|
||||
<View className={styles.refundPolicy}>
|
||||
@@ -69,8 +77,22 @@ function renderCancelContent(checkOrderInfo) {
|
||||
{/* 订单信息摘要 */}
|
||||
<View className={styles.policyList}>
|
||||
{policyList.map((item, index) => (
|
||||
<View key={index} className={styles.policyItem}>
|
||||
<View className={styles.time}>{item.time}</View>
|
||||
<View
|
||||
key={index}
|
||||
className={classnames(
|
||||
styles.policyItem,
|
||||
targetIndex > index && index !== 0 ? styles.pastItem : "",
|
||||
targetIndex === index ? styles.currentItem : ""
|
||||
)}
|
||||
>
|
||||
<View className={styles.time}>
|
||||
{targetIndex === index && (
|
||||
<View className={styles.currentTag}>
|
||||
<Text>当前时间段</Text>
|
||||
</View>
|
||||
)}
|
||||
<Text>{item.time}</Text>
|
||||
</View>
|
||||
<View className={styles.rule}>{item.rule}</View>
|
||||
</View>
|
||||
))}
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
flex: 0 0 40px;
|
||||
}
|
||||
|
||||
&-message {
|
||||
@@ -41,7 +42,11 @@
|
||||
font-size: 13px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 24px; /* 184.615% */
|
||||
line-height: 24px;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
max-width: 180px;
|
||||
}
|
||||
|
||||
&-stats {
|
||||
@@ -65,6 +70,7 @@
|
||||
|
||||
.organizer-actions {
|
||||
display: flex;
|
||||
flex: 0 0 103px;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-left: auto;
|
||||
|
||||
@@ -44,7 +44,9 @@ function genRecommendGames(games, location, avatar) {
|
||||
checkedApplications: current_players,
|
||||
levelRequirements:
|
||||
skill_level_max !== skill_level_min
|
||||
? `${formatNtrpDisplay(skill_level_min) || "-"}-${formatNtrpDisplay(skill_level_max) || "-"}`
|
||||
? `${formatNtrpDisplay(skill_level_min) || "-"}-${
|
||||
formatNtrpDisplay(skill_level_max) || "-"
|
||||
}`
|
||||
: skill_level_min === "1"
|
||||
? "无要求"
|
||||
: `${formatNtrpDisplay(skill_level_min)}以上`,
|
||||
@@ -125,7 +127,9 @@ export default function OrganizerInfo(props) {
|
||||
styles["organizer-avatar-name-message-stats-separator"]
|
||||
}
|
||||
/>
|
||||
<Text>NTRP {ntrp_level ? formatNtrpDisplay(ntrp_level) : "初学者"}</Text>
|
||||
<Text>
|
||||
NTRP {ntrp_level ? formatNtrpDisplay(ntrp_level) : "初学者"}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View className={styles["organizer-actions"]}>
|
||||
|
||||
@@ -1,19 +1,91 @@
|
||||
import React, { useRef } from "react";
|
||||
import Taro from "@tarojs/taro";
|
||||
import { View, Text, Image, ScrollView } from "@tarojs/components";
|
||||
import dayjs from "dayjs";
|
||||
import img from "@/config/images";
|
||||
import { formatNtrpDisplay } from "@/utils/helper";
|
||||
import { useUserInfo } from "@/store/userStore";
|
||||
import { formatNtrpDisplay, toast, navto } from "@/utils/helper";
|
||||
import RMB_ICON from "@/static/detail/rmb.svg";
|
||||
import { MATCH_STATUS, IsSubstituteSupported } from "@/services/detailService";
|
||||
import OrderService from "@/services/orderService";
|
||||
import styles from "./index.module.scss";
|
||||
import NTRPEvaluatePopup from "@/components/NTRPEvaluatePopup";
|
||||
import { EvaluateCallback, EvaluateScene } from "@/store/evaluateStore";
|
||||
|
||||
function isFull(counts) {
|
||||
const {
|
||||
max_players,
|
||||
current_players,
|
||||
max_substitute_players,
|
||||
current_substitute_count,
|
||||
is_substitute_supported,
|
||||
} = counts;
|
||||
|
||||
if (
|
||||
max_players === current_players &&
|
||||
is_substitute_supported === IsSubstituteSupported.NOTSUPPORT
|
||||
) {
|
||||
return true;
|
||||
} else if (
|
||||
max_players === current_players &&
|
||||
is_substitute_supported === IsSubstituteSupported.SUPPORT
|
||||
) {
|
||||
return max_substitute_players === current_substitute_count;
|
||||
}
|
||||
|
||||
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 Participants(props) {
|
||||
const { detail = {}, handleJoinGame, handleViewUserInfo } = props;
|
||||
const ntrpRef = useRef<{
|
||||
show: (evaluateCallback: EvaluateCallback) => void;
|
||||
}>({ show: () => {} });
|
||||
const userInfo = useUserInfo();
|
||||
const participants = detail.participants || [];
|
||||
const {
|
||||
participant_count,
|
||||
max_participants,
|
||||
user_action_status = {},
|
||||
start_time,
|
||||
} = detail;
|
||||
price,
|
||||
ntrp_level,
|
||||
skill_level_min,
|
||||
skill_level_max,
|
||||
is_organizer,
|
||||
match_status,
|
||||
end_time,
|
||||
id,
|
||||
} = detail || {};
|
||||
const { can_join, can_pay, can_substitute, is_substituting, waiting_start } =
|
||||
user_action_status;
|
||||
const showApplicationEntry =
|
||||
@@ -22,8 +94,235 @@ export default function Participants(props) {
|
||||
) &&
|
||||
can_join &&
|
||||
dayjs(start_time).isAfter(dayjs());
|
||||
const leftCount = max_participants - participant_count;
|
||||
|
||||
// 检查手机号绑定的包装函数
|
||||
const checkPhoneAndExecute = (action: () => void) => {
|
||||
return () => {
|
||||
if (!userInfo?.phone) {
|
||||
Taro.showModal({
|
||||
title: "提示",
|
||||
content: "该功能需要绑定手机号",
|
||||
confirmText: "去绑定",
|
||||
cancelText: "取消",
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
const currentPath = Taro.getCurrentInstance().router?.path || "";
|
||||
const currentParams =
|
||||
Taro.getCurrentInstance().router?.params || {};
|
||||
const queryString = Object.keys(currentParams)
|
||||
.map((key) => `${key}=${currentParams[key]}`)
|
||||
.join("&");
|
||||
const fullPath = queryString
|
||||
? `${currentPath}?${queryString}`
|
||||
: currentPath;
|
||||
|
||||
Taro.navigateTo({
|
||||
url: `/login_pages/index/index?redirect=${encodeURIComponent(
|
||||
fullPath
|
||||
)}`,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
action();
|
||||
};
|
||||
};
|
||||
|
||||
const matchNtrpReq = matchNtrpRequestment(
|
||||
ntrp_level,
|
||||
skill_level_min,
|
||||
skill_level_max
|
||||
);
|
||||
|
||||
function handleSelfEvaluate() {
|
||||
ntrpRef?.current?.show({
|
||||
type: EvaluateScene.detail,
|
||||
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}`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
Taro.redirectTo({ url: `/order_pages/orderDetail/index?gameId=${id}` });
|
||||
},
|
||||
onCancel: () => {
|
||||
// Taro.redirectTo({ url: `/game_pages/detail/index?id=${id}` });
|
||||
Taro.navigateBack();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function generateTextAndAction(
|
||||
user_action_status: null | { [key: string]: boolean }
|
||||
):
|
||||
| undefined
|
||||
| { text: string | React.FC; action?: () => void; available?: boolean } {
|
||||
if (!user_action_status) {
|
||||
return;
|
||||
}
|
||||
const priceStrArr = price?.toString().split(".") ?? [];
|
||||
const displayPrice = is_organizer ? (
|
||||
<>
|
||||
<Text className={styles.integer}>0</Text>
|
||||
{/* <Text className={styles.decimalPart}>.00</Text> */}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Text className={styles.integer}>{priceStrArr[0]}</Text>
|
||||
<Text className={styles.decimalPart}>.{priceStrArr[1]}</Text>
|
||||
</>
|
||||
);
|
||||
// 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 (MATCH_STATUS.FINISHED === 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: () => (
|
||||
<>
|
||||
<Image className={styles.crrrencySymbol} src={RMB_ICON} />
|
||||
{displayPrice}
|
||||
<Text className={styles.btnText}>已加入</Text>
|
||||
</>
|
||||
),
|
||||
action: () => toast("您已参与了本次活动"),
|
||||
};
|
||||
} else if (is_substituting) {
|
||||
return {
|
||||
text: () => (
|
||||
<>
|
||||
<Image className={styles.crrrencySymbol} src={RMB_ICON} />
|
||||
{displayPrice}
|
||||
<Text className={styles.btnText}>已加入候补</Text>
|
||||
</>
|
||||
),
|
||||
action: () => toast("您已加入候补,候补失败会全额退款~"),
|
||||
};
|
||||
} else if (can_pay) {
|
||||
return {
|
||||
text: () => (
|
||||
<>
|
||||
<Image className={styles.crrrencySymbol} src={RMB_ICON} />
|
||||
{displayPrice}
|
||||
<Text className={styles.btnText}>继续支付</Text>
|
||||
</>
|
||||
),
|
||||
action: checkPhoneAndExecute(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 (!matchNtrpReq) {
|
||||
return {
|
||||
text: () => (
|
||||
<>
|
||||
<Image className={styles.crrrencySymbol} src={RMB_ICON} />
|
||||
{displayPrice}
|
||||
<Text className={styles.btnText}>立即加入</Text>
|
||||
</>
|
||||
),
|
||||
available: false,
|
||||
action: () =>
|
||||
toast("您当前不符合此球局NTRP水平要求,去看看其他活动吧~"),
|
||||
};
|
||||
} else if (can_substitute) {
|
||||
return {
|
||||
text: () => (
|
||||
<>
|
||||
<Image className={styles.crrrencySymbol} src={RMB_ICON} />
|
||||
{displayPrice}
|
||||
<Text className={styles.btnText}>我要候补</Text>
|
||||
</>
|
||||
),
|
||||
action: checkPhoneAndExecute(handleJoinGame),
|
||||
};
|
||||
} else if (can_join) {
|
||||
return {
|
||||
text: () => {
|
||||
return (
|
||||
<>
|
||||
<Image className={styles.crrrencySymbol} src={RMB_ICON} />
|
||||
{displayPrice}
|
||||
<Text className={styles.btnText}>立即加入</Text>
|
||||
</>
|
||||
);
|
||||
},
|
||||
action: checkPhoneAndExecute(handleJoinGame),
|
||||
};
|
||||
} else if (can_assess) {
|
||||
return {
|
||||
text: () => (
|
||||
<>
|
||||
<Image className={styles.crrrencySymbol} src={RMB_ICON} />
|
||||
{displayPrice}
|
||||
<Text className={styles.btnText}>立即加入</Text>
|
||||
</>
|
||||
),
|
||||
action: checkPhoneAndExecute(handleSelfEvaluate),
|
||||
};
|
||||
}
|
||||
return {
|
||||
text: "球局无法加入",
|
||||
available: false,
|
||||
};
|
||||
}
|
||||
|
||||
const { action = () => {} } = generateTextAndAction(user_action_status)!;
|
||||
|
||||
const leftCount = max_participants - participant_count;
|
||||
|
||||
return (
|
||||
<>
|
||||
<View className={styles["detail-page-content-participants"]}>
|
||||
<View className={styles["participants-title"]}>
|
||||
<Text>参与者</Text>
|
||||
@@ -37,7 +336,7 @@ export default function Participants(props) {
|
||||
<View
|
||||
className={styles["participants-list-application"]}
|
||||
onClick={() => {
|
||||
handleJoinGame();
|
||||
action?.();
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
@@ -74,7 +373,9 @@ export default function Participants(props) {
|
||||
// 优先使用 ntrp_level,如果没有则使用 level
|
||||
const ntrpValue = ntrp_level || level;
|
||||
// 格式化显示 NTRP,如果没有值则显示"初学者"
|
||||
const displayNtrp = ntrpValue ? formatNtrpDisplay(ntrpValue) : "初学者";
|
||||
const displayNtrp = ntrpValue
|
||||
? formatNtrpDisplay(ntrpValue)
|
||||
: "初学者";
|
||||
return (
|
||||
<View
|
||||
key={participant.id}
|
||||
@@ -108,5 +409,7 @@ export default function Participants(props) {
|
||||
""
|
||||
)}
|
||||
</View>
|
||||
<NTRPEvaluatePopup type={EvaluateScene.detail} ref={ntrpRef} showGuide />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -441,6 +441,44 @@
|
||||
line-height: 20px;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.06);
|
||||
|
||||
&.pastItem {
|
||||
color: #3c3c43;
|
||||
}
|
||||
|
||||
&.currentItem {
|
||||
position: relative;
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 3px;
|
||||
height: 100%;
|
||||
background: #007aff;
|
||||
z-index: 0;
|
||||
}
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 3px;
|
||||
top: 15px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid;
|
||||
border-width: 3px 0 3px 6px;
|
||||
border-color: transparent transparent transparent #007bff;
|
||||
z-index: 0;
|
||||
}
|
||||
.currentTag {
|
||||
color: #007aff;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
font-family: "pingfang SC";
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-child(1) {
|
||||
color: #000;
|
||||
text-align: center;
|
||||
@@ -459,6 +497,11 @@
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.time {
|
||||
text-align: left;
|
||||
padding-left: 30px;
|
||||
}
|
||||
|
||||
.rule {
|
||||
border-left: 1px solid rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ function GameInfo(props) {
|
||||
start_time,
|
||||
end_time,
|
||||
weather,
|
||||
title,
|
||||
} = detail || {};
|
||||
|
||||
const [{ iconDay, tempMax, tempMin }] = weather || [{}];
|
||||
@@ -106,7 +107,9 @@ function GameInfo(props) {
|
||||
|
||||
const startTime = dayjs(start_time);
|
||||
const endTime = dayjs(end_time);
|
||||
const game_length = endTime.diff(startTime, "minutes") / 60;
|
||||
const game_length = Number(
|
||||
(endTime.diff(startTime, "minutes") / 60).toFixed()
|
||||
);
|
||||
|
||||
const startMonth = startTime.format("M");
|
||||
const startDay = startTime.format("D");
|
||||
@@ -248,6 +251,11 @@ function GameInfo(props) {
|
||||
{gameNotice.content && <Text>{gameNotice.content}</Text>}
|
||||
</View>
|
||||
)}
|
||||
{!orderDetail.order_id && (
|
||||
<View className={styles.gameStatus}>
|
||||
<Text className={styles.statusText}>{title}</Text>
|
||||
</View>
|
||||
)}
|
||||
<View className={styles.gameInfo}>
|
||||
{/* Date and Weather */}
|
||||
<View className={styles.gameInfoDateWeather}>
|
||||
@@ -322,9 +330,8 @@ function GameInfo(props) {
|
||||
</View>
|
||||
</View>
|
||||
{/* Action bar */}
|
||||
{orderDetail.order_id && (
|
||||
<View className={styles.gameInfoActions}>
|
||||
{orderDetail.order_id ? (
|
||||
<>
|
||||
{generateOrderActions(
|
||||
orderDetail,
|
||||
{
|
||||
@@ -336,14 +343,9 @@ function GameInfo(props) {
|
||||
},
|
||||
"detail"
|
||||
)?.map((obj) => (
|
||||
<View
|
||||
className={classnames(styles.button, styles[obj.className])}
|
||||
>
|
||||
<View className={classnames(styles.button, styles[obj.className])}>
|
||||
<Text className={styles.buttonText}>{obj.text}</Text>
|
||||
<Button
|
||||
className={styles.transparentButton}
|
||||
onClick={obj.action}
|
||||
>
|
||||
<Button className={styles.transparentButton} onClick={obj.action}>
|
||||
{obj.text}
|
||||
</Button>
|
||||
</View>
|
||||
@@ -352,11 +354,8 @@ function GameInfo(props) {
|
||||
<Image className={styles.customerIcon} src={CustomerIcon} />
|
||||
<Text>客服</Text>
|
||||
</View>
|
||||
</>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
<Dialog id="detailCancelOrder" />
|
||||
<RefundPopup ref={refundRef} />
|
||||
</View>
|
||||
@@ -489,6 +488,7 @@ function OrderMsg(props) {
|
||||
function RefundPolicy(props) {
|
||||
const { checkOrderInfo } = props;
|
||||
const { refund_policy = [] } = checkOrderInfo;
|
||||
const current = dayjs();
|
||||
const policyList = [
|
||||
{
|
||||
time: "申请退款时间",
|
||||
@@ -508,9 +508,11 @@ function RefundPolicy(props) {
|
||||
return {
|
||||
time: `${year}年${month}月${day}日${time} ${isLast ? "后" : "前"}`,
|
||||
rule: item.refund_rule,
|
||||
beforeCurrent: isLast ? true : current.isBefore(theTimeObj),
|
||||
};
|
||||
}),
|
||||
];
|
||||
const targetIndex = policyList.findIndex((item) => item.beforeCurrent);
|
||||
return (
|
||||
<View className={styles.refundPolicy}>
|
||||
<View className={styles.moduleTitle}>
|
||||
@@ -519,8 +521,22 @@ function RefundPolicy(props) {
|
||||
{/* 订单信息摘要 */}
|
||||
<View className={styles.policyList}>
|
||||
{policyList.map((item, index) => (
|
||||
<View key={index} className={styles.policyItem}>
|
||||
<View className={styles.time}>{item.time}</View>
|
||||
<View
|
||||
key={index}
|
||||
className={classnames(
|
||||
styles.policyItem,
|
||||
targetIndex > index && index !== 0 ? styles.pastItem : "",
|
||||
targetIndex === index ? styles.currentItem : ""
|
||||
)}
|
||||
>
|
||||
<View className={styles.time}>
|
||||
{targetIndex === index && (
|
||||
<View className={styles.currentTag}>
|
||||
<Text>当前时间段</Text>
|
||||
</View>
|
||||
)}
|
||||
<Text>{item.time}</Text>
|
||||
</View>
|
||||
<View className={styles.rule}>{item.rule}</View>
|
||||
</View>
|
||||
))}
|
||||
|
||||
@@ -151,7 +151,7 @@
|
||||
|
||||
.gameTitle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
padding: 12px 15px 0;
|
||||
|
||||
@@ -168,12 +168,14 @@
|
||||
}
|
||||
|
||||
.payNum {
|
||||
width: 90px;
|
||||
font-feature-settings: "liga" off, "clig" off;
|
||||
font-family: "PingFang SC";
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
line-height: 18px;
|
||||
line-height: 26px;
|
||||
text-align: right;
|
||||
&.paid {
|
||||
color: #000;
|
||||
}
|
||||
@@ -359,6 +361,45 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.payTipContainer {
|
||||
margin-top: -8px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: flex-start;
|
||||
padding: 0 12px 14px 12px;
|
||||
.payTip {
|
||||
font-family: PingFang SC;
|
||||
font-weight: 400;
|
||||
font-style: Regular;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
// letter-spacing: -0.23px;
|
||||
padding: 4px 12px;
|
||||
background-color: #f7f7f7;
|
||||
border-radius: 4px;
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
right: 30px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid;
|
||||
border-width: 0 4px 6px 4px;
|
||||
border-color: transparent transparent #f7f7f7 transparent;
|
||||
}
|
||||
|
||||
.timeLeft {
|
||||
display: inline-block;
|
||||
color: #ff3b30;
|
||||
font-weight: 600;
|
||||
padding: 0 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,11 @@ 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, genNTRPRequirementText, requireLoginWithPhone } from "@/utils/helper";
|
||||
import {
|
||||
insertDotInTags,
|
||||
genNTRPRequirementText,
|
||||
requireLoginWithPhone,
|
||||
} from "@/utils/helper";
|
||||
import styles from "./index.module.scss";
|
||||
|
||||
dayjs.locale("zh-cn");
|
||||
@@ -306,6 +310,12 @@ const OrderList = () => {
|
||||
court_type,
|
||||
} = game_info || {};
|
||||
|
||||
const diffMs = dayjs(item.expire_time).diff();
|
||||
const mm = String(Math.floor(diffMs / 1000 / 60)).padStart(2, "0");
|
||||
const ss = String(Math.floor((diffMs / 1000) % 60)).padStart(2, "0");
|
||||
|
||||
const timeLeft = `${mm}:${ss}`;
|
||||
|
||||
return (
|
||||
<View key={item.id} className={styles.orderItem}>
|
||||
<View
|
||||
@@ -412,6 +422,20 @@ const OrderList = () => {
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
{unPay && diffMs > 0 && (
|
||||
<View className={styles.payTipContainer}>
|
||||
<View className={styles.payTip}>
|
||||
{current_players > 0 ? (
|
||||
<Text>{`已有${current_players}人参加, `}</Text>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<Text>请在</Text>
|
||||
<Text className={styles.timeLeft}>{timeLeft}</Text>
|
||||
<Text>分钟内完成支付</Text>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
})}
|
||||
|
||||
Reference in New Issue
Block a user