feat: 分包
This commit is contained in:
531
src/publish_pages/publishBall/index.tsx
Normal file
531
src/publish_pages/publishBall/index.tsx
Normal file
@@ -0,0 +1,531 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { View, Text, Button, Image } from "@tarojs/components";
|
||||
import { Checkbox } from "@nutui/nutui-react-taro";
|
||||
import Taro from "@tarojs/taro";
|
||||
import { type ActivityType } from "@/components/ActivityTypeSwitch";
|
||||
import CommonDialog from "@/components/CommonDialog";
|
||||
import { withAuth } from "@/components";
|
||||
import PublishForm from "./publishForm";
|
||||
import {
|
||||
FormFieldConfig,
|
||||
publishBallFormSchema,
|
||||
} from "@/config/formSchema/publishBallFormSchema";
|
||||
import { PublishBallFormData } from "../../../types/publishBall";
|
||||
import PublishService from "@/services/publishService";
|
||||
import { getNextHourTime, getEndTime, delay } from "@/utils";
|
||||
import images from "@/config/images";
|
||||
import styles from "./index.module.scss";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
const defaultFormData: PublishBallFormData = {
|
||||
title: "",
|
||||
image_list: [],
|
||||
timeRange: {
|
||||
start_time: getNextHourTime(),
|
||||
end_time: getEndTime(getNextHourTime()),
|
||||
},
|
||||
activityInfo: {
|
||||
play_type: "不限",
|
||||
price: "",
|
||||
venue_id: null,
|
||||
location_name: "",
|
||||
location: "",
|
||||
latitude: "",
|
||||
longitude: "",
|
||||
court_type: "",
|
||||
court_surface: "",
|
||||
venue_description_tag: [],
|
||||
venue_description: "",
|
||||
venue_image_list: [],
|
||||
},
|
||||
players: [1, 1],
|
||||
skill_level: [1.0, 5.0],
|
||||
descriptionInfo: {
|
||||
description: "",
|
||||
description_tag: [],
|
||||
},
|
||||
is_substitute_supported: true,
|
||||
is_wechat_contact: true,
|
||||
wechat_contact: "14223332214",
|
||||
};
|
||||
|
||||
const PublishBall: React.FC = () => {
|
||||
const [activityType, setActivityType] = useState<ActivityType>("individual");
|
||||
const [isSubmitDisabled, setIsSubmitDisabled] = useState(false);
|
||||
// 获取页面参数并设置导航标题
|
||||
const [optionsConfig, setOptionsConfig] = useState<FormFieldConfig[]>(
|
||||
publishBallFormSchema,
|
||||
);
|
||||
const [formData, setFormData] = useState<PublishBallFormData[]>([
|
||||
defaultFormData,
|
||||
]);
|
||||
const [checked, setChecked] = useState(true);
|
||||
|
||||
// 删除确认弹窗状态
|
||||
const [deleteConfirm, setDeleteConfirm] = useState<{
|
||||
visible: boolean;
|
||||
index: number;
|
||||
}>({
|
||||
visible: false,
|
||||
index: -1,
|
||||
});
|
||||
|
||||
// 更新表单数据
|
||||
const updateFormData = (
|
||||
key: keyof PublishBallFormData,
|
||||
value: any,
|
||||
index: number,
|
||||
) => {
|
||||
console.log(key, value, index, "key, value, index");
|
||||
setFormData((prev) => {
|
||||
const newData = [...prev];
|
||||
newData[index] = { ...newData[index], [key]: value };
|
||||
console.log(newData, "newData");
|
||||
return newData;
|
||||
});
|
||||
};
|
||||
|
||||
// 处理活动类型变化
|
||||
const handleActivityTypeChange = (type: ActivityType) => {
|
||||
if (type === "group") {
|
||||
setFormData([defaultFormData]);
|
||||
} else {
|
||||
setFormData([defaultFormData]);
|
||||
}
|
||||
};
|
||||
|
||||
// 检查相邻两组数据是否相同
|
||||
const checkAdjacentDataSame = (formDataArray: PublishBallFormData[]) => {
|
||||
if (formDataArray.length < 2) return false;
|
||||
|
||||
const lastIndex = formDataArray.length - 1;
|
||||
const secondLastIndex = formDataArray.length - 2;
|
||||
|
||||
const lastData = formDataArray[lastIndex];
|
||||
const secondLastData = formDataArray[secondLastIndex];
|
||||
|
||||
// 比较关键字段是否相同
|
||||
return JSON.stringify(lastData) === JSON.stringify(secondLastData);
|
||||
};
|
||||
|
||||
const handleAdd = () => {
|
||||
// 检查最后两组数据是否相同
|
||||
if (checkAdjacentDataSame(formData)) {
|
||||
Taro.showToast({
|
||||
title: "信息不可与前序场完全一致",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
const newStartTime = getNextHourTime();
|
||||
setFormData((prev) => [
|
||||
...prev,
|
||||
{
|
||||
...defaultFormData,
|
||||
title: "",
|
||||
timeRange: {
|
||||
start_time: newStartTime,
|
||||
end_time: getEndTime(newStartTime),
|
||||
},
|
||||
},
|
||||
]);
|
||||
};
|
||||
|
||||
// 复制上一场数据
|
||||
const handleCopyPrevious = (index: number) => {
|
||||
if (index > 0) {
|
||||
setFormData((prev) => {
|
||||
const newData = [...prev];
|
||||
newData[index] = { ...newData[index - 1] };
|
||||
return newData;
|
||||
});
|
||||
Taro.showToast({
|
||||
title: "复制上一场填入",
|
||||
icon: "success",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 删除确认弹窗
|
||||
const showDeleteConfirm = (index: number) => {
|
||||
setDeleteConfirm({
|
||||
visible: true,
|
||||
index,
|
||||
});
|
||||
};
|
||||
|
||||
// 关闭删除确认弹窗
|
||||
const closeDeleteConfirm = () => {
|
||||
setDeleteConfirm({
|
||||
visible: false,
|
||||
index: -1,
|
||||
});
|
||||
};
|
||||
|
||||
// 确认删除
|
||||
const confirmDelete = () => {
|
||||
if (deleteConfirm.index >= 0) {
|
||||
setFormData((prev) =>
|
||||
prev.filter((_, index) => index !== deleteConfirm.index),
|
||||
);
|
||||
closeDeleteConfirm();
|
||||
Taro.showToast({
|
||||
title: "已删除该场次",
|
||||
icon: "success",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const validateFormData = (
|
||||
formData: PublishBallFormData,
|
||||
isOnSubmit: boolean = false,
|
||||
) => {
|
||||
const { activityInfo, image_list, title, timeRange } = formData;
|
||||
const { play_type, price, location_name } = activityInfo;
|
||||
if (!image_list?.length) {
|
||||
if (!isOnSubmit) {
|
||||
Taro.showToast({
|
||||
title: `请上传活动封面`,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!title) {
|
||||
if (!isOnSubmit) {
|
||||
Taro.showToast({
|
||||
title: `请输入活动标题`,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
!price ||
|
||||
(typeof price === "number" && price <= 0) ||
|
||||
(typeof price === "string" && !price.trim())
|
||||
) {
|
||||
if (!isOnSubmit) {
|
||||
Taro.showToast({
|
||||
title: `请输入费用`,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!play_type || !play_type.trim()) {
|
||||
if (!isOnSubmit) {
|
||||
Taro.showToast({
|
||||
title: `请选择玩法类型`,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!location_name || !location_name.trim()) {
|
||||
if (!isOnSubmit) {
|
||||
Taro.showToast({
|
||||
title: `请选择场地`,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// 时间范围校验:结束时间需晚于开始时间,且至少间隔30分钟(支持跨天)
|
||||
if (timeRange?.start_time && timeRange?.end_time) {
|
||||
const start = dayjs(timeRange.start_time);
|
||||
const end = dayjs(timeRange.end_time);
|
||||
if (!end.isAfter(start)) {
|
||||
if (!isOnSubmit) {
|
||||
Taro.showToast({
|
||||
title: `结束时间需晚于开始时间`,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (end.isBefore(start.add(30, "minute"))) {
|
||||
if (!isOnSubmit) {
|
||||
Taro.showToast({
|
||||
title: `时间间隔至少30分钟`,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
const validateOnSubmit = () => {
|
||||
const isValid =
|
||||
activityType === "individual"
|
||||
? validateFormData(formData[0], true)
|
||||
: formData.every((item) => validateFormData(item, true));
|
||||
if (!isValid) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// 提交表单
|
||||
const handleSubmit = async () => {
|
||||
// 基础验证
|
||||
console.log(formData, "formData");
|
||||
if (activityType === "individual") {
|
||||
const isValid = validateFormData(formData[0]);
|
||||
if (!isValid) {
|
||||
return;
|
||||
}
|
||||
const {
|
||||
activityInfo,
|
||||
descriptionInfo,
|
||||
timeRange,
|
||||
players,
|
||||
skill_level,
|
||||
image_list,
|
||||
...rest
|
||||
} = formData[0];
|
||||
const options = {
|
||||
...rest,
|
||||
...activityInfo,
|
||||
...descriptionInfo,
|
||||
...timeRange,
|
||||
max_players: players[1],
|
||||
current_players: players[0],
|
||||
skill_level_min: skill_level[0],
|
||||
skill_level_max: skill_level[1],
|
||||
image_list: image_list.map((item) => item.url),
|
||||
};
|
||||
const res = await PublishService.createPersonal(options);
|
||||
if (res.code === 0 && res.data) {
|
||||
Taro.showToast({
|
||||
title: "发布成功",
|
||||
icon: "success",
|
||||
});
|
||||
delay(1000);
|
||||
// 如果是个人球局,则跳转到详情页,并自动分享
|
||||
// 如果是畅打,则跳转第一个球局详情页,并自动分享 @刘杰
|
||||
Taro.navigateTo({
|
||||
// @ts-expect-error: id
|
||||
url: `/game_pages/detail/index?id=${res.data.id || 1}&from=publish`,
|
||||
});
|
||||
} else {
|
||||
Taro.showToast({
|
||||
title: res.message,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
}
|
||||
if (activityType === "group") {
|
||||
const isValid = formData.every((item) => validateFormData(item));
|
||||
if (!isValid) {
|
||||
return;
|
||||
}
|
||||
if (checkAdjacentDataSame(formData)) {
|
||||
Taro.showToast({
|
||||
title: "信息不可与前序场完全一致",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
const options = formData.map((item) => {
|
||||
const {
|
||||
activityInfo,
|
||||
descriptionInfo,
|
||||
timeRange,
|
||||
players,
|
||||
skill_level,
|
||||
...rest
|
||||
} = item;
|
||||
return {
|
||||
...rest,
|
||||
...activityInfo,
|
||||
...descriptionInfo,
|
||||
...timeRange,
|
||||
max_players: players[1],
|
||||
current_players: players[0],
|
||||
skill_level_min: skill_level[0],
|
||||
skill_level_max: skill_level[1],
|
||||
image_list: item.image_list.map((img) => img.url),
|
||||
};
|
||||
});
|
||||
const res = await PublishService.create_play_pmoothlys({ rows: options });
|
||||
if (res.code === 0 && res.data) {
|
||||
Taro.showToast({
|
||||
title: "发布成功",
|
||||
icon: "success",
|
||||
});
|
||||
delay(1000);
|
||||
// 如果是个人球局,则跳转到详情页,并自动分享
|
||||
// 如果是畅打,则跳转第一个球局详情页,并自动分享 @刘杰
|
||||
Taro.navigateTo({
|
||||
// @ts-expect-error: id
|
||||
url: `/game_pages/detail/index?id=${res.data?.[0].id || 1}&from=publish`,
|
||||
});
|
||||
} else {
|
||||
Taro.showToast({
|
||||
title: res.message,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const initFormData = () => {
|
||||
const currentInstance = Taro.getCurrentInstance();
|
||||
const params = currentInstance.router?.params;
|
||||
if (params?.type) {
|
||||
const type = params.type as ActivityType;
|
||||
if (type === "individual" || type === "group") {
|
||||
setActivityType(type);
|
||||
if (type === "group") {
|
||||
const newFormSchema = publishBallFormSchema.reduce((acc, item) => {
|
||||
if (item.prop === "is_wechat_contact") {
|
||||
return acc;
|
||||
}
|
||||
if (item.prop === "image_list") {
|
||||
if (item.props) {
|
||||
item.props.source = ["album", "history"];
|
||||
}
|
||||
}
|
||||
if (item.prop === "players") {
|
||||
if (item.props) {
|
||||
item.props.max = 100;
|
||||
}
|
||||
}
|
||||
acc.push(item);
|
||||
return acc;
|
||||
}, [] as FormFieldConfig[]);
|
||||
setOptionsConfig(newFormSchema);
|
||||
setFormData([defaultFormData]);
|
||||
}
|
||||
// 根据type设置导航标题
|
||||
if (type === "group") {
|
||||
Taro.setNavigationBarTitle({
|
||||
title: "发布畅打活动",
|
||||
});
|
||||
} else {
|
||||
Taro.setNavigationBarTitle({
|
||||
title: "发布",
|
||||
});
|
||||
}
|
||||
}
|
||||
handleActivityTypeChange(type);
|
||||
}
|
||||
};
|
||||
const onCheckedChange = (checked: boolean) => {
|
||||
setChecked(checked);
|
||||
};
|
||||
useEffect(() => {
|
||||
const isValid = validateOnSubmit();
|
||||
if (!isValid) {
|
||||
setIsSubmitDisabled(true);
|
||||
} else {
|
||||
setIsSubmitDisabled(false);
|
||||
}
|
||||
console.log(formData, "formData");
|
||||
}, [formData]);
|
||||
|
||||
useEffect(() => {
|
||||
initFormData();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<View className={styles["publish-ball"]}>
|
||||
{/* 活动类型切换 */}
|
||||
<View className={styles["activity-type-switch"]}>
|
||||
{/* <ActivityTypeSwitch
|
||||
value={activityType}
|
||||
onChange={handleActivityTypeChange}
|
||||
/> */}
|
||||
</View>
|
||||
|
||||
<View className={styles["publish-ball__scroll"]}>
|
||||
{formData.map((item, index) => (
|
||||
<View key={index}>
|
||||
{/* 场次标题行 */}
|
||||
{activityType === "group" && index > 0 && (
|
||||
<View className={styles["session-header"]}>
|
||||
<View className={styles["session-title"]}>
|
||||
第{index + 1}场
|
||||
<View
|
||||
className={styles["session-delete"]}
|
||||
onClick={() => showDeleteConfirm(index)}
|
||||
>
|
||||
<Image
|
||||
src={images.ICON_DELETE}
|
||||
className={styles["session-delete-icon"]}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<View className={styles["session-actions"]}>
|
||||
{index > 0 && (
|
||||
<View
|
||||
className={styles["session-action-btn"]}
|
||||
onClick={() => handleCopyPrevious(index)}
|
||||
>
|
||||
复制上一场
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
<PublishForm
|
||||
formData={item}
|
||||
onChange={(key, value) => updateFormData(key, value, index)}
|
||||
optionsConfig={optionsConfig}
|
||||
/>
|
||||
</View>
|
||||
))}
|
||||
{activityType === "group" && (
|
||||
<View className={styles["publish-ball__add"]} onClick={handleAdd}>
|
||||
<Image
|
||||
src={images.ICON_ADD}
|
||||
className={styles["publish-ball__add-icon"]}
|
||||
/>
|
||||
再添加一场
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* 删除确认弹窗 */}
|
||||
<CommonDialog
|
||||
visible={deleteConfirm.visible}
|
||||
cancelText="再想想"
|
||||
confirmText="确认移除"
|
||||
onCancel={closeDeleteConfirm}
|
||||
onConfirm={confirmDelete}
|
||||
contentTitle="确认移除该场次?"
|
||||
contentDesc="该操作不可恢复"
|
||||
/>
|
||||
{/* 完成按钮 */}
|
||||
<View className={styles["submit-section"]}>
|
||||
<Button
|
||||
className={`${styles["submit-btn"]} ${isSubmitDisabled ? styles["submit-btn-disabled"] : ""}`}
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
发布
|
||||
</Button>
|
||||
{activityType === "individual" && (
|
||||
<Text className={styles["submit-tip"]}>
|
||||
点击确定发布约球,即表示已经同意条款
|
||||
<Text className={styles["link"]}>《约球规则》</Text>
|
||||
</Text>
|
||||
)}
|
||||
{activityType === "group" && (
|
||||
<View className={styles["submit-tip"]}>
|
||||
<Checkbox
|
||||
className={styles["submit-checkbox"]}
|
||||
checked={checked}
|
||||
onChange={onCheckedChange}
|
||||
/>
|
||||
已认证 徐汇爱打球官方球场,请严格遵守签约协议
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default withAuth(PublishBall);
|
||||
Reference in New Issue
Block a user