Merge branch 'feat/liujie'

This commit is contained in:
2025-10-01 17:27:26 +08:00
15 changed files with 295 additions and 187 deletions

View File

@@ -1,17 +1,24 @@
import { Component, ReactNode } from "react"; import { Component, ReactNode } from "react";
import "./nutui-theme.scss"; import "./nutui-theme.scss";
import "./app.scss"; import "./app.scss";
import "./scss/qweather-icons/qweather-icons.css"; import "./scss/qweather-icons/qweather-icons.css";
import { useGlobalStore } from "./store/global"; import { useGlobalStore } from "./store/global";
import { removeStorage } from "./store/storage";
interface AppProps { interface AppProps {
children: ReactNode; children: ReactNode;
} }
function clearSpecStorage() {
removeStorage('list_reload_page_number')
removeStorage('backFlag')
}
class App extends Component<AppProps> { class App extends Component<AppProps> {
onLaunch(options) { onLaunch(options) {
console.log('launch options: ', options) console.log('launch options: ', options)
console.log("小程序启动,初始化逻辑写这里"); console.log("小程序启动,初始化逻辑写这里");
clearSpecStorage()
} }
componentDidMount() { componentDidMount() {
@@ -20,9 +27,9 @@ class App extends Component<AppProps> {
// this.getLocation() // this.getLocation()
} }
componentDidShow() {} componentDidShow() { }
componentDidHide() {} componentDidHide() { }

View File

@@ -40,7 +40,7 @@ function NtrpPopupGuide(props: {
<Image <Image
className={styles.avatarUrl} className={styles.avatarUrl}
src={userInfo.avatar_url} src={userInfo.avatar_url}
mode="aspectFit" mode="aspectFill"
/> />
</View> </View>
{/* avatar side */} {/* avatar side */}

View File

@@ -90,7 +90,7 @@ function NTRPTestEntryCard(props: {
<Image <Image
className={styles.avatarUrl} className={styles.avatarUrl}
src={userInfo.avatar_url} src={userInfo.avatar_url}
mode="aspectFit" mode="aspectFill"
/> />
</View> </View>
{/* avatar side */} {/* avatar side */}
@@ -119,7 +119,7 @@ function NTRPTestEntryCard(props: {
<Image <Image
className={styles.avatarUrl} className={styles.avatarUrl}
src={userInfo.avatar_url} src={userInfo.avatar_url}
mode="aspectFit" mode="aspectFill"
/> />
</View> </View>
{/* avatar side */} {/* avatar side */}

View File

@@ -231,7 +231,7 @@ export const UserInfoCard: React.FC<UserInfoCardProps> = ({
{/* 头像和基本信息 */} {/* 头像和基本信息 */}
<View className="basic_info"> <View className="basic_info">
<View className="avatar_container"> <View className="avatar_container">
<Image className="avatar" src={user_info.avatar} /> <Image className="avatar" src={user_info.avatar} mode="aspectFill" />
</View> </View>
<View className="info_container"> <View className="info_container">
<Text className="nickname">{user_info.nickname}</Text> <Text className="nickname">{user_info.nickname}</Text>
@@ -331,7 +331,12 @@ export const UserInfoCard: React.FC<UserInfoCardProps> = ({
)} )}
</View> </View>
) : is_current_user && user_info.gender !== "2" ? ( ) : is_current_user && user_info.gender !== "2" ? (
<View className="button_edit" onClick={() => { handle_open_edit_modal('gender') }}> <View
className="button_edit"
onClick={() => {
handle_open_edit_modal("gender");
}}
>
<Text></Text> <Text></Text>
</View> </View>
) : null} ) : null}
@@ -340,16 +345,28 @@ export const UserInfoCard: React.FC<UserInfoCardProps> = ({
<Text className="tag_text">{`NTRP ${user_info.ntrp_level}`}</Text> <Text className="tag_text">{`NTRP ${user_info.ntrp_level}`}</Text>
</View> </View>
) : is_current_user ? ( ) : is_current_user ? (
<View className="button_edit" onClick={() => { handle_open_edit_modal('ntrp_level') }}> <View
className="button_edit"
onClick={() => {
handle_open_edit_modal("ntrp_level");
}}
>
<Text>NTRP水平</Text> <Text>NTRP水平</Text>
</View> </View>
) : null} ) : null}
{user_info.occupation ? ( {user_info.occupation ? (
<View className="tag_item"> <View className="tag_item">
<Text className="tag_text">{user_info.occupation.split(" ")[1]}</Text> <Text className="tag_text">
{user_info.occupation.split(" ")[1]}
</Text>
</View> </View>
) : is_current_user ? ( ) : is_current_user ? (
<View className="button_edit" onClick={() => { handle_open_edit_modal('occupation') }}> <View
className="button_edit"
onClick={() => {
handle_open_edit_modal("occupation");
}}
>
<Text></Text> <Text></Text>
</View> </View>
) : null} ) : null}
@@ -358,7 +375,10 @@ export const UserInfoCard: React.FC<UserInfoCardProps> = ({
<Text className="tag_text">{`${user_info.province}${user_info.city}`}</Text> <Text className="tag_text">{`${user_info.province}${user_info.city}`}</Text>
</View> </View>
) : is_current_user ? ( ) : is_current_user ? (
<View className="button_edit" onClick={() => handle_open_edit_modal('location')}> <View
className="button_edit"
onClick={() => handle_open_edit_modal("location")}
>
<Text></Text> <Text></Text>
</View> </View>
) : null} ) : null}
@@ -601,8 +621,9 @@ export const GameTabs: React.FC<GameTabsProps> = ({
<Text className="tab_text">{hosted_text}</Text> <Text className="tab_text">{hosted_text}</Text>
</View> </View>
<View <View
className={`tab_item ${active_tab === "participated" ? "active" : "" className={`tab_item ${
}`} active_tab === "participated" ? "active" : ""
}`}
onClick={() => on_tab_change("participated")} onClick={() => on_tab_change("participated")}
> >
<Text className="tab_text">{participated_text}</Text> <Text className="tab_text">{participated_text}</Text>

View File

@@ -24,11 +24,6 @@ import {
GameManagePopup, GameManagePopup,
Comments, Comments,
} from "@/components"; } from "@/components";
// import {
// EvaluateType,
// SceneType,
// DisplayConditionType,
// } from "@/components/NTRPEvaluatePopup";
import DetailService, { import DetailService, {
MATCH_STATUS, MATCH_STATUS,
IsSubstituteSupported, IsSubstituteSupported,
@@ -36,7 +31,6 @@ import DetailService, {
import * as LoginService from "@/services/loginService"; import * as LoginService from "@/services/loginService";
import OrderService from "@/services/orderService"; import OrderService from "@/services/orderService";
import { getCurrentLocation, calculateDistance } from "@/utils/locationUtils"; import { getCurrentLocation, calculateDistance } from "@/utils/locationUtils";
// import { getCurrentFullPath } from "@/utils";
import { useUserInfo, useUserActions } from "@/store/userStore"; import { useUserInfo, useUserActions } from "@/store/userStore";
import { EvaluateCallback, EvaluateScene } from "@/store/evaluateStore"; import { EvaluateCallback, EvaluateScene } from "@/store/evaluateStore";
import img from "@/config/images"; import img from "@/config/images";
@@ -55,22 +49,22 @@ function GameTags(props) {
const { userInfo, handleViewUserInfo } = props; const { userInfo, handleViewUserInfo } = props;
const { avatar_url, id } = userInfo; const { avatar_url, id } = userInfo;
const tags = [ const tags = [
{ // {
name: "🕙 急招", // name: "🕙 急招",
icon: "", // icon: "",
}, // },
{ // {
name: "🔥 本周热门", // name: "🔥 本周热门",
icon: "", // icon: "",
}, // },
{ // {
name: "🎉 新活动", // name: "🎉 新活动",
icon: "", // icon: "",
}, // },
{ // {
name: "官方组织", // name: "官方组织",
icon: "", // icon: "",
}, // },
]; ];
return ( return (
<View className="detail-page-content-avatar-tags"> <View className="detail-page-content-avatar-tags">
@@ -144,6 +138,13 @@ function Coursel(props) {
getImagesMsg(image_list || []); getImagesMsg(image_list || []);
}, [image_list]); }, [image_list]);
function previewImage(current_url) {
Taro.previewImage({
current: current_url,
urls: list?.length > 0 ? list.map((c) => c.url) : [],
});
}
return ( return (
<View className="detail-swiper-container"> <View className="detail-swiper-container">
<View <View
@@ -152,7 +153,11 @@ function Coursel(props) {
> >
{list.map((item, index) => { {list.map((item, index) => {
return ( return (
<View className="detail-swiper-item" key={index}> <View
className="detail-swiper-item"
key={index}
onClick={() => previewImage(item.url)}
>
<Image <Image
src={item.url} src={item.url}
mode="aspectFill" mode="aspectFill"
@@ -788,13 +793,16 @@ function Participants(props) {
participant_count, participant_count,
max_participants, max_participants,
user_action_status = {}, user_action_status = {},
start_time,
} = detail; } = detail;
const { can_join, can_pay, can_substitute, is_substituting, waiting_start } = const { can_join, can_pay, can_substitute, is_substituting, waiting_start } =
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 &&
dayjs(start_time).isAfter(dayjs());
const leftCount = max_participants - participant_count; const leftCount = max_participants - participant_count;
return ( return (
<View className="detail-page-content-participants"> <View className="detail-page-content-participants">
@@ -1140,10 +1148,15 @@ function Index() {
const sharePopupRef = useRef<any>(null); const sharePopupRef = useRef<any>(null);
const commentRef = useRef(); const commentRef = useRef();
useEffect(() => {
updateLocation();
fetchUserInfo();
}, []);
useDidShow(async () => { useDidShow(async () => {
await updateLocation(); // await updateLocation();
await fetchUserInfo(); // await fetchUserInfo();
// await fetchDetail(); await fetchDetail();
}); });
const updateLocation = async () => { const updateLocation = async () => {

View File

@@ -27,9 +27,7 @@
border-bottom: 0.5px solid rgba(0, 0, 0, 0.06); border-bottom: 0.5px solid rgba(0, 0, 0, 0.06);
padding: 8px 12px; padding: 8px 12px;
color: #000; color: #000;
font-feature-settings: font-feature-settings: "liga" off, "clig" off;
"liga" off,
"clig" off;
font-family: "PingFang SC"; font-family: "PingFang SC";
font-size: 14px; font-size: 14px;
font-style: normal; font-style: normal;
@@ -46,9 +44,7 @@
align-items: flex-start; align-items: flex-start;
color: rgba(60, 60, 67, 0.6); color: rgba(60, 60, 67, 0.6);
font-feature-settings: font-feature-settings: "liga" off, "clig" off;
"liga" off,
"clig" off;
font-family: "PingFang SC"; font-family: "PingFang SC";
font-size: 12px; font-size: 12px;
font-style: normal; font-style: normal;
@@ -136,9 +132,7 @@
.date { .date {
color: #000; color: #000;
font-feature-settings: font-feature-settings: "liga" off, "clig" off;
"liga" off,
"clig" off;
font-family: "PingFang SC"; font-family: "PingFang SC";
font-size: 16px; font-size: 16px;
font-style: normal; font-style: normal;
@@ -148,9 +142,7 @@
.venueTime { .venueTime {
color: rgba(0, 0, 0, 0.8); color: rgba(0, 0, 0, 0.8);
font-feature-settings: font-feature-settings: "liga" off, "clig" off;
"liga" off,
"clig" off;
font-family: "PingFang SC"; font-family: "PingFang SC";
font-size: 12px; font-size: 12px;
font-style: normal; font-style: normal;
@@ -177,9 +169,7 @@
align-items: center; align-items: center;
gap: 12px; gap: 12px;
color: rgba(0, 0, 0, 0.8); color: rgba(0, 0, 0, 0.8);
font-feature-settings: font-feature-settings: "liga" off, "clig" off;
"liga" off,
"clig" off;
font-family: "PingFang SC"; font-family: "PingFang SC";
font-size: 12px; font-size: 12px;
font-style: normal; font-style: normal;
@@ -223,9 +213,7 @@
gap: 4px; gap: 4px;
color: #000; color: #000;
text-align: center; text-align: center;
font-feature-settings: font-feature-settings: "liga" off, "clig" off;
"liga" off,
"clig" off;
font-family: "PingFang SC"; font-family: "PingFang SC";
font-size: 16px; font-size: 16px;
font-style: normal; font-style: normal;
@@ -241,9 +229,7 @@
&Address { &Address {
color: rgba(0, 0, 0, 0.8); color: rgba(0, 0, 0, 0.8);
text-align: center; text-align: center;
font-feature-settings: font-feature-settings: "liga" off, "clig" off;
"liga" off,
"clig" off;
font-family: "PingFang SC"; font-family: "PingFang SC";
font-size: 12px; font-size: 12px;
font-style: normal; font-style: normal;
@@ -255,6 +241,26 @@
} }
} }
.customer {
margin-left: auto;
display: flex;
align-items: center;
justify-content: flex-start;
gap: 4px;
color: var(--Labels-Secondary, rgba(60, 60, 67, 0.6));
font-feature-settings: "liga" off, "clig" off;
font-family: "PingFang SC";
font-size: 12px;
font-style: normal;
font-weight: 600;
line-height: 16px;
.customerIcon {
width: 16px;
height: 16px;
}
}
.gameInfoActions { .gameInfoActions {
min-height: 12px; min-height: 12px;
padding: 0 12px; padding: 0 12px;
@@ -298,9 +304,7 @@
align-items: center; align-items: center;
align-self: stretch; align-self: stretch;
color: #000; color: #000;
font-feature-settings: font-feature-settings: "liga" off, "clig" off;
"liga" off,
"clig" off;
font-family: "PingFang SC"; font-family: "PingFang SC";
font-size: 14px; font-size: 14px;
font-style: normal; font-style: normal;
@@ -326,9 +330,7 @@
width: 120px; width: 120px;
display: inline-block; display: inline-block;
color: rgba(60, 60, 67, 0.6); color: rgba(60, 60, 67, 0.6);
font-feature-settings: font-feature-settings: "liga" off, "clig" off;
"liga" off,
"clig" off;
font-family: "PingFang SC"; font-family: "PingFang SC";
font-size: 14px; font-size: 14px;
font-style: normal; font-style: normal;
@@ -338,9 +340,7 @@
.content { .content {
color: #000; color: #000;
font-feature-settings: font-feature-settings: "liga" off, "clig" off;
"liga" off,
"clig" off;
font-family: "PingFang SC"; font-family: "PingFang SC";
font-size: 14px; font-size: 14px;
font-style: normal; font-style: normal;
@@ -362,7 +362,7 @@
gap: 8px; gap: 8px;
.copy { .copy {
color: #007AFF; color: #007aff;
} }
} }
} }
@@ -378,9 +378,7 @@
align-items: center; align-items: center;
align-self: stretch; align-self: stretch;
color: #000; color: #000;
font-feature-settings: font-feature-settings: "liga" off, "clig" off;
"liga" off,
"clig" off;
font-family: "PingFang SC"; font-family: "PingFang SC";
font-size: 14px; font-size: 14px;
font-style: normal; font-style: normal;
@@ -401,9 +399,7 @@
align-items: center; align-items: center;
color: #000; color: #000;
text-align: center; text-align: center;
font-feature-settings: font-feature-settings: "liga" off, "clig" off;
"liga" off,
"clig" off;
font-family: "PingFang SC"; font-family: "PingFang SC";
font-size: 12px; font-size: 12px;
font-style: normal; font-style: normal;
@@ -414,9 +410,7 @@
&:nth-child(1) { &:nth-child(1) {
color: #000; color: #000;
text-align: center; text-align: center;
font-feature-settings: font-feature-settings: "liga" off, "clig" off;
"liga" off,
"clig" off;
font-family: "PingFang SC"; font-family: "PingFang SC";
font-size: 14px; font-size: 14px;
font-style: normal; font-style: normal;
@@ -451,9 +445,7 @@
align-items: center; align-items: center;
align-self: stretch; align-self: stretch;
color: #000; color: #000;
font-feature-settings: font-feature-settings: "liga" off, "clig" off;
"liga" off,
"clig" off;
font-family: "PingFang SC"; font-family: "PingFang SC";
font-size: 14px; font-size: 14px;
font-style: normal; font-style: normal;
@@ -489,9 +481,7 @@
background: #000; background: #000;
box-shadow: 0 8px 64px 0 rgba(0, 0, 0, 0.1); box-shadow: 0 8px 64px 0 rgba(0, 0, 0, 0.1);
backdrop-filter: blur(16px); backdrop-filter: blur(16px);
font-feature-settings: font-feature-settings: "liga" off, "clig" off;
"liga" off,
"clig" off;
font-family: "PingFang SC"; font-family: "PingFang SC";
font-size: 16px; font-size: 16px;
font-style: normal; font-style: normal;
@@ -516,7 +506,8 @@
border-bottom-right-radius: 16px; border-bottom-right-radius: 16px;
overflow: hidden; overflow: hidden;
& > .cancel, & > .confirm { & > .cancel,
& > .confirm {
padding: 12px 10px; padding: 12px 10px;
height: 44px; height: 44px;
width: 50%; width: 50%;
@@ -545,9 +536,9 @@
.cancelTip { .cancelTip {
padding: 12px 15px; padding: 12px 15px;
color: rgba(60, 60, 67, 0.60); color: rgba(60, 60, 67, 0.6);
text-align: center; text-align: center;
font-feature-settings: 'liga' off, 'clig' off; font-feature-settings: "liga" off, "clig" off;
font-family: "PingFang SC"; font-family: "PingFang SC";
font-size: 16px; font-size: 16px;
font-style: normal; font-style: normal;

View File

@@ -19,9 +19,12 @@ import {
getOrderStatus, getOrderStatus,
generateOrderActions, generateOrderActions,
} from "@/utils"; } from "@/utils";
import { getStorage, setStorage } from "@/store/storage";
import detailService, { GameData } from "@/services/detailService"; import detailService, { GameData } from "@/services/detailService";
import { withAuth, RefundPopup } from "@/components"; import { withAuth, RefundPopup } from "@/components";
import img from "@/config/images"; import img from "@/config/images";
import CustomerIcon from "@/static/order/customer.svg";
import { handleCustomerService } from "@/services/userService";
import { DECLAIMER } from "./config"; import { DECLAIMER } from "./config";
import styles from "./index.module.scss"; import styles from "./index.module.scss";
@@ -65,8 +68,15 @@ function genGameNotice(order_status, start_time) {
function GameInfo(props) { function GameInfo(props) {
const { detail, currentLocation, orderDetail, init } = props; const { detail, currentLocation, orderDetail, init } = props;
const { order_status, refund_status, amount } = orderDetail; const { order_status, refund_status, amount } = orderDetail;
const { latitude, longitude, location, location_name, start_time, end_time, weather } = const {
detail || {}; latitude,
longitude,
location,
location_name,
start_time,
end_time,
weather,
} = detail || {};
const [{ iconDay, tempMax, tempMin }] = weather || [{}]; const [{ iconDay, tempMax, tempMin }] = weather || [{}];
@@ -306,8 +316,9 @@ function GameInfo(props) {
</View> </View>
{/* Action bar */} {/* Action bar */}
<View className={styles.gameInfoActions}> <View className={styles.gameInfoActions}>
{orderDetail.order_id {orderDetail.order_id ? (
? generateOrderActions( <>
{generateOrderActions(
orderDetail, orderDetail,
{ {
handleDeleteOrder, handleDeleteOrder,
@@ -324,8 +335,15 @@ function GameInfo(props) {
> >
{obj.text} {obj.text}
</Button> </Button>
)) ))}
: ""} <View className={styles.customer} onClick={handleCustomerService}>
<Image className={styles.customerIcon} src={CustomerIcon} />
<Text></Text>
</View>
</>
) : (
""
)}
</View> </View>
<Dialog id="detailCancelOrder" /> <Dialog id="detailCancelOrder" />
<RefundPopup ref={refundRef} /> <RefundPopup ref={refundRef} />
@@ -353,10 +371,7 @@ function OrderMsg(props) {
const { order_info: { registrant_phone } = {} } = checkOrderInfo; const { order_info: { registrant_phone } = {} } = checkOrderInfo;
const startTime = dayjs(start_time); const startTime = dayjs(start_time);
const endTime = dayjs(end_time); const endTime = dayjs(end_time);
const startYear = startTime.format("YYYY"); const startDate = startTime.format("YYYY年M月D日");
const startMonth = startTime.format("M");
const startDay = startTime.format("D");
const startDate = `${startYear}${startMonth}${startDay}`;
const gameRange = `${startTime.format("HH:mm")} - ${endTime.format("HH:mm")}`; const gameRange = `${startTime.format("HH:mm")} - ${endTime.format("HH:mm")}`;
const summary = [ const summary = [
{ {
@@ -485,9 +500,10 @@ const OrderCheck = () => {
const [location, setLocation] = useState<number[]>([0, 0]); const [location, setLocation] = useState<number[]>([0, 0]);
const [checkOrderInfo, setCheckOrderInfo] = useState<GameOrderRes | {}>({}); const [checkOrderInfo, setCheckOrderInfo] = useState<GameOrderRes | {}>({});
const [orderDetail, setOrderDetail] = useState({}); const [orderDetail, setOrderDetail] = useState({});
const [paying, setPaying] = useState(false);
useDidShow(() => { useDidShow(() => {
init() init();
}); });
async function init() { async function init() {
@@ -535,20 +551,32 @@ const OrderCheck = () => {
//TODO: get order msg from id //TODO: get order msg from id
const handlePay = async () => { const handlePay = async () => {
setPaying(true);
Taro.showLoading({ Taro.showLoading({
title: "支付中...", title: "支付中...",
mask: true, mask: true,
}); });
let payment_params = {} let payment_params = {};
try { try {
payment_params = await getPaymentParams(); payment_params = await getPaymentParams();
if (!id) {
setStorage("backFlag", "1");
Taro.redirectTo({
url: `/order_pages/orderDetail/index?id=${payment_params.order_id}`,
});
}
await payOrder(payment_params); await payOrder(payment_params);
Taro.hideLoading(); Taro.hideLoading();
Taro.showToast({ Taro.showToast({
title: "支付成功", title: "支付成功",
icon: "success", icon: "success",
}); });
const backFlag = getStorage("backFlag");
if (backFlag === "1") {
setStorage("backFlag", "0");
Taro.navigateBack();
}
// Taro.navigateBack({ // Taro.navigateBack({
// delta: 1, // delta: 1,
// }); // });
@@ -559,14 +587,9 @@ const OrderCheck = () => {
icon: "none", icon: "none",
}); });
} finally { } finally {
await delay(1000); setStorage("backFlag", "0");
if (!id) { init();
Taro.redirectTo({ setPaying(false);
url: `/order_pages/orderDetail/index?id=${payment_params.order_id}`,
});
} else {
init()
}
} }
}; };
if (!id && !gameId) { if (!id && !gameId) {
@@ -609,7 +632,11 @@ const OrderCheck = () => {
{(!id || {(!id ||
(order_status === OrderStatus.PENDING && (order_status === OrderStatus.PENDING &&
cancel_type === CancelType.NONE)) && ( cancel_type === CancelType.NONE)) && (
<Button className={styles.payButton} onClick={handlePay}> <Button
className={styles.payButton}
disabled={paying}
onClick={handlePay}
>
{order_status === OrderStatus.PENDING ? "继续" : "确认"} {order_status === OrderStatus.PENDING ? "继续" : "确认"}
</Button> </Button>

View File

@@ -29,9 +29,7 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
color: rgba(0, 0, 0, 0.8); color: rgba(0, 0, 0, 0.8);
font-feature-settings: font-feature-settings: "liga" off, "clig" off;
"liga" off,
"clig" off;
font-family: "PingFang SC"; font-family: "PingFang SC";
font-size: 12px; font-size: 12px;
font-style: normal; font-style: normal;
@@ -146,7 +144,7 @@
.title { .title {
overflow: hidden; overflow: hidden;
color: #000; color: #000;
font-feature-settings: 'liga' off, 'clig' off; font-feature-settings: "liga" off, "clig" off;
text-overflow: ellipsis; text-overflow: ellipsis;
font-family: "PingFang SC"; font-family: "PingFang SC";
font-size: 16px; font-size: 16px;
@@ -156,9 +154,7 @@
} }
.payNum { .payNum {
font-feature-settings: font-feature-settings: "liga" off, "clig" off;
"liga" off,
"clig" off;
font-family: "PingFang SC"; font-family: "PingFang SC";
font-size: 12px; font-size: 12px;
font-style: normal; font-style: normal;
@@ -180,8 +176,8 @@
align-items: center; align-items: center;
justify-content: flex-start; justify-content: flex-start;
gap: 8px; gap: 8px;
color: rgba(60, 60, 67, 0.60); color: rgba(60, 60, 67, 0.6);
font-feature-settings: 'liga' off, 'clig' off; font-feature-settings: "liga" off, "clig" off;
text-overflow: ellipsis; text-overflow: ellipsis;
font-family: "PingFang SC"; font-family: "PingFang SC";
font-size: 12px; font-size: 12px;
@@ -197,8 +193,8 @@
justify-content: flex-start; justify-content: flex-start;
gap: 4px; gap: 4px;
color: rgba(60, 60, 67, 0.60); color: rgba(60, 60, 67, 0.6);
font-feature-settings: 'liga' off, 'clig' off; font-feature-settings: "liga" off, "clig" off;
text-overflow: ellipsis; text-overflow: ellipsis;
font-family: "PingFang SC"; font-family: "PingFang SC";
font-size: 12px; font-size: 12px;
@@ -226,13 +222,15 @@
height: 20px; height: 20px;
border-radius: 50%; border-radius: 50%;
border: 1px solid rgba(0, 0, 0, 0.06); border: 1px solid rgba(0, 0, 0, 0.06);
&+.avatar { & + .avatar {
margin-left: -10px; margin-left: -10px;
} }
} }
} }
.participantProgress, .levelReq, .playType { .participantProgress,
.levelReq,
.playType {
display: flex; display: flex;
height: 20px; height: 20px;
padding: 0px 8px; padding: 0px 8px;
@@ -240,9 +238,9 @@
gap: 4px; gap: 4px;
border-radius: 999px; border-radius: 999px;
border: 0.5px solid rgba(0, 0, 0, 0.16); border: 0.5px solid rgba(0, 0, 0, 0.16);
background: #FFF; background: #fff;
color: #000; color: #000;
font-feature-settings: 'liga' off, 'clig' off; font-feature-settings: "liga" off, "clig" off;
font-family: "PingFang SC"; font-family: "PingFang SC";
font-size: 11px; font-size: 11px;
font-style: normal; font-style: normal;
@@ -271,6 +269,24 @@
justify-content: space-between; justify-content: space-between;
.extraActions { .extraActions {
.customer {
display: flex;
align-items: center;
justify-content: flex-start;
gap: 4px;
color: var(--Labels-Secondary, rgba(60, 60, 67, 0.6));
font-feature-settings: "liga" off, "clig" off;
font-family: "PingFang SC";
font-size: 12px;
font-style: normal;
font-weight: 600;
line-height: 16px;
.customerIcon {
width: 16px;
height: 16px;
}
}
} }
.mainActions { .mainActions {
@@ -328,7 +344,8 @@
border-bottom-right-radius: 16px; border-bottom-right-radius: 16px;
overflow: hidden; overflow: hidden;
& > .cancel, & > .confirm { & > .cancel,
& > .confirm {
padding: 12px 10px; padding: 12px 10px;
height: 44px; height: 44px;
width: 50%; width: 50%;
@@ -357,9 +374,9 @@
.cancelTip { .cancelTip {
padding: 12px 15px; padding: 12px 15px;
color: rgba(60, 60, 67, 0.60); color: rgba(60, 60, 67, 0.6);
text-align: center; text-align: center;
font-feature-settings: 'liga' off, 'clig' off; font-feature-settings: "liga" off, "clig" off;
font-family: "PingFang SC"; font-family: "PingFang SC";
font-size: 16px; font-size: 16px;
font-style: normal; font-style: normal;
@@ -377,7 +394,7 @@
.emptyTip { .emptyTip {
color: rgba(0, 0, 0, 0.85); color: rgba(0, 0, 0, 0.85);
font-feature-settings: 'liga' off, 'clig' off; font-feature-settings: "liga" off, "clig" off;
font-family: "PingFang SC"; font-family: "PingFang SC";
font-size: 14px; font-size: 14px;
font-style: normal; font-style: normal;

View File

@@ -5,10 +5,17 @@ import { Avatar, Dialog } from "@nutui/nutui-react-taro";
import dayjs from "dayjs"; import dayjs from "dayjs";
import "dayjs/locale/zh-cn"; import "dayjs/locale/zh-cn";
import classnames from "classnames"; import classnames from "classnames";
import orderService, { OrderStatus, CancelType, refundTextMap } from "@/services/orderService"; import orderService, {
OrderStatus,
CancelType,
refundTextMap,
} from "@/services/orderService";
import { getStorage, removeStorage, setStorage } from "@/store/storage";
import { handleCustomerService } from "@/services/userService";
import { withAuth, RefundPopup } from "@/components"; import { withAuth, RefundPopup } from "@/components";
import { payOrder, generateOrderActions } from "@/utils"; import { payOrder, generateOrderActions } from "@/utils";
import emptyContent from "@/static/emptyStatus/publish-empty.png"; import emptyContent from "@/static/emptyStatus/publish-empty.png";
import CustomerIcon from "@/static/order/customer.svg";
import styles from "./index.module.scss"; import styles from "./index.module.scss";
dayjs.locale("zh-cn"); dayjs.locale("zh-cn");
@@ -69,6 +76,14 @@ const OrderList = () => {
getOrders(1); getOrders(1);
}, []); }, []);
useDidShow(() => {
const targetPage = getStorage("list_reload_page_number");
if (targetPage) {
removeStorage("list_reload_page_number");
getOrders(Number(targetPage));
}
});
function addPageInfo(arr, page) { function addPageInfo(arr, page) {
return arr.map((item) => ({ ...item, page })); return arr.map((item) => ({ ...item, page }));
} }
@@ -236,13 +251,14 @@ const OrderList = () => {
} }
} }
function handleViewOrderDetail(orderId) { function handleViewOrderDetail({ page, id: orderId }) {
setStorage("list_reload_page_number", page);
Taro.navigateTo({ Taro.navigateTo({
url: `/order_pages/orderDetail/index?id=${orderId}`, url: `/order_pages/orderDetail/index?id=${orderId}`,
}); });
} }
const flatList = list.flat() const flatList = list.flat();
return ( return (
<View className={styles.container}> <View className={styles.container}>
@@ -260,6 +276,7 @@ const OrderList = () => {
const unPay = const unPay =
item.order_status === OrderStatus.PENDING && item.order_status === OrderStatus.PENDING &&
item.cancel_type === CancelType.NONE; item.cancel_type === CancelType.NONE;
const timeout = item.cancel_type === CancelType.TIMEOUT;
const { game_info } = item; const { game_info } = item;
const { const {
@@ -277,19 +294,25 @@ const OrderList = () => {
<View key={item.id} className={styles.orderItem}> <View key={item.id} className={styles.orderItem}>
<View <View
className={styles.gameInfo} className={styles.gameInfo}
onClick={handleViewOrderDetail.bind(null, item.id)} onClick={() => handleViewOrderDetail(item)}
> >
<View className={styles.gameTitle}> <View className={styles.gameTitle}>
<View className={styles.title}>{item?.game_info?.title}</View> <View className={styles.title}>{item?.game_info?.title}</View>
<View {!timeout && (
className={classnames( <View
styles.payNum, className={classnames(
styles[unPay ? "pending" : "paid"] styles.payNum,
)} styles[unPay ? "pending" : "paid"]
> )}
<Text>{unPay ? "待支付" : refundTextMap.get(item.refund_status)}</Text> ¥{" "} >
<Text>{item.amount}</Text> <Text>
</View> {unPay
? "待支付"
: refundTextMap.get(item.refund_status)}
</Text>{" "}
¥ <Text>{item.amount}</Text>
</View>
)}
</View> </View>
<View className={styles.gameTime}> <View className={styles.gameTime}>
{generateTimeMsg(item.game_info || {})} {generateTimeMsg(item.game_info || {})}
@@ -304,40 +327,19 @@ const OrderList = () => {
<View className={styles.gameOtherInfo}> <View className={styles.gameOtherInfo}>
{participants?.length >= 0 ? ( {participants?.length >= 0 ? (
<View className={styles.avatarCards}> <View className={styles.avatarCards}>
{ {participants.map((participant) => {
/* participants */ [ const {
{ user: { avatar_url, id },
user: { } = participant;
avatar_url: "https://img.yzcdn.cn/vant/cat.jpeg", return (
id: 1, <Image
}, className={styles.avatar}
}, mode="aspectFill"
{ key={id}
user: { src={avatar_url}
avatar_url: "https://img.yzcdn.cn/vant/cat.jpeg", />
id: 2, );
}, })}
},
{
user: {
avatar_url: "https://img.yzcdn.cn/vant/cat.jpeg",
id: 3,
},
},
].map((participant) => {
const {
user: { avatar_url, id },
} = participant;
return (
<Image
className={styles.avatar}
mode="aspectFill"
key={id}
src={avatar_url}
/>
);
})
}
</View> </View>
) : ( ) : (
"" ""
@@ -360,7 +362,15 @@ const OrderList = () => {
</View> </View>
</View> </View>
<View className={styles.orderActions}> <View className={styles.orderActions}>
<View className={styles.extraActions}></View> <View className={styles.extraActions}>
<View
className={styles.customer}
onClick={handleCustomerService}
>
<Image className={styles.customerIcon} src={CustomerIcon} />
<Text></Text>
</View>
</View>
<View className={styles.mainActions}> <View className={styles.mainActions}>
{generateOrderActions( {generateOrderActions(
item, item,

View File

@@ -176,7 +176,7 @@ function Intro() {
<Image <Image
className={styles.avatarUrl} className={styles.avatarUrl}
src={userInfo.avatar_url} src={userInfo.avatar_url}
mode="aspectFit" mode="aspectFill"
/> />
</View> </View>
{/* avatar side */} {/* avatar side */}

View File

@@ -116,7 +116,7 @@ class GameDetailService {
longitude: number; longitude: number;
}): Promise<ApiResponse<UpdateLocationRes>> { }): Promise<ApiResponse<UpdateLocationRes>> {
return httpService.post("/user/update_location", location, { return httpService.post("/user/update_location", location, {
showLoading: true, showLoading: false,
}); });
} }

View File

@@ -414,7 +414,9 @@ export const updateUserPhone = async (payload: ChangePhoneParams) => {
// 获取指定用户信息 // 获取指定用户信息
export const getUserInfoById = async (id) => { export const getUserInfoById = async (id) => {
try { try {
const response = await httpService.post("/user/detail_by_id", { id }); const response = await httpService.post("/user/detail_by_id", { id }, {
showLoading: false,
},);
return response; return response;
} catch (error) { } catch (error) {
console.error("获取用户信息失败:", error); console.error("获取用户信息失败:", error);

View File

@@ -0,0 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
<g clip-path="url(#clip0_4767_29603)">
<path d="M12 10.6666C13.4728 10.6666 14.6667 9.47269 14.6667 7.99992C14.6667 6.52715 13.4728 5.33325 12 5.33325" stroke="#8C8C8C" stroke-width="1.33333" stroke-linejoin="round"/>
<path d="M4.00016 5.33325C2.5274 5.33325 1.3335 6.52715 1.3335 7.99992C1.3335 9.47269 2.5274 10.6666 4.00016 10.6666" stroke="#8C8C8C" stroke-width="1.33333" stroke-linejoin="round"/>
<path d="M4 10.6666V10.4999V9.66658V7.99992V5.33325C4 3.12411 5.79087 1.33325 8 1.33325C10.2091 1.33325 12 3.12411 12 5.33325V10.6666C12 12.8757 10.2091 14.6666 8 14.6666" stroke="#8C8C8C" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_4767_29603">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 908 B

View File

@@ -9,7 +9,7 @@ import { clear_login_state } from "@/services/loginService";
import { convert_db_gender_to_display } from "@/utils/genderUtils"; import { convert_db_gender_to_display } from "@/utils/genderUtils";
import { EditModal } from "@/components"; import { EditModal } from "@/components";
import img from "@/config/images"; import img from "@/config/images";
import CommonDialog from '@/components/CommonDialog' import CommonDialog from "@/components/CommonDialog";
const EditProfilePage: React.FC = () => { const EditProfilePage: React.FC = () => {
// 用户信息状态 // 用户信息状态
@@ -309,7 +309,7 @@ const EditProfilePage: React.FC = () => {
// 注销账户 // 注销账户
const handle_close_account = () => { const handle_close_account = () => {
setShowLogoutDialog(true); setShowLogoutDialog(true);
} };
const onGetPhoneNumber = async (e) => { const onGetPhoneNumber = async (e) => {
if (!e.detail || !e.detail.code) { if (!e.detail || !e.detail.code) {
@@ -362,7 +362,11 @@ const EditProfilePage: React.FC = () => {
{/* 头像编辑区域 */} {/* 头像编辑区域 */}
<View className="avatar_section"> <View className="avatar_section">
<View className="avatar_container" onClick={handle_avatar_upload}> <View className="avatar_container" onClick={handle_avatar_upload}>
<Image className="avatar" src={user_info.avatar} /> <Image
className="avatar"
src={user_info.avatar}
mode="aspectFill"
/>
<View className="avatar_overlay"> <View className="avatar_overlay">
<Image <Image
className="upload_icon" className="upload_icon"
@@ -699,7 +703,9 @@ const EditProfilePage: React.FC = () => {
visible={showLogoutDialog} visible={showLogoutDialog}
cancelText="确定注销" cancelText="确定注销"
confirmText="再想想" confirmText="再想想"
onCancel={() => {UserService.logout()}} onCancel={() => {
UserService.logout();
}}
onConfirm={() => setShowLogoutDialog(false)} onConfirm={() => setShowLogoutDialog(false)}
contentTitle="确定要注销账号吗?" contentTitle="确定要注销账号吗?"
contentDesc="你的账号将会彻底删除,该操作不可恢复。" contentDesc="你的账号将会彻底删除,该操作不可恢复。"

View File

@@ -5,13 +5,13 @@ export function getOrderStatus(orderData) {
if (!order_no) { if (!order_no) {
return 'none' return 'none'
} }
const unPay = order_status === OrderStatus.PENDING && cancel_type === CancelType.NONE; const unPay = order_status === OrderStatus.PENDING && ([CancelType.NONE].includes(cancel_type));
const refund = [RefundStatus.PENDING, RefundStatus.SUCCESS].includes(refund_status); const refund = [RefundStatus.PENDING, RefundStatus.SUCCESS].includes(refund_status);
const expired = const expired =
order_status === OrderStatus.FINISHED || order_status === OrderStatus.FINISHED ||
[CancelType.TIMEOUT, CancelType.USER].includes(cancel_type); [CancelType.TIMEOUT, CancelType.USER].includes(cancel_type);
return unPay ? 'unpay' : refund ? 'refund' : expired ? 'expired' : 'progress' return unPay ? 'unpay' : refund ? 'refund' : expired ? cancel_type === CancelType.TIMEOUT ? 'timeout' : 'expired' : 'progress'
} }
// scene: list、detail // scene: list、detail
@@ -54,6 +54,7 @@ export function generateOrderActions(orderData, actions, scene) {
if (scene === 'list') { if (scene === 'list') {
const actionMap = new Map([ const actionMap = new Map([
['timeout', [deleteOrder, gameDetail]],
['expired', [deleteOrder, gameDetail]], ['expired', [deleteOrder, gameDetail]],
['progress', [quitGame, gameDetail]], ['progress', [quitGame, gameDetail]],
['refund', [deleteOrder, gameDetail]], ['refund', [deleteOrder, gameDetail]],
@@ -64,6 +65,7 @@ export function generateOrderActions(orderData, actions, scene) {
if (scene === 'detail') { if (scene === 'detail') {
const actionMap = new Map([ const actionMap = new Map([
['timeout', [deleteOrder, gameDetail]],
['expired', [gameDetail, deleteOrder]], ['expired', [gameDetail, deleteOrder]],
['progress', [gameDetail, quitGame]], ['progress', [gameDetail, quitGame]],
['refund', [deleteOrder, gameDetail]], ['refund', [deleteOrder, gameDetail]],