feat: NTRP测试入口接入

This commit is contained in:
2025-10-01 09:34:20 +08:00
parent 61b70773e3
commit 273da07959
14 changed files with 629 additions and 304 deletions

View File

@@ -9,6 +9,7 @@
justify-content: space-between;
// padding: 20px;
box-sizing: border-box;
padding-bottom: 40px;
.entryCard {
width: 100%;
@@ -56,5 +57,47 @@
.picker {
width: 100%;
height: 300px;
height: 252px;
}
.actions {
width: 100%;
padding: 10px;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
.buttonWrap {
width: 50%;
height: 50px;
border-radius: 16px;
border: 1px solid rgba(0, 0, 0, 0.06);
box-shadow: 0 8px 64px 0 rgba(0, 0, 0, 0.1);
backdrop-filter: blur(16px);
overflow: hidden;
.button {
width: 100%;
height: 50px;
color: #000;
background: #fff;
font-feature-settings: "liga" off, "clig" off;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 600;
line-height: normal;
display: flex;
align-items: center;
justify-content: center;
&.primary {
color: #fff;
background: #000;
}
}
}
}

View File

@@ -7,21 +7,25 @@ import React, {
} from "react";
import { Button, Input, View, Text, Image } from "@tarojs/components";
import Taro from "@tarojs/taro";
import classnames from "classnames";
import CommonPopup from "../CommonPopup";
import { getCurrentFullPath } from "@/utils";
import evaluateService from "@/services/evaluateService";
import { useUserActions } from "@/store/userStore";
import { EvaluateCallback, EvaluateScene } from "@/store/evaluateStore";
import NTRPTestEntryCard from "../NTRPTestEntryCard";
import NtrpPopupGuide from "../NTRPPopupGuide";
import Picker from "../Picker/Picker";
import CloseIcon from "@/static/ntrp/ntrp_popup_close.svg";
import styles from "./index.module.scss";
const options = ["1.5", "2.0", "2.5", "3.0", "3.5", "4.0", "4.5"].map(
(item) => ({
const ntrpLevels = ["1.5", "2.0", "2.5", "3.0", "3.5", "4.0", "4.5"];
const options = [
ntrpLevels.map((item) => ({
text: item,
value: item,
})
);
})),
];
export enum EvaluateType {
EDIT = "edit",
@@ -41,45 +45,57 @@ export enum SceneType {
}
interface NTRPEvaluatePopupProps {
types: EvaluateType[];
displayCondition: DisplayConditionType;
scene: SceneType;
// types: EvaluateType[];
// displayCondition: DisplayConditionType;
// scene: SceneType;
showGuide: boolean;
children: React.ReactNode;
type: EvaluateScene;
// children: React.ReactNode;
}
function showCondition(scene, ntrp) {
if (scene === "list") {
// TODO: 显示频率
return Math.random() < 0.1 && [0, undefined].includes(ntrp);
}
return ntrp === "0";
}
// function showCondition(scene, ntrp) {
// if (scene === "list") {
// // TODO: 显示频率
// return Math.random() < 0.1 && [0, undefined].includes(ntrp);
// }
// return true;
// return !ntrpLevels.includes(ntrp);
// }
const NTRPEvaluatePopup = (props: NTRPEvaluatePopupProps, ref) => {
const {
types = ["edit", "evaluate"],
displayCondition = "auto",
scene = "list",
// types = ["edit", "evaluate"],
// displayCondition = "auto",
// scene = "list",
type,
showGuide = false,
} = props;
const [visible, setVisible] = useState(true);
const [ntrp, setNtrp] = useState<undefined | string>();
const [guideShow, setGuideShow] = useState(() => props.showGuide);
const [visible, setVisible] = useState(false);
const [ntrp, setNtrp] = useState<string>("");
const [guideShow, setGuideShow] = useState(() => showGuide);
const { updateUserInfo } = useUserActions();
const [evaCallback, setEvaCallback] = useState<EvaluateCallback>({
type: "",
next: () => {},
onCancel: () => {},
});
useImperativeHandle(ref, () => ({
show: () => setVisible(true),
show: (evaluateCallback) => {
setVisible(true);
setEvaCallback(evaluateCallback);
},
}));
function handleEvaluate() {
setVisible(false);
// TODO: 实现NTRP评估逻辑
Taro.navigateTo({
url: `/other_pages/ntrp-evaluate/index?redirect=${encodeURIComponent(
getCurrentFullPath()
)}`,
});
}
// function handleEvaluate() {
// setVisible(false);
// // TODO: 实现NTRP评估逻辑
// Taro.navigateTo({
// url: `/other_pages/ntrp-evaluate/index?redirect=${encodeURIComponent(
// getCurrentFullPath()
// )}`,
// });
// }
useEffect(() => {
getNtrp();
@@ -88,20 +104,32 @@ const NTRPEvaluatePopup = (props: NTRPEvaluatePopupProps, ref) => {
async function getNtrp() {
const res = await evaluateService.getLastResult();
if (res.code === 0 && res.data.has_ntrp_level) {
// setNtrp(res.data.user_ntrp_level)
setNtrp("0");
setNtrp(res.data.user_ntrp_level);
} else {
setNtrp("0");
setNtrp("");
}
}
const showEntry =
displayCondition === "auto"
? showCondition(scene, ntrp)
: displayCondition === "always";
// const showEntry =
// displayCondition === "auto"
// ? showCondition(scene, ntrp)
// : displayCondition === "always";
function handleClose() {
console.log("hide ....");
setVisible(false);
setGuideShow(showGuide);
}
async function handleChangeNtrp() {
Taro.showLoading({ title: "修改中" });
await updateUserInfo({ ntrp_level: ntrp });
Taro.showToast({
title: "NTRP水平修改成功",
icon: "none",
});
evaCallback.next(true);
handleClose();
}
return (
@@ -116,10 +144,11 @@ const NTRPEvaluatePopup = (props: NTRPEvaluatePopupProps, ref) => {
>
{guideShow ? (
<NtrpPopupGuide
close={handleClose}
close={() => handleClose()}
skipGuide={() => {
setGuideShow(false);
}}
evaluateCallback={evaCallback}
/>
) : (
<View className={styles.container}>
@@ -130,23 +159,42 @@ const NTRPEvaluatePopup = (props: NTRPEvaluatePopupProps, ref) => {
</View>
</View>
<View className={styles.entryCard}>
<NTRPTestEntryCard />
<NTRPTestEntryCard type={type} evaluateCallback={evaCallback} />
</View>
<View className={styles.picker}>
<Picker
visible={visible}
options={options}
value={ntrp}
onChange={(val) => {
console.log(val);
setNtrp(val.values);
}}
/>
{/* FIXME: 有异常渲染问题 */}
{visible && (
<Picker
visible
options={options}
defaultValue={[ntrp]}
onChange={(val) => {
console.log(val[0]);
if (val[0]?.value) {
setNtrp(val[0]?.value as string);
}
}}
/>
)}
</View>
<View className={styles.actions}>
<View className={styles.buttonWrap}>
<Button className={styles.button} onClick={handleClose}>
</Button>
</View>
<View className={styles.buttonWrap}>
<Button
className={classnames(styles.button, styles.primary)}
onClick={handleChangeNtrp}
>
</Button>
</View>
</View>
</View>
)}
</CommonPopup>
{showEntry ? props.children : ""}
</>
);
};

View File

@@ -3,22 +3,32 @@ import { View, Text, Button, Image } from "@tarojs/components";
import Taro from "@tarojs/taro";
import classnames from "classnames";
import { useUserInfo } from "@/store/userStore";
import { useEvaluate, EvaluateCallback } from "@/store/evaluateStore";
import { delay } from "@/utils";
import ArrwoRight from "@/static/ntrp/ntrp_arrow_right.svg";
import CloseIcon from "@/static/ntrp/ntrp_popup_close.svg";
import DocCopy from "@/static/ntrp/ntrp_doc_copy.svg";
import styles from "./index.module.scss";
function NtrpPopupGuide(props: { close: () => void; skipGuide: () => void }) {
const { close, skipGuide } = props;
function NtrpPopupGuide(props: {
close: () => void;
skipGuide: () => void;
evaluateCallback: EvaluateCallback;
}) {
const { close, skipGuide, evaluateCallback } = props;
const userInfo = useUserInfo();
const { setCallback } = useEvaluate();
function handleTest() {
Taro.redirectTo({
url: `/other_pages/ntrp-evaluate/index`,
async function handleTest() {
setCallback(evaluateCallback);
Taro.navigateTo({
url: `/other_pages/ntrp-evaluate/index?stage=test`,
});
await delay(1000);
close();
}
return (
<View className={styles.container}>
<View className={styles.container} onClick={(e) => e.stopPropagation()}>
<View className={styles.header}>
<View className={styles.closeBtn} onClick={close}>
<Image className={styles.closeIcon} src={CloseIcon} />

View File

@@ -1,20 +1,72 @@
import React, { useEffect } from "react";
import { View, Image, Text } from "@tarojs/components";
import Taro from "@tarojs/taro";
import { useUserInfo, useUserActions } from "@/store/userStore";
// import { getCurrentFullPath } from "@/utils";
import DocCopy from "@/static/ntrp/ntrp_doc_copy.svg";
import ArrowRight from "@/static/ntrp/ntrp_arrow_right_color.svg";
import {
EvaluateScene,
useEvaluate,
EvaluateCallback,
} from "@/store/evaluateStore";
import styles from "./index.module.scss";
function NTRPTestEntryCard(props) {
function NTRPTestEntryCard(props: {
type: EvaluateScene;
evaluateCallback?: EvaluateCallback;
}) {
const { type, evaluateCallback } = props;
const userInfo = useUserInfo();
const { setCallback } = useEvaluate();
// const { fetchUserInfo } = useUserActions()
// useEffect(() => {
// fetchUserInfo()
// }, [])
const { type } = props;
return type === "list" ? (
<View className={styles.higher}>
function handleTest() {
switch (type) {
case (EvaluateScene.list, EvaluateScene.share):
setCallback({
type,
next: () => {
Taro.redirectTo({ url: "/game_pages/list/index" });
},
onCancel: () => {
Taro.redirectTo({ url: "/game_pages/list/index" });
},
});
case (EvaluateScene.detail, EvaluateScene.publish):
setCallback(evaluateCallback as EvaluateCallback);
case (EvaluateScene.user, EvaluateScene.userEdit):
setCallback({
type,
next: () => {
Taro.redirectTo({ url: "/game_pages/list/index" });
},
onCancel: () => {
Taro.redirectTo({ url: "/user_pages/myself/index" });
},
});
default:
setCallback({
type,
next: () => {
Taro.redirectTo({ url: "/game_pages/list/index" });
},
onCancel: () => {
Taro.redirectTo({ url: "/game_pages/list/index" });
},
});
}
Taro.redirectTo({
url: `/other_pages/ntrp-evaluate/index?stage=test`,
});
}
return type === EvaluateScene.list ? (
<View className={styles.higher} onClick={handleTest}>
<View className={styles.desc}>
<View>
<View className={styles.title}>
@@ -48,7 +100,7 @@ function NTRPTestEntryCard(props) {
</View>
</View>
) : (
<View className={styles.lower}>
<View className={styles.lower} onClick={handleTest}>
<View className={styles.desc}>
<View className={styles.title}>
<Text></Text>

View File

@@ -7,6 +7,8 @@ import {
renderYearMonthDay,
renderHourMinute,
} from "./PickerData";
import NTRPTestEntryCard from "../NTRPTestEntryCard";
import { EvaluateScene } from "@/store/evaluateStore";
import imgs from "@/config/images";
import styles from "./index.module.scss";
interface PickerOption {
@@ -106,25 +108,28 @@ const PopupPicker = ({
zIndex={1000}
>
{type === "ntrp" && (
<View className={`${styles["examination-btn"]}}`}>
<View className={`${styles["text-container"]}}`}>
<View className={`${styles["text-title"]}}`}>
<Text>NTRP</Text>
</View>
<View className={`${styles["text-btn"]}}`}>
<Text></Text>
<Image src={imgs.ICON_ARROW_GREEN} className={`${styles["icon-arrow"]}`}></Image>
</View>
</View>
<View className={`${styles["img-container"]}}`}>
<View className={`${styles["img-box"]}`}>
<Image src={img!}></Image>
</View>
<View className={`${styles["img-box"]}`}>
<Image src={imgs.ICON_EXAMINATION}></Image>
</View>
</View>
<View className={styles.evaluateCardWrap}>
<NTRPTestEntryCard type={EvaluateScene.userEdit} />
</View>
// <View className={`${styles["examination-btn"]}}`}>
// <View className={`${styles["text-container"]}}`}>
// <View className={`${styles["text-title"]}}`}>
// 不知道自己的<Text>NTRP</Text>水平
// </View>
// <View className={`${styles["text-btn"]}}`}>
// <Text>快速测试</Text>
// <Image src={imgs.ICON_ARROW_GREEN} className={`${styles["icon-arrow"]}`}></Image>
// </View>
// </View>
// <View className={`${styles["img-container"]}}`}>
// <View className={`${styles["img-box"]}`}>
// <Image src={img!}></Image>
// </View>
// <View className={`${styles["img-box"]}`}>
// <Image src={imgs.ICON_EXAMINATION}></Image>
// </View>
// </View>
// </View>
)}
<Picker
visible={visible}

View File

@@ -26,90 +26,89 @@
}
}
.examination-btn {
padding: 8px 16px;
margin: 16px;
border-radius: 12px;
border: 1px solid rgba(0, 0, 0, 0.08);
display: flex;
justify-content: space-between;
align-items: center;
box-sizing: border-box;
background: linear-gradient(to bottom,
#CCFFF2,
/* 开始颜色 */
#F7FFFD
/* 结束颜色 */
),
repeating-linear-gradient(90deg,
/* 垂直方向 */
rgba(0, 0, 0, 1),
/* 条纹的开始颜色 */
rgba(0, 0, 0, 0.01) 1px,
/* 条纹的结束颜色及宽度 */
#CCFFF2 8px,
/* 条纹之间的开始颜色 */
#F7FFFD 10px
/* 条纹之间的结束颜色及宽度 */
);
background-blend-mode: luminosity;
/* 将两个渐变层叠在一起 */
.evaluateCardWrap {
padding: 16px;
}
.text-container {
.text-title {
font-family: Noto Sans SC;
font-weight: 900;
color: #2a4d44;
font-size: 16px;
margin-bottom: 4px;
// .examination-btn {
// padding: 8px 16px;
// margin: 16px;
// border-radius: 12px;
// border: 1px solid rgba(0, 0, 0, 0.08);
// display: flex;
// justify-content: space-between;
// align-items: center;
// box-sizing: border-box;
// background: linear-gradient(
// to bottom,
// #ccfff2,
// /* 开始颜色 */ #f7fffd /* 结束颜色 */
// ),
// repeating-linear-gradient(
// 90deg,
// /* 垂直方向 */ rgba(0, 0, 0, 1),
// /* 条纹的开始颜色 */ rgba(0, 0, 0, 0.01) 1px,
// /* 条纹的结束颜色及宽度 */ #ccfff2 8px,
// /* 条纹之间的开始颜色 */ #f7fffd 10px /* 条纹之间的结束颜色及宽度 */
// );
// background-blend-mode: luminosity;
// /* 将两个渐变层叠在一起 */
Text {
color: #00e5ad;
}
}
// .text-container {
// .text-title {
// font-family: Noto Sans SC;
// font-weight: 900;
// color: #2a4d44;
// font-size: 16px;
// margin-bottom: 4px;
.text-btn {
font-size: 12px;
color: #5ca693;
display: flex;
align-items: center;
gap: 6px;
// Text {
// color: #00e5ad;
// }
// }
.icon-arrow {
width: 12px;
height: 12px;
}
}
}
// .text-btn {
// font-size: 12px;
// color: #5ca693;
// display: flex;
// align-items: center;
// gap: 6px;
.img-container {
display: flex;
// .icon-arrow {
// width: 12px;
// height: 12px;
// }
// }
// }
.img-box {
width: 47px;
height: 47px;
border: 3px solid #fff;
border-radius: 50%;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
// .img-container {
// display: flex;
Image {
width: 100%;
height: 100%;
}
// .img-box {
// width: 47px;
// height: 47px;
// border: 3px solid #fff;
// border-radius: 50%;
// overflow: hidden;
// display: flex;
// justify-content: center;
// align-items: center;
&:nth-child(2) {
border-radius: 8px;
background-color: #ccfff2;
transform: scale(0.88) rotate(15deg) translateX(-10px);
// Image {
// width: 100%;
// height: 100%;
// }
Image {
width: 66%;
height: 66%;
}
}
}
}
}
// &:nth-child(2) {
// border-radius: 8px;
// background-color: #ccfff2;
// transform: scale(0.88) rotate(15deg) translateX(-10px);
// Image {
// width: 66%;
// height: 66%;
// }
// }
// }
// }
// }

View File

@@ -1,9 +1,16 @@
import React, { useState } from "react";
import React, { useState, useRef } from "react";
import { View, Text, Image } from "@tarojs/components";
import Taro from "@tarojs/taro";
import { useUserInfo } from "@/store/userStore";
import {
useEvaluate,
EvaluateCallback,
EvaluateScene,
} from "@/store/evaluateStore";
import styles from "./index.module.scss";
import images from "@/config/images";
import AiImportPopup from "@/publish_pages/publishBall/components/AiImportPopup";
import NTRPEvaluatePopup from "../NTRPEvaluatePopup";
export interface PublishMenuProps {
onPersonalPublish?: () => void;
@@ -13,6 +20,10 @@ export interface PublishMenuProps {
const PublishMenu: React.FC<PublishMenuProps> = () => {
const [isVisible, setIsVisible] = useState(false);
const [aiImportVisible, setAiImportVisible] = useState(false);
const userInfo = useUserInfo();
const ntrpRef = useRef<{
show: (evaluateCallback: EvaluateCallback) => void;
}>({ show: () => {} });
const handleIconClick = () => {
setIsVisible(!isVisible);
@@ -20,18 +31,42 @@ const PublishMenu: React.FC<PublishMenuProps> = () => {
const handleOverlayClick = () => {
setIsVisible(false);
};
const handleMenuItemClick = (type: "individual" | "group" | "ai") => {
const handleMenuClick = (type: "individual" | "group" | "ai") => {
// 跳转到publishBall页面并传递type参数
console.log(type, "type");
setIsVisible(false);
if (type === "ai") {
setAiImportVisible(true);
setIsVisible(false);
return;
}
Taro.navigateTo({
url: `/publish_pages/publishBall/index?type=${type}`,
});
setIsVisible(false);
};
const handleMenuItemClick = (type: "individual" | "group" | "ai") => {
if (!userInfo.ntrp_level) {
ntrpRef.current.show({
type: EvaluateScene.publish,
next: (flag) => {
if (flag) {
handleMenuClick(type);
} else if (type === "ai") {
Taro.navigateBack();
setAiImportVisible(true);
} else {
Taro.redirectTo({
url: `/publish_pages/publishBall/index?type=${type}`,
});
}
},
onCancel: () => {
Taro.navigateBack();
},
});
setIsVisible(false);
return;
}
handleMenuClick(type);
};
const handleAiImportClose = () => {
@@ -136,6 +171,8 @@ const PublishMenu: React.FC<PublishMenuProps> = () => {
onClose={handleAiImportClose}
onManualPublish={handleManualPublish}
/>
<NTRPEvaluatePopup type={EvaluateScene.publish} ref={ntrpRef} showGuide />
</View>
);
};

View File

@@ -24,6 +24,7 @@ import Comments from "./Comments";
import GeneralNavbar from "./GeneralNavbar";
import RadarChart from './Radar'
import EmptyState from './EmptyState';
import NTRPTestEntryCard from './NTRPTestEntryCard'
export {
ActivityTypeSwitch,
@@ -53,4 +54,5 @@ export {
GeneralNavbar,
RadarChart,
EmptyState,
NTRPTestEntryCard,
};