32 Commits

Author SHA1 Message Date
李瑞
4dc8e84f5c 修改日期筛选交互 2026-03-27 22:30:46 +08:00
b84c3bb409 fix: 时间展示修复 2026-03-25 06:03:07 +08:00
fa41842e75 fix: 逻辑补全 2026-03-20 23:24:22 +08:00
3bbb64d58c style: 修复地址展示的问题 2026-03-20 23:10:23 +08:00
58cf46e93d fix: 修复订单详情页球局时间展示问题、修复候补列表NTRP文案缺失的问题 2026-03-20 22:56:18 +08:00
张成
8004b26bd1 换logo 2026-03-19 15:00:08 +08:00
张成
98baa371ee 1 2026-03-16 11:25:50 +08:00
张成
f87859da0e 1 2026-03-11 15:33:26 +08:00
d3390d5e81 fix: debug 分享卡片生成问题 2026-03-11 11:48:40 +08:00
筱野
883ce3c2c4 修改标题换行替换 2026-03-10 21:34:45 +08:00
张成
63bcf6fe86 Merge branch 'fix/jgh/0310' 2026-03-10 11:35:19 +08:00
a68da08c85 feat: 订单详情页退款政策和报名须知修改文案和页面结构 2026-03-10 11:09:32 +08:00
李瑞
b854ef7505 处理场馆方字段 2026-03-10 00:03:42 +08:00
张成
2e4fd16383 修改文字 2026-03-09 17:23:32 +08:00
张成
636e218a63 1 2026-03-09 16:15:06 +08:00
张成
47c19f0fa5 1 2026-03-09 16:02:26 +08:00
243bb59c1d fix: 修改以支持非整数小时数 2026-03-09 15:48:34 +08:00
aed3c4cc54 feat: 排查生成海报失败的原因 2026-03-06 11:10:07 +08:00
05b89a4aeb fix: 修复取消活动管理弹窗输入框聚焦问题 2026-03-06 10:30:37 +08:00
张成
1aa12a86c2 钱包页返回也要拉数据 2026-03-04 16:03:23 +08:00
69248d33c8 优化样式 2026-03-02 16:15:59 +08:00
1973ec3faa input placeholder样式修改 2026-02-27 15:35:03 +08:00
abc2dfeecf 设置交易密码页面样式优化 2026-02-27 12:08:47 +08:00
bafb44ff06 设置交易密码页面样式优化 2026-02-27 12:06:40 +08:00
0e27d801a4 fix: 文案修改 2026-02-27 10:06:49 +08:00
0a0203e36d fix: 修复退出活动弹窗文案展示 2026-02-26 20:34:13 +08:00
2656c59475 feat: 退款政策接口获取 2026-02-26 19:43:40 +08:00
23eb9dc467 fix: 退款展示退款金额、球局详情页样式修复 2026-02-26 17:56:42 +08:00
44f971b1c2 往期球局排序处理 2026-02-25 16:42:14 +08:00
4a553c63fc 往期球局排序处理 2026-02-25 16:37:47 +08:00
张成
baa60bbfcb 添加内容过滤功能 2026-02-14 13:56:54 +08:00
张成
64f0267457 修改上传图片安全验证问题 2026-02-14 12:59:21 +08:00
80 changed files with 1185 additions and 685 deletions

View File

@@ -473,7 +473,7 @@ async function safeMarkAsRead(type, ids) {
})
} catch (err) {
// 标记已读失败不影响用户体验,静默处理
console.error('标记已读失败:', err)
console.warn('标记已读失败:', err)
}
}
```

View File

@@ -28,7 +28,7 @@ function formatSize(bytes) {
function analyze() {
if (!fs.existsSync(DIST_DIR)) {
console.error('dist 目录不存在,请先执行 taro build --type weapp');
console.warn('dist 目录不存在,请先执行 taro build --type weapp');
return;
}

View File

@@ -11,7 +11,7 @@ const { envConfigs } = require(envConfigPath);
const config = envConfigs[appEnv];
if (!config) {
console.error(`[sync-project-config] Unknown APP_ENV: ${appEnv}`);
console.warn(`[sync-project-config] Unknown APP_ENV: ${appEnv}`);
process.exit(1);
}

View File

@@ -11,7 +11,7 @@ import dayjs from "dayjs";
import classnames from "classnames";
import CommentServices from "@/services/commentServices";
import messageService from "@/services/messageService";
import { delay } from "@/utils";
import { delay, getBackendErrorMsg } from "@/utils";
import type {
BaseComment,
Comment,
@@ -342,7 +342,7 @@ export default forwardRef(function Comments(
try {
await messageService.markAsRead("comment", [message_id]);
} catch (e) {
console.error("标记评论已读失败:", e);
console.warn("标记评论已读失败:", e);
}
}
@@ -459,36 +459,48 @@ export default forwardRef(function Comments(
}
async function createComment(val: string) {
const res = await CommentServices.createComment({ game_id, content: val });
if (res.code === 0) {
setComments((prev) => {
commentCountUpdateRef.current?.(prev.length + 1);
return [{ ...res.data, replies: [] }, ...prev];
});
toast("发布成功");
try {
const res = await CommentServices.createComment({ game_id, content: val });
if (res.code === 0) {
setComments((prev) => {
commentCountUpdateRef.current?.(prev.length + 1);
return [{ ...res.data, replies: [] }, ...prev];
});
toast("发布成功");
} else {
toast(getBackendErrorMsg(res, "评论失败"));
}
} catch (error) {
toast(getBackendErrorMsg(error, "评论失败"));
}
}
async function replyComment({ parent_id, reply_to_user_id, content }) {
const res = await CommentServices.replyComment({
parent_id,
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;
});
try {
const res = await CommentServices.replyComment({
parent_id,
reply_to_user_id,
content,
});
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

@@ -134,7 +134,7 @@ const DistanceQuickFilterV2 = (props) => {
throw new Error('获取位置信息失败');
}
} catch (error: any) {
console.error('重新定位失败:', error);
console.warn('重新定位失败:', error);
(Taro as any).showToast({
title: error?.message || '定位失败,请检查定位权限',
icon: 'none',

View File

@@ -32,36 +32,52 @@ const FilterPopup = (props: FilterPopupProps) => {
const { timeBubbleData, gamesNum } = store;
/**
* @description 处理字典选项
* @param dictionaryValue 字典选项
* @returns 选项列表
* @description 日期排序
* @param a 日期字符串
* @param b 日期字符串
* @returns 日期差值
*/
// const [selectedDates, setSelectedDates] = useState<String[]>([])
const sortByDate = (a: string, b: string) => {
return new Date(a).getTime() - new Date(b).getTime();
}
const handleDateChange = (dates: Date[]) => {
let times: String[] = [];
if (dates.length > 1) {
times = [dayjs(dates[0]).format('YYYY-MM-DD'), dayjs(dates[dates.length - 1]).format('YYYY-MM-DD')]
onChange({
'dateRange': times,
})
// ================================ 日期处理 ================================
// 默认是是当前日期为开始日期,结束日期为当前日期 + 30天
const defaultDateRange = [dayjs().format('YYYY-MM-DD'), dayjs().add(1, 'M').format('YYYY-MM-DD')];
// 处理空数组的情况
if (!dates.length) {
onChange({ dateRange: defaultDateRange });
return;
}
if (Array.isArray(dates)) {
const currentDay = dayjs(dates[0]).format('YYYY-MM-DD');
if (filterOptions.dateRange.length === 0 || filterOptions.dateRange.length === 2) {
times.push(currentDay);
} else {
times = [...filterOptions.dateRange, currentDay].sort(
(a, b) => new Date(a).getTime() - new Date(b).getTime()
)
}
// 处理多日期范围选择超过1个日期
if (dates.length > 1) {
const dateRange = [
dayjs(dates[0]).format('YYYY-MM-DD'),
dayjs(dates[dates.length - 1]).format('YYYY-MM-DD')
];
onChange({ dateRange });
return;
}
onChange({
'dateRange': times,
})
// 处理单个日期选择
const currentFilterOptionsDateRange = Array.isArray(filterOptions?.dateRange)
? filterOptions.dateRange
: defaultDateRange;
// 当前选择的日期
const currentDay = dayjs(dates?.[0]).format('YYYY-MM-DD');
// 当 dates 每次只返回单个日期时,使用已选范围判断是“第一次点”还是“第二次点”
let dateRange: string[];
if (
currentFilterOptionsDateRange.length === 2 &&
currentFilterOptionsDateRange?.[0] === currentFilterOptionsDateRange?.[1]
) {
// 已是单日,点击当前日期扩展为日期范围
dateRange = [currentFilterOptionsDateRange[0], currentDay].sort(sortByDate);
} else {
// 默认区间/已选区间/异常状态,点击当前日期统一收敛为单日
dateRange = [currentDay, currentDay];
}
onChange({ dateRange });
}
const handleOptions = (dictionaryValue: []) => {

View File

@@ -42,7 +42,7 @@ const FollowUserCard: React.FC<FollowUserCardProps> = ({ user, tabKey, onFollowC
onFollowChange?.(user.id, new_status);
} catch (error) {
console.error('关注操作失败:', error);
console.warn('关注操作失败:', error);
Taro.showToast({
title: '操作失败',
icon: 'none'
@@ -67,7 +67,7 @@ const FollowUserCard: React.FC<FollowUserCardProps> = ({ user, tabKey, onFollowC
onBlockSuccess?.(user.id);
}
} catch (error) {
console.error('删除推荐人员失败:', error);
console.warn('删除推荐人员失败:', error);
Taro.showToast({
title: '操作失败',
icon: 'none'

View File

@@ -16,8 +16,8 @@ const CancelPopup = forwardRef((props, ref) => {
const { detail } = props;
const [visible, setVisible] = useState(false);
const [cancelReason, setCancelReason] = useState("");
const [inputFocus, setInputFocus] = useState(false);
const onFinish = useRef(null);
const inputRef = useRef(null);
const { current_players, participants = [], publisher_id } = detail;
const realParticipants = participants
@@ -32,16 +32,15 @@ const CancelPopup = forwardRef((props, ref) => {
show: (onAct) => {
onFinish.current = onAct;
setVisible(true);
// 使用 requestAnimationFrame 替代 setTimeout(0),性能更好
requestAnimationFrame(() => {
requestAnimationFrame(() => {
inputRef.current && inputRef.current.focus();
});
// 使用 Taro.nextTick 确保在下一个渲染周期后聚焦
Taro.nextTick(() => {
setInputFocus(true);
});
},
}));
function onClose() {
setInputFocus(false);
setVisible(false);
setCancelReason("");
}
@@ -85,13 +84,13 @@ const CancelPopup = forwardRef((props, ref) => {
{hasOtherJoin && (
<View className={styles.cancelReason}>
<Input
ref={inputRef}
className={styles.input}
placeholder="请输入取消理由"
focus
focus={inputFocus}
value={cancelReason}
onInput={(e) => setCancelReason(e.detail.value)}
maxlength={100}
onBlur={() => setInputFocus(false)}
/>
</View>
)}

View File

@@ -146,7 +146,7 @@ const HomeNavbar = (props: IProps) => {
console.log(`[HomeNavbar] 距离上次选择"继续浏览"还不到2小时剩余时间: ${Math.ceil((TWO_HOURS_MS - time_diff) / 1000 / 60)}分钟`);
return false;
} catch (error) {
console.error('[HomeNavbar] 检查定位弹窗显示条件失败:', error);
console.warn('[HomeNavbar] 检查定位弹窗显示条件失败:', error);
return true; // 出错时默认显示
}
};
@@ -239,7 +239,7 @@ const HomeNavbar = (props: IProps) => {
// console.log(`距离上次选择"继续浏览"还不到2小时剩余时间: ${Math.ceil((TWO_HOURS_MS - time_diff) / 1000 / 60)}分钟`);
// return false;
// } catch (error) {
// console.error('检查定位弹窗显示条件失败:', error);
// console.warn('检查定位弹窗显示条件失败:', error);
// return true; // 出错时默认显示
// }
// };
@@ -276,7 +276,7 @@ const HomeNavbar = (props: IProps) => {
(Taro as any).setStorageSync(CITY_CHANGE_TIME_KEY, current_time);
console.log(`[LocationDialog] 已记录用户切换城市的时间2小时内不再提示`);
} catch (error) {
console.error('保存城市切换时间失败:', error);
console.warn('保存城市切换时间失败:', error);
}
console.log("切换到用户详情中的位置信息并更新缓存:", detectedProvince);
@@ -304,7 +304,7 @@ const HomeNavbar = (props: IProps) => {
(Taro as any).setStorageSync(LOCATION_DIALOG_DISMISS_TIME_KEY, current_time);
console.log(`[LocationDialog] 已记录用户选择"继续浏览"的时间2小时内不再提示`);
} catch (error) {
console.error('保存定位弹窗关闭时间失败:', error);
console.warn('保存定位弹窗关闭时间失败:', error);
}
// 关闭弹窗
@@ -409,7 +409,7 @@ const HomeNavbar = (props: IProps) => {
(Taro as any).setStorageSync(CITY_CHANGE_TIME_KEY, current_time);
console.log("已保存城市到缓存并记录切换时间:", _newArea, current_time);
} catch (error) {
console.error("保存城市缓存失败:", error);
console.warn("保存城市缓存失败:", error);
}
// 先调用列表接口(会使用更新后的 state.area

View File

@@ -43,7 +43,7 @@ const ImageUpload: React.FC<ImageUploadProps> = ({
onChange([...images, ...newImages])
},
fail: (err) => {
console.error('选择图片失败:', err)
console.warn('选择图片失败:', err)
}
})
}, [images.length, maxCount, onChange])

View File

@@ -27,7 +27,7 @@ const ListCard: React.FC<ListCardProps> = ({
key,
participants, // 参与者图片
venue_image_list, // 场馆图片
venue_description,
location_name = '', // 场馆方
game_type, // 球局类型
}) => {
// 参与者要前三个数据
@@ -257,13 +257,13 @@ const ListCard: React.FC<ListCardProps> = ({
/>
{/* <Text className="smoothTitle">{game_type}</Text> */}
</View>
{venue_description && <View className="line" />}
{venue_description && (
{location_name && <View className="line" />}
{location_name && (
<View className="localAreaContainer">
<View className="localAreaTitle">:</View>
<View className="localAreaWrapper">
<Image className="localArea" src={venueImage} />
<Text className="localAreaText">{venue_description}</Text>
{venueImage && <Image className="localArea" src={venueImage} />}
<Text className="localAreaText">{location_name}</Text>
</View>
</View>
)}

View File

@@ -194,17 +194,6 @@ const RadarChartV2 = forwardRef<RadarChartV2Ref, RadarChartV2Props>(
ctx.closePath();
}
// 格式化 NTRP 显示
function formatNtrpDisplay(level: string): string {
if (!level) return "";
// 检查是否包含 + 号
const hasPlus = level.includes("+");
const num = parseFloat(level);
if (isNaN(num)) return level;
const formatted = num % 1 === 0 ? num.toFixed(0) : num.toFixed(1);
return hasPlus ? `${formatted}+` : formatted;
}
useImperativeHandle(ref, () => ({
// 生成原始雷达图(已废弃,现在直接在 exportCanvasV2 中绘制)
generateImage: () => Promise.resolve(""),
@@ -256,7 +245,7 @@ const RadarChartV2 = forwardRef<RadarChartV2Ref, RadarChartV2Props>(
const bgImg = await loadImage(canvas, shareBgUrl);
ctx.drawImage(bgImg, 0, 0, width, height);
} catch (error) {
console.error("Failed to load background image:", error);
console.warn("Failed to load background image:", error);
// 如果加载失败,使用白色背景作为兜底
ctx.fillStyle = "#FFFFFF";
ctx.fillRect(0, 0, width, height);
@@ -392,12 +381,12 @@ const RadarChartV2 = forwardRef<RadarChartV2Ref, RadarChartV2Props>(
);
ctx.restore();
} catch (error) {
console.error("Failed to load docCopy image:", error);
console.warn("Failed to load docCopy image:", error);
}
currentY += (48 + 20) * scale; // 头像区域高度 + gap
} catch (error) {
console.error("Failed to load avatar image:", error);
console.warn("Failed to load avatar image:", error);
}
}
@@ -421,7 +410,7 @@ const RadarChartV2 = forwardRef<RadarChartV2Ref, RadarChartV2Props>(
ctx.textBaseline = "top";
const ntrpText = "NTRP";
const levelText = formatNtrpDisplay(options.ntrpLevel);
const levelText = options.ntrpLevel ?? "";
const ntrpWidth = ctx.measureText(ntrpText).width;
const levelWidth = ctx.measureText(levelText).width;
const totalWidth = ntrpWidth + levelWidth; // 设计稿中紧挨着
@@ -523,7 +512,7 @@ const RadarChartV2 = forwardRef<RadarChartV2Ref, RadarChartV2Props>(
iconSize,
);
} catch (error) {
console.error("Failed to load icon:", error);
console.warn("Failed to load icon:", error);
}
// 绘制底部文字
@@ -601,7 +590,7 @@ const RadarChartV2 = forwardRef<RadarChartV2Ref, RadarChartV2Props>(
// 恢复上下文状态
ctx.restore();
} catch (error) {
console.error("Failed to load QR code:", error);
console.warn("Failed to load QR code:", error);
}
}

View File

@@ -575,7 +575,7 @@ const ShareCardCanvas: React.FC<ShareCardCanvasProps> = ({
setTempImagePath(res.tempFilePath)
},
fail: (error: any) => {
console.error('图片生成失败:', error)
console.warn('图片生成失败:', error)
setIsDrawing(false)
reject(error)
}
@@ -595,7 +595,7 @@ const ShareCardCanvas: React.FC<ShareCardCanvasProps> = ({
console.log('Canvas绘制命令已发送')
} catch (error) {
console.error('绘制分享卡片失败:', error)
console.warn('绘制分享卡片失败:', error)
setIsDrawing(false) // 绘制失败,重置状态
Taro.showToast({
title: '生成分享卡片失败',

View File

@@ -16,7 +16,7 @@ const SubscribeNotificationTip: React.FC<SubscribeNotificationTipProps> = ({
navigateTo({
url: '/other_pages/enable_notification/index',
}).catch((err) => {
console.error('跳转失败:', err);
console.warn('跳转失败:', err);
});
};

View File

@@ -86,9 +86,9 @@ async function onChooseImageSuccess(tempFiles) {
...fileRes,
...(height > IMAGE_MAX_SIZE.height
? {
width: Math.floor(IMAGE_MAX_SIZE.height * image_aspect_ratio),
height: IMAGE_MAX_SIZE.height,
}
width: Math.floor(IMAGE_MAX_SIZE.height * image_aspect_ratio),
height: IMAGE_MAX_SIZE.height,
}
: { width: Math.floor(height * image_aspect_ratio), height }),
};
} else {
@@ -96,9 +96,9 @@ async function onChooseImageSuccess(tempFiles) {
...fileRes,
...(width > IMAGE_MAX_SIZE.width
? {
width: IMAGE_MAX_SIZE.width,
height: Math.floor(IMAGE_MAX_SIZE.width / image_aspect_ratio),
}
width: IMAGE_MAX_SIZE.width,
height: Math.floor(IMAGE_MAX_SIZE.width / image_aspect_ratio),
}
: { width, height: Math.floor(width / image_aspect_ratio) }),
};
}
@@ -119,7 +119,6 @@ export default function UploadFromWx(props: UploadFromWxProps) {
sourceType: ["album", "camera"],
}).then(async (res) => {
const analyzedFiles = await onChooseImageSuccess(res.tempFiles);
// cropping image to standard size
const compressedTempFiles = await compressImage(analyzedFiles);
let start = Date.now();
@@ -130,19 +129,22 @@ export default function UploadFromWx(props: UploadFromWxProps) {
is_public: 1 as unknown as 0 | 1,
id: (start++).toString(),
}));
const onFileUpdate = uploadApi.batchUpload(files).then((res) => {
return res.map((item) => ({
id: item.id,
url: item ? item.data.file_url : "",
}));
});
onAdd(
files.map((item) => ({
id: item.id,
url: item.filePath,
})),
onFileUpdate
);
Taro.showLoading({ title: "上传中..." });
try {
const uploadRes = await uploadApi.batchUpload(files);
const successful = uploadRes
.filter((item) => item.data != null)
.map((item) => ({
id: item.id,
url: (item.data as { file_url: string }).file_url,
}));
onAdd(successful, Promise.resolve(successful));
} catch (e) {
console.warn("批量上传失败:", e);
} finally {
Taro.hideLoading();
}
});
};
return (

View File

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

View File

@@ -13,7 +13,7 @@ import orderService from "@/services/orderService";
import styles from "./index.module.scss";
import closeIcon from "@/static/order/orderListClose.svg";
function genRefundNotice(refund_policy) {
function genRefundNotice(refund_policy, order_amount) {
if (refund_policy.length === 0) {
return {};
}
@@ -23,8 +23,7 @@ function genRefundNotice(refund_policy) {
if (matchPolicyIndex === -1) {
matchPolicyIndex = refund_policy.length - 1;
}
const { deadline_formatted, price, refund_rate } =
refund_policy[matchPolicyIndex];
const { time_range, price, refund_rate } = refund_policy[matchPolicyIndex];
if (refund_rate === 1) {
return {
refundPrice: price,
@@ -33,20 +32,18 @@ function genRefundNotice(refund_policy) {
} else if (refund_rate === 0) {
return {
refundPrice: 0,
notice: `当前退出不可退款,后续流程未明确,@麻真瑜`,
notice: `当前退出不可退款,¥${order_amount} 将不予退回`,
};
}
const refundPrice = Number(Math.ceil(price * refund_rate * 100) / 100);
const leftHours = dayjs(deadline_formatted).diff(dayjs(), "hour");
// const refundPrice = Number(Math.ceil(price * refund_rate * 100) / 100);
// const leftHours = dayjs(deadline_formatted).diff(dayjs(), "hour");
return {
refundPrice,
notice: `活动开始已不足${leftHours}h,当前退出需扣除${
Math.floor((price - refundPrice) * 100) / 100
}`,
refundPrice: price,
notice: `活动开始${time_range},当前退出需扣除${Math.ceil((order_amount - price) * 100) / 100}`,
};
}
function renderCancelContent(refund_policy = []) {
function renderCancelContent(refund_policy = [], amount) {
const current = dayjs();
const policyList = [
{
@@ -65,7 +62,7 @@ function renderCancelContent(refund_policy = []) {
}),
];
const targetIndex = policyList.findIndex((item) => item.beforeCurrent);
const { notice } = genRefundNotice(refund_policy);
const { notice } = genRefundNotice(refund_policy, amount);
return (
<View className={styles.refundPolicy}>
{/* <View className={styles.moduleTitle}>
@@ -80,7 +77,7 @@ function renderCancelContent(refund_policy = []) {
className={classnames(
styles.policyItem,
targetIndex > index && index !== 0 ? styles.pastItem : "",
targetIndex === index ? styles.currentItem : ""
targetIndex === index ? styles.currentItem : "",
)}
>
<View className={styles.time}>
@@ -169,7 +166,7 @@ export default forwardRef<RefundRef>(function RefundPopup(_props, ref) {
onClick={onClose}
/>
</View>
{renderCancelContent(refundPolicy)}
{renderCancelContent(refundPolicy, orderData.amount)}
<Button className={styles.action} onClick={handleConfirmQuit}>
退
</Button>

View File

@@ -1,27 +1,13 @@
import Taro from "@tarojs/taro";
import dayjs, { Dayjs } from "dayjs";
import "dayjs/locale/zh-cn";
import { calculateDistance } from "@/utils";
import { calculateDistance, genGameLength } from "@/utils";
import { View, Image, Text, Map } from "@tarojs/components";
import img from "@/config/images";
import styles from "./index.module.scss";
dayjs.locale("zh-cn");
function genGameLength(startTime: Dayjs, endTime: Dayjs) {
if (!startTime || !endTime) {
return "";
}
const hours = endTime.diff(startTime, "hour");
if (Math.floor(hours / 24) >= 1) {
const leftHours = Math.floor(hours % 24);
return `${Math.floor(hours / 24)}${
leftHours !== 0 ? `${leftHours}小时` : ""
}`;
}
return `${hours}小时`;
}
function genGameRange(startTime: Dayjs, endTime: Dayjs) {
if (!startTime || !endTime) {
return "";

View File

@@ -48,8 +48,8 @@ function genRecommendGames(games, location, avatar) {
formatNtrpDisplay(skill_level_max) || "-"
}`
: skill_level_min === "1"
? "无要求"
: `${formatNtrpDisplay(skill_level_min)}以上`,
? "无要求"
: `${formatNtrpDisplay(skill_level_min)}以上`,
playType: play_type,
};
});
@@ -220,7 +220,9 @@ export default function OrganizerInfo(props) {
>
<Text>{game.venue}</Text>
<Text>·</Text>
<Text>{game.venueType}</Text>
<Text style={{ whiteSpace: "nowrap" }}>
{game.venueType}
</Text>
<Text>·</Text>
<Text>{game.distance}</Text>
</View>
@@ -247,7 +249,7 @@ export default function OrganizerInfo(props) {
styles[
"recommend-games-list-item-addon-message-applications"
],
styles.joinMsg
styles.joinMsg,
)}
>
<Text></Text>

