feat: 订单详情 & 问卷调查
This commit is contained in:
292
src/mod_user/orderDetail/index.tsx
Normal file
292
src/mod_user/orderDetail/index.tsx
Normal file
@@ -0,0 +1,292 @@
|
||||
import React, { useState } from "react";
|
||||
import { View, Text, Button, Image } from "@tarojs/components";
|
||||
import Taro, { useDidShow, useRouter } from "@tarojs/taro";
|
||||
import dayjs from "dayjs";
|
||||
import { delay } from "@/utils";
|
||||
import orderService, { GameOrderRes } from "@/services/orderService";
|
||||
import detailService, { GameDetail } from "@/services/detailService";
|
||||
import { withAuth } from "@/components";
|
||||
import { calculateDistance, getCurrentLocation } from "@/utils";
|
||||
import img from "@/config/images";
|
||||
import { DECLAIMER } from "./config";
|
||||
import styles from "./index.module.scss";
|
||||
|
||||
dayjs.locale("zh-cn");
|
||||
|
||||
function GameInfo(props) {
|
||||
const { detail, currentLocation } = props;
|
||||
const { latitude, longitude, location, location_name, start_time, end_time } =
|
||||
detail || {};
|
||||
|
||||
const openMap = () => {
|
||||
Taro.openLocation({
|
||||
latitude, // 纬度(必填)
|
||||
longitude, // 经度(必填)
|
||||
name: location_name, // 位置名(可选)
|
||||
address: location, // 地址详情(可选)
|
||||
scale: 15, // 地图缩放级别(1-28)
|
||||
});
|
||||
};
|
||||
|
||||
const [c_latitude, c_longitude] = currentLocation;
|
||||
const distance =
|
||||
c_latitude + c_longitude === 0
|
||||
? 0
|
||||
: calculateDistance(c_latitude, c_longitude, latitude, longitude) / 1000;
|
||||
|
||||
const startTime = dayjs(start_time);
|
||||
const endTime = dayjs(end_time);
|
||||
const game_length = endTime.diff(startTime, "minutes") / 60;
|
||||
|
||||
const startMonth = startTime.format("M");
|
||||
const startDay = startTime.format("D");
|
||||
const theDayOfWeek = startTime.format("dddd");
|
||||
const startDate = `${startMonth}月${startDay}日 ${theDayOfWeek}`;
|
||||
const gameRange = `${startTime.format("HH:mm")} - ${endTime.format("HH:mm")}`;
|
||||
|
||||
return (
|
||||
<View className={styles.gameInfoContainer}>
|
||||
<View className={styles.gameInfo}>
|
||||
{/* Date and Weather */}
|
||||
<View className={styles.gameInfoDateWeather}>
|
||||
{/* Calendar and Date time */}
|
||||
<View className={styles.gameInfoDateWeatherCalendarDate}>
|
||||
{/* Calendar */}
|
||||
<View className={styles.gameInfoDateWeatherCalendarDateCalendar}>
|
||||
<View className={styles.month}>{startMonth}月</View>
|
||||
<View className={styles.day}>{startDay}</View>
|
||||
</View>
|
||||
{/* Date time */}
|
||||
<View className={styles.gameInfoDateWeatherCalendarDateDate}>
|
||||
<View className={styles.date}>{startDate}</View>
|
||||
<View className={styles.venueTime}>
|
||||
{gameRange} ({game_length}小时)
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
{/* Place */}
|
||||
<View className={styles.gameInfoPlace}>
|
||||
{/* venue location message */}
|
||||
<View className={styles.locationMessage}>
|
||||
{/* location icon */}
|
||||
<View className={styles.locationMessageIcon}>
|
||||
<Image
|
||||
className={styles.locationMessageIconImage}
|
||||
src="https://bimwe.oss-cn-shanghai.aliyuncs.com/front/ball/images/43aab7e9-061e-4e3b-88c6-61c19b660b22.png"
|
||||
/>
|
||||
</View>
|
||||
{/* location message */}
|
||||
<View className={styles.locationMessageText}>
|
||||
{/* venue name and distance */}
|
||||
<View
|
||||
className={styles.locationMessageTextNameDistance}
|
||||
onClick={openMap}
|
||||
>
|
||||
<Text>{location_name || "-"}</Text>
|
||||
{distance ? (
|
||||
<>
|
||||
<Text>·</Text>
|
||||
<Text>{distance.toFixed(1)}km</Text>
|
||||
</>
|
||||
) : null}
|
||||
|
||||
<Image
|
||||
className={styles.locationMessageTextNameDistanceArrow}
|
||||
src={img.ICON_DETAIL_ARROW_RIGHT}
|
||||
/>
|
||||
</View>
|
||||
{/* venue address */}
|
||||
<View className={styles.locationMessageTextAddress}>
|
||||
<Text>{location || "-"}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
{/* Action bar */}
|
||||
<View className={styles.gameInfoActions}></View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
function OrderMsg(props) {
|
||||
const { detail, orderInfo } = props;
|
||||
const {
|
||||
start_time,
|
||||
end_time,
|
||||
location,
|
||||
location_name,
|
||||
wechat_contact,
|
||||
price,
|
||||
} = detail;
|
||||
const { order_info: { registrant_nickname } = {} } = orderInfo
|
||||
const startTime = dayjs(start_time);
|
||||
const endTime = dayjs(end_time);
|
||||
const startYear = startTime.format('YYYY')
|
||||
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 summary = [
|
||||
{
|
||||
title: "时间",
|
||||
content: `${startDate} ${gameRange}`,
|
||||
},
|
||||
{
|
||||
title: "地址",
|
||||
content: `${location} ${location_name}`,
|
||||
},
|
||||
{
|
||||
title: "组织者昵称",
|
||||
content: registrant_nickname,
|
||||
},
|
||||
{
|
||||
title: "组织者电话",
|
||||
content: wechat_contact,
|
||||
},
|
||||
{
|
||||
title: "费用",
|
||||
content: `${price} 元`,
|
||||
},
|
||||
];
|
||||
return (
|
||||
<View className={styles.orderSummary}>
|
||||
<View className={styles.moduleTitle}>
|
||||
<Text>确认订单信息</Text>
|
||||
</View>
|
||||
{/* 订单信息摘要 */}
|
||||
<View className={styles.summaryList}>
|
||||
{
|
||||
summary.map((item, index) => (<View key={index} className={styles.summaryItem}>
|
||||
<Text className={styles.title}>{item.title}</Text>
|
||||
<Text className={styles.content}>{item.content}</Text>
|
||||
</View>))
|
||||
}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
function RefundPolicy(props) {
|
||||
const { orderInfo } = props
|
||||
const { refund_policy = [] } = orderInfo
|
||||
const policyList = [{
|
||||
time: '申请退款时间',
|
||||
rule: '退款规则',
|
||||
}, ...refund_policy.map((item, index) => {
|
||||
const [, theTime] = item.application_time.split('undefined ')
|
||||
const theTimeObj = dayjs(theTime)
|
||||
const year = theTimeObj.format('YYYY')
|
||||
const month = theTimeObj.format('M')
|
||||
const day = theTimeObj.format('D')
|
||||
const time = theTimeObj.format('HH:MM')
|
||||
return { time: `${year}年${month}月${day}日${time}${index === 0 ? '前' : '后'}`, rule: item.refund_rule }
|
||||
})]
|
||||
return (
|
||||
<View className={styles.refundPolicy}>
|
||||
<View className={styles.moduleTitle}>
|
||||
<Text>退款政策</Text>
|
||||
</View>
|
||||
{/* 订单信息摘要 */}
|
||||
<View className={styles.policyList}>
|
||||
{
|
||||
policyList.map((item, index) => (<View key={index} className={styles.policyItem}>
|
||||
<View className={styles.time}>{item.time}</View>
|
||||
<View className={styles.rule}>{item.rule}</View>
|
||||
</View>))
|
||||
}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
function Disclaimer() {
|
||||
return (
|
||||
<View className={styles.declaimer}>
|
||||
<Text className={styles.title}>免责声明</Text>
|
||||
<Text className={styles.content}>{DECLAIMER}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const OrderCheck = () => {
|
||||
const { params } = useRouter();
|
||||
const { id, gameId } = params;
|
||||
const [detail, setDetail] = useState<GameDetail | {}>({});
|
||||
const [location, setLocation] = useState<number[]>([0, 0]);
|
||||
const [orderInfo, setOrderInfo] = useState<GameOrderRes | {}>({})
|
||||
|
||||
useDidShow(async () => {
|
||||
const res = await detailService.getDetail(Number(gameId));
|
||||
const orderRes = await orderService.getOrderInfo(Number(gameId))
|
||||
setOrderInfo(orderRes.data)
|
||||
console.log(res);
|
||||
if (res.code === 0) {
|
||||
setDetail(res.data);
|
||||
}
|
||||
const location = await getCurrentLocation();
|
||||
setLocation([location.latitude, location.longitude]);
|
||||
});
|
||||
|
||||
//TODO: get order msg from id
|
||||
const handlePay = async () => {
|
||||
Taro.showLoading({
|
||||
title: "支付中...",
|
||||
mask: true,
|
||||
});
|
||||
const res = await orderService.createOrder(Number(gameId));
|
||||
if (res.code === 0) {
|
||||
const { payment_required, payment_params } = res.data;
|
||||
if (payment_required) {
|
||||
const {
|
||||
timeStamp,
|
||||
nonceStr,
|
||||
package: package_,
|
||||
signType,
|
||||
paySign,
|
||||
} = payment_params;
|
||||
await Taro.requestPayment({
|
||||
timeStamp,
|
||||
nonceStr,
|
||||
package: package_,
|
||||
signType,
|
||||
paySign,
|
||||
success: async () => {
|
||||
Taro.hideLoading();
|
||||
Taro.showToast({
|
||||
title: "支付成功",
|
||||
icon: "success",
|
||||
});
|
||||
await delay(1000);
|
||||
Taro.navigateBack({
|
||||
delta: 1,
|
||||
});
|
||||
},
|
||||
fail: () => {
|
||||
Taro.hideLoading();
|
||||
Taro.showToast({
|
||||
title: "支付失败",
|
||||
icon: "none",
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
return (
|
||||
<View className={styles.container}>
|
||||
{/* Game Date and Address */}
|
||||
<GameInfo detail={detail} currentLocation={location} />
|
||||
{/* Order message */}
|
||||
<OrderMsg detail={detail} orderInfo={orderInfo} />
|
||||
{/* Refund policy */}
|
||||
<RefundPolicy orderInfo={orderInfo} />
|
||||
{/* Disclaimer */}
|
||||
<Disclaimer />
|
||||
<Button className={styles.payButton} type="primary" onClick={handlePay}>支付</Button>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default withAuth(OrderCheck);
|
||||
Reference in New Issue
Block a user