Merge branch 'feat/liujie'

This commit is contained in:
2026-02-07 17:38:28 +08:00
10 changed files with 194 additions and 168 deletions

View File

@@ -34,7 +34,7 @@ function toast(msg) {
interface CommentInputProps {
onConfirm?: (
value: { content: string } & Partial<CommentInputReplyParamsType>
value: { content: string } & Partial<CommentInputReplyParamsType>,
) => void;
}
@@ -49,10 +49,8 @@ interface CommentInputReplyParamsType {
nickname: string;
}
const CommentInput = forwardRef<CommentInputRef, CommentInputProps>(function (
props,
ref
) {
const CommentInput = forwardRef<CommentInputRef, CommentInputProps>(
function (props, ref) {
const { onConfirm } = props;
const [visible, setVisible] = useState(false);
const [value, setValue] = useState("");
@@ -73,9 +71,8 @@ const CommentInput = forwardRef<CommentInputRef, CommentInputProps>(function (
initializeKeyboardListener();
// 添加本地监听器
const removeListener = addListener((height, visible) => {
console.log("PublishBall 收到键盘变化:", height, visible);
// 这里只记录或用于其他逻辑,布局是否响应交由 shouldReactToKeyboard 决定
const removeListener = addListener(() => {
// 布局是否响应交由 shouldReactToKeyboard 决定
});
return () => {
@@ -112,7 +109,6 @@ const CommentInput = forwardRef<CommentInputRef, CommentInputProps>(function (
setValue("");
inputDomRef.current && inputDomRef.current?.blur();
}
console.log(keyboardHeight, "keyboardHeight");
return (
<CommonPopup
visible={visible}
@@ -124,7 +120,9 @@ const CommentInput = forwardRef<CommentInputRef, CommentInputProps>(function (
// height: "60px!important",
minHeight: "unset",
bottom:
isKeyboardVisible && keyboardHeight > 0 ? `${keyboardHeight}px` : "0",
isKeyboardVisible && keyboardHeight > 0
? `${keyboardHeight}px`
: "0",
}}
enableDragToClose={false}
>
@@ -149,7 +147,7 @@ const CommentInput = forwardRef<CommentInputRef, CommentInputProps>(function (
<View
className={classnames(
styles.limit,
value.length > 200 ? styles.red : ""
value.length > 200 ? styles.red : "",
)}
>
<Text>{value.length}</Text>/<Text>200</Text>
@@ -161,7 +159,8 @@ const CommentInput = forwardRef<CommentInputRef, CommentInputProps>(function (
</View>
</CommonPopup>
);
});
},
);
function isReplyComment(item: BaseComment<any>): item is ReplyComment {
return "reply_to_user" in item;
@@ -208,7 +207,7 @@ function CommentItem(props: {
className={classnames(
styles.commentItem,
blink_id === comment.id && styles.blink,
styles.weight_super
styles.weight_super,
)}
key={comment.id}
id={`comment_id_${comment.id}`}
@@ -293,7 +292,8 @@ function CommentItem(props: {
/>
))}
{!isReplyComment(comment) &&
comment.replies.length !== comment.reply_count && (
comment.replies.length !== comment.reply_count &&
comment.replies.length > 3 && (
<View
className={styles.viewMore}
onClick={() => handleLoadMore(comment)}
@@ -313,7 +313,7 @@ export default forwardRef(function Comments(
message_id?: number;
onScrollTo: (id: string) => void;
},
ref
ref,
) {
const { game_id, publisher_id, message_id, onScrollTo } = props;
const [comments, setComments] = useState<Comment[]>([]);
@@ -371,7 +371,7 @@ export default forwardRef(function Comments(
replies: [res.data, ...item.replies].sort((a, b) =>
dayjs(a.create_time).isAfter(dayjs(b.create_time))
? 1
: -1
: -1,
),
};
});
@@ -435,7 +435,7 @@ export default forwardRef(function Comments(
item.replies.splice(
page === 1 ? 0 : page * PAGESIZE - 1,
newReplies.length,
...newReplies
...newReplies,
);
item.reply_count = res.data.count;
}
@@ -502,7 +502,7 @@ export default forwardRef(function Comments(
return {
...item,
replies: item.replies.filter(
(replyItem) => replyItem.id !== id
(replyItem) => replyItem.id !== id,
),
reply_count: item.reply_count - 1,
};

View File

@@ -105,10 +105,10 @@ const NTRPEvaluatePopup = (props: NTRPEvaluatePopupProps, ref) => {
if (match) {
setNtrp(match[0]);
} else {
setNtrp("");
setNtrp("1.5");
}
} else {
setNtrp("");
setNtrp("1.5");
}
}
}, [visible, userInfo?.ntrp_level]);

View File

@@ -87,7 +87,7 @@ export default forwardRef(({ id, from, detail, userInfo }, ref) => {
gameType: play_type,
skillLevel: `NTRP ${genNTRPRequirementText(
skill_level_min,
skill_level_max
skill_level_max,
)}`,
gameDate: `${startTime.format("M月D日")} (${dayofWeek})`,
gameTime: `${startTime.format("ah")}${gameLength}`,
@@ -133,9 +133,10 @@ export default forwardRef(({ id, from, detail, userInfo }, ref) => {
page: "game_pages/detail/index",
scene: `id=${id}`,
});
const qrCodeUrl = await base64ToTempFilePath(
qrCodeUrlRes.data.qr_code_base64
);
// const qrCodeUrl = await base64ToTempFilePath(
// qrCodeUrlRes.data.qr_code_base64
// );
const qrCodeUrl = qrCodeUrlRes.data.ossPath;
await delay(100);
// Taro.showLoading({ title: "生成中..." });
const url = await generatePosterImage({
@@ -165,6 +166,18 @@ export default forwardRef(({ id, from, detail, userInfo }, ref) => {
setVisible(false);
}
async function handleCopyLink() {
const linkUrlRes = await DetailService.getLinkUrl({
path: "game_pages/detail/index",
query: `id=${id}`,
});
await Taro.setClipboardData({
data: linkUrlRes.data.url_link,
});
Taro.showToast({ title: "链接已复制到剪贴板", icon: "success" });
setVisible(false);
}
function onClose() {
setVisible(false);
setPublishFlag(false);
@@ -201,7 +214,7 @@ export default forwardRef(({ id, from, detail, userInfo }, ref) => {
catchMove
className={classnames(
styles.title,
publishFlag ? styles.publishTitle : ""
publishFlag ? styles.publishTitle : "",
)}
>
{publishFlag ? (
@@ -255,7 +268,7 @@ export default forwardRef(({ id, from, detail, userInfo }, ref) => {
</View>
</View>
<View className={styles.customBtnWrapper}>
<Button className={styles.button}>
<Button className={styles.button} onClick={handleCopyLink}>
<View className={styles.icon}>
<Image className={styles.linkIcon} src={LinkIcon} />
</View>

View File

@@ -81,9 +81,9 @@ function Index() {
// 位置更新后,重新获取详情页数据(因为距离等信息可能发生变化)
// 注意:这里不调用 fetchDetail避免与 useDidShow 中的调用重复
// 如果需要更新距离信息,可以在 fetchDetail 成功后根据当前位置重新计算
if (from === "publish") {
handleShare(true);
}
// if (from === "publish") {
// handleShare(true);
// }
} catch (error) {
console.error("用户位置更新失败", error);
}
@@ -105,6 +105,10 @@ function Index() {
fetchUserInfoById(res.data.publisher_id);
}
if (from === "publish") {
handleShare(true);
}
// Taro.hideLoading();
};
@@ -161,7 +165,7 @@ function Index() {
navto(
userId === myInfo.id
? "/user_pages/myself/index"
: `/user_pages/other/index?userid=${userId}`
: `/user_pages/other/index?userid=${userId}`,
);
}
@@ -195,7 +199,7 @@ function Index() {
<View
className={classnames(
styles["custom-navbar"],
glass ? styles.glass : ""
glass ? styles.glass : "",
)}
style={{
height: `${totalHeight}px`,

View File

@@ -5,7 +5,7 @@ import Taro, { useRouter } from "@tarojs/taro";
import classnames from "classnames";
import dayjs from "dayjs";
import "dayjs/locale/zh-cn";
import { generatePosterImage, base64ToTempFilePath, delay } from "@/utils";
import { generatePosterImage, delay } from "@/utils";
import { withAuth } from "@/components";
import GeneralNavbar from "@/components/GeneralNavbar";
import DetailService from "@/services/detailService";
@@ -59,10 +59,11 @@ function SharePoster(props) {
page: "game_pages/detail/index",
scene: `id=${id}`,
});
const qrCodeUrl = await base64ToTempFilePath(
qrCodeUrlRes.data.qr_code_base64
);
debugger
const qrCodeUrl = qrCodeUrlRes.data.ossPath;
// const qrCodeUrl = await base64ToTempFilePath(
// qrCodeUrlRes.data.qr_code_base64
// );
// debugger
await delay(100);
const url = await generatePosterImage({
playType: play_type,

View File

@@ -18,7 +18,6 @@ import { formatNtrpDisplay } from "@/utils/helper";
import { waitForAuthInit } from "@/utils/authInit";
import httpService from "@/services/httpService";
import DetailService from "@/services/detailService";
import { base64ToTempFilePath } from "@/utils/genPoster";
import { OSS_BASE_URL } from "@/config/api";
import CloseIcon from "@/static/ntrp/ntrp_close_icon.svg";
import DocCopy from "@/static/ntrp/ntrp_doc_copy.svg";
@@ -38,7 +37,7 @@ const sourceTypeToTextMap = new Map([
function adjustRadarLabels(
source: [string, number][],
topK: number = 4 // 默认挑前4个最长的标签保护
topK: number = 4, // 默认挑前4个最长的标签保护
): [string, number][] {
if (source.length === 0) return source;
@@ -216,7 +215,8 @@ function Intro() {
});
}
Taro.redirectTo({
url: `/other_pages/ntrp-evaluate/index?stage=${type}${type === StageType.RESULT ? `&id=${id}` : ""
url: `/other_pages/ntrp-evaluate/index?stage=${type}${
type === StageType.RESULT ? `&id=${id}` : ""
}`,
});
}
@@ -380,7 +380,7 @@ function Test() {
prev.map((item, pIndex) => ({
...item,
...(pIndex === index ? { choosen: i } : {}),
}))
})),
);
}
@@ -522,13 +522,14 @@ function Result() {
page: "other_pages/ntrp-evaluate/index",
scene: `stage=${StageType.INTRO}`,
});
if (qrCodeUrlRes.code === 0 && qrCodeUrlRes.data?.qr_code_base64) {
// 将 base64 转换为临时文件路径
const tempFilePath = await base64ToTempFilePath(
qrCodeUrlRes.data.qr_code_base64
);
setQrCodeUrl(tempFilePath);
}
setQrCodeUrl(qrCodeUrlRes.data.ossPath);
// if (qrCodeUrlRes.code === 0 && qrCodeUrlRes.data?.qr_code_base64) {
// // 将 base64 转换为临时文件路径
// const tempFilePath = await base64ToTempFilePath(
// qrCodeUrlRes.data.qr_code_base64
// );
// setQrCodeUrl(tempFilePath);
// }
} catch (error) {
console.error("获取二维码失败:", error);
}
@@ -542,13 +543,17 @@ function Result() {
const sortOrder = res.data.sort || [];
const abilities = res.data.radar_data.abilities;
const sortedKeys = sortOrder.filter((k) => k in abilities);
const remainingKeys = Object.keys(abilities).filter((k) => !sortOrder.includes(k));
const remainingKeys = Object.keys(abilities).filter(
(k) => !sortOrder.includes(k),
);
const allKeys = [...sortedKeys, ...remainingKeys];
let radarData: [string, number][] = allKeys.map((key) => [
key,
Math.min(
100,
Math.floor((abilities[key].current_score / abilities[key].max_score) * 100)
Math.floor(
(abilities[key].current_score / abilities[key].max_score) * 100,
),
),
]);
// 直接使用接口 sort 顺序,不经过 adjustRadarLabels 重新排序
@@ -590,7 +595,7 @@ function Result() {
if (!userInfo?.phone) {
Taro.redirectTo({
url: `/login_pages/index/index?redirect=${encodeURIComponent(
`/main_pages/index`
`/main_pages/index`,
)}`,
});
clear();
@@ -615,11 +620,12 @@ function Result() {
page: "other_pages/ntrp-evaluate/index",
scene: `stage=${StageType.INTRO}`,
});
if (qrCodeUrlRes.code === 0 && qrCodeUrlRes.data?.qr_code_base64) {
finalQrCodeUrl = await base64ToTempFilePath(
qrCodeUrlRes.data.qr_code_base64
);
}
finalQrCodeUrl = qrCodeUrlRes.data.ossPath;
// if (qrCodeUrlRes.code === 0 && qrCodeUrlRes.data?.qr_code_base64) {
// finalQrCodeUrl = await base64ToTempFilePath(
// qrCodeUrlRes.data.qr_code_base64
// );
// }
}
// 使用 RadarV2 的 generateFullImage 方法生成完整图片
@@ -700,12 +706,13 @@ function Result() {
}
const currentPage = getCurrentFullPath();
Taro.redirectTo({
url: `/login_pages/index/index${currentPage ? `?redirect=${encodeURIComponent(currentPage)}` : ""
url: `/login_pages/index/index${
currentPage ? `?redirect=${encodeURIComponent(currentPage)}` : ""
}`,
});
}
function handleGo() { }
function handleGo() {}
return (
<View className={styles.resultContainer}>
@@ -763,7 +770,8 @@ function Result() {
{userInfo?.phone ? (
<View className={styles.updateTip}>
<Text>
NTRP {formatNtrpDisplay(result?.ntrp_level || "")}{" "}
NTRP {" "}
{formatNtrpDisplay(result?.ntrp_level || "")}{" "}
</Text>
<Text className={styles.grayTip}>()</Text>
</View>

View File

@@ -78,9 +78,8 @@ const PublishBall: React.FC = () => {
} = useKeyboardHeight();
// 获取页面参数并设置导航标题
const [optionsConfig, setOptionsConfig] = useState<FormFieldConfig[]>(
publishBallFormSchema
publishBallFormSchema,
);
console.log(userInfo, "userInfo");
const [formData, setFormData] = useState<PublishBallFormData[]>([
defaultFormData,
]);
@@ -103,13 +102,11 @@ const PublishBall: React.FC = () => {
const updateFormData = (
key: keyof PublishBallFormData,
value: any,
index: number
index: number,
) => {
console.log(key, value, index, "key, value, index");
setFormData((prev) => {
const newData = [...prev];
newData[index] = { ...newData[index], [key]: value };
console.log(newData, "newData");
return newData;
});
};
@@ -186,7 +183,7 @@ const PublishBall: React.FC = () => {
const confirmDelete = () => {
if (deleteConfirm.index >= 0) {
setFormData((prev) =>
prev.filter((_, index) => index !== deleteConfirm.index)
prev.filter((_, index) => index !== deleteConfirm.index),
);
closeDeleteConfirm();
Taro.showToast({
@@ -198,7 +195,7 @@ const PublishBall: React.FC = () => {
const validateFormData = (
formData: PublishBallFormData,
isOnSubmit: boolean = false
isOnSubmit: boolean = false,
) => {
const {
activityInfo,
@@ -207,7 +204,7 @@ const PublishBall: React.FC = () => {
image_list,
players,
current_players,
descriptionInfo
descriptionInfo,
} = formData;
const { play_type, price, location_name } = activityInfo;
const { description } = descriptionInfo;
@@ -225,7 +222,7 @@ const PublishBall: React.FC = () => {
// 判断图片是否上传完成
if (image_list?.length > 0) {
const uploadInProgress = image_list.some((item) =>
item.url.startsWith("http://tmp/")
item?.url?.startsWith?.("http://tmp/"),
);
if (uploadInProgress) {
Taro.showToast({
@@ -368,7 +365,6 @@ const PublishBall: React.FC = () => {
// 提交表单
const handleSubmit = async () => {
// 基础验证
console.log(formData, "formData");
const params = getParams();
const { republish } = params || {};
if (activityType === "individual") {
@@ -516,7 +512,7 @@ const PublishBall: React.FC = () => {
const mergeWithDefault = (
data: any,
isDetail: boolean = false
isDetail: boolean = false,
): PublishBallFormData => {
// ai导入与详情数据处理
const {
@@ -741,7 +737,6 @@ const PublishBall: React.FC = () => {
} else {
setIsSubmitDisabled(false);
}
console.log(formData, "formData");
}, [formData]);
useEffect(() => {
@@ -754,9 +749,8 @@ const PublishBall: React.FC = () => {
initializeKeyboardListener();
// 添加本地监听器
const removeListener = addListener((height, visible) => {
console.log("PublishBall 收到键盘变化:", height, visible);
// 这里只记录或用于其他逻辑,布局是否响应交由 shouldReactToKeyboard 决定
const removeListener = addListener(() => {
// 布局是否响应交由 shouldReactToKeyboard 决定
});
return () => {

View File

@@ -158,6 +158,7 @@ class GameDetailService {
async getQrCodeUrl(req: { page: string, scene: string }): Promise<ApiResponse<{
qr_code_base64: string,
image_size: number,
ossPath: string,
page: string,
scene: string,
width: number
@@ -166,6 +167,10 @@ class GameDetailService {
showLoading: true
})
}
async getLinkUrl(req: { path: string, query: string }): Promise<ApiResponse<{ url_link: string, path: string, query: string }>> {
return httpService.post('/user/generate_url_link', req, { showLoading: true })
}
}
// 导出认证服务实例

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -11,7 +11,8 @@ const mapIcon = `${OSS_BASE_URL}/images/06b994fa-9227-4708-8555-8a07af8d0c3b.jpg
// const logo = `${OSS_BASE_URL}/images/fb732da6-11b9-4022-a524-a377b17635eb.jpg`
const logoText = `${OSS_BASE_URL}/images/9d8cbc9d-9601-4e2d-ab23-76420a4537d6.png`;
// const logoText = `${OSS_BASE_URL}/images/9d8cbc9d-9601-4e2d-ab23-76420a4537d6.png`;
const logoText = `${OSS_BASE_URL}/system/youchang_tip_text.png`
export function base64ToTempFilePath(base64Data: string): Promise<string> {
return new Promise((resolve, reject) => {