View File

@@ -489,7 +489,7 @@ export default function Participants(props) {
<Text
className={styles["participants-list-item-level"]}
>
{displayNtrp}
NTRP {displayNtrp}
</Text>
<Text className={styles["participants-list-item-role"]}>
{role}

View File

@@ -1,7 +1,7 @@
import { forwardRef, useState, useEffect, useImperativeHandle } from "react";
import { View, Button, Image, Text } from "@tarojs/components";
import Taro, { useShareAppMessage } from "@tarojs/taro";
import dayjs from "dayjs";
import dayjs, { Dayjs } from "dayjs";
import "dayjs/locale/zh-cn";
import classnames from "classnames";
import { generateShareImage } from "@/utils";
@@ -12,7 +12,7 @@ import WechatLogo from "@/static/detail/wechat_icon.svg";
// import WechatTimeline from "@/static/detail/wechat_timeline.svg";
import LinkIcon from "@/static/detail/link.svg";
import CrossIcon from "@/static/detail/cross.svg";
import { genNTRPRequirementText, navto } from "@/utils/helper";
import { genNTRPRequirementText, navto, genGameLength } from "@/utils/helper";
import { waitForAuthInit } from "@/utils/authInit";
import { useUserActions } from "@/store/userStore";
import { OSS_BASE } from "@/config/api";
@@ -28,7 +28,19 @@ export default forwardRef(({ id, from, detail, userInfo }, ref) => {
const [shareImageUrl, setShareImageUrl] = useState("");
const { fetchUserInfo } = useUserActions();
async function ensureUserInfo() {
if (userInfo?.avatar_url && userInfo?.nickname) {
return userInfo;
}
const fetchedUserInfo = await fetchUserInfo();
return {
avatar_url: fetchedUserInfo?.avatar_url || userInfo?.avatar_url || "",
nickname: fetchedUserInfo?.nickname || userInfo?.nickname || "",
};
}
const publishFlag = from === "publish";
// const posterRef = useRef();
const { max_participants, participant_count } = detail || {};
@@ -50,6 +62,16 @@ export default forwardRef(({ id, from, detail, userInfo }, ref) => {
withShareTicket: false, // 是否需要返回 shareTicket
isUpdatableMessage: true, // 是否是动态消息(需要服务端配置过模版)
activityId: res.data.activity_id, // 动态消息的活动 id
templateInfo: {
parameterList: [
{
name: "member_count",
value: (participant_count ?? 0).toString(),
},
{ name: "room_limit", value: (max_participants ?? 0).toString() },
],
templateId: "666F374D69D16C932E45D7E7D9F10CEF6177F5F5",
},
});
}
} catch (e) {
@@ -86,25 +108,34 @@ export default forwardRef(({ id, from, detail, userInfo }, ref) => {
const endTime = dayjs(end_time);
const dayofWeek = DayOfWeekMap.get(startTime.day());
const gameLength = `${endTime.diff(startTime, "hour")}小时`;
console.log(userInfo, "userInfo");
const url = await generateShareImage({
userAvatar: userInfo.avatar_url,
userNickname: userInfo.nickname,
gameType: play_type,
skillLevel: `NTRP ${genNTRPRequirementText(
skill_level_min,
skill_level_max,
)}`,
gameDate: `${startTime.format("M月D日")} (${dayofWeek})`,
gameTime: `${startTime.format("ah")} ${gameLength}`,
venueName: location_name,
venueImages: image_list ? image_list : [],
});
return url;
const currentUserInfo = await ensureUserInfo();
try {
const url = await generateShareImage({
userAvatar: currentUserInfo.avatar_url,
userNickname: currentUserInfo.nickname,
gameType: play_type,
skillLevel: `NTRP ${genNTRPRequirementText(
skill_level_min,
skill_level_max,
)}`,
gameDate: `${startTime.format("M月D日")} (${dayofWeek})`,
gameTime: `${startTime.format("ah")}${gameLength}`,
venueName: location_name,
venueImages: image_list ? image_list : [],
});
if (!url) {
throw new Error("生成分享图片失败URL 为空");
}
return url;
} catch (e) {
console.error("生成分享卡片失败", e);
return `${OSS_BASE}/system/game_dou_di_tu.png`;
}
}
useShareAppMessage(async (res) => {
await changeMessageType();
await ensureUserInfo();
const url = await generateShareImageUrl();
// console.log(res, "res");
return {
@@ -128,41 +159,49 @@ export default forwardRef(({ id, from, detail, userInfo }, ref) => {
} = detail || {};
// 先等待静默登录完成
await waitForAuthInit();
const userInfo = await fetchUserInfo();
const { avatar_url, nickname } = userInfo;
const currentUserInfo = await ensureUserInfo();
const { avatar_url, nickname } = currentUserInfo;
const startTime = dayjs(start_time);
const endTime = dayjs(end_time);
const dayofWeek = DayOfWeekMap.get(startTime.day());
const gameLength = `${endTime.diff(startTime, "hour")}小时`;
// Taro.showLoading({ title: "生成中..." });
const qrCodeUrlRes = await DetailService.getQrCodeUrl({
page: "game_pages/detail/index",
scene: `id=${id}`,
});
// const qrCodeUrl = await base64ToTempFilePath(
// qrCodeUrlRes.data.qr_code_base64
// );
const qrCodeUrl = qrCodeUrlRes.data.ossPath;
// const gameLength = `${endTime.diff(startTime, "hour")}小时`;
const game_length = genGameLength(startTime, endTime);
let qrCodeUrl = "";
try {
const qrCodeUrlRes = await DetailService.getQrCodeUrl({
page: "game_pages/detail/index",
scene: `id=${id}`,
});
qrCodeUrl = qrCodeUrlRes.data.ossPath;
} catch (e) {
Taro.showToast({ title: "获取二维码失败", icon: "error" });
return;
}
await delay(100);
// Taro.showLoading({ title: "生成中..." });
console.log('url', qrCodeUrl)
const url = await generatePosterImage({
playType: play_type,
ntrp: `NTRP ${genNTRPRequirementText(skill_level_min, skill_level_max)}`,
mainCoursal:
image_list[0] && image_list[0].startsWith("http")
? image_list[0]
: `${OSS_BASE}/front/ball/images/0621b8cf-f7d6-43ad-b852-7dc39f29a782.png`,
nickname,
avatarUrl: avatar_url,
title,
locationName: location_name,
date: `${startTime.format("M月D日")} (${dayofWeek})`,
time: `${startTime.format("ah")} ${gameLength}`,
qrCodeUrl,
});
console.log("url", qrCodeUrl);
let url = "";
try {
url = await generatePosterImage({
playType: play_type,
ntrp: `NTRP ${genNTRPRequirementText(skill_level_min, skill_level_max)}`,
mainCoursal:
image_list[0] && image_list[0].startsWith("http")
? image_list[0]
: `${OSS_BASE}/front/ball/images/0621b8cf-f7d6-43ad-b852-7dc39f29a782.png`,
nickname,
avatarUrl: avatar_url,
title,
locationName: location_name,
date: `${startTime.format("M月D日")} (${dayofWeek})`,
time: `${startTime.format("ah")}${game_length}`,
qrCodeUrl,
});
} catch (e) {
Taro.showToast({ title: "生成海报失败,请重试", icon: "error" });
return;
}
console.log('urlend', url)
console.log("urlend", url);
// Taro.hideLoading();
Taro.showShareImageMenu({
path: url,

View File

@@ -24,12 +24,12 @@ function isFull(counts) {
} = counts;
if (
max_players === current_players &&
current_players >= max_players &&
is_substitute_supported === IsSubstituteSupported.NOTSUPPORT
) {
return true;
} else if (
max_players === current_players &&
current_players >= max_players &&
is_substitute_supported === IsSubstituteSupported.SUPPORT
) {
return max_substitute_players === current_substitute_count;
@@ -45,7 +45,7 @@ function RmbIcon() {
function matchNtrpRequestment(
target?: string,
min?: string,
max?: string
max?: string,
): boolean {
// 目标值为空或 undefined
if (!target?.trim()) return true;
@@ -123,7 +123,7 @@ export default function StickyButton(props) {
Taro.navigateTo({
url: `/login_pages/index/index?redirect=${encodeURIComponent(
fullPath
fullPath,
)}`,
});
}
@@ -138,7 +138,7 @@ export default function StickyButton(props) {
const matchNtrpReq = matchNtrpRequestment(
ntrp_level,
skill_level_min,
skill_level_max
skill_level_max,
);
const gameManageRef = useRef();
@@ -173,7 +173,7 @@ export default function StickyButton(props) {
}, [getCommentCount]);
function generateTextAndAction(
user_action_status: null | { [key: string]: boolean }
user_action_status: null | { [key: string]: boolean },
):
| undefined
| { text: string | React.FC; action?: () => void; available?: boolean } {
@@ -271,7 +271,7 @@ export default function StickyButton(props) {
const res = await OrderService.getUnpaidOrder(id);
if (res.code === 0) {
navto(
`/order_pages/orderDetail/index?id=${res.data.order_info.order_id}`
`/order_pages/orderDetail/index?id=${res.data.order_info.order_id}`,
);
}
}),
@@ -387,7 +387,7 @@ export default function StickyButton(props) {
<View
className={classnames(
styles["detail-main-action"],
available ? "" : styles.disabled
available ? "" : styles.disabled,
)}
>
<View

View File

@@ -16,6 +16,11 @@ export default function VenueInfo(props) {
venue_image_list = [],
} = detail;
// 统一为 URL 数组:接口可能是 { id, url }[] 或 string[]
const screenshot_urls = (venue_image_list || []).map((item) =>
typeof item === "string" ? item : (item?.url ?? "")
).filter(Boolean);
function showScreenShot() {
setVisible(true);
}
@@ -23,10 +28,10 @@ export default function VenueInfo(props) {
setVisible(false);
}
function previewImage(current_url) {
function previewImage(current_url: string) {
Taro.previewImage({
current: current_url,
urls: venue_image_list || [],
urls: screenshot_urls,
});
}
return (
@@ -34,14 +39,14 @@ export default function VenueInfo(props) {
{/* venue detail title and venue ordered status */}
<View className={styles["venue-detail-title"]}>
<Text></Text>
{venue_image_list?.length > 0 ? (
{screenshot_urls.length > 0 ? (
<>
<Text>·</Text>
<View
className={styles["venue-reserve-status"]}
onClick={showScreenShot}
>
<Text></Text>
<Text></Text>
<Image
className={styles["venue-reserve-screenshot"]}
src={img.ICON_DETAIL_ARROW_RIGHT}
@@ -81,22 +86,20 @@ export default function VenueInfo(props) {
<View className={styles["venue-screenshot-title"]}></View>
<ScrollView scrollY className={styles["venue-screenshot-scroll-view"]}>
<View className={styles["venue-screenshot-image-list"]}>
{venue_image_list?.length > 0 &&
venue_image_list.map((url, index) => {
return (
<View
className={styles["venue-screenshot-image-item"]}
onClick={previewImage.bind(null, url)}
key={index}
>
<Image
className={styles["venue-screenshot-image-item-image"]}
mode="aspectFill"
src={url}
/>
</View>
);
})}
{screenshot_urls.length > 0 &&
screenshot_urls.map((url, index) => (
<View
className={styles["venue-screenshot-image-item"]}
onClick={() => previewImage(url)}
key={index}
>
<Image
className={styles["venue-screenshot-image-item-image"]}
mode="aspectFill"
src={url}
/>
</View>
))}
</View>
</ScrollView>
</CommonPopup>

View File

@@ -86,7 +86,7 @@ function Index() {
// handleShare(true);
// }
} catch (error) {
console.error("用户位置更新失败", error);
console.warn("用户位置更新失败", error);
}
};

View File

@@ -17,14 +17,14 @@ const HomePage: React.FC = () => {
if (loginResult.success) {
// 静默登录成功,获取用户信息
fetchUserInfo().catch((error) => {
console.error("获取用户信息失败:", error);
console.warn("获取用户信息失败:", error);
});
checkNicknameChangeStatus().catch((error) => {
console.error("检查昵称变更状态失败:", error);
console.warn("检查昵称变更状态失败:", error);
});
}
} catch (error) {
console.error("静默登录失败:", error);
console.warn("静默登录失败:", error);
// 静默登录失败不影响使用
}

View File

@@ -139,7 +139,7 @@ const VerificationPage: React.FC = () => {
});
}
} catch (error) {
console.error("发送验证码异常:", error);
console.warn("发送验证码异常:", error);
Taro.showToast({
title: "发送失败,请重试",
icon: "none",

View File

@@ -235,7 +235,7 @@ const ListPageContent: React.FC<ListPageContentProps> = ({
if (isActive) {
getLocation().catch((error) => {
console.error('获取位置信息失败:', error);
console.warn('获取位置信息失败:', error);
});
}
}, [isActive, showHomeQrcode]);
@@ -309,7 +309,7 @@ const ListPageContent: React.FC<ListPageContentProps> = ({
lastLoadedAreaRef.current = [...currentArea] as [string, string];
}
} catch (error) {
console.error("重新加载数据失败:", error);
console.warn("重新加载数据失败:", error);
}
}, delayMs);
prevIsActiveRef.current = isActive;
@@ -375,7 +375,7 @@ const ListPageContent: React.FC<ListPageContentProps> = ({
await updateUserLocation(location.latitude, location.longitude, isFirstCall);
hasUpdatedLocationRef.current = true;
} catch (error) {
console.error("更新用户位置失败:", error);
console.warn("更新用户位置失败:", error);
}
}
// 先调用列表接口
@@ -462,7 +462,7 @@ const ListPageContent: React.FC<ListPageContentProps> = ({
await getMatchesData();
await fetchGetGamesCount();
} catch (error) {
console.error("刷新列表失败:", error);
console.warn("刷新列表失败:", error);
}
};
@@ -477,7 +477,7 @@ const ListPageContent: React.FC<ListPageContentProps> = ({
const { fetchDictionary } = useDictionaryStore.getState();
await fetchDictionary();
} catch (error) {
console.error("初始化字典数据失败:", error);
console.warn("初始化字典数据失败:", error);
}
};
@@ -616,7 +616,7 @@ const ListPageContent: React.FC<ListPageContentProps> = ({
try {
await loadMoreMatches();
} catch (error) {
console.error("加载更多失败:", error);
console.warn("加载更多失败:", error);
} finally {
loadingMoreRef.current = false;
}

View File

@@ -82,7 +82,7 @@ const MyselfPageContent: React.FC<MyselfPageContentProps> = ({
const end_time_str = end_time.replace(/\s/, "T");
new Date(end_time_str).getTime() > now
? notEndGames.push(game)
: finishedGames.push(game);
: finishedGames.unshift(game);
}
console.log("notEndGames", notEndGames);
@@ -117,7 +117,7 @@ const MyselfPageContent: React.FC<MyselfPageContentProps> = ({
set_game_records(notEndGames);
setEndedGameRecords(finishedGames);
} catch (error) {
console.error("加载球局数据失败:", error);
console.warn("加载球局数据失败:", error);
}
}, [active_tab, user_info, classifyGameRecords]);
@@ -150,7 +150,7 @@ const MyselfPageContent: React.FC<MyselfPageContentProps> = ({
duration: 1500,
});
} catch (error) {
console.error("关注操作失败:", error);
console.warn("关注操作失败:", error);
(Taro as any).showToast({
title: "操作失败,请重试",
icon: "error",
@@ -198,7 +198,7 @@ const MyselfPageContent: React.FC<MyselfPageContentProps> = ({
try {
await Promise.all([fetchUserInfo(), load_game_data()]);
} catch (error) {
console.error("刷新失败:", error);
console.warn("刷新失败:", error);
(Taro as any).showToast({
title: "刷新失败,请重试",
icon: "none",

View File

@@ -68,7 +68,7 @@ const MainPage: React.FC = () => {
return;
}
} catch (error) {
console.error("微信授权异常:", error);
console.warn("微信授权异常:", error);
setAuthErrorMessage("微信授权失败,请重试");
setShowAuthError(true);
return;
@@ -81,7 +81,7 @@ const MainPage: React.FC = () => {
await fetchUserInfo();
await checkNicknameChangeStatus();
} catch (error) {
console.error("获取用户信息失败:", error);
console.warn("获取用户信息失败:", error);
}
}
};

View File

@@ -22,3 +22,135 @@ export const DECLAIMER = `
发起人临时失联/爽约发起人恶意删除队员GO支持全额退款
参与者爽约不通知,不可退款但鼓励用户评分机制中反馈,平台将限制其部分功能使用(如发起权限、报名权限等)。
`;
interface RegInsChildTipType {
text: string
strong?: boolean
}
interface RegInsChildTableType {
refundApplicationTime: string
participantRefundableAmount: string
liquidatedDamages: string
}
interface RegInsChildType {
title: string
desc: string
table?: RegInsChildTableType[]
tips: RegInsChildTipType[]
}
interface RegInsType {
title: string,
desc: string,
children: RegInsChildType[]
}
export const RegistrationInstructions: RegInsType = {
title: '报名须知',
desc: '请在确认支付前仔细阅读以下内容,完成支付即视为您已同意本须知全部内容。',
children: [
{
title: '一、退款规则',
desc: '',
table: [
{
refundApplicationTime: '申请退款时间',
participantRefundableAmount: '参与者可退',
liquidatedDamages: '违约金',
},
{
refundApplicationTime: '活动开始前24小时',
participantRefundableAmount: '报名费 100%',
liquidatedDamages: '无',
},
{
refundApplicationTime: '活动开始前1224小时',
participantRefundableAmount: '报名费 50%',
liquidatedDamages: '报名费 50%',
},
{
refundApplicationTime: '活动开始前12小时内',
participantRefundableAmount: '报名费 20%',
liquidatedDamages: '报名费 80%',
},
{
refundApplicationTime: '未申请 / 直接缺席',
participantRefundableAmount: '0%',
liquidatedDamages: '视为放弃,全归组织者',
},
],
tips: [
{
text: '以上时间节点以提交申请时间为准,非活动开始时间;',
strong: false,
},
{
text: '退款申请入口:活动详情页 > 退出活动',
},
{
text: '退款原路退回至微信支付账户,到账时间 15 个工作日;',
},
{
text: '违约金由组织者95%与平台5%)按比例分配。其中组织者所得部分用于补偿其因人数临时变动产生的场地费损失,平台所得部分用于覆盖违约事务的处理成本;',
},
{
text: '未申请退款直接缺席的,报名费于活动结束后自动结算给组织者,平台不参与分配',
},
],
},
{
title: '二、特殊情形退款',
desc: '以下特殊情形可申请全额退款,需联系客服并提供相关证明材料:',
tips: [
{
text: '活动当天遭遇极端恶劣天气(台风、暴雨红色预警等);',
},
{
text: '球场临时关闭或其他不可抗力导致活动无法进行;',
},
{
text: '参与者本人突发疾病或意外(需提供医院证明)。',
},
],
},
{
title: '三、活动取消规则',
desc: '',
tips: [
{
text: '到达活动开始时间时,报名人数仍未达到最低成局人数,活动自动取消,已付款参与者全额退款;',
},
{
text: '组织者主动取消活动,所有已付款参与者全额退款;',
},
{
text: '以上退款均由系统自动处理,无需申请。',
},
],
},
{
title: '四、免责声明',
desc: '',
tips: [
{
text: '本平台仅为网球约球信息撮合平台,不直接提供场地或运动服务,不对活动中的人身安全及财物损失承担责任;',
},
{
text: '网球运动存在固有运动风险,请在参与前评估自身身体状况,患有心脏病、高血压等基础疾病者请在医生许可下参与;',
},
{
text: '平台强烈建议参与者购买运动意外保险;',
strong: true,
},
{
text: '因组织者或场地方原因导致活动变更或取消,平台将协助处理但不承担连带责任;',
},
{
text: '本平台不对因网络故障、系统维护或不可抗力导致的服务中断承担责任。',
},
],
},
],
}

View File

@@ -424,6 +424,7 @@
align-items: flex-end;
justify-content: center;
gap: 8px;
word-break: break-all;
}
.orderNo {
@@ -544,21 +545,160 @@
.time {
text-align: left;
padding-left: 30px;
border-right: 1px solid rgba(0, 0, 0, 0.06);
}
.rule {
border-left: 1px solid rgba(0, 0, 0, 0.06);
}
// .rule {
// border-left: 1px solid rgba(0, 0, 0, 0.06);
// }
}
}
.refundTip {
margin-top: 16px;
color: rgba(60, 60, 67, 0.6);
text-align: center;
font-feature-settings:
"liga" off,
"clig" off;
font-family: "PingFang SC";
font-size: 12px;
font-style: normal;
font-weight: 400;
}
}
.declaimer {
.disclaimer {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 8px;
padding-bottom: 100px;
gap: 16px;
margin-top: 16px;
.disclaimerTitle {
font-size: 14px;
font-weight: bold;
color: #000;
line-height: 20px;
}
.disclaimerDesc {
font-size: 12px;
color: rgba(0, 0, 0, 0.65);
line-height: 18px;
}
.disclaimerSection {
display: flex;
flex-direction: column;
gap: 8px;
.sectionTitle {
font-size: 14px;
font-weight: bold;
color: #000;
line-height: 20px;
}
.sectionDesc {
font-size: 12px;
color: rgba(0, 0, 0, 0.65);
line-height: 18px;
}
.tableContainer {
display: flex;
flex-direction: column;
// gap: 8px;
margin: 8px 0;
border-radius: 12px;
border: 1px solid rgba(0, 0, 0, 0.06);
background: #fff;
box-shadow: 0 4px 36px 0 rgba(0, 0, 0, 0.06);
overflow: hidden;
.tableRow {
display: flex;
min-height: 44px;
&:first-child {
.tableCell {
color: #000;
font-weight: 600;
}
}
&:not(:last-child) {
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
}
.tableCell {
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
color: rgba(0, 0, 0, 0.65);
line-height: 18px;
word-break: break-word;
padding: 4px 0;
&:not(:last-child) {
border-right: 1px solid rgba(0, 0, 0, 0.06);
}
&:nth-child(1) {
flex: 1;
}
&:nth-child(2) {
flex: 0.6;
}
&:nth-child(3) {
flex: 1;
}
.tipText {
text-align: center;
}
}
}
}
.tipsList {
display: flex;
flex-direction: column;
gap: 6px;
margin: 8px 0;
.tipItem {
display: flex;
align-items: flex-start;
&::before {
content: "";
margin-right: 6px;
margin-top: -2px;
font-size: 12px;
color: rgba(0, 0, 0, 0.65);
flex-shrink: 0;
line-height: 18px;
}
.tipText {
font-size: 12px;
color: rgba(0, 0, 0, 0.65);
line-height: 18px;
}
.tipTextStrong {
font-size: 12px;
color: #000;
font-weight: bold;
line-height: 18px;
}
}
}
}
.title {
display: flex;
padding: 15px 0 0;

View File

@@ -2,7 +2,7 @@ import React, { useState, useRef } from "react";
import { View, Text, Button, Image } from "@tarojs/components";
import { Dialog } from "@nutui/nutui-react-taro";
import Taro, { useDidShow, useRouter } from "@tarojs/taro";
import dayjs from "dayjs";
import dayjs, { Dayjs } from "dayjs";
import "dayjs/locale/zh-cn";
import classnames from "classnames";
import orderService, {
@@ -10,6 +10,7 @@ import orderService, {
GameOrderRes,
OrderStatus,
refundTextMap,
RefundStatus,
} from "@/services/orderService";
import { debounce } from "@tarojs/runtime";
import {
@@ -20,6 +21,7 @@ import {
getOrderStatus,
generateOrderActions,
isPhoneNumber,
genGameLength,
} from "@/utils";
import { getStorage, setStorage } from "@/store/storage";
import { useGlobalStore } from "@/store/global";
@@ -31,7 +33,7 @@ import img from "@/config/images";
import CustomerIcon from "@/static/order/customer.svg";
import { handleCustomerService } from "@/services/userService";
import { requireLoginWithPhone } from "@/utils/helper";
import { DECLAIMER } from "./config";
import { RegistrationInstructions } from "./config";
import styles from "./index.module.scss";
dayjs.locale("zh-cn");
@@ -74,9 +76,20 @@ function genGameNotice(order_status, start_time) {
return gameNoticeMap.get(key) || {};
}
function genGameRange(startTime: Dayjs, endTime: Dayjs) {
if (!startTime || !endTime) {
return "";
}
// 如果跨天(自然日)
if (!startTime.isSame(endTime, "day")) {
return `${startTime.format("HH:mm")} - ${endTime.format("MM月DD日 HH:mm")}`;
}
return `${startTime.format("HH:mm")} - ${endTime.format("HH:mm")}`;
}
function GameInfo(props) {
const { detail, currentLocation, orderDetail, init } = props;
const { order_status, refund_status, amount } = orderDetail;
const { order_status, refund_status, amount, refund_amount } = orderDetail;
const {
latitude,
longitude,
@@ -110,15 +123,17 @@ function GameInfo(props) {
const startTime = dayjs(start_time);
const endTime = dayjs(end_time);
const game_length = Number(
(endTime.diff(startTime, "minutes") / 60).toFixed()
);
// const game_length = Number(
// (endTime.diff(startTime, "minutes") / 60).toFixed(),
// );
const game_length = genGameLength(startTime, endTime);
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")}`;
// const gameRange = `${startTime.format("HH:mm")} - ${endTime.format("HH:mm")}`;
const gameRange = genGameRange(startTime, endTime);
const orderStatus = getOrderStatus(orderDetail);
@@ -244,7 +259,10 @@ function GameInfo(props) {
<View className={styles.gameInfoContainer}>
{["refund", "progress", "expired"].includes(orderStatus) && (
<View className={styles.paidInfo}>
{refundTextMap.get(refund_status)} ¥ {amount}
{refundTextMap.get(refund_status)} ¥{" "}
{[RefundStatus.PENDING, RefundStatus.SUCCESS].includes(refund_status)
? refund_amount
: amount}
</View>
)}
{["progress", "expired"].includes(orderStatus) &&
@@ -273,7 +291,7 @@ function GameInfo(props) {
<View className={styles.gameInfoDateWeatherCalendarDateDate}>
<View className={styles.date}>{startDate}</View>
<View className={styles.venueTime}>
{gameRange} {game_length}
{gameRange} {game_length}
</View>
</View>
</View>
@@ -344,7 +362,7 @@ function GameInfo(props) {
handlePayNow: () => {},
handleViewGame,
},
"detail"
"detail",
)?.map((obj) => (
<View className={classnames(styles.button, styles[obj.className])}>
<Text className={styles.buttonText}>{obj.text}</Text>
@@ -504,7 +522,7 @@ function RefundPolicy(props) {
const theTimeObj = dayjs(
isLast
? refund_policy.at(-2).deadline_formatted
: item.deadline_formatted
: item.deadline_formatted,
);
const year = theTimeObj.format("YYYY");
const month = theTimeObj.format("M");
@@ -531,7 +549,7 @@ function RefundPolicy(props) {
className={classnames(
styles.policyItem,
targetIndex > index && index !== 0 ? styles.pastItem : "",
targetIndex === index ? styles.currentItem : ""
targetIndex === index ? styles.currentItem : "",
)}
>
<View className={styles.time}>
@@ -546,15 +564,66 @@ function RefundPolicy(props) {
</View>
))}
</View>
<Text className={styles.refundTip}>
95%5%481退
</Text>
</View>
);
}
function Disclaimer() {
return (
<View className={styles.declaimer}>
<Text className={styles.title}></Text>
<Text className={styles.content}>{DECLAIMER}</Text>
<View className={styles.disclaimer}>
<View className={styles.disclaimerTitle}>
<Text>{RegistrationInstructions.title}</Text>
</View>
<View className={styles.disclaimerDesc}>
<Text>{RegistrationInstructions.desc}</Text>
</View>
{RegistrationInstructions.children.map((section, sectionIndex) => (
<View key={sectionIndex} className={styles.disclaimerSection}>
<View className={styles.sectionTitle}>
<Text>{section.title}</Text>
</View>
{section.desc && (
<View className={styles.sectionDesc}>
<Text>{section.desc}</Text>
</View>
)}
{section.table && (
<View className={styles.tableContainer}>
{section.table.map((row, rowIndex) => (
<View key={rowIndex} className={styles.tableRow}>
<View className={styles.tableCell}>
<Text>{row.refundApplicationTime}</Text>
</View>
<View className={styles.tableCell}>
<Text>{row.participantRefundableAmount}</Text>
</View>
<View className={styles.tableCell}>
<Text>{row.liquidatedDamages}</Text>
</View>
</View>
))}
</View>
)}
{section.tips && (
<View className={styles.tipsList}>
{section.tips.map((tip, tipIndex) => (
<View key={tipIndex} className={styles.tipItem}>
<Text
className={
tip.strong ? styles.tipTextStrong : styles.tipText
}
>
{tip.text}
</Text>
</View>
))}
</View>
)}
</View>
))}
</View>
);
}

View File

@@ -9,6 +9,7 @@ import orderService, {
OrderStatus,
CancelType,
refundTextMap,
RefundStatus,
} from "@/services/orderService";
import { getStorage, removeStorage, setStorage } from "@/store/storage";
import { useGlobalStore } from "@/store/global";
@@ -101,7 +102,7 @@ const OrderList = () => {
newList.splice(
index,
clear ? newList.length - index : 1,
addPageInfo(res.data.rows, page)
addPageInfo(res.data.rows, page),
);
return newList;
});
@@ -264,13 +265,17 @@ const OrderList = () => {
});
}
function handleQuit(item) {
async function handleQuit(item) {
if (refundRef.current) {
refundRef.current.show(item, (result) => {
if (result) {
getOrders(item.page);
}
});
const res = await orderService.getRefundPolicy({ order_id: item.id });
refundRef.current.show(
{ ...item, refund_policy: res.data.refund_policy },
(result) => {
if (result) {
getOrders(item.page);
}
},
);
}
}
@@ -316,7 +321,7 @@ const OrderList = () => {
item.order_status === OrderStatus.PENDING &&
item.cancel_type === CancelType.NONE;
const canceled = [CancelType.USER, CancelType.TIMEOUT].includes(
item.cancel_type
item.cancel_type,
);
const { game_info } = item;
@@ -349,7 +354,7 @@ const OrderList = () => {
<View
className={classnames(
styles.payNum,
styles[unPay ? "pending" : "paid"]
styles[unPay ? "pending" : "paid"],
)}
>
<Text>
@@ -358,7 +363,15 @@ const OrderList = () => {
: refundTextMap.get(item.refund_status)}
</Text>{" "}
<View className={styles.amount}>
¥ <Text>{item.amount}</Text>
¥{" "}
<Text>
{[
RefundStatus.PENDING,
RefundStatus.SUCCESS,
].includes(item.refund_status)
? item.refund_amount
: item.amount}
</Text>
</View>
</View>
)}
@@ -370,7 +383,7 @@ const OrderList = () => {
{insertDotInTags([location_name, court_type, "3.5km"]).map(
(text, index) => (
<Text key={index}>{text}</Text>
)
),
)}
</View>
<View className={styles.gameOtherInfo}>
@@ -426,12 +439,12 @@ const OrderList = () => {
handlePayNow,
handleViewGame,
},
"list"
"list",
)?.map((obj) => (
<View
className={classnames(
styles.button,
styles[obj.className]
styles[obj.className],
)}
>
<Text className={styles.buttonText}>{obj.text}</Text>

View File

@@ -77,7 +77,7 @@ const CommentReply = () => {
if (allCommentIds.length > 0) {
// 使用统一接口标记已读传入所有评论ID
messageService.markAsRead('comment', allCommentIds).catch(e => {
console.error("标记评论已读失败:", e);
console.warn("标记评论已读失败:", e);
});
}
}
@@ -221,7 +221,7 @@ const CommentReply = () => {
if (allCommentIds.length > 0) {
messageService.markAsRead('comment', allCommentIds).catch(e => {
console.error("标记评论已读失败:", e);
console.warn("标记评论已读失败:", e);
});
}
}

View File

@@ -21,7 +21,7 @@ const EnableNotificationPage: React.FC = () => {
setQrCodeUrl(res.data.ServiceAccountQRCode);
}
} catch (error) {
console.error('获取二维码失败:', error);
console.warn('获取二维码失败:', error);
}
};
fetchQRCode();

View File

@@ -62,7 +62,7 @@ const NewFollow = () => {
if (allFanIds.length > 0) {
// 使用统一接口标记已读传入所有关注者ID
messageService.markAsRead('follow', allFanIds).catch(e => {
console.error("标记关注已读失败:", e);
console.warn("标记关注已读失败:", e);
});
}
} else {
@@ -168,7 +168,7 @@ const NewFollow = () => {
if (allFanIds.length > 0) {
messageService.markAsRead('follow', allFanIds).catch(e => {
console.error("标记关注已读失败:", e);
console.warn("标记关注已读失败:", e);
});
}
} else {

View File

@@ -99,7 +99,7 @@ function isOnCancelEmpty(onCancelFunc) {
const normalized = funcString.replace(/\s/g, "");
return emptyFunctionPatterns.includes(normalized);
} catch (error) {
console.error("检查 onCancel 函数时出错:", error);
console.warn("检查 onCancel 函数时出错:", error);
return false;
}
}
@@ -531,7 +531,7 @@ function Result() {
// setQrCodeUrl(tempFilePath);
// }
} catch (error) {
console.error("获取二维码失败:", error);
console.warn("获取二维码失败:", error);
}
}
@@ -645,7 +645,7 @@ function Result() {
});
return imageUrl;
} catch (error) {
console.error("生成图片失败:", error);
console.warn("生成图片失败:", error);
throw error;
}
}

View File

@@ -88,7 +88,7 @@ const AiImportPopup: React.FC<AiImportPopupProps> = ({
})
}
} catch (error) {
console.error('获取剪切板失败:', error)
console.warn('获取剪切板失败:', error)
Taro.showToast({
title: '读取剪切板失败,请手动输入',
icon: 'error',
@@ -163,7 +163,7 @@ const AiImportPopup: React.FC<AiImportPopupProps> = ({
}
}
} catch (error) {
console.error('选择图片失败:', error)
console.warn('选择图片失败:', error)
if (!(typeof error === 'object' && error.errMsg && error.errMsg.includes('fail cancel'))) {
setUploadFailCount(prev => prev + 1)
Taro.showToast({

View File

@@ -5,6 +5,7 @@ import img from '@/config/images';
import { FormFieldConfig } from '@/config/formSchema/publishBallFormSchema';
import SelectStadium from '../SelectStadium/SelectStadium'
import { Stadium } from '../SelectStadium/StadiumDetail'
import { normalize_address } from '@/utils/locationUtils'
import './FormBasicInfo.scss'
type PlayGame = {
@@ -54,7 +55,7 @@ const FormBasicInfo: React.FC<FormBasicInfoProps> = ({
onChange({...value,
venue_id,
location_name: name,
location: address,
location: normalize_address(address || ''),
latitude,
longitude,
court_type,

View File

@@ -4,7 +4,7 @@ import Taro from '@tarojs/taro'
import { Loading } from '@nutui/nutui-react-taro'
import StadiumDetail, { StadiumDetailRef } from './StadiumDetail'
import { CommonPopup, CustomPopup } from '../../../../components'
import { getLocation } from '@/utils/locationUtils'
import { getLocation, normalize_address } from '@/utils/locationUtils'
import PublishService from '@/services/publishService'
import images from '@/config/images'
import './SelectStadium.scss'
@@ -53,7 +53,7 @@ const SelectStadium: React.FC<SelectStadiumProps> = ({
}
}
} catch (error) {
console.error('获取场馆列表失败:', error)
console.warn('获取场馆列表失败:', error)
} finally {
setLoading(false)
}
@@ -100,14 +100,14 @@ const SelectStadium: React.FC<SelectStadiumProps> = ({
success: (res) => {
setSelectedStadium({
name: res.name,
address: res.address,
address: normalize_address(res.address || ''),
longitude: res.longitude,
latitude: res.latitude
})
setShowDetail(true)
},
fail: (err: { errMsg: string }) => {
console.error('选择位置失败:', err)
console.warn('选择位置失败:', err)
const { errMsg } = err || {};
if (!errMsg.includes('fail cancel')) {
Taro.showToast({

View File

@@ -7,6 +7,7 @@ import TextareaTag from '@/components/TextareaTag'
import UploadCover, { type CoverImageValue } from '@/components/UploadCover'
import { useKeyboardHeight } from '@/store/keyboardStore'
import { useDictionaryActions } from '@/store/dictionaryStore'
import { normalize_address } from '@/utils/locationUtils'
import './StadiumDetail.scss'
@@ -145,14 +146,14 @@ const StadiumDetail = forwardRef<StadiumDetailRef, StadiumDetailProps>(({
setFormData({
...formData,
name: res.name,
address: res.address,
address: normalize_address(res.address || ''),
latitude: res.latitude,
longitude: res.longitude,
istance: null
})
},
fail: (err: { errMsg: string }) => {
console.error('选择位置失败:', err)
console.warn('选择位置失败:', err)
const { errMsg } = err || {};
if (!errMsg.includes('fail cancel')) {
Taro.showToast({

View File

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

View File

@@ -51,7 +51,7 @@ export class FollowService {
throw new Error(response.message || '获取互关列表失败');
}
} catch (error) {
console.error('获取互关列表失败:', error);
console.warn('获取互关列表失败:', error);
return { list: [], total: 0 };
}
}
@@ -79,7 +79,7 @@ export class FollowService {
throw new Error(response.message || '获取粉丝列表失败');
}
} catch (error) {
console.error('获取粉丝列表失败:', error);
console.warn('获取粉丝列表失败:', error);
return { list: [], total: 0 };
}
}
@@ -107,7 +107,7 @@ export class FollowService {
throw new Error(response.message || '获取新增粉丝列表失败');
}
} catch (error) {
console.error('获取新增粉丝列表失败:', error);
console.warn('获取新增粉丝列表失败:', error);
return { list: [], total: 0 };
}
}
@@ -135,7 +135,7 @@ export class FollowService {
throw new Error(response.message || '获取关注列表失败');
}
} catch (error) {
console.error('获取关注列表失败:', error);
console.warn('获取关注列表失败:', error);
return { list: [], total: 0 };
}
}
@@ -178,7 +178,7 @@ export class FollowService {
throw new Error(response.message || '关注失败');
}
} catch (error) {
console.error('关注失败:', error);
console.warn('关注失败:', error);
throw error;
}
}
@@ -201,7 +201,7 @@ export class FollowService {
throw new Error(response.message || '取消关注失败');
}
} catch (error) {
console.error('取消关注失败:', error);
console.warn('取消关注失败:', error);
throw error;
}
}
@@ -231,7 +231,7 @@ export class FollowService {
throw new Error(response.message || '获取推荐用户失败');
}
} catch (error) {
console.error('获取推荐用户失败:', error);
console.warn('获取推荐用户失败:', error);
return { list: [], total: 0 };
}
}
@@ -251,7 +251,7 @@ export class FollowService {
return 'none';
}
} catch (error) {
console.error('检查关注状态失败:', error);
console.warn('检查关注状态失败:', error);
return 'none';
}
}
@@ -269,7 +269,7 @@ export class FollowService {
throw new Error(response.message || '屏蔽推荐用户失败');
}
} catch (error) {
console.error('屏蔽推荐用户失败:', error);
console.warn('屏蔽推荐用户失败:', error);
throw error;
}
}

View File

@@ -140,9 +140,13 @@ class HttpService {
this.hideLoadingTimer = null
}
// 延时300ms后隐藏loading避免频繁切换
// 延时 800ms 后隐藏 loading避免频繁切换;捕获 hideLoading 失败(如 toast 已被关闭)避免报错打断流程
this.hideLoadingTimer = setTimeout(() => {
Taro.hideLoading()
try {
Taro.hideLoading()
} catch (e) {
// 忽略 "toast can't be found" 等,避免发布后分享等流程报错
}
this.currentLoadingText = ''
this.hideLoadingTimer = null
}, 800)

View File

@@ -27,7 +27,7 @@ export const getGamesList = async (params?: Record<string, any>) => {
// const fetchApi = isIntegrate ? '/games/integrate_list' : '/games/list'
return httpService.post('/games/list', params, { showLoading: false })
} catch (error) {
console.error("列表数据获取失败:", error);
console.warn("列表数据获取失败:", error);
throw error;
}
};
@@ -41,7 +41,7 @@ export const getGamesIntegrateList = async (params?: Record<string, any>) => {
try {
return httpService.post('/games/integrate_list', params, { showLoading: false })
} catch (error) {
console.error("列表数据获取失败:", error);
console.warn("列表数据获取失败:", error);
throw error;
}
};
@@ -55,7 +55,7 @@ export const getGamesCount = async (params?: Record<string, any>) => {
try {
return httpService.post('/games/count', params, { showLoading: false })
} catch (error) {
console.error("列表数量获取失败:", error);
console.warn("列表数量获取失败:", error);
throw error;
}
};
@@ -71,7 +71,7 @@ export const getSearchHistory = async (params) => {
return httpService.post('/games/search_history', params, { showLoading: false })
} catch (error) {
// 捕获并打印错误信息
console.error("历史记录获取失败:", error);
console.warn("历史记录获取失败:", error);
// 抛出错误以便上层处理
throw error;
}
@@ -87,7 +87,7 @@ export const clearHistory = async (params) => {
return httpService.post('/games/search_history/delete_all', params, { showLoading: false })
} catch (error) {
// 捕获并打印错误信息
console.error("清除历史记录失败:", error);
console.warn("清除历史记录失败:", error);
// 抛出错误以便上层处理
throw error;
}
@@ -104,7 +104,7 @@ export const searchSuggestion = async (params) => {
return httpService.post('/games/search_recommendations', params)
} catch (error) {
// 捕获并打印错误信息
console.error("搜索建议获取失败:", error);
console.warn("搜索建议获取失败:", error);
// 抛出错误以便上层处理
throw error;
}
@@ -116,7 +116,7 @@ export const getCities = async () => {
return httpService.post('/cities/tree', {})
} catch (error) {
// 捕获并打印错误信息
console.error("城市列表获取失败:", error);
console.warn("城市列表获取失败:", error);
// 抛出错误以便上层处理
throw error;
}
@@ -127,7 +127,7 @@ export const getCityQrCode = async () => {
return httpService.post('/hot_city_qr/list', {})
} catch (error) {
// 捕获并打印错误信息
console.error("城市二维码获取失败:", error);
console.warn("城市二维码获取失败:", error);
// 抛出错误以便上层处理
throw error;
}
@@ -140,7 +140,7 @@ export const getDistricts = async (params: { province: string; city: string }) =
return httpService.post('/cities/cities', params)
} catch (error) {
// 捕获并打印错误信息
console.error("行政区列表获取失败:", error);
console.warn("行政区列表获取失败:", error);
// 抛出错误以便上层处理
throw error;
}

View File

@@ -122,7 +122,7 @@ export const wechat_auth_login = async (
};
}
} catch (error) {
console.error("微信授权登录失败:", error);
console.warn("微信授权登录失败:", error);
return {
success: false,
message: "微信授权失败,请重试",
@@ -160,7 +160,7 @@ export const phone_auth_login = async (
await useUser.getState().fetchUserInfo();
await useUser.getState().checkNicknameChangeStatus();
} catch (error) {
console.error("更新用户信息到 store 失败:", error);
console.warn("更新用户信息到 store 失败:", error);
}
return {
@@ -178,7 +178,7 @@ export const phone_auth_login = async (
};
}
} catch (error) {
console.error("手机号登录失败:", error);
console.warn("手机号登录失败:", error);
return {
success: false,
message: error.message,
@@ -206,7 +206,7 @@ export const send_sms_code = async (phone: string): Promise<SmsResponse> => {
};
}
} catch (error) {
console.error("发送短信失败:", error);
console.warn("发送短信失败:", error);
return {
success: false,
message: error.message,
@@ -232,7 +232,7 @@ export const verify_sms_code = async (
user_info: response.data?.userInfo,
};
} catch (error) {
console.error("验证验证码失败:", error);
console.warn("验证验证码失败:", error);
return {
success: false,
message: error.message,
@@ -255,7 +255,7 @@ export const save_login_state = (token: string, user_info: WechatUserInfo) => {
Taro.setStorageSync("is_logged_in", true);
Taro.setStorageSync("login_time", Date.now());
} catch (error) {
console.error("保存登录状态失败:", error);
console.warn("保存登录状态失败:", error);
}
};
@@ -270,7 +270,7 @@ export const clear_login_state = () => {
Taro.removeStorageSync("is_logged_in");
Taro.removeStorageSync("login_time");
} catch (error) {
console.error("清除登录状态失败:", error);
console.warn("清除登录状态失败:", error);
}
};
@@ -374,7 +374,7 @@ export const refresh_login_status = async (): Promise<boolean> => {
// 检查本地存储的登录状态
return check_login_status();
} catch (error) {
console.error("刷新登录状态失败:", error);
console.warn("刷新登录状态失败:", error);
return false;
}
};
@@ -385,7 +385,7 @@ export const updateUserPhone = async (payload: ChangePhoneParams) => {
const response = await httpService.post("/user/update_phone", payload);
return response;
} catch (error) {
console.error("更新用户手机号失败:", error);
console.warn("更新用户手机号失败:", error);
throw error;
}
};
@@ -402,7 +402,7 @@ export const getUserInfoById = async (id) => {
);
return response;
} catch (error) {
console.error("获取用户信息失败:", error);
console.warn("获取用户信息失败:", error);
throw error;
}
};
@@ -415,7 +415,7 @@ export const followUser = async (following_id) => {
});
return response;
} catch (error) {
console.error("关注失败:", error);
console.warn("关注失败:", error);
throw error;
}
};
@@ -428,7 +428,7 @@ export const unFollowUser = async (following_id) => {
});
return response;
} catch (error) {
console.error("取消关注失败:", error);
console.warn("取消关注失败:", error);
throw error;
}
};
@@ -464,7 +464,7 @@ export const silentLogin = async (): Promise<LoginResponse> => {
console.log("微信登录结果:", login_result);
if (!login_result.code) {
console.error("微信登录失败未获取到code");
console.warn("微信登录失败未获取到code");
return {
success: false,
message: "微信登录失败",
@@ -506,14 +506,14 @@ export const silentLogin = async (): Promise<LoginResponse> => {
user_info,
};
} else {
console.error("静默登录失败:", auth_response.message);
console.warn("静默登录失败:", auth_response.message);
return {
success: false,
message: auth_response.message || "静默登录失败",
};
}
} catch (error) {
console.error("静默登录异常:", error);
console.warn("静默登录异常:", error);
return {
success: false,
message: "静默登录失败,请重试",

View File

@@ -188,6 +188,21 @@ class OrderService {
},
);
}
// 获取退款政策
async getRefundPolicy({
order_id,
}: {
order_id: number;
}): Promise<ApiResponse<any>> {
return httpService.post(
"/payment/order_refund_policy",
{ order_id },
{
showLoading: true,
},
);
}
}
// 导出认证服务实例

View File

@@ -39,19 +39,28 @@ export interface uploadFileResponseData {
updated_at: string,
}
// 从上传错误中取出可展示的文案
function get_upload_error_msg(error: any): string {
if (!error) return "上传失败";
const msg =
error?.message ||
(typeof error?.error === "string" ? error.error : error?.error?.message) ||
(error?.data?.message ?? error?.data?.msg) ||
"";
return (msg && String(msg).trim()) || "上传失败";
}
// 发布球局类
class UploadApi {
async upload(req: UploadFilesData): Promise<{ id: string, data: uploadFileResponseData }> {
let fullUrl = `${envConfig.apiBaseURL}/api/gallery/upload`
const authHeader = tokenManager.getAuthHeader()
const { id, ...rest } = req
const fullUrl = `${envConfig.apiBaseURL}/api/gallery/upload`;
const authHeader = tokenManager.getAuthHeader();
const { id, ...rest } = req;
try {
const res = await Taro.uploadFile({
url: fullUrl,
filePath: rest.filePath,
name: 'file',
name: "file",
formData: {
description: rest.description,
tags: rest.tags,
@@ -59,12 +68,17 @@ class UploadApi {
},
header: authHeader,
});
return {
id,
data: JSON.parse(res.data).data,
const parsed = JSON.parse(res.data);
if (parsed.code !== 0) {
const msg = get_upload_error_msg(parsed);
Taro.showToast({ title: msg, icon: "none" });
throw new Error(msg);
}
return { id, data: parsed.data };
} catch (error) {
throw { id, error }
const msg = get_upload_error_msg(error);
Taro.showToast({ title: msg, icon: "none" });
throw { id, error };
}
}
@@ -103,7 +117,7 @@ class UploadApi {
throw new Error(result.message || '上传失败');
}
} catch (error) {
console.error('上传图片失败:', error);
console.warn('上传图片失败:', error);
throw error;
}
}

View File

@@ -351,7 +351,7 @@ export class UserService {
throw new Error(response.message || "获取用户信息失败");
}
} catch (error) {
console.error("获取用户信息失败:", error);
console.warn("获取用户信息失败:", error);
// 返回默认用户信息
return {} as UserInfo;
}
@@ -392,7 +392,7 @@ export class UserService {
throw new Error(response.message || "更新用户信息失败");
}
} catch (error) {
console.error("更新用户信息失败:", error);
console.warn("更新用户信息失败:", error);
throw error;
}
}
@@ -417,7 +417,7 @@ export class UserService {
throw new Error(response.message || "获取主办球局失败");
}
} catch (error) {
console.error("获取主办球局失败:", error);
console.warn("获取主办球局失败:", error);
// 返回符合ListContainer data格式的模拟数据
return [];
}
@@ -443,7 +443,7 @@ export class UserService {
throw new Error(response.message || "获取参与球局失败");
}
} catch (error) {
console.error("获取参与球局失败:", error);
console.warn("获取参与球局失败:", error);
// 返回符合ListContainer data格式的模拟数据
return [];
}
@@ -485,7 +485,7 @@ export class UserService {
throw new Error(response.message || "操作失败");
}
} catch (error) {
console.error("关注操作失败:", error);
console.warn("关注操作失败:", error);
throw error;
}
}
@@ -543,7 +543,7 @@ export class UserService {
throw new Error(response.message || "更新用户信息失败");
}
} catch (error) {
console.error("保存用户信息失败:", error);
console.warn("保存用户信息失败:", error);
throw error;
}
}
@@ -573,26 +573,16 @@ export class UserService {
throw new Error(response.message || "获取用户动态失败");
}
} catch (error) {
console.error("获取用户动态失败:", error);
console.warn("获取用户动态失败:", error);
return [];
}
}
// 上传头像
// 上传头像:仅在上传成功且 save 成功时返回 ossPath失败则抛出由调用方处理避免误调 user/update
static async upload_avatar(file_path: string): Promise<string> {
try {
// 先上传文件到服务器
const result = await uploadFiles.upload_oss_img(file_path);
await this.save_user_info({ avatar: result.ossPath });
// 使用新的响应格式中的file_url字段
return result.ossPath;
} catch (error) {
console.error("头像上传失败:", error);
// 如果上传失败,返回默认头像
return require("../static/userInfo/default_avatar.svg");
}
const result = await uploadFiles.upload_oss_img(file_path);
await this.save_user_info({ avatar: result.ossPath });
return result.ossPath;
}
// 解析用户手机号
@@ -612,7 +602,7 @@ export class UserService {
throw new Error(response.message || "获取手机号失败");
}
} catch (error) {
console.error("获取手机号失败:", error);
console.warn("获取手机号失败:", error);
return "";
}
}
@@ -628,7 +618,7 @@ export class UserService {
throw new Error(message || "获取职业树失败");
}
} catch (error) {
console.error("获取职业树失败:", error);
console.warn("获取职业树失败:", error);
return [];
}
}
@@ -644,7 +634,7 @@ export class UserService {
throw new Error(message || "获取城市树失败");
}
} catch (error) {
console.error("获取职业树失败:", error);
console.warn("获取职业树失败:", error);
return [];
}
}
@@ -665,7 +655,7 @@ export class UserService {
throw new Error(message || "注销账户失败");
}
} catch (error) {
console.error("注销账户失败:", error);
console.warn("注销账户失败:", error);
}
}
}
@@ -680,7 +670,7 @@ export const fetchUserProfile = async (): Promise<
const response = await httpService.post("user/detail");
return response;
} catch (error) {
console.error("获取用户信息失败:", error);
console.warn("获取用户信息失败:", error);
throw error;
}
};
@@ -695,7 +685,7 @@ export const checkNicknameChangeStatus = async (): Promise<
);
return response;
} catch (error) {
console.error("获取昵称修改状态失败:", error);
console.warn("获取昵称修改状态失败:", error);
throw error;
}
};
@@ -707,7 +697,7 @@ export const updateNickname = async (nickname: string) => {
});
return response;
} catch (error) {
console.error("昵称修改失败:", error);
console.warn("昵称修改失败:", error);
throw error;
}
};
@@ -718,7 +708,7 @@ export const updateUserProfile = async (payload: Partial<UserInfoType>) => {
const response = await httpService.post("/user/update", payload);
return response;
} catch (error) {
console.error("更新用户信息失败:", error);
console.warn("更新用户信息失败:", error);
throw error;
}
};
@@ -737,7 +727,7 @@ export const updateUserLocation = async (
});
return response;
} catch (error) {
console.error("更新用户坐标位置失败:", error);
console.warn("更新用户坐标位置失败:", error);
throw error;
}
};
@@ -774,13 +764,13 @@ export const handleCustomerService = async (): Promise<void> => {
console.log("打开客服成功:", res);
},
fail: (error) => {
console.error("打开客服失败:", error);
console.warn("打开客服失败:", error);
// 如果官方客服不可用,显示备用联系方式
showCustomerServiceFallback(customerService);
},
});
} catch (error) {
console.error("客服功能异常:", error);
console.warn("客服功能异常:", error);
// 备用方案:显示联系信息
showCustomerServiceFallback();
}
@@ -810,7 +800,7 @@ const showCustomerServiceFallback = (customerInfo?: any) => {
phoneNumber: customerInfo.phoneNumber,
});
} catch (error) {
console.error("拨打电话失败:", error);
console.warn("拨打电话失败:", error);
Taro.showToast({
title: "拨打电话失败",
icon: "none",
@@ -827,7 +817,7 @@ const showCustomerServiceFallback = (customerInfo?: any) => {
icon: "success",
});
} catch (error) {
console.error("复制邮箱失败:", error);
console.warn("复制邮箱失败:", error);
Taro.showToast({
title: "复制失败",
icon: "none",

View File

@@ -39,7 +39,7 @@ export class WalletService {
throw new Error(response.message || "获取钱包信息失败");
}
} catch (error) {
console.error("获取钱包信息失败:", error);
console.warn("获取钱包信息失败:", error);
// 返回模拟数据
return {
balance: 1588.80,
@@ -62,7 +62,7 @@ export class WalletService {
throw new Error(response.message || "获取交易记录失败");
}
} catch (error) {
console.error("获取交易记录失败:", error);
console.warn("获取交易记录失败:", error);
// 返回模拟数据
return [
{
@@ -107,7 +107,7 @@ export class WalletService {
throw new Error(response.message || "提现申请提交失败");
}
} catch (error) {
console.error("提现申请提交失败:", error);
console.warn("提现申请提交失败:", error);
throw error;
}
}

View File

@@ -1,11 +1,18 @@
<svg width="24" height="32" viewBox="0 0 24 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_7504_18610)">
<path d="M12.3076 0.0971837C12.7381 0.438102 12.2325 2.22445 12.328 2.76282C13.7134 2.51292 15.1145 2.01928 16.5062 1.81874C16.8928 1.76321 17.9933 1.57501 17.89 2.28307C17.8274 2.71346 16.6377 4.52912 16.73 4.62167C17.9667 4.78673 19.2128 4.97647 20.4214 5.28962C20.8346 5.39607 21.9226 5.57501 21.8209 6.15503C21.7223 6.71192 20.0394 8.18974 20.0848 8.37331C21.1211 9.25414 22.4017 9.9838 23.402 10.8909C23.712 11.1716 24.119 11.457 23.9671 11.926C23.8028 12.4366 22.0009 12.6541 21.5469 12.9965C21.525 13.1215 22.552 14.7351 22.7069 15.0204C22.8995 15.3752 23.8028 17.0613 23.7871 17.3236C23.726 18.2754 22.051 17.5827 21.4827 17.6383C21.6596 18.3648 21.8131 19.1408 21.8929 19.8843C21.9774 20.6679 22.2514 21.6753 21.0632 21.4932C21.237 29.4763 12.3624 34.5546 5.2928 30.6641C-0.183159 27.6514 -1.69069 20.6001 2.09614 15.6467C2.21199 15.494 2.76459 14.9402 2.78964 14.8801C2.81782 14.8122 2.73642 14.2831 2.75364 14.0902C2.80999 13.4624 3.15439 12.8824 3.58802 12.4366C2.80686 11.693 1.97874 10.8461 1.52945 9.85268C1.36977 9.50096 1.30559 9.0027 1.16 8.70189C1.04103 8.45661 0.72324 8.31623 0.593307 8.0216C0.190985 7.11762 0.835953 6.08561 1.87228 6.20902C2.38262 6.26919 2.4609 6.6317 3.13091 6.54069C4.43807 6.36637 5.06425 4.00154 5.53545 2.98804C5.73583 2.5592 6.59839 0.737369 6.94749 0.59082C7.976 0.161974 7.82102 2.05939 8.23899 2.54994C9.08747 1.94986 9.8702 1.2526 10.7281 0.664866C11.0991 0.410335 11.8724 -0.251447 12.3076 0.0925559V0.0971837ZM11.1993 6.0563C10.9629 6.20285 10.2944 5.55804 10.022 5.41149C8.99824 4.86232 7.73648 4.72348 6.62814 5.09988C5.22236 5.57809 5.13626 6.89394 3.68039 7.42923C3.52854 7.48477 3.02133 7.55418 2.9775 7.59738C2.94462 7.62977 2.87418 7.99846 2.75364 8.16814C2.6331 8.33475 2.4061 8.51832 2.19477 8.55071C2.40297 9.81874 3.62873 11.7146 5.15661 11.0189C5.63407 10.8014 5.73583 10.263 5.89707 10.1643C6.15694 10.0069 6.41367 10.1658 6.45437 10.4466C6.57178 11.258 5.30689 11.9676 4.57113 11.9213L5.26776 12.3702C6.99289 13.2865 8.93719 13.6429 10.8846 13.3575C10.9989 13.322 11.2165 12.5245 11.3605 12.3116C11.5515 12.0278 11.9178 11.8072 12.1182 11.5418C12.5033 11.0297 12.6598 9.76166 12.6066 9.13228C12.5847 8.87466 12.3452 8.2931 12.4297 8.13266C12.9792 7.84265 13.5897 7.80409 13.8793 7.14693C14.5384 5.64905 12.6035 4.40879 11.4904 5.55033C11.3777 5.66602 11.2259 6.03934 11.2008 6.05476L11.1993 6.0563ZM12.8665 12.2808C12.2513 12.418 11.6439 13.683 12.1511 14.1273C12.7882 14.6826 14.2582 13.5488 14.6981 13.049C14.4006 12.5183 13.4473 12.1512 12.8665 12.2808ZM6.45594 13.7802C6.16163 13.7324 5.8642 13.6645 5.58085 13.575C4.81847 13.3313 4.25647 12.7312 3.85572 13.7324C3.66786 14.1998 3.64751 14.823 4.27213 14.9387C4.7809 15.0328 6.34323 14.4142 6.45594 13.7817V13.7802ZM10.9973 13.8511C9.58215 14.1921 8.2343 14.1859 6.80817 13.919C6.76746 14.8091 5.6012 15.4477 4.79656 15.5526C4.52573 15.5881 4.07645 15.5156 3.87294 15.6066C3.74144 15.6653 3.02603 16.4165 2.89609 16.5708C0.767073 19.1192 0.635574 22.5885 2.06484 25.5118C2.36853 26.1319 2.43428 26.3756 3.20918 26.4512C5.43839 26.6672 6.16633 25.3606 7.9713 24.6016C11.4137 23.1562 15.7767 24.2237 17.6051 27.5526C20.7376 24.0617 20.4417 18.7906 17.2576 15.4323C16.9257 15.0837 15.7328 14.118 15.3117 13.9699C15.0675 13.8835 14.8123 14.297 14.6292 14.4296C13.3659 15.3521 11.3589 15.9105 10.9989 13.8527L10.9973 13.8511ZM3.59115 27.6915C3.55985 27.8103 3.64125 27.8288 3.69447 27.8982C4.0968 28.4103 4.98284 29.0305 5.55267 29.3729C8.98102 31.4354 13.5036 31.1145 16.5719 28.5553C15.415 25.5164 11.647 24.6232 8.74463 25.6429C6.98819 26.2599 5.62468 28.0972 3.59115 27.6915Z" fill="black"/>
<path d="M7.69734 6.77362C8.84169 6.70883 9.28002 8.38257 8.18264 8.8361C6.57804 9.49788 6.06457 6.86463 7.69734 6.77362Z" fill="black"/>
</g>
<defs>
<clipPath id="clip0_7504_18610">
<rect width="24" height="32" fill="white"/>
</clipPath>
</defs>
</svg>
<?xml version="1.0" encoding="UTF-8"?>
<svg id="_图层_2" data-name="图层 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 74.87 89.85">
<defs>
<style>
.cls-1 {
fill: #e6ff54;
}
</style>
</defs>
<g id="_图层_1-2" data-name=" 图层 1">
<path class="cls-1" d="M39.79,82.22h0c-3.1,1.7-6.7,2.6-10.3,2.6-9.9,0-18.3-6.7-21-15.7,1.7,1.4,3.6,2.3,5.6,2.7,4.7,1,8.3,0,11.8-1,3.1-.8,5.9-1.6,9.7-1.2,3.9.5,6.6,2.6,7.3,5.7.6,2.7-.5,5.4-3,6.9h-.1Z"/>
<path class="cls-1" d="M51.29,62.92c0,.9,0,1.9-.2,2.8-.5,3.7-1.8,7.2-4,10.2,0-.5,0-1-.2-1.5-1.1-4.9-5.3-8.3-10.9-9-4.5-.6-8.1.4-11.3,1.3-3.3,1-6.2,1.7-9.9,1-3.9-.8-7.6-4.7-6.6-10.4h0c0-.6.3-1.1.5-1.7,0-.4.3-.8.5-1.2,1.1.2,2.2.2,3.3,0h.4c2.6-.9,4.4-2.8,4.8-5.2v-.2c4.8,1.4,10.4,1.3,15.4,0h0c.2-.2.4-.2.6-.3,0,1,.5,2,1.1,2.9,1.1,1.6,2.9,2.6,5,2.8,1.1,0,2.2,0,3.3-.4h0c1-.2,2-.7,3-1.3.6-.4,1.1-.8,1.6-1.2,2.3,3.5,3.5,7.6,3.5,11.9v-.3l.1-.2Z"/>
<g>
<path d="M74.59,37.52c-2.1-6.1-6.4-11.7-12.2-15.9h0c1.7-2,2.6-3,4.5-4.6.5-.4.7-1,.6-1.6,0-.6-.4-1.1-1-1.4-6.5-3.2-12.1-4.7-18.9-5,.9-2.4,1.8-4.1,3-6.4.3-.6.3-1.3,0-1.9-.4-.6-1.1-.8-1.8-.7-7.6,1.7-13.8,4-20.9,8.1-1.9-2.4-4.1-4.3-6.8-6-.5-.3-1.2-.3-1.8,0s-.9.9-.9,1.5c0,5.6-1,9.9-3.2,14.4-1.6,3.3-3.3,5.7-4.4,7.4-1.3,1.9-2.1,2.9-3,3.4-1.35-1.86-4.14-2.86-6.42-.58-1.03,1.03-1.51,2.46-1.33,3.91.21,1.67,1.05,2.27,2.25,2.87.7,2.3,1.7,4.5,2.9,6.3-1.4,1.1-2.3,2.7-2.7,4.5-.6,2.7,0,5.3,1.9,7.2-1.2,3.1-1.8,6.4-1.8,9.8,0,14.9,13.39,27.65,27,27,6.31-.3,9.55-.58,15.79-5.21,1.57-1.16,3.02-2.5,4.26-4.01,3.31-4.03,5.89-8.65,6.65-13.38,1.2.4,2.4.9,3.3,1.3.4.2.8.2,1.3,0h.2c.5-.2.8-.6,1-1.1.9-2.9,1.4-7.5,1.6-10.6,1.5,0,3.1.3,5.2.7.5,0,1.1,0,1.5-.4s.6-.9.6-1.4c-.2-5.6-1-10-2.5-14.3,1.8-.8,3.3-1.4,5.1-1.8.5,0,.9-.4,1.1-.9.2-.4.3-.9,0-1.4v.2h-.1ZM44.09,41.82c.7,0,1.2.3,1.7.8l.17.17c.26.26.52,1.15.72,1.96.29,1.21-.08,2.48-.97,3.36,0,0-.01.01-.02.02-.4.4-.8.7-1.3,1-1.4.9-2.8,1.3-4.1,1.2-1,0-1.8-.5-2.3-1.2-.5-.8-.7-1.6-.5-2.4,0-.4.2-.8.4-1.2.2-.3.4-.6.6-.9h0c.2-.3.5-.6.8-.8s.6-.4.9-.6c.8-.5,1.6-.9,2.3-1.1.48-.09.65-.19,1.21-.27l.39-.03ZM7.09,34.12h.4c3.7-.5,5.6-3.2,7.3-5.8,1.3-1.8,2.6-3.8,4.8-5.3,3.7-2.5,8.6-2.6,12.6,0,.3.2.6.2,1,.2h.4c.5,0,.9-.5,1.1-.9.6-1.3,1.7-2.2,3-2.4,1.1-.2,2.1,0,2.8.7.8.7,1.2,1.8,1,2.9-.2,1.2-1.2,2.1-2.6,2.7-.6.2-.9.6-1.1,1.2-.2.6,0,1.2.3,1.6,2.1,2.7,2.9,6.5,2.1,9.5,0,.3-.2.6-.3.9-.6.3-1.1.6-1.7,1-1.6,1-2.8,2.2-3.5,3.6,0,0-.2.3-.2.5l-1.1.3c-1.1.4-2.2.7-3.4.9-2.7.5-5.5.6-8.2.2-1.2-.2-2.3-.4-3.4-.8h0c-.4,0-.8-.2-1.2-.4-.3,0-.5-.2-.8-.3h-.3c-.2,0-.4-.2-.7-.3-.2,0-.4-.2-.6-.3.2,0,.4-.2.6-.4,0,0,.2,0,.3-.2,1.1-.9,2.1-2.1,2.7-3.7.2-.5.2-1,0-1.5s-.6-.9-1.1-1c-1-.4-2.2,0-2.6,1.1-.6,1.4-1.5,2.3-2.6,2.4-.5,0-1.1,0-1.7-.3h0c-1.3-1.6-2.3-3.5-3-5.6v-.2h-.2l-.1-.3ZM7.79,49.72c-.2-.2-.3-.5-.5-.9h0c0-.4-.2-.8,0-1.4h0v-.5c.3-1.4,1.2-2,1.8-2.3h.7c.2,0,.3.3.5.4.2.2.5.3.7.5.4.2.7.5,1.1.7.5.3,1,.6,1.5.8,0,0,.2,0,.4.2h0v1.1c-.2,1.1-1.1,2-2.5,2.3h-.5c-.8,0-1.6,0-2.3-.3-.3-.2-.6-.4-.8-.6s0,0-.2-.2h.2l-.1.2ZM39.79,82.22h0c-3.1,1.7-6.7,2.6-10.3,2.6-9.9,0-18.3-6.7-21-15.7,1.7,1.4,3.6,2.3,5.6,2.7,4.7,1,8.3,0,11.8-1,3.1-.8,5.9-1.6,9.7-1.2,3.9.5,6.6,2.6,7.3,5.7.6,2.7-.5,5.4-3,6.9h-.1ZM47.09,75.92c0-.5,0-1-.2-1.5-1.1-4.9-5.3-8.3-10.9-9-4.5-.6-8.1.4-11.3,1.3-3.3,1-6.2,1.7-9.9,1-3.9-.8-7.6-4.7-6.6-10.4h0c0-.6.3-1.1.5-1.7,0-.4.3-.8.5-1.2,1.1.2,2.2.2,3.3,0h.4c2.6-.9,4.4-2.8,4.8-5.2v-.2c4.8,1.4,10.2,1.4,15.1,0,0,0,.6-.3.8-.4,0,1,.5,2,1.1,2.9,1.1,1.6,2.9,2.6,5,2.8,1.1,0,3.4-.3,3.4-.3,1-.3,2-.8,3-1.4.6-.4,1.1-.8,1.6-1.2,2.3,3.5,3.52,7.6,3.5,11.9-.01,2.59,0,1.9-.2,2.8,0,0-1.7,6.8-3.9,9.8Z"/>
<path d="M24.69,34.92c-1.6.2-3.1-.9-3.3-2.5-.3-1.6.8-3.1,2.4-3.3h0c1.6-.2,3.1.9,3.3,2.5.3,1.6-.8,3.1-2.4,3.3Z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -93,7 +93,7 @@ function MyComponent() {
console.log('请求成功!')
} catch (error) {
console.error('请求失败:', error)
console.warn('请求失败:', error)
} finally {
setLoading(false)
}

View File

@@ -76,7 +76,7 @@ export const useDictionaryStore = create<DictionaryState>()((set, get) => ({
error: errorMessage,
isLoading: false
})
console.error('获取字典数据失败:', error)
console.warn('获取字典数据失败:', error)
}
},

View File

@@ -76,7 +76,7 @@ export const useKeyboardStore = create<KeyboardStore>((set, get) => ({
try {
listener(height, true)
} catch (error) {
console.error('键盘监听器执行错误:', error)
console.warn('键盘监听器执行错误:', error)
}
})
})
@@ -92,7 +92,7 @@ export const useKeyboardStore = create<KeyboardStore>((set, get) => ({
try {
listener(0, false)
} catch (error) {
console.error('键盘监听器执行错误:', error)
console.warn('键盘监听器执行错误:', error)
}
})
})

View File

@@ -410,7 +410,7 @@ export const useListStore = create<TennisStore>()((set, get) => ({
return Promise.resolve();
} catch (error) {
console.error("更新列表数据失败:", error);
console.warn("更新列表数据失败:", error);
return Promise.reject(error);
}
},
@@ -724,7 +724,7 @@ export const useListStore = create<TennisStore>()((set, get) => ({
}
return [];
} catch (error) {
console.error("获取行政区列表失败:", error);
console.warn("获取行政区列表失败:", error);
return [];
}
},

View File

@@ -46,7 +46,7 @@ export const useMessageStore = create<MessageStore>()((set, get) => ({
set({ loading: false });
}
} catch (e) {
console.error("获取红点信息失败:", e);
console.warn("获取红点信息失败:", e);
set({ loading: false });
}
},

View File

@@ -5,7 +5,7 @@ export const setStorage = (key: string, data: any) => {
try {
Taro.setStorageSync(key, JSON.stringify(data))
} catch (error) {
console.error('保存数据失败:', error)
console.warn('保存数据失败:', error)
}
}
@@ -17,7 +17,7 @@ export const getStorage = <T>(key: string): T | null => {
}
return null
} catch (error) {
console.error('读取数据失败:', error)
console.warn('读取数据失败:', error)
return null
}
}
@@ -26,7 +26,7 @@ export const removeStorage = (key: string) => {
try {
Taro.removeStorageSync(key)
} catch (error) {
console.error('清除数据失败:', error)
console.warn('清除数据失败:', error)
}
}
@@ -34,6 +34,6 @@ export const clearAllStorage = () => {
try {
Taro.clearStorageSync()
} catch (error) {
console.error('清除所有数据失败:', error)
console.warn('清除所有数据失败:', error)
}
}

