添加内容过滤功能

This commit is contained in:
张成
2026-02-14 13:56:54 +08:00
parent 64f0267457
commit baa60bbfcb
6 changed files with 171 additions and 147 deletions

View File

@@ -11,7 +11,7 @@ import dayjs from "dayjs";
import classnames from "classnames"; import classnames from "classnames";
import CommentServices from "@/services/commentServices"; import CommentServices from "@/services/commentServices";
import messageService from "@/services/messageService"; import messageService from "@/services/messageService";
import { delay } from "@/utils"; import { delay, getBackendErrorMsg } from "@/utils";
import type { import type {
BaseComment, BaseComment,
Comment, Comment,
@@ -459,36 +459,48 @@ export default forwardRef(function Comments(
} }
async function createComment(val: string) { async function createComment(val: string) {
const res = await CommentServices.createComment({ game_id, content: val }); try {
if (res.code === 0) { const res = await CommentServices.createComment({ game_id, content: val });
setComments((prev) => { if (res.code === 0) {
commentCountUpdateRef.current?.(prev.length + 1); setComments((prev) => {
return [{ ...res.data, replies: [] }, ...prev]; commentCountUpdateRef.current?.(prev.length + 1);
}); return [{ ...res.data, replies: [] }, ...prev];
toast("发布成功"); });
toast("发布成功");
} else {
toast(getBackendErrorMsg(res, "评论失败"));
}
} catch (error) {
toast(getBackendErrorMsg(error, "评论失败"));
} }
} }
async function replyComment({ parent_id, reply_to_user_id, content }) { async function replyComment({ parent_id, reply_to_user_id, content }) {
const res = await CommentServices.replyComment({ try {
parent_id, const res = await CommentServices.replyComment({
reply_to_user_id, parent_id,
content, reply_to_user_id,
}); content,
if (res.code === 0) {
setComments((prev) => {
return prev.map((item) => {
if (item.id === parent_id) {
return {
...item,
replies: [res.data, ...item.replies],
reply_count: item.reply_count + 1,
};
}
return item;
});
}); });
toast("回复成功"); if (res.code === 0) {
setComments((prev) => {
return prev.map((item) => {
if (item.id === parent_id) {
return {
...item,
replies: [res.data, ...item.replies],
reply_count: item.reply_count + 1,
};
}
return item;
});
});
toast("回复成功");
} else {
toast(getBackendErrorMsg(res, "回复失败"));
}
} catch (error) {
toast(getBackendErrorMsg(error, "回复失败"));
} }
} }

View File

@@ -18,7 +18,7 @@ import {
useProfessions, useProfessions,
useNtrpLevels, useNtrpLevels,
} from "@/store/pickerOptionsStore"; } from "@/store/pickerOptionsStore";
import { formatNtrpDisplay } from "@/utils/helper"; import { formatNtrpDisplay, getBackendErrorMsg } from "@/utils/helper";
import { useGlobalState } from "@/store/global"; import { useGlobalState } from "@/store/global";
// 用户信息接口 // 用户信息接口
@@ -252,8 +252,8 @@ const UserInfoCardComponent: React.FC<UserInfoCardProps> = ({
} catch (error) { } catch (error) {
console.warn("保存失败:", error); console.warn("保存失败:", error);
Taro.showToast({ Taro.showToast({
title: "保存失败", title: getBackendErrorMsg(error, "保存失败"),
icon: "error", icon: "none",
}); });
} }
}; };
@@ -295,8 +295,8 @@ const UserInfoCardComponent: React.FC<UserInfoCardProps> = ({
} catch (error) { } catch (error) {
console.warn("保存失败:", error); console.warn("保存失败:", error);
Taro.showToast({ Taro.showToast({
title: "保存失败", title: getBackendErrorMsg(error, "保存失败"),
icon: "error", icon: "none",
}); });
} }
}; };

View File

@@ -13,7 +13,7 @@ import {
} from "../../config/formSchema/publishBallFormSchema"; } from "../../config/formSchema/publishBallFormSchema";
import { PublishBallFormData } from "../../../types/publishBall"; import { PublishBallFormData } from "../../../types/publishBall";
import PublishService from "@/services/publishService"; import PublishService from "@/services/publishService";
import { getNextHourTime, getEndTime, delay } from "@/utils"; import { getNextHourTime, getEndTime, delay, getBackendErrorMsg } from "@/utils";
import { useGlobalState } from "@/store/global"; import { useGlobalState } from "@/store/global";
import GeneralNavbar from "@/components/GeneralNavbar"; import GeneralNavbar from "@/components/GeneralNavbar";
import images from "@/config/images"; import images from "@/config/images";
@@ -364,104 +364,27 @@ const PublishBall: React.FC = () => {
}; };
// 提交表单 // 提交表单
const handleSubmit = async () => { const handleSubmit = async () => {
// 基础验证
const params = getParams(); const params = getParams();
const { republish } = params || {}; const { republish } = params || {};
if (activityType === "individual") { if (activityType === "individual") {
const isValid = validateFormData(formData[0]); const isValid = validateFormData(formData[0]);
if (!isValid || publishLoading) { if (!isValid || publishLoading) return;
return;
}
setPublishLoading(true); setPublishLoading(true);
const { try {
activityInfo,
descriptionInfo,
is_substitute_supported,
timeRange,
players,
skill_level,
image_list,
wechat,
id,
...rest
} = formData[0];
const { min, max, organizer_joined } = players;
const options = {
...rest,
...activityInfo,
...descriptionInfo,
...timeRange,
max_players: max,
min_players: min,
organizer_joined: organizer_joined === true ? 1 : 0,
skill_level_min: skill_level[0],
skill_level_max: skill_level[1],
image_list: image_list.map((item) => item.url),
is_wechat_contact: wechat.is_wechat_contact ? 1 : 0,
wechat_contact: wechat.wechat_contact || wechat.default_wechat_contact,
is_substitute_supported: is_substitute_supported ? "1" : "0",
...(republish === "0" ? { id } : {}),
};
const res =
republish === "0"
? await PublishService.gamesUpdate(options)
: await PublishService.createPersonal(options);
const successText = republish === "0" ? "更新成功" : "发布成功";
if (res.code === 0 && res.data) {
Taro.showToast({
title: successText,
icon: "success",
});
delay(1000);
// 如果是个人球局,则跳转到详情页,并自动分享
// 如果是畅打,则跳转第一个球局详情页,并自动分享 @刘杰
const id = (res as any).data?.id;
// 如果是编辑,就返回,否则就是新发布
if (republish === "0") {
Taro.navigateBack();
} else {
// 使用 redirectTo 替换当前页面,避免返回时回到发布页面
Taro.redirectTo({
// @ts-expect-error: id
url: `/game_pages/detail/index?id=${
id || 1
}&from=publish&autoShare=1`,
});
}
} else {
Taro.showToast({
title: res.message,
icon: "none",
});
setPublishLoading(false);
}
}
if (activityType === "group") {
const isValid = formData.every((item) => validateFormData(item));
if (!isValid || publishLoading) {
return;
}
setPublishLoading(true);
if (checkAdjacentDataSame(formData)) {
Taro.showToast({
title: "信息不可与前序场完全一致",
icon: "none",
});
return;
}
const options = formData.map((item) => {
const { const {
activityInfo, activityInfo,
descriptionInfo, descriptionInfo,
is_substitute_supported,
timeRange, timeRange,
players, players,
skill_level, skill_level,
is_substitute_supported, image_list,
wechat,
id, id,
...rest ...rest
} = item; } = formData[0];
const { min, max, organizer_joined } = players; const { min, max, organizer_joined } = players;
return { const options = {
...rest, ...rest,
...activityInfo, ...activityInfo,
...descriptionInfo, ...descriptionInfo,
@@ -471,38 +394,108 @@ const PublishBall: React.FC = () => {
organizer_joined: organizer_joined === true ? 1 : 0, organizer_joined: organizer_joined === true ? 1 : 0,
skill_level_min: skill_level[0], skill_level_min: skill_level[0],
skill_level_max: skill_level[1], skill_level_max: skill_level[1],
image_list: image_list.map((item) => item.url),
is_wechat_contact: wechat.is_wechat_contact ? 1 : 0,
wechat_contact: wechat.wechat_contact || wechat.default_wechat_contact,
is_substitute_supported: is_substitute_supported ? "1" : "0", is_substitute_supported: is_substitute_supported ? "1" : "0",
image_list: item.image_list.map((img) => img.url),
...(republish === "0" ? { id } : {}), ...(republish === "0" ? { id } : {}),
}; };
}); const res =
const successText = republish === "0" ? "更新成功" : "发布成功";
const res =
republish === "0"
? await PublishService.gamesUpdate(options[0])
: await PublishService.create_play_pmoothlys({ rows: options });
if (res.code === 0 && res.data) {
Taro.showToast({
title: successText,
icon: "success",
});
delay(1000);
// 如果是个人球局,则跳转到详情页,并自动分享
// 如果是畅打,则跳转第一个球局详情页,并自动分享 @刘杰
const id =
republish === "0" republish === "0"
? (res as any).data?.id ? await PublishService.gamesUpdate(options)
: (res as any).data?.[0]?.id; : await PublishService.createPersonal(options);
// 使用 redirectTo 替换当前页面,避免返回时回到发布页面 const successText = republish === "0" ? "更新成功" : "发布成功";
Taro.redirectTo({ if (res.code === 0 && res.data) {
// @ts-expect-error: id Taro.showToast({ title: successText, icon: "success" });
url: `/game_pages/detail/index?id=${ delay(1000);
id || 1 const id = (res as any).data?.id;
}&from=publish&autoShare=1`, if (republish === "0") {
}); Taro.navigateBack();
} else { } else {
Taro.redirectTo({
url: `/game_pages/detail/index?id=${id || 1}&from=publish&autoShare=1`,
});
}
} else {
Taro.showToast({
title: getBackendErrorMsg(res, "发布失败"),
icon: "none",
});
setPublishLoading(false);
}
} catch (error) {
Taro.showToast({ Taro.showToast({
title: res.message, title: getBackendErrorMsg(error, "发布失败"),
icon: "none",
});
setPublishLoading(false);
}
return;
}
if (activityType === "group") {
const isValid = formData.every((item) => validateFormData(item));
if (!isValid || publishLoading) return;
if (checkAdjacentDataSame(formData)) {
Taro.showToast({
title: "信息不可与前序场完全一致",
icon: "none",
});
return;
}
setPublishLoading(true);
try {
const options = formData.map((item) => {
const {
activityInfo,
descriptionInfo,
timeRange,
players,
skill_level,
is_substitute_supported,
id,
...rest
} = item;
const { min, max, organizer_joined } = players;
return {
...rest,
...activityInfo,
...descriptionInfo,
...timeRange,
max_players: max,
min_players: min,
organizer_joined: organizer_joined === true ? 1 : 0,
skill_level_min: skill_level[0],
skill_level_max: skill_level[1],
is_substitute_supported: is_substitute_supported ? "1" : "0",
image_list: item.image_list.map((img) => img.url),
...(republish === "0" ? { id } : {}),
};
});
const successText = republish === "0" ? "更新成功" : "发布成功";
const res =
republish === "0"
? await PublishService.gamesUpdate(options[0])
: await PublishService.create_play_pmoothlys({ rows: options });
if (res.code === 0 && res.data) {
Taro.showToast({ title: successText, icon: "success" });
delay(1000);
const id =
republish === "0"
? (res as any).data?.id
: (res as any).data?.[0]?.id;
Taro.redirectTo({
url: `/game_pages/detail/index?id=${id || 1}&from=publish&autoShare=1`,
});
} else {
Taro.showToast({
title: getBackendErrorMsg(res, "发布失败"),
icon: "none",
});
setPublishLoading(false);
}
} catch (error) {
Taro.showToast({
title: getBackendErrorMsg(error, "发布失败"),
icon: "none", icon: "none",
}); });
setPublishLoading(false); setPublishLoading(false);

View File

@@ -12,6 +12,7 @@ import evaluateService, {
LastTimeTestResult, LastTimeTestResult,
} from "@/services/evaluateService"; } from "@/services/evaluateService";
import { useListStore } from "./listStore"; import { useListStore } from "./listStore";
import { getBackendErrorMsg } from "@/utils/helper";
export interface UserState { export interface UserState {
user: UserInfoType | {}; user: UserInfoType | {};
@@ -123,6 +124,10 @@ export const useUser = create<UserState>()((set) => ({
// 如果需要确保数据一致性,可以在特定场景下手动调用 fetchUserInfo // 如果需要确保数据一致性,可以在特定场景下手动调用 fetchUserInfo
} catch (error) { } catch (error) {
console.warn("更新用户信息失败:", error); console.warn("更新用户信息失败:", error);
Taro.showToast({
title: getBackendErrorMsg(error, "保存失败"),
icon: "none",
});
throw error; throw error;
} }
}, },

View File

@@ -22,6 +22,7 @@ import {
} from "@/store/pickerOptionsStore"; } from "@/store/pickerOptionsStore";
import { handleCustomerService } from "@/services/userService"; import { handleCustomerService } from "@/services/userService";
import evaluateService from "@/services/evaluateService"; import evaluateService from "@/services/evaluateService";
import { getBackendErrorMsg } from "@/utils/helper";
const EditProfilePage: React.FC = () => { const EditProfilePage: React.FC = () => {
const { updateUserInfo, updateNickname } = useUserActions(); const { updateUserInfo, updateNickname } = useUserActions();
@@ -248,8 +249,8 @@ const EditProfilePage: React.FC = () => {
} catch (error) { } catch (error) {
console.warn("保存失败:", error); console.warn("保存失败:", error);
Taro.showToast({ Taro.showToast({
title: "保存失败", title: getBackendErrorMsg(error, "保存失败"),
icon: "error", icon: "none",
}); });
} }
}; };
@@ -309,8 +310,8 @@ const EditProfilePage: React.FC = () => {
} catch (error) { } catch (error) {
console.warn("保存失败:", error); console.warn("保存失败:", error);
Taro.showToast({ Taro.showToast({
title: "保存失败", title: getBackendErrorMsg(error, "保存失败"),
icon: "error", icon: "none",
}); });
} }
}; };

View File

@@ -94,6 +94,19 @@ export function toast(message) {
Taro.showToast({ title: message, icon: "none" }); Taro.showToast({ title: message, icon: "none" });
} }
/** 从接口/请求错误中取出后端返回的文案,用于保存失败等场景的 toast */
export function getBackendErrorMsg(error: any, fallback = "操作失败"): string {
if (error == null) return fallback;
const msg =
error?.message ||
(typeof error?.error === "string" ? error.error : error?.error?.message) ||
error?.data?.message ||
error?.data?.msg ||
"";
const s = String(msg).trim();
return s || fallback;
}
// 将·作为连接符插入到标签文本之间 // 将·作为连接符插入到标签文本之间
export function insertDotInTags(tags: string[]) { export function insertDotInTags(tags: string[]) {
if (!tags) return []; if (!tags) return [];