778 lines
23 KiB
TypeScript
778 lines
23 KiB
TypeScript
import { useState, useEffect, useRef, useId, useMemo } from "react";
|
||
import { View, Text, Image, Button, Canvas } from "@tarojs/components";
|
||
import Taro, { useRouter, useShareAppMessage } from "@tarojs/taro";
|
||
import dayjs from "dayjs";
|
||
import classnames from "classnames";
|
||
import { withAuth, RadarChart } from "@/components";
|
||
import evaluateService, {
|
||
LastTimeTestResult,
|
||
Question,
|
||
TestResultData,
|
||
StageType,
|
||
} from "@/services/evaluateService";
|
||
import { useUserInfo, useUserActions } from "@/store/userStore";
|
||
import { useEvaluate, EvaluateScene } from "@/store/evaluateStore";
|
||
import { useGlobalState } from "@/store/global";
|
||
import { delay, getCurrentFullPath } from "@/utils";
|
||
import { formatNtrpDisplay } from "@/utils/helper";
|
||
import { waitForAuthInit } from "@/utils/authInit";
|
||
import CloseIcon from "@/static/ntrp/ntrp_close_icon.svg";
|
||
import DocCopy from "@/static/ntrp/ntrp_doc_copy.svg";
|
||
import ArrowRight from "@/static/ntrp/ntrp_arrow_right.svg";
|
||
import ArrowBack from "@/static/ntrp/ntrp_arrow_back.svg";
|
||
import CircleChecked from "@/static/ntrp/ntrp_circle_checked.svg";
|
||
import CircleUnChecked from "@/static/ntrp/ntrp_circle_unchecked.svg";
|
||
import WechatIcon from "@/static/ntrp/ntrp_wechat.svg";
|
||
import DownloadIcon from "@/static/ntrp/ntrp_download.svg";
|
||
import ReTestIcon from "@/static/ntrp/ntrp_re-action.svg";
|
||
import styles from "./index.module.scss";
|
||
|
||
const sourceTypeToTextMap = new Map([
|
||
[EvaluateScene.detail, "继续加入球局"],
|
||
[EvaluateScene.publish, "继续发布球局"],
|
||
]);
|
||
|
||
function adjustRadarLabels(
|
||
source: [string, number][],
|
||
topK: number = 4 // 默认挑前4个最长的标签保护
|
||
): [string, number][] {
|
||
if (source.length === 0) return source;
|
||
|
||
// 复制并按长度排序(降序)
|
||
let sorted = [...source].sort((a, b) => b[0].length - a[0].length);
|
||
|
||
// 取出前 K 个最长标签
|
||
let protectedLabels = sorted.slice(0, topK);
|
||
// 其他标签(保持原始顺序,但排除掉 protected)
|
||
let protectedSet = new Set(protectedLabels.map(([l]) => l));
|
||
let others = source.filter(([l]) => !protectedSet.has(l));
|
||
|
||
let n = source.length;
|
||
let result: ([string, number] | undefined)[] = new Array(n);
|
||
|
||
// 放首尾
|
||
result[0] = protectedLabels.shift() || others.shift();
|
||
result[n - 1] = protectedLabels.shift() || others.shift();
|
||
|
||
// 放中间(支持偶数两个位置)
|
||
if (n % 2 === 0) {
|
||
let mid1 = n / 2 - 1;
|
||
let mid2 = n / 2;
|
||
result[mid1] = protectedLabels.shift() || others.shift();
|
||
result[mid2] = protectedLabels.shift() || others.shift();
|
||
} else {
|
||
let mid = Math.floor(n / 2);
|
||
result[mid] = protectedLabels.shift() || others.shift();
|
||
}
|
||
|
||
// 把剩余标签按顺序塞进空位
|
||
let pool = [...protectedLabels, ...others];
|
||
for (let i = 0; i < n; i++) {
|
||
if (!result[i]) result[i] = pool.shift();
|
||
}
|
||
|
||
return result as [string, number][];
|
||
}
|
||
|
||
function isOnCancelEmpty(onCancelFunc) {
|
||
if (typeof onCancelFunc !== "function") {
|
||
console.log("onCancel 不是函数");
|
||
return false;
|
||
}
|
||
|
||
try {
|
||
const funcString = onCancelFunc.toString().trim();
|
||
|
||
// 常见空函数模式
|
||
const emptyFunctionPatterns = [
|
||
"functiononCancel(){}",
|
||
"function onCancel() {}",
|
||
"onCancel(){}",
|
||
"()=>{}",
|
||
"functiononCancel(){ }",
|
||
"() => {}",
|
||
];
|
||
|
||
const normalized = funcString.replace(/\s/g, "");
|
||
return emptyFunctionPatterns.includes(normalized);
|
||
} catch (error) {
|
||
console.error("检查 onCancel 函数时出错:", error);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
function CommonGuideBar(props) {
|
||
const { title, confirm } = props;
|
||
const { onCancel } = useEvaluate();
|
||
const { statusNavbarHeightInfo } = useGlobalState();
|
||
const { statusBarHeight, navBarHeight } = statusNavbarHeightInfo;
|
||
// const userInfo = useUserInfo()
|
||
|
||
function handleClose() {
|
||
//TODO: 二次确认
|
||
if (confirm) {
|
||
}
|
||
try {
|
||
console.log(onCancel, isOnCancelEmpty(onCancel));
|
||
if (isOnCancelEmpty(onCancel)) {
|
||
Taro.redirectTo({ url: "/main_pages/index" });
|
||
}
|
||
onCancel();
|
||
} catch {
|
||
Taro.redirectTo({ url: "/main_pages/index" });
|
||
}
|
||
}
|
||
|
||
return (
|
||
<View
|
||
className={styles.header}
|
||
style={{
|
||
height: navBarHeight + "px",
|
||
paddingTop: statusBarHeight + "px",
|
||
}}
|
||
>
|
||
<View className={styles.closeIcon} onClick={handleClose}>
|
||
<Image className={styles.closeImg} src={CloseIcon} />
|
||
</View>
|
||
<View className={styles.title}>
|
||
<Text>{title}</Text>
|
||
</View>
|
||
</View>
|
||
);
|
||
}
|
||
|
||
function Intro() {
|
||
const [ntrpData, setNtrpData] = useState<LastTimeTestResult>();
|
||
const userInfo = useUserInfo();
|
||
const { fetchUserInfo } = useUserActions();
|
||
const [ready, setReady] = useState(false);
|
||
const { setCallback } = useEvaluate();
|
||
|
||
const { last_test_result = null } = ntrpData || {};
|
||
const { ntrp_level, create_time, id } = last_test_result || {};
|
||
const lastTestTime = create_time
|
||
? dayjs(create_time).format("YYYY年M月D日")
|
||
: "";
|
||
|
||
useEffect(() => {
|
||
const init = async () => {
|
||
// 先等待静默登录完成
|
||
await waitForAuthInit();
|
||
// 然后再调用接口
|
||
await getLastResult();
|
||
};
|
||
init();
|
||
}, []);
|
||
|
||
async function getLastResult() {
|
||
const res = await evaluateService.getLastResult();
|
||
if (res.code === 0) {
|
||
setNtrpData(res.data);
|
||
if (res.data.has_ntrp_level) {
|
||
// 确保用户信息已加载
|
||
if (!userInfo || Object.keys(userInfo).length === 0) {
|
||
await fetchUserInfo();
|
||
}
|
||
}
|
||
setReady(true);
|
||
}
|
||
}
|
||
if (!ready) {
|
||
return "";
|
||
}
|
||
|
||
function handleNext(type) {
|
||
if (!id) {
|
||
setCallback({
|
||
type: EvaluateScene.share,
|
||
next: () => {
|
||
Taro.redirectTo({ url: "/main_pages/index" });
|
||
},
|
||
onCancel: () => {
|
||
Taro.redirectTo({ url: "/main_pages/index" });
|
||
},
|
||
});
|
||
}
|
||
Taro.redirectTo({
|
||
url: `/other_pages/ntrp-evaluate/index?stage=${type}${type === StageType.RESULT ? `&id=${id}` : ""
|
||
}`,
|
||
});
|
||
}
|
||
|
||
return (
|
||
<View className={styles.introContainer}>
|
||
<CommonGuideBar />
|
||
{ntrpData?.has_test_record ? (
|
||
<View className={styles.result}>
|
||
<View className={styles.avatarWrap}>
|
||
<View className={styles.avatar}>
|
||
<Image
|
||
className={styles.avatarUrl}
|
||
src={userInfo?.avatar_url || ""}
|
||
mode="aspectFill"
|
||
/>
|
||
</View>
|
||
{/* avatar side */}
|
||
<View className={styles.addonImage}>
|
||
<Image
|
||
className={styles.docImage}
|
||
src={DocCopy}
|
||
mode="aspectFill"
|
||
/>
|
||
</View>
|
||
</View>
|
||
{/* tip */}
|
||
<View className={styles.tip}>
|
||
<Image
|
||
className={styles.tipImage}
|
||
src="https://bimwe.oss-cn-shanghai.aliyuncs.com/front/ball/images/b7cb47aa-b609-4112-899f-3fde02ed2431.png"
|
||
mode="aspectFit"
|
||
/>
|
||
</View>
|
||
<View className={styles.lastResult}>
|
||
<View className={styles.tipAndTime}>
|
||
<Text>上次测试结果</Text>
|
||
<Text>{lastTestTime}</Text>
|
||
</View>
|
||
<View className={styles.levelWrap}>
|
||
<Text>NTRP</Text>
|
||
<Text className={styles.level}>
|
||
{formatNtrpDisplay(ntrp_level || "")}
|
||
</Text>
|
||
</View>
|
||
<View className={styles.slogan}>
|
||
<Text>变线+网前,下一步就是赢比赛!</Text>
|
||
</View>
|
||
</View>
|
||
<View className={styles.actions}>
|
||
<View className={styles.buttonWrap}>
|
||
<Button
|
||
className={classnames(styles.button, styles.primary)}
|
||
type="primary"
|
||
onClick={() => handleNext(StageType.TEST)}
|
||
>
|
||
<Text>再次测试</Text>
|
||
<Image className={styles.arrowImage} src={ArrowRight} />
|
||
</Button>
|
||
</View>
|
||
<View className={styles.buttonWrap}>
|
||
<Button
|
||
className={styles.button}
|
||
onClick={() => handleNext(StageType.RESULT)}
|
||
>
|
||
<Text>继续使用上次测试结果</Text>
|
||
</Button>
|
||
</View>
|
||
</View>
|
||
</View>
|
||
) : (
|
||
<View className={styles.guide}>
|
||
{/* tip */}
|
||
<View className={styles.tip}>
|
||
<Image
|
||
className={styles.tipImage}
|
||
src="https://bimwe.oss-cn-shanghai.aliyuncs.com/front/ball/images/b7cb47aa-b609-4112-899f-3fde02ed2431.png"
|
||
mode="aspectFit"
|
||
/>
|
||
</View>
|
||
{/* radar */}
|
||
<View className={styles.radar}>
|
||
<Image
|
||
className={styles.radarImage}
|
||
src="https://bimwe.oss-cn-shanghai.aliyuncs.com/front/ball/images/a2e1b639-82a9-4ab8-b767-8605556eafcb.png"
|
||
mode="aspectFit"
|
||
/>
|
||
</View>
|
||
<View className={styles.desc}>
|
||
<Text>
|
||
NTRP(National Tennis Rating
|
||
Program)是一种常用的网球水平分级系统,这不是绝对精准的“分数”,而是一个参考标准,能够帮助你更清晰地了解自己的网球水平,从而在训练、比赛或娱乐活动中找到「难度合适」的球友,避免过度碾压或被碾压。
|
||
</Text>
|
||
</View>
|
||
<View className={styles.actions}>
|
||
<View className={styles.buttonWrap}>
|
||
<Button
|
||
className={classnames(styles.button, styles.primary)}
|
||
type="primary"
|
||
onClick={() => handleNext(StageType.TEST)}
|
||
>
|
||
<Text>开始测试</Text>
|
||
<Image className={styles.arrowImage} src={ArrowRight} />
|
||
</Button>
|
||
</View>
|
||
</View>
|
||
</View>
|
||
)}
|
||
</View>
|
||
);
|
||
}
|
||
|
||
function Test() {
|
||
const [disabled, setDisabled] = useState(false);
|
||
const [index, setIndex] = useState(0);
|
||
const [questions, setQuestions] = useState<
|
||
(Question & { choosen: number })[]
|
||
>([]);
|
||
const startTimeRef = useRef<number>(0);
|
||
|
||
useEffect(() => {
|
||
startTimeRef.current = Date.now();
|
||
getQUestions();
|
||
}, []);
|
||
|
||
useEffect(() => {
|
||
setDisabled(questions[index]?.choosen === -1);
|
||
}, [index, questions]);
|
||
|
||
const doneFlag = useMemo(() => {
|
||
const [q1, q2, q3] = questions;
|
||
return [q1, q2, q3].every((q) => q?.choosen === 0);
|
||
}, [questions]);
|
||
|
||
async function getQUestions() {
|
||
const res = await evaluateService.getQuestions();
|
||
if (res.code === 0) {
|
||
setQuestions(res.data.map((item) => ({ ...item, choosen: -1 })));
|
||
}
|
||
}
|
||
|
||
function handleSelect(i) {
|
||
setQuestions((prev) =>
|
||
prev.map((item, pIndex) => ({
|
||
...item,
|
||
...(pIndex === index ? { choosen: i } : {}),
|
||
}))
|
||
);
|
||
}
|
||
|
||
async function handleSubmit() {
|
||
setDisabled(true);
|
||
try {
|
||
const res = await evaluateService.submit({
|
||
answers: questions
|
||
.filter((item) => item.choosen >= 0)
|
||
.map((item) => ({
|
||
question_id: item.id,
|
||
answer_index: item.choosen,
|
||
})),
|
||
test_duration: (Date.now() - startTimeRef.current) / 1000,
|
||
});
|
||
if (res.code === 0) {
|
||
Taro.redirectTo({
|
||
url: `/other_pages/ntrp-evaluate/index?stage=${StageType.RESULT}&id=${res.data.record_id}`,
|
||
});
|
||
}
|
||
} catch (e) {
|
||
Taro.showToast({ title: e.message, icon: "error" });
|
||
} finally {
|
||
setDisabled(false);
|
||
}
|
||
}
|
||
|
||
function handIndexChange(direction) {
|
||
if (disabled && direction > 0) {
|
||
return;
|
||
}
|
||
if ((index === questions.length - 1 || doneFlag) && direction > 0) {
|
||
handleSubmit();
|
||
return;
|
||
}
|
||
setIndex((prev) => prev + direction);
|
||
}
|
||
|
||
const question = questions[index];
|
||
if (!question) {
|
||
return "";
|
||
}
|
||
return (
|
||
<View className={styles.testContainer}>
|
||
<CommonGuideBar confirm title={`${index + 1} / ${questions.length}`} />
|
||
<View className={styles.bar}>
|
||
<View
|
||
className={styles.progressBar}
|
||
style={{ width: `${100 * ((index + 1) / questions.length)}%` }}
|
||
/>
|
||
</View>
|
||
<View className={styles.notice}>
|
||
<Text>根据近3个月实际表现勾选最符合项</Text>
|
||
</View>
|
||
<View className={styles.question}>
|
||
<View className={styles.content}>{question.question_content}</View>
|
||
<View className={styles.options}>
|
||
{question.options.map((item, i) => {
|
||
const checked = question.choosen === i;
|
||
return (
|
||
<View
|
||
key={i}
|
||
className={styles.optionItem}
|
||
onClick={() => handleSelect(i)}
|
||
>
|
||
<View className={styles.optionText}>{item.text}</View>
|
||
<View className={styles.optionIcon}>
|
||
<Image
|
||
className={styles.icon}
|
||
src={checked ? CircleChecked : CircleUnChecked}
|
||
/>
|
||
</View>
|
||
</View>
|
||
);
|
||
})}
|
||
</View>
|
||
</View>
|
||
<View className={styles.actions}>
|
||
<View
|
||
className={classnames(styles.next, disabled ? styles.disabled : "")}
|
||
onClick={() => handIndexChange(1)}
|
||
>
|
||
<Button className={styles.nextBtn} type="primary">
|
||
{index === questions.length - 1 || doneFlag ? "完成测试" : "继续"}
|
||
</Button>
|
||
</View>
|
||
{index !== 0 && (
|
||
<View className={styles.prev} onClick={() => handIndexChange(-1)}>
|
||
<Image className={styles.backIcon} src={ArrowBack} />
|
||
<Text>返回</Text>
|
||
</View>
|
||
)}
|
||
</View>
|
||
</View>
|
||
);
|
||
}
|
||
|
||
function Result() {
|
||
const { params } = useRouter();
|
||
const { id } = params;
|
||
const userInfo = useUserInfo();
|
||
const { fetchUserInfo } = useUserActions();
|
||
const { type, next, clear } = useEvaluate();
|
||
const radarRef = useRef();
|
||
|
||
const [result, setResult] = useState<TestResultData>();
|
||
const [radarData, setRadarData] = useState<
|
||
[propName: string, prop: number][]
|
||
>([]);
|
||
|
||
useEffect(() => {
|
||
const init = async () => {
|
||
// 先等待静默登录完成
|
||
await waitForAuthInit();
|
||
// 然后再调用接口
|
||
await getResultById();
|
||
// 确保用户信息已加载
|
||
if (!userInfo || Object.keys(userInfo).length === 0) {
|
||
await fetchUserInfo();
|
||
}
|
||
};
|
||
init();
|
||
}, [id]);
|
||
|
||
async function getResultById() {
|
||
const res = await evaluateService.getTestResult({ record_id: Number(id) });
|
||
if (res.code === 0) {
|
||
setResult(res.data);
|
||
// delay(1000);
|
||
setRadarData(
|
||
adjustRadarLabels(
|
||
Object.entries(res.data.radar_data.abilities).map(([key, value]) => [
|
||
key,
|
||
Math.min(
|
||
100,
|
||
Math.floor((value.current_score / value.max_score) * 100)
|
||
),
|
||
])
|
||
)
|
||
);
|
||
updateUserLevel(res.data.record_id, res.data.ntrp_level);
|
||
}
|
||
}
|
||
|
||
function updateUserLevel(record_id, ntrp_level) {
|
||
try {
|
||
evaluateService.updateNtrp({
|
||
record_id,
|
||
ntrp_level,
|
||
update_type: "test_result",
|
||
});
|
||
} catch (e) {
|
||
Taro.showToast({ title: e.message, icon: "none" });
|
||
}
|
||
}
|
||
|
||
function handleReTest() {
|
||
if (!userInfo.phone) {
|
||
handleAuth();
|
||
return false;
|
||
}
|
||
Taro.redirectTo({
|
||
url: `/other_pages/ntrp-evaluate/index?stage=${StageType.TEST}`,
|
||
});
|
||
}
|
||
|
||
function handleViewGames() {
|
||
Taro.redirectTo({
|
||
url: "/main_pages/index",
|
||
});
|
||
}
|
||
|
||
async function handleGoon() {
|
||
if (!userInfo?.phone) {
|
||
Taro.redirectTo({
|
||
url: `/login_pages/index/index?redirect=${encodeURIComponent(
|
||
`/main_pages/index`
|
||
)}`,
|
||
});
|
||
clear();
|
||
return;
|
||
}
|
||
if (type) {
|
||
next({ flag: false, score: result?.ntrp_level as string });
|
||
await delay(1500);
|
||
clear();
|
||
} else {
|
||
handleViewGames();
|
||
}
|
||
}
|
||
|
||
async function genCardImage() {
|
||
return new Promise(async (resolve, reject) => {
|
||
const url = await radarRef.current.generateImage();
|
||
const query = Taro.createSelectorQuery();
|
||
query
|
||
.select("#exportCanvas")
|
||
.fields({ node: true, size: true })
|
||
.exec((res2) => {
|
||
const canvas = res2[0].node;
|
||
const ctx = canvas.getContext("2d");
|
||
const dpr = Taro.getWindowInfo().pixelRatio;
|
||
const width = 300;
|
||
const height = 400;
|
||
canvas.width = width * dpr;
|
||
canvas.height = height * dpr;
|
||
ctx.scale(dpr, dpr);
|
||
|
||
// 背景
|
||
ctx.fillStyle = "#e9fdf8";
|
||
ctx.fillRect(0, 0, width, height);
|
||
|
||
// 标题文字
|
||
ctx.fillStyle = "#000";
|
||
ctx.font = "16px sans-serif";
|
||
ctx.fillText("你的 NTRP 测试结果为", 20, 40);
|
||
ctx.fillStyle = "#00E5AD";
|
||
ctx.font = "bold 22px sans-serif";
|
||
ctx.fillText(`NTRP ${formatNtrpDisplay(result?.ntrp_level)}`, 20, 70);
|
||
|
||
// 绘制雷达图
|
||
const img = canvas.createImage();
|
||
img.src = url;
|
||
img.onload = () => {
|
||
ctx.drawImage(img, 20, 100, 260, 260);
|
||
|
||
// 第三步:导出最终卡片
|
||
Taro.canvasToTempFilePath({
|
||
canvas,
|
||
success: (res3) => {
|
||
console.log("导出成功:", res3.tempFilePath);
|
||
resolve(res3.tempFilePath);
|
||
},
|
||
});
|
||
};
|
||
});
|
||
});
|
||
}
|
||
|
||
async function handleSaveImage() {
|
||
console.log(userInfo);
|
||
if (!userInfo?.phone) {
|
||
handleAuth();
|
||
return;
|
||
}
|
||
Taro.getSetting().then(async (res) => {
|
||
if (!res.authSetting["scope.writePhotosAlbum"]) {
|
||
Taro.authorize({
|
||
scope: "scope.writePhotosAlbum",
|
||
success: async () => {
|
||
try {
|
||
const url = await genCardImage();
|
||
Taro.saveImageToPhotosAlbum({ filePath: url });
|
||
Taro.showToast({ title: "保存成功" });
|
||
} catch (e) {
|
||
Taro.showToast({ title: "图片保存失败", icon: "none" });
|
||
}
|
||
},
|
||
fail: () => {
|
||
Taro.showModal({
|
||
title: "提示",
|
||
content: "需要开启相册权限才能保存图片",
|
||
success: (r) => {
|
||
if (r.confirm) Taro.openSetting();
|
||
},
|
||
});
|
||
},
|
||
});
|
||
} else {
|
||
try {
|
||
const url = await genCardImage();
|
||
Taro.saveImageToPhotosAlbum({ filePath: url });
|
||
Taro.showToast({ title: "保存成功" });
|
||
} catch (e) {
|
||
Taro.showToast({ title: "图片保存失败", icon: "none" });
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
useShareAppMessage(async (res) => {
|
||
// const url = await genCardImage();
|
||
console.log(res, "res");
|
||
return {
|
||
title: "来测一测你的NTRP等级吧",
|
||
// imageUrl: url,
|
||
path: `/other_pages/ntrp-evaluate/index?stage=${StageType.INTRO}`,
|
||
};
|
||
});
|
||
|
||
function handleAuth() {
|
||
if (userInfo?.phone) {
|
||
return true;
|
||
}
|
||
const currentPage = getCurrentFullPath();
|
||
Taro.redirectTo({
|
||
url: `/login_pages/index/index${currentPage ? `?redirect=${encodeURIComponent(currentPage)}` : ""
|
||
}`,
|
||
});
|
||
}
|
||
|
||
function handleGo() { }
|
||
|
||
return (
|
||
<View className={styles.resultContainer}>
|
||
<CommonGuideBar />
|
||
<View className={styles.card}>
|
||
<View className={styles.avatarWrap}>
|
||
<View className={styles.avatar}>
|
||
<Image
|
||
className={styles.avatarUrl}
|
||
src={userInfo?.avatar_url || ""}
|
||
mode="aspectFill"
|
||
/>
|
||
</View>
|
||
{/* avatar side */}
|
||
<View className={styles.addonImage}>
|
||
<Image
|
||
className={styles.docImage}
|
||
src={DocCopy}
|
||
mode="aspectFill"
|
||
/>
|
||
</View>
|
||
</View>
|
||
<View className={styles.desc}>
|
||
<View className={styles.tip}>
|
||
<Text>你的 NTRP 测试结果为</Text>
|
||
</View>
|
||
<View className={styles.levelWrap}>
|
||
<Text>NTRP</Text>
|
||
<Text className={styles.level}>
|
||
{formatNtrpDisplay(result?.ntrp_level)}
|
||
</Text>
|
||
</View>
|
||
<View className={styles.slogan}>
|
||
<Text>变线+网前,下一步就是赢比赛!</Text>
|
||
</View>
|
||
</View>
|
||
<View>
|
||
<RadarChart ref={radarRef} data={radarData} />
|
||
</View>
|
||
<View className={styles.retest} onClick={handleReTest}>
|
||
<Image className={styles.re_actIcon} src={ReTestIcon} />
|
||
<Text>重新测试</Text>
|
||
</View>
|
||
</View>
|
||
{userInfo?.phone ? (
|
||
<View className={styles.updateTip}>
|
||
<Text>
|
||
你的 NTRP 水平已更新为 {formatNtrpDisplay(result?.ntrp_level || "")}{" "}
|
||
</Text>
|
||
<Text className={styles.grayTip}>(可在个人信息中修改)</Text>
|
||
</View>
|
||
) : (
|
||
<View className={styles.updateTip}>
|
||
<Text>登录「有场」小程序,查看匹配你的球局</Text>
|
||
</View>
|
||
)}
|
||
<View className={styles.actions}>
|
||
<View className={styles.viewGame} onClick={handleGoon}>
|
||
<Button className={styles.viewGameBtn}>
|
||
{sourceTypeToTextMap.get(type) || "去看看适合你的球局"}
|
||
</Button>
|
||
</View>
|
||
<View className={styles.otherActions}>
|
||
<View className={styles.share}>
|
||
<Button
|
||
className={styles.shareBtn}
|
||
openType={userInfo?.phone ? "share" : undefined}
|
||
onClick={handleAuth}
|
||
></Button>
|
||
<View className={styles.shareBtnCover}>
|
||
<Image className={styles.wechatIcon} src={WechatIcon} />
|
||
<Text>邀请好友测试</Text>
|
||
</View>
|
||
</View>
|
||
<View className={styles.saveImage} onClick={handleSaveImage}>
|
||
<Button className={styles.saveImageBtn}></Button>
|
||
<View className={styles.saveImageBtnCover}>
|
||
<Image className={styles.downloadIcon} src={DownloadIcon} />
|
||
<Text>保存图片</Text>
|
||
</View>
|
||
</View>
|
||
</View>
|
||
</View>
|
||
<Canvas
|
||
type="2d"
|
||
id="exportCanvas"
|
||
style={{
|
||
width: "0px",
|
||
height: "0px",
|
||
position: "absolute",
|
||
left: "-9999px",
|
||
}}
|
||
/>
|
||
</View>
|
||
);
|
||
}
|
||
|
||
const ComponentsMap = {
|
||
[StageType.INTRO]: Intro,
|
||
[StageType.TEST]: Test,
|
||
[StageType.RESULT]: Result,
|
||
};
|
||
|
||
function NtrpEvaluate() {
|
||
// const { updateUserInfo } = useUserActions();
|
||
const { params } = useRouter();
|
||
// const { redirect } = params;
|
||
|
||
const stage = params.stage as StageType;
|
||
|
||
// async function handleUpdateNtrp() {
|
||
// await updateUserInfo({
|
||
// ntrp_level: "4.0",
|
||
// });
|
||
// Taro.showToast({
|
||
// title: "更新成功",
|
||
// icon: "success",
|
||
// duration: 2000,
|
||
// });
|
||
// await delay(2000);
|
||
// if (redirect) {
|
||
// Taro.redirectTo({ url: decodeURIComponent(redirect) });
|
||
// }
|
||
// }
|
||
|
||
const Component = ComponentsMap[stage];
|
||
|
||
return <Component />;
|
||
}
|
||
|
||
export default withAuth(NtrpEvaluate);
|