View File

@@ -12,6 +12,7 @@ import evaluateService, {
LastTimeTestResult,
} from "@/services/evaluateService";
import { useListStore } from "./listStore";
import { getBackendErrorMsg } from "@/utils/helper";
export interface UserState {
user: UserInfoType | {};
@@ -77,7 +78,7 @@ export const useUser = create<UserState>()((set) => ({
return userData;
} catch (error) {
console.error("获取用户信息失败:", error);
console.warn("获取用户信息失败:", error);
return undefined;
}
},
@@ -87,7 +88,7 @@ export const useUser = create<UserState>()((set) => ({
try {
(Taro as any).setStorageSync?.(CITY_CACHE_KEY, newArea);
} catch (error) {
console.error("保存城市缓存失败:", error);
console.warn("保存城市缓存失败:", error);
}
},
@@ -122,7 +123,11 @@ export const useUser = create<UserState>()((set) => ({
// 只有在更新头像等需要服务器返回新URL的字段时才需要重新获取
// 如果需要确保数据一致性,可以在特定场景下手动调用 fetchUserInfo
} catch (error) {
console.error("更新用户信息失败:", error);
console.warn("更新用户信息失败:", error);
Taro.showToast({
title: getBackendErrorMsg(error, "保存失败"),
icon: "none",
});
throw error;
}
},
@@ -153,7 +158,7 @@ export const useUser = create<UserState>()((set) => ({
},
});
} catch (error) {
console.error("检查昵称变更状态失败:", error);
console.warn("检查昵称变更状态失败:", error);
} finally {
isCheckingNicknameStatus = false;
}
@@ -167,7 +172,7 @@ export const useUser = create<UserState>()((set) => ({
user: { ...state.user, nickname },
}));
} catch (error) {
console.error("更新用户昵称失败:", error);
console.warn("更新用户昵称失败:", error);
}
},
// NTRP 测试结果缓存
@@ -201,7 +206,7 @@ export const useUser = create<UserState>()((set) => ({
}
return null;
} catch (error) {
console.error("获取NTRP测试结果失败:", error);
console.warn("获取NTRP测试结果失败:", error);
return null;
} finally {
isFetchingLastTestResult = false;

View File

@@ -25,7 +25,7 @@ const TestPage: React.FC = () => {
}
},
fail(err) {
console.error('订阅失败:', err);
console.warn('订阅失败:', err);
Taro.showToast({
title: '订阅失败',
icon: 'error',

View File

@@ -206,11 +206,11 @@ const DownloadBill: React.FC = () => {
}
},
fail: function (err) {
console.error("文件下载失败:", err);
console.warn("文件下载失败:", err);
},
});
} catch (error) {
console.error(error);
console.warn(error);
}
};
const handleDownloadBill = async () => {
@@ -240,11 +240,11 @@ const DownloadBill: React.FC = () => {
}
},
fail: function (err) {
console.error("文件下载失败:", err);
console.warn("文件下载失败:", err);
},
});
} catch (error) {
console.error(error);
console.warn(error);
}
};
return (

View File

@@ -82,15 +82,15 @@ const DownloadBillRecords: React.FC = () => {
console.log('打开文档成功');
},
fail: (err) => {
console.error('打开文档失败', err);
console.warn('打开文档失败', err);
}
});
} else {
console.error('下载失败,状态码:', res.statusCode);
console.warn('下载失败,状态码:', res.statusCode);
}
},
fail: (err) => {
console.error('下载失败', err);
console.warn('下载失败', err);
}
});
}

View File

@@ -22,6 +22,7 @@ import {
} from "@/store/pickerOptionsStore";
import { handleCustomerService } from "@/services/userService";
import evaluateService from "@/services/evaluateService";
import { getBackendErrorMsg } from "@/utils/helper";
const EditProfilePage: React.FC = () => {
const { updateUserInfo, updateNickname } = useUserActions();
@@ -142,7 +143,7 @@ const EditProfilePage: React.FC = () => {
// city: user_data.city || "",
// });
// } catch (error) {
// console.error("加载用户信息失败:", error);
// console.warn("加载用户信息失败:", error);
// Taro.showToast({
// title: "加载用户信息失败",
// icon: "error",
@@ -169,9 +170,9 @@ const EditProfilePage: React.FC = () => {
icon: "success",
});
} catch (error) {
console.error("头像上传失败:", error);
console.warn("头像上传失败:", error);
Taro.showToast({
title: "头像上传失败",
title: error.message,
icon: "none",
});
}
@@ -246,10 +247,10 @@ const EditProfilePage: React.FC = () => {
icon: "success",
});
} catch (error) {
console.error("保存失败:", error);
console.warn("保存失败:", error);
Taro.showToast({
title: "保存失败",
icon: "error",
title: getBackendErrorMsg(error, "保存失败"),
icon: "none",
});
}
};
@@ -307,10 +308,10 @@ const EditProfilePage: React.FC = () => {
icon: "success",
});
} catch (error) {
console.error("保存失败:", error);
console.warn("保存失败:", error);
Taro.showToast({
title: "保存失败",
icon: "error",
title: getBackendErrorMsg(error, "保存失败"),
icon: "none",
});
}
};
@@ -438,7 +439,7 @@ const EditProfilePage: React.FC = () => {
const phone = await UserService.parse_phone(e.detail.code);
handle_field_edit("phone", phone);
} catch (e) {
console.error("解析手机号失败:", e);
console.warn("解析手机号失败:", e);
Taro.showToast({
title: "解析手机号失败,请重试",
icon: "none",
@@ -564,9 +565,8 @@ const EditProfilePage: React.FC = () => {
</View>
<View className="item_right">
<Text
className={`item_value ${
form_data.gender ? "" : "placeholder"
}`}
className={`item_value ${form_data.gender ? "" : "placeholder"
}`}
>
{convert_db_gender_to_display(form_data.gender)}
</Text>
@@ -597,9 +597,8 @@ const EditProfilePage: React.FC = () => {
</View>
<View className="item_right">
<Text
className={`item_value ${
form_data.birthday ? "" : "placeholder"
}`}
className={`item_value ${form_data.birthday ? "" : "placeholder"
}`}
>
{form_data.birthday || "选择生日"}
</Text>
@@ -628,9 +627,8 @@ const EditProfilePage: React.FC = () => {
</View>
<View className="item_right">
<Text
className={`item_value ${
form_data.personal_profile ? "" : "placeholder"
}`}
className={`item_value ${form_data.personal_profile ? "" : "placeholder"
}`}
>
{form_data.personal_profile.replace(/\n/g, " ") ||
"介绍一下自己"}
@@ -661,17 +659,16 @@ const EditProfilePage: React.FC = () => {
</View>
<View className="item_right">
<Text
className={`item_value ${
form_data.province ||
className={`item_value ${form_data.province ||
form_data.city ||
form_data.district
? ""
: "placehoder"
}`}
? ""
: "placehoder"
}`}
>
{form_data.province ||
form_data.city ||
form_data.district
form_data.city ||
form_data.district
? `${form_data.province} ${form_data.city} ${form_data.district}`
: "选择所在地区"}
</Text>
@@ -697,9 +694,8 @@ const EditProfilePage: React.FC = () => {
</View>
<View className="item_right">
<Text
className={`item_value ${
form_data.ntrp_level ? "" : "placeholder"
}`}
className={`item_value ${form_data.ntrp_level ? "" : "placeholder"
}`}
>
{form_data.ntrp_level || "测测你的 NTRP 水平"}
</Text>
@@ -724,14 +720,12 @@ const EditProfilePage: React.FC = () => {
<Text className="item_label"></Text>
</View>
<View
className={`item_right ${
form_data.occupation ? "" : "placeholder"
}`}
className={`item_right ${form_data.occupation ? "" : "placeholder"
}`}
>
<Text
className={`item_value ${
form_data.occupation ? "" : "placeholder"
}`}
className={`item_value ${form_data.occupation ? "" : "placeholder"
}`}
>
{form_data.occupation || "填写你的职业"}
</Text>
@@ -771,9 +765,9 @@ const EditProfilePage: React.FC = () => {
>
{form_data.phone
? form_data.phone.replace(
/(\d{3})(\d{4})(\d{4})/,
"$1 $2 $3"
)
/(\d{3})(\d{4})(\d{4})/,
"$1 $2 $3"
)
: "未绑定"}
</Button>
<Image

View File

@@ -85,7 +85,7 @@ const FollowPage: React.FC = () => {
}));
} catch (error) {
console.error(`加载${TAB_CONFIG.find(t => t.key === tab)?.label}列表失败:`, error);
console.warn(`加载${TAB_CONFIG.find(t => t.key === tab)?.label}列表失败:`, error);
Taro.showToast({
title: '加载失败',
icon: 'none'
@@ -163,7 +163,7 @@ const FollowPage: React.FC = () => {
}
} catch (error) {
console.error('关注操作失败:', error);
console.warn('关注操作失败:', error);
Taro.showToast({
title: '操作失败',
icon: 'none'
@@ -202,7 +202,7 @@ const FollowPage: React.FC = () => {
try {
load_user_list(default_tab, true);
} catch (error) {
console.error('初始化加载失败:', error);
console.warn('初始化加载失败:', error);
Taro.showToast({
title: '初始化失败',
icon: 'none'
@@ -243,7 +243,7 @@ const FollowPage: React.FC = () => {
// icon: 'success'
// });
} catch (error) {
console.error('取消关注失败:', error);
console.warn('取消关注失败:', error);
Taro.showToast({
title: '操作失败',
icon: 'none'

View File

@@ -16,7 +16,7 @@ import { waitForAuthInit } from "@/utils/authInit";
const MyselfPage: React.FC = () => {
const pickerOption = usePickerOption();
// 获取页面参数
const instance = Taro.getCurrentInstance();
const user_id = instance.router?.params?.userid || "";
@@ -38,7 +38,7 @@ const MyselfPage: React.FC = () => {
// 最近一个月是否有测试记录
const [has_test_in_last_month, setHasTestInLastMonth] = useState(false);
const { fetchUserInfo } = useUserActions();
// 当前激活的标签页
@@ -62,7 +62,7 @@ const MyselfPage: React.FC = () => {
// // }
// // set_game_records(games_data);
// } catch (error) {
// console.error("加载用户数据失败:", error);
// console.warn("加载用户数据失败:", error);
// Taro.showToast({
// title: "加载失败,请重试",
// icon: "error",
@@ -89,11 +89,10 @@ const MyselfPage: React.FC = () => {
await fetchUserInfo();
}
// 获取测试结果
const res = await evaluateService.getLastResult();
if (res.code === 0) {
console.log( "getLastResult", res.data);
console.log("getLastResult", res.data);
setHasTestInLastMonth(res.data.has_test_in_last_month);
}
};
@@ -110,25 +109,28 @@ const MyselfPage: React.FC = () => {
});
// 分类球局数据(使用 useCallback 包装,避免每次渲染都创建新函数)
const classifyGameRecords = useCallback((
game_records: TennisMatch[]
): { notEndGames: TennisMatch[]; finishedGames: TennisMatch[] } => {
const now = new Date().getTime();
return game_records.reduce(
(result, cur) => {
let { end_time } = cur;
end_time = end_time.replace(/\s/, "T");
new Date(end_time).getTime() > now
? result.notEndGames.push(cur)
: result.finishedGames.push(cur);
return result;
},
{
notEndGames: [] as TennisMatch[],
finishedGames: [] as TennisMatch[],
}
);
}, []);
const classifyGameRecords = useCallback(
(
game_records: TennisMatch[]
): { notEndGames: TennisMatch[]; finishedGames: TennisMatch[] } => {
const now = new Date().getTime();
return game_records.reduce(
(result, cur) => {
let { end_time } = cur;
end_time = end_time.replace(/\s/, "T");
new Date(end_time).getTime() > now
? result.notEndGames.push(cur)
: result.finishedGames.unshift(cur);
return result;
},
{
notEndGames: [] as TennisMatch[],
finishedGames: [] as TennisMatch[],
}
);
},
[]
);
// 加载球局数据(使用 useCallback 包装,避免每次渲染都创建新函数)
const load_game_data = useCallback(async () => {
@@ -150,7 +152,7 @@ const MyselfPage: React.FC = () => {
setEndedGameRecords(finishedGames);
// set_game_records(games_data);
} catch (error) {
console.error("加载球局数据失败:", error);
console.warn("加载球局数据失败:", error);
}
}, [active_tab, user_info, classifyGameRecords]);
@@ -176,7 +178,7 @@ const MyselfPage: React.FC = () => {
duration: 1500,
});
} catch (error) {
console.error("关注操作失败:", error);
console.warn("关注操作失败:", error);
Taro.showToast({
title: "操作失败,请重试",
icon: "error",
@@ -272,7 +274,7 @@ const MyselfPage: React.FC = () => {
</View>
{/* 球局列表 */}
<View className="game_list_section" >
<View className="game_list_section">
<ScrollView scrollY refresherBackground="#FAFAFA">
<ListContainer
data={game_records}

View File

@@ -117,7 +117,7 @@ const OtherUserPage: React.FC = () => {
});
setIsFollowing(userData.is_following || false);
} catch (error) {
console.error("加载用户数据失败:", error);
console.warn("加载用户数据失败:", error);
Taro.showToast({
title: "加载失败",
icon: "none",
@@ -141,7 +141,7 @@ const OtherUserPage: React.FC = () => {
end_time = end_time.replace(/\s/, "T");
new Date(end_time).getTime() > now
? result.notEndGames.push(cur)
: result.finishedGames.push(cur);
: result.finishedGames.unshift(cur);
return result;
},
{
@@ -169,7 +169,7 @@ const OtherUserPage: React.FC = () => {
setGameRecords(notEndGames);
setEndedGameRecords(finishedGames);
} catch (error) {
console.error("加载球局数据失败:", error);
console.warn("加载球局数据失败:", error);
Taro.showToast({
title: "加载失败,请重试",
icon: "error",
@@ -200,7 +200,7 @@ const OtherUserPage: React.FC = () => {
duration: 1500,
});
} catch (error) {
console.error("关注操作失败:", error);
console.warn("关注操作失败:", error);
Taro.showToast({
title: "操作失败",
icon: "none",
@@ -235,7 +235,7 @@ const OtherUserPage: React.FC = () => {
try {
await Promise.all([load_user_data(), load_game_data()]);
} catch (error) {
console.error("刷新失败:", error);
console.warn("刷新失败:", error);
} finally {
setRefreshing(false);
}

View File

@@ -84,7 +84,7 @@ const QueryTransactions = () => {
setSearchHistory(response.data);
}
} catch (e) {
console.error(e);
console.warn(e);
}
};
/**

View File

@@ -3,6 +3,7 @@
background-color: #f5f5f5;
box-sizing: border-box;
overflow: hidden;
padding: 0 20px;
.custom-navbar {
height: 56px;
/* 通常与原生导航栏高度一致 */
@@ -17,6 +18,7 @@
top: 0;
z-index: 100;
background-color: #f5f5f5;
padding: 0 20px;
}
.detail-navigator {
@@ -48,18 +50,22 @@
}
.form-item {
padding: 20px;
padding: 16px 0;
box-sizing: border-box;
height: 50px;
display: flex;
gap: 10px;
gap: 20px;
align-items: center;
border-bottom: 1px solid #0000000d;
font-size: 14px;
.form-label {
width: 56px;
text-align: right;
font-weight: 600;
}
Input {
flex: 1;
}
}
@@ -72,7 +78,6 @@
letter-spacing: 0px;
vertical-align: middle;
color: #3c3c4366;
padding: 0 20px;
}
.btn {
@@ -106,6 +111,5 @@
border-radius: 16px;
font-size: 16px;
font-weight: 600;
transform: translateX(20px);
}
}

View File

@@ -67,10 +67,12 @@ const SetTransactionPassword: React.FC = () => {
const { new_password, confirm_password, sms_code } = formData;
if (handleType === "set") {
setValid(
(sms_code !== "") && (new_password.length === 6) && (confirm_password.length === 6)
sms_code !== "" &&
new_password.length === 6 &&
confirm_password.length === 6
);
} else {
setValid((new_password.length === 6) && (confirm_password.length === 6));
setValid(new_password.length === 6 && confirm_password.length === 6);
}
}, [formData]);
@@ -97,7 +99,7 @@ const SetTransactionPassword: React.FC = () => {
icon: "success",
});
let delta = handleType === "set" ? 1 : 2;
Taro.navigateBack({ delta })
Taro.navigateBack({ delta });
} catch (error) {
Taro.showToast({
title: "设置交易密码失败",
@@ -166,13 +168,11 @@ const SetTransactionPassword: React.FC = () => {
Taro.navigateBack();
}}
/>
<View
className="form-item"
style={{ marginTop: `${totalHeight}px` }}
>
<View className="form-item" style={{ marginTop: `${totalHeight}px` }}>
<Text className="form-label"></Text>
<Input
placeholder="请输入交易密码"
placeholderStyle="color: #d9d9d9;"
password
type="number"
maxlength={6}
@@ -185,6 +185,7 @@ const SetTransactionPassword: React.FC = () => {
<Text className="form-label"></Text>
<Input
placeholder="请再次输入交易密码"
placeholderStyle="color: #d9d9d9;"
password
type="number"
maxlength={6}
@@ -198,6 +199,7 @@ const SetTransactionPassword: React.FC = () => {
<Text className="form-label"></Text>
<Input
placeholder="请输入验证码"
placeholderStyle="color: #d9d9d9;"
type="number"
onInput={(e) => {
handleInput(e, "sms_code");

View File

@@ -3,6 +3,7 @@
box-sizing: border-box;
height: 100vh;
overflow-y: hidden;
padding: 0 20px;
.custom-navbar {
height: 56px;
/* 通常与原生导航栏高度一致 */
@@ -48,18 +49,22 @@
}
.form-item {
padding: 20px;
padding: 16px 0;
box-sizing: border-box;
height: 50px;
display: flex;
gap: 10px;
gap: 20px;
align-items: center;
border-bottom: 1px solid #0000000d;
font-size: 14px;
.form-label {
width: 56px;
text-align: right;
font-weight: 600;
}
Input {
flex: 1;
}
}
@@ -95,6 +100,5 @@
border-radius: 16px;
font-size: 16px;
font-weight: 600;
transform: translateX(20px);
}
}

View File

@@ -139,10 +139,7 @@ const ValidPhone: React.FC = () => {
Taro.navigateBack();
}}
/>
<View
className="form-item"
style={{ marginTop: `${totalHeight}px` }}
>
<View className="form-item" style={{ marginTop: `${totalHeight}px` }}>
<Text className="form-label"></Text>
<Input defaultValue={formData.phone} type="number" disabled></Input>
</View>
@@ -150,6 +147,7 @@ const ValidPhone: React.FC = () => {
<Text className="form-label"></Text>
<Input
placeholder="请输入验证码"
placeholderStyle="color: #d9d9d9;"
type="number"
onInput={(e) => {
handleInput(e, "sms_code");

View File

@@ -195,7 +195,7 @@ const WalletPage: React.FC = () => {
const res = await httpService.post("/wallet/check_password_status");
set_password_status(res.data.is_password_set);
} catch (e) {
console.error("检查交易密码状态失败:", e);
console.warn("检查交易密码状态失败:", e);
}
};
@@ -218,7 +218,7 @@ const WalletPage: React.FC = () => {
total_withdraw,
});
} catch (error: any) {
console.error("加载钱包数据失败:", error);
console.warn("加载钱包数据失败:", error);
let errorMessage = "加载失败,请重试";
if (
@@ -262,7 +262,7 @@ const WalletPage: React.FC = () => {
set_transactions([]);
}
} catch (error: any) {
console.error("加载交易记录失败:", error);
console.warn("加载交易记录失败:", error);
set_transactions([]);
let errorMessage = "加载交易记录失败";

View File

@@ -49,7 +49,7 @@ const Withdrawal: React.FC = () => {
}, [initializeKeyboardListener, addListener]);
const [showTips, setShowTips] = useState(false);
const [tipsText, setTipsText] = useState<string>("");
const [inputValue, setInputValue] = useState<string>("0.00");
const [inputValue, setInputValue] = useState<string>("");
const [walletInfo, setWalletInfo] = useState<WalletInfo>({
balance: "0.00",
});
@@ -65,8 +65,8 @@ const Withdrawal: React.FC = () => {
const [inputValueObj, setInputValueObj] = useState({
integer: "0",
decimal: "00"
})
decimal: "00",
});
useDidShow(() => {
load_wallet_data();
@@ -87,11 +87,11 @@ const Withdrawal: React.FC = () => {
}, [show_withdraw_popup]);
useEffect(() => {
const value = Number(inputValue).toFixed(2).split(".")
const integer = value[0]
const decimal = value[1]
setInputValueObj({ integer, decimal })
}, [inputValue])
const value = Number(inputValue).toFixed(2).split(".");
const integer = value[0];
const decimal = value[1];
setInputValueObj({ integer, decimal });
}, [inputValue]);
const validateWithdrawAmount = (amount: string) => {
if (Number(amount) > Number(walletInfo.balance)) {
@@ -135,7 +135,7 @@ const Withdrawal: React.FC = () => {
total_withdraw,
});
} catch (error: any) {
console.error("加载钱包数据失败:", error);
console.warn("加载钱包数据失败:", error);
let errorMessage = "加载失败,请重试";
if (
@@ -171,7 +171,7 @@ const Withdrawal: React.FC = () => {
setMapErrorCodes(mapErrorCodes);
}
} catch (error: any) {
console.error("获取提现错误码失败:", error);
console.warn("获取提现错误码失败:", error);
}
};
const handleWithdraw = async () => {
@@ -307,15 +307,13 @@ const Withdrawal: React.FC = () => {
showBack={true}
showAvatar={false}
onBack={() => {
const pages = Taro.getCurrentPages()
const prevPage = pages[pages.length - 2]
prevPage.setData({
updateList: withdrawSuccess
})
const pages = Taro.getCurrentPages();
const prevPage = pages[pages.length - 2];
prevPage.setData({ updateList: true });
Taro.navigateBack();
}}
/>
<View
<View
className="withdrawal-container"
style={{ marginTop: `${totalHeight}px` }}
>
@@ -325,6 +323,7 @@ const Withdrawal: React.FC = () => {
<Input
type="digit"
placeholder="0.00"
placeholderStyle="color:rgba(120, 120, 128, 0.12);"
cursorColor="#000"
value={inputValue}
onInput={handleInput}

View File

@@ -33,7 +33,7 @@ const initUserAuthCore = async (): Promise<void> => {
await fetchUserInfo();
await checkNicknameChangeStatus();
} catch (error) {
console.error("获取用户信息失败:", error);
console.warn("获取用户信息失败:", error);
}
} else {
// 未登录,尝试静默登录
@@ -45,12 +45,12 @@ const initUserAuthCore = async (): Promise<void> => {
await checkNicknameChangeStatus();
}
} catch (error) {
console.error("静默登录失败:", error);
console.warn("静默登录失败:", error);
// 静默登录失败不影响使用
}
}
} catch (error) {
console.error("初始化用户授权失败:", error);
console.warn("初始化用户授权失败:", error);
} finally {
isInitializingAuth = false;
authInitPromise = null;

View File

@@ -7,6 +7,12 @@ const dateIcon = `${OSS_BASE}/front/ball/images/1b49476e-0eda-42ff-b08c-002ce510
const mapIcon = `${OSS_BASE}/front/ball/images/06b994fa-9227-4708-8555-8a07af8d0c3b.jpg`;
const logoText = `${OSS_BASE}/system/youchang_tip_text.png`;
/** 给图片 URL 加随机参数,避免同一链接二次加载不触发 onload */
function with_cache_bust(url: string): string {
const sep = url.includes('?') ? '&' : '?';
return `${url}${sep}_t=${Date.now()}_${Math.random().toString(36).slice(2)}`;
}
export function base64ToTempFilePath(base64Data: string): Promise<string> {
return new Promise((resolve, reject) => {
const fsm = Taro.getFileSystemManager();
@@ -55,26 +61,26 @@ function getImageWh(src: string): Promise<{ width: number; height: number }> {
}
/** 加载图片 */
function loadImage(canvas: any, src: string): Promise<any> {
function loadImage(canvas: any, src: string, key?: string): Promise<any> {
return new Promise((resolve, reject) => {
let timer: any;
let timer: ReturnType<typeof setTimeout>;
const img = canvas.createImage();
img.crossOrigin = "anonymous"
img.crossOrigin = "anonymous";
img.onload = () => {
clearTimeout(timer);
resolve(img);
};
img.onerror = () => {
img.onerror = (e: Error) => {
clearTimeout(timer);
console.log('img error', src)
}
const errMsg = `Image load failed: ${key}: ${src}`
console.warn(errMsg)
reject(new Error(errMsg));
};
timer = setTimeout(() => {
reject(new Error(`Image load timeout: ${src}`));
reject(new Error(`Image load timeout: ${key}: ${src}`));
}, 8000);
img.src = src;
@@ -327,21 +333,21 @@ export async function generatePosterImage(data: any): Promise<string> {
console.log('ctx', ctx)
// 背景渐变
roundRectGradient(ctx, 0, 0, width, height, 24, "#BFFFEF", "#F2FFFC");
console.log('bgUrl', bgUrl)
const bgImg = await loadImage(canvas, bgUrl);
const bgImg = await loadImage(canvas, with_cache_bust(bgUrl), 'bgUrl');
ctx.drawImage(bgImg, 0, 0, width, height);
console.log('bgUrlend', )
console.log('bgUrlend',)
roundRotateRect(ctx, 70, 100, width - 140, width - 140, 20, '#fff', deg2rad(-6));
// 顶部图片
const mainImg = await loadImage(canvas, data.mainCoursal);
const mainImg = await loadImage(canvas, with_cache_bust(data.mainCoursal), 'mainCoursal');
console.log('mainCoursal', data.mainCoursal)
await drawRotateCoverImage(
ctx,
@@ -375,7 +381,7 @@ export async function generatePosterImage(data: any): Promise<string> {
left = 20;
// 用户头像
const avatarImg = await loadImage(canvas, data.avatarUrl);
const avatarImg = await loadImage(canvas, with_cache_bust(data.avatarUrl), 'avatar');
ctx.save();
ctx.beginPath();
ctx.arc(left + 30, top + 30, 30, 0, Math.PI * 2);
@@ -396,7 +402,7 @@ export async function generatePosterImage(data: any): Promise<string> {
ctx.fillStyle = "#00B578";
ctx.fillText("球局", left, top);
const ringImg = await loadImage(canvas, ringUrl);
const ringImg = await loadImage(canvas, with_cache_bust(ringUrl), 'ring');
ctx.drawImage(ringImg, left - 10, top - 30, 80, 36);
left = 20;
@@ -410,7 +416,7 @@ export async function generatePosterImage(data: any): Promise<string> {
top = r.top + 30;
left = 20;
const dateImg = await loadImage(canvas, dateIcon);
const dateImg = await loadImage(canvas, with_cache_bust(dateIcon), 'date');
console.log('dateIcon', dateIcon)
await drawCoverImage(
@@ -440,7 +446,7 @@ export async function generatePosterImage(data: any): Promise<string> {
top += 24;
const mapImg = await loadImage(canvas, mapIcon);
const mapImg = await loadImage(canvas, with_cache_bust(mapIcon), 'map');
await drawCoverImage(ctx, canvas, mapIcon, mapImg, left, top, 40, 40, 12);
left += 40 + 16;
@@ -454,7 +460,7 @@ export async function generatePosterImage(data: any): Promise<string> {
top = r.top + 60;
const logoWh = await getImageWh(logoText);
const logoTextImg = await loadImage(canvas, logoText);
const logoTextImg = await loadImage(canvas, with_cache_bust(logoText), 'logo');
ctx.drawImage(
logoTextImg,
left,
@@ -464,7 +470,7 @@ export async function generatePosterImage(data: any): Promise<string> {
400 / (logoWh.width / logoWh.height)
);
const qrImg = await loadImage(canvas, data.qrCodeUrl);
const qrImg = await loadImage(canvas, with_cache_bust(data.qrCodeUrl), 'qrcode');
// roundRectGradient(ctx, width - 12 - 150, height - 22 - 140, 140, 140, 20, "#fff", "#fff")
ctx.drawImage(qrImg, width - 22 - 100, height - 22 - 100 - 2, 100, 100);

View File

@@ -1,6 +1,7 @@
import Taro from "@tarojs/taro";
import { check_login_status, get_user_info } from "@/services/loginService";
import { useUser } from "@/store/userStore";
import { Dayjs } from "dayjs";
// 普通函数,不调用 useLoad
export const sceneRedirectLogic = (options, defaultPage: string) => {
@@ -23,7 +24,7 @@ export const sceneRedirectLogic = (options, defaultPage: string) => {
url: query ? `/${defaultPage}?${query}` : `/${defaultPage}`,
});
} catch (e) {
console.error(e);
console.warn(e);
}
};
@@ -94,6 +95,19 @@ export function toast(message) {
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[]) {
if (!tags) return [];
@@ -122,3 +136,31 @@ export function genNTRPRequirementText(min, max) {
export function isPhoneNumber(str) {
return /^1[3-9]\d{9}$/.test(str);
}
export function genGameLength(startTime: Dayjs, endTime: Dayjs) {
if (!startTime || !endTime) {
return "";
}
const totalMinutes = endTime.diff(startTime, "minute");
const totalHours = totalMinutes / 60;
if (totalHours >= 24) {
const days = Math.floor(totalHours / 24);
const remainingHours = totalHours % 24;
if (remainingHours === 0) {
return `${days}`;
}
// 保留一位小数
const displayHours = parseFloat(remainingHours.toFixed(1));
return `${days}${displayHours}小时`;
}
// 如果是整数小时,不显示小数点
if (Number.isInteger(totalHours)) {
return `${totalHours}小时`;
}
// 保留一位小数去除末尾的0
return `${parseFloat(totalHours.toFixed(1))}小时`;
}

View File

@@ -14,10 +14,20 @@ export interface LocationInfo {
name?: string
}
/** 规范化地址:去掉类似“上海市上海市...”的重复前缀 */
export const normalize_address = (address: string): string => {
if (!address) return ''
// 去空格(包含全角空格)
const trimmed = address.replace(/[\s\u3000]+/g, '')
// 处理 “xx市xx市...” / “xx省xx省...” 等连续重复
// 例:上海市上海市静安区... -> 上海市静安区...
return trimmed.replace(/^(.{2,6}?[市省])\1+/, '$1')
}
// 获取当前位置
export const getCurrentLocation = (): Promise<LocationInfo> => {
return new Promise((resolve, reject) => {
Taro.getLocation({
;(Taro as any).getLocation({
type: 'wgs84',
success: (res) => {
console.log('===获取地理位置', res)
@@ -27,7 +37,7 @@ export const getCurrentLocation = (): Promise<LocationInfo> => {
resolve({
latitude: res.latitude,
longitude: res.longitude,
address
address: normalize_address(address)
})
})
.catch(() => {
@@ -48,12 +58,12 @@ export const getCurrentLocation = (): Promise<LocationInfo> => {
// 选择地图位置
export const chooseLocation = (): Promise<LocationInfo> => {
return new Promise((resolve, reject) => {
Taro.chooseLocation({
;(Taro as any).chooseLocation({
success: (res) => {
resolve({
latitude: res.latitude,
longitude: res.longitude,
address: res.address,
address: normalize_address(res.address),
name: res.name
})
},
@@ -66,7 +76,7 @@ export const chooseLocation = (): Promise<LocationInfo> => {
export const getLocation = (): Promise<Location> => {
return new Promise((resolve, reject) => {
Taro.getLocation({
;(Taro as any).getLocation({
success: (res) => {
resolve({
latitude: res.latitude,

View File

@@ -106,6 +106,12 @@ const drawLabel = (ctx: any, x: number, y: number, width: number, height: number
ctx.restore()
}
/** 给图片 URL 加随机参数,避免同一链接二次加载不触发 onload */
function with_cache_bust(url: string): string {
const sep = url.includes('?') ? '&' : '?';
return `${url}${sep}_t=${Date.now()}_${Math.random().toString(36).slice(2)}`;
}
// 工具函数 - OffscreenCanvas 下加载图片(使用 offscreen.createImage
const loadImage = (src: string): Promise<any> => {
return new Promise((resolve, reject) => {
@@ -117,7 +123,7 @@ const loadImage = (src: string): Promise<any> => {
const img = off.createImage()
img.onload = () => resolve(img)
img.onerror = reject
img.src = src
img.src = with_cache_bust(src)
} catch (e) {
reject(e)
}
@@ -553,7 +559,7 @@ const drawShareCard = async (ctx: any, data: ShareCardData, offscreen: any): Pro
console.log('Canvas绘制命令已发送')
} catch (error) {
console.error('绘制分享卡片失败:', error)
console.warn('绘制分享卡片失败:', error)
Taro.showToast({
title: '生成分享卡片失败',
icon: 'none'

View File

@@ -16,7 +16,7 @@ class TokenManager {
try {
return Taro.getStorageSync(TOKEN_KEY)
} catch (error) {
console.error('获取访问令牌失败:', error)
console.warn('获取访问令牌失败:', error)
return null
}
}
@@ -26,7 +26,7 @@ class TokenManager {
try {
return Taro.getStorageSync(REFRESH_TOKEN_KEY)
} catch (error) {
console.error('获取刷新令牌失败:', error)
console.warn('获取刷新令牌失败:', error)
return null
}
}
@@ -36,7 +36,7 @@ class TokenManager {
try {
return Taro.getStorageSync(TOKEN_EXPIRES_KEY)
} catch (error) {
console.error('获取令牌过期时间失败:', error)
console.warn('获取令牌过期时间失败:', error)
return null
}
}
@@ -54,7 +54,7 @@ class TokenManager {
Taro.setStorageSync(TOKEN_EXPIRES_KEY, tokenInfo.expiresAt)
}
} catch (error) {
console.error('设置令牌失败:', error)
console.warn('设置令牌失败:', error)
}
}
@@ -65,7 +65,7 @@ class TokenManager {
Taro.removeStorageSync(REFRESH_TOKEN_KEY)
Taro.removeStorageSync(TOKEN_EXPIRES_KEY)
} catch (error) {
console.error('清除令牌失败:', error)
console.warn('清除令牌失败:', error)
}
}

View File

@@ -17,7 +17,7 @@ export function saveImage(url) {
await Taro.saveImageToPhotosAlbum({ filePath })
Taro.showToast({ title: "保存成功" })
} catch (e) {
console.error(e)
console.warn(e)
Taro.showToast({ title: "图片保存失败", icon: "none" })
}
}

View File

@@ -237,7 +237,7 @@ export interface ListCardProps {
venue_image_list: {
url: string;
}[];
venue_description: string;
location_name: string;
game_type: string;
type: string;
}