diff --git a/package.json b/package.json index bc36d80..9ef1f6d 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "@tarojs/runtime": "4.1.5", "@tarojs/shared": "4.1.5", "@tarojs/taro": "4.1.5", + "dayjs": "^1.11.13", "qqmap-wx-jssdk": "^1.0.0", "react": "^18.0.0", "react-dom": "^18.0.0", diff --git a/src/components/FormBasicInfo/index.ts b/src/components/FormBasicInfo/index.ts deleted file mode 100644 index 97a6f31..0000000 --- a/src/components/FormBasicInfo/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default } from './FormBasicInfo' -export type { FormBasicInfoProps } from './FormBasicInfo' \ No newline at end of file diff --git a/src/components/TextareaTag/TextareaTag.tsx b/src/components/TextareaTag/TextareaTag.tsx index f8f0d6e..83152c7 100644 --- a/src/components/TextareaTag/TextareaTag.tsx +++ b/src/components/TextareaTag/TextareaTag.tsx @@ -24,6 +24,7 @@ const TextareaTag: React.FC = ({ }) => { // 处理输入框变化 const [tags, setTags] = useState([]) + console.log(value, 'options') const handleInputChange = useCallback((e: any) => { onChange(e.detail.value) }, [onChange]) @@ -43,6 +44,7 @@ const TextareaTag: React.FC = ({ onChange(newValue) }, [value, onChange]) + console.log(options, 'options') return ( {/* 选择选项 */} diff --git a/src/components/TimeSelector/TimeSelector.tsx b/src/components/TimeSelector/TimeSelector.tsx index a538b10..303536a 100644 --- a/src/components/TimeSelector/TimeSelector.tsx +++ b/src/components/TimeSelector/TimeSelector.tsx @@ -1,11 +1,11 @@ import React from 'react' import { View, Text, Picker } from '@tarojs/components' +import { getDate, getTime } from '@/utils/timeUtils' import './TimeSelector.scss' export interface TimeRange { - startDate: string - startTime: string - endTime: string + start_time: string + end_time: string } interface TimeSelectorProps { @@ -15,40 +15,13 @@ interface TimeSelectorProps { const TimeSelector: React.FC = ({ value = { - startDate: '', - startTime: '', - endTime: '' + start_time: '', + end_time: '' }, onChange }) => { // 格式化日期显示 - const formatDate = (dateStr: string) => { - return dateStr.replace(/-/g, '年').replace(/-/g, '月') + '日' - } - - // 处理开始日期变化 - const handleStartDateChange = (e: any) => { - onChange({ - ...value, - startDate: e.detail.value - }) - } - - // 处理开始时间变化 - const handleStartTimeChange = (e: any) => { - onChange({ - ...value, - startTime: e.detail.value - }) - } - - // 处理结束时间变化 - const handleEndTimeChange = (e: any) => { - onChange({ - ...value, - endTime: e.detail.value - }) - } + return ( @@ -61,8 +34,8 @@ const TimeSelector: React.FC = ({ 开始时间 - 2025年11月23日 - 8:00 AM + {getDate(value.start_time)} + {getTime(value.start_time)} @@ -75,8 +48,7 @@ const TimeSelector: React.FC = ({ 结束时间 - 2025年11月23日 - 8:00 AM + {getTime(value.end_time)} diff --git a/src/components/TitleInput/index.ts b/src/components/TitleInput/index.ts deleted file mode 100644 index 18c7cc7..0000000 --- a/src/components/TitleInput/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './TitleInput' \ No newline at end of file diff --git a/src/components/TitleInput/TitleInput.tsx b/src/components/TitleTextarea/TitleTextarea.tsx similarity index 86% rename from src/components/TitleInput/TitleInput.tsx rename to src/components/TitleTextarea/TitleTextarea.tsx index 1a72cfc..413af77 100644 --- a/src/components/TitleInput/TitleInput.tsx +++ b/src/components/TitleTextarea/TitleTextarea.tsx @@ -3,14 +3,14 @@ import { View } from '@tarojs/components' import { TextArea } from '@nutui/nutui-react-taro' import './index.scss' -interface TitleInputProps { +interface TitleTextareaProps { value: string onChange: (value: string) => void maxLength?: number placeholder?: string } -const TitleInput: React.FC = ({ +const TitleTextarea: React.FC = ({ value, onChange, maxLength = 20, @@ -32,4 +32,4 @@ const TitleInput: React.FC = ({ ) } -export default TitleInput \ No newline at end of file +export default TitleTextarea \ No newline at end of file diff --git a/src/components/TitleInput/index.scss b/src/components/TitleTextarea/index.scss similarity index 100% rename from src/components/TitleInput/index.scss rename to src/components/TitleTextarea/index.scss diff --git a/src/components/TitleTextarea/index.ts b/src/components/TitleTextarea/index.ts new file mode 100644 index 0000000..75bd966 --- /dev/null +++ b/src/components/TitleTextarea/index.ts @@ -0,0 +1 @@ +export { default } from './TitleTextarea' \ No newline at end of file diff --git a/src/components/index.ts b/src/components/index.ts index cc5f816..4e2e1e4 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -2,12 +2,11 @@ import ActivityTypeSwitch from './ActivityTypeSwitch' import TextareaTag from './TextareaTag' import FormSwitch from './FormSwitch' import ImageUpload from './ImageUpload' -import FormBasicInfo from './FormBasicInfo' import Range from './Range' import NumberInterval from './NumberInterval' -import { SelectStadium, StadiumDetail } from './SelectStadium' + import TimeSelector from './TimeSelector' -import TitleInput from './TitleInput' +import TitleTextarea from './TitleTextarea' import CommonPopup from './CommonPopup' export { @@ -15,13 +14,10 @@ export { TextareaTag, FormSwitch, ImageUpload, - FormBasicInfo, Range, NumberInterval, - SelectStadium, TimeSelector, - TitleInput, - StadiumDetail, + TitleTextarea, CommonPopup } diff --git a/src/components/index.types.ts b/src/components/index.types.ts index 61bcc79..47f3a3c 100644 --- a/src/components/index.types.ts +++ b/src/components/index.types.ts @@ -1,5 +1,4 @@ import { type TimeRange } from './TimeSelector' -import { type Stadium } from './SelectStadium' import { type ActivityType } from './ActivityTypeSwitch' import { type CoverImage } from './ImageUpload' -export type { TimeRange, Stadium, ActivityType, CoverImage } \ No newline at end of file +export type { TimeRange, ActivityType, CoverImage } \ No newline at end of file diff --git a/src/config/formSchema/publishBallFormSchema.ts b/src/config/formSchema/publishBallFormSchema.ts index 02d5820..f67ce89 100644 --- a/src/config/formSchema/publishBallFormSchema.ts +++ b/src/config/formSchema/publishBallFormSchema.ts @@ -43,7 +43,7 @@ export interface FormFieldConfig { // 发布球局表单配置 export const publishBallFormSchema: FormFieldConfig[] = [ { - key: 'coverImages', + key: 'image_list', label: '活动封页', type: FieldType.UPLOADIMAGE, placeholder: '请选择活动类型', @@ -59,115 +59,101 @@ export const publishBallFormSchema: FormFieldConfig[] = [ placeholder: '好的标题更吸引人哦', required: true, props: { - maxLength: 80 - }, - rules: [ - { required: true, message: '请输入活动标题' }, - { max: 20, message: '标题不能超过20个字符' } - ] - }, - { - key: 'date', - label: '', - type: FieldType.TIMEINTERVAL, - placeholder: '请选择活动日期', - required: true, - rules: [ - { required: true, message: '请选择活动日期' } - ] - }, - { - key: 'timeRange', - label: '活动信息', - type: FieldType.ACTIVITYINFO, - placeholder: '请选择活动时间', - required: true, - rules: [ - { required: true, message: '请选择活动时间' } - ], - children: [ - { - key: 'fee', - label: '费用', - iconType: 'ICON_COST', - type: FieldType.NUMBER, - placeholder: '请输入活动费用(元)', - defaultValue: 0, - rules: [ - { min: 0, message: '费用不能为负数' }, - { max: 1000, message: '费用不能超过1000元' } - ], - }, - { - key: 'location', - label: '地点', - iconType: 'ICON_LOCATION', - type: FieldType.LOCATION, - placeholder: '请选择活动地点', - required: true, - }, - { - key: 'sport', - label: '玩法', - iconType: 'ICON_GAMEPLAY', - type: FieldType.SELECT, - placeholder: '请选择玩法', - required: true, - options: [ - { label: '篮球', value: 'basketball' }, - { label: '足球', value: 'football' }, - { label: '羽毛球', value: 'badminton' }, - { label: '网球', value: 'tennis' }, - { label: '乒乓球', value: 'pingpong' }, - { label: '排球', value: 'volleyball' } - ], - } - ] - }, - { - key: 'minParticipants', - label: '人数要求', - type: FieldType.NUMBERINTERVAL, - placeholder: '请输入最少参与人数', - defaultValue: 1, - props: { - showSummary: true, - summary: '最少1人,最多4人', - }, - rules: [ - { min: 1, message: '最少参与人数不能为0' }, - { max: 4, message: '最少参与人数不能超过100人' } - ], - }, - - { - key: 'ntpLevel', - label: 'NTRP 水平要求', - type: FieldType.RANGE, - placeholder: '请选择开始时间', - required: true, - props: { - showTitle: false, - showSummary: true, - className: 'ntrp-range', - step: 0.5, - min: 1.0, - max: 5.0, + maxLength: 20 } }, { - key: 'additionalRequirements', + key: 'timeRange', + label: '', + type: FieldType.TIMEINTERVAL, + placeholder: '请选择活动日期', + required: true + }, + // { + // key: 'activityInfo', + // label: '活动信息', + // type: FieldType.ACTIVITYINFO, + // placeholder: '请选择活动时间', + // required: true, + // rules: [ + // { required: true, message: '请选择活动时间' } + // ], + // children: [ + // { + // key: 'price', + // label: '费用', + // iconType: 'ICON_COST', + // type: FieldType.NUMBER, + // placeholder: '请输入活动费用(元)', + // defaultValue: 0, + // rules: [ + // { min: 0, message: '费用不能为负数' }, + // { max: 1000, message: '费用不能超过1000元' } + // ], + // }, + // { + // key: 'location', + // label: '地点', + // iconType: 'ICON_LOCATION', + // type: FieldType.LOCATION, + // placeholder: '请选择活动地点', + // required: true, + // }, + // { + // key: 'play_type', + // label: '玩法', + // iconType: 'ICON_GAMEPLAY', + // type: FieldType.SELECT, + // placeholder: '请选择玩法', + // required: true, + // options: [ + // { label: '篮球', value: 'basketball' }, + // { label: '足球', value: 'football' }, + // { label: '羽毛球', value: 'badminton' }, + // { label: '网球', value: 'tennis' }, + // { label: '乒乓球', value: 'pingpong' }, + // { label: '排球', value: 'volleyball' } + // ], + // } + // ] + // }, + // { + // key: 'players', + // label: '人数要求', + // type: FieldType.NUMBERINTERVAL, + // placeholder: '请输入最少参与人数', + // defaultValue: 1, + // props: { + // showSummary: true, + // summary: '最少1人,最多4人', + // } + // }, + + // { + // key: 'skill_level', + // label: 'NTRP 水平要求', + // type: FieldType.RANGE, + // placeholder: '请选择开始时间', + // required: true, + // props: { + // showTitle: false, + // showSummary: true, + // className: 'ntrp-range', + // step: 0.5, + // min: 1.0, + // max: 5.0, + // } + // }, + { + key: 'descriptionInfo', label: '补充要求(选填)', type: FieldType.TEXTAREATAG, placeholder: '补充性别偏好、特殊要求和注意事项等信息', required: true, options:[ - { label: '仅限男生', value: 'beginner' }, - { label: '仅限女生', value: 'intermediate' }, - { label: '性别不限', value: 'advanced' } - ], - rules: [ - { max: 100, message: '补充要求不能超过100个字符' } + { label: '仅限男生', value: '仅限男生' }, + { label: '仅限女生', value: '仅限女生' }, + { label: '性别不限', value: '性别不限' } ] }, { @@ -180,9 +166,6 @@ export const publishBallFormSchema: FormFieldConfig[] = [ subTitle: '开启自动候补逻辑', showToast: true, description: '开启后,当活动人数不足时,系统会自动将活动状态改为“候补”,并通知用户。', - }, - rules: [ - { required: true, message: '请选择开启自动候补逻辑' } - ] + } } ] \ No newline at end of file diff --git a/src/components/FormBasicInfo/FormBasicInfo.scss b/src/pages/publishBall/components/FormBasicInfo/FormBasicInfo.scss similarity index 96% rename from src/components/FormBasicInfo/FormBasicInfo.scss rename to src/pages/publishBall/components/FormBasicInfo/FormBasicInfo.scss index f60c080..0e07b71 100644 --- a/src/components/FormBasicInfo/FormBasicInfo.scss +++ b/src/pages/publishBall/components/FormBasicInfo/FormBasicInfo.scss @@ -75,6 +75,9 @@ overflow: hidden; white-space: nowrap; text-align: right; + &.selected{ + color: #000; + } } .arrow{ width: 16px; diff --git a/src/components/FormBasicInfo/FormBasicInfo.tsx b/src/pages/publishBall/components/FormBasicInfo/FormBasicInfo.tsx similarity index 56% rename from src/components/FormBasicInfo/FormBasicInfo.tsx rename to src/pages/publishBall/components/FormBasicInfo/FormBasicInfo.tsx index 176bb23..5e7534d 100644 --- a/src/components/FormBasicInfo/FormBasicInfo.tsx +++ b/src/pages/publishBall/components/FormBasicInfo/FormBasicInfo.tsx @@ -1,33 +1,36 @@ -import React from 'react' +import React, { useState } from 'react' import { View, Text, Input, Image, Picker } from '@tarojs/components' -import { Stadium } from '../SelectStadium' +import PopupGameplay from '../PopupGameplay' import img from '@/config/images'; import './FormBasicInfo.scss' import { FormFieldConfig } from '@/config/formSchema/publishBallFormSchema'; interface FormBasicInfoProps { - fee: string - location: string - gameplay: string - selectedStadium: Stadium | null - onFeeChange: (value: string) => void - onLocationChange: (value: string) => void - onGameplayChange: (value: string) => void - onStadiumSelect: () => void + value: any + onChange: (value: any) => void children: FormFieldConfig[] } const FormBasicInfo: React.FC = ({ - fee, - location, - gameplay, - selectedStadium, - onFeeChange, - onLocationChange, - onGameplayChange, - onStadiumSelect, + value, + onChange, children }) => { + const [gameplayVisible, setGameplayVisible] = useState(false) + + const handleGameplaySelect = () => { + setGameplayVisible(true) + } + + const handleGameplayConfirm = (selectedGameplay: string) => { + onGameplayChange(selectedGameplay) + setGameplayVisible(false) + } + + const handleGameplayClose = () => { + setGameplayVisible(false) + } + const renderChildren = () => { return children.map((child: any, index: number) => { return @@ -43,8 +46,8 @@ const FormBasicInfo: React.FC = ({ placeholder='请输入' placeholderClass='title-placeholder' type='digit' - value={fee} - onInput={(e) => onFeeChange(e.detail.value)} + value={value[child.key]} + onInput={(e) => onChange(child.key, e.detail.value)} /> 元/每人 @@ -53,9 +56,9 @@ const FormBasicInfo: React.FC = ({ { index === 1 && ( {child.label} - - - {selectedStadium ? selectedStadium.name : '请选择'} + {}}> + + {value[child.key] ? value[child.key] : '请选择'} @@ -64,9 +67,9 @@ const FormBasicInfo: React.FC = ({ { index === 2 && ( {child.label} - - - {gameplay ? gameplay : '请选择'} + + + {value[child.key] ? value[child.key] : '请选择'} @@ -78,7 +81,15 @@ const FormBasicInfo: React.FC = ({ return ( {/* 费用 */} - {renderChildren()} + {/* {renderChildren()} */} + + {/* 玩法选择弹窗 */} + {/* */} ) } diff --git a/src/pages/publishBall/components/FormBasicInfo/index.ts b/src/pages/publishBall/components/FormBasicInfo/index.ts new file mode 100644 index 0000000..b545137 --- /dev/null +++ b/src/pages/publishBall/components/FormBasicInfo/index.ts @@ -0,0 +1 @@ +export { default } from './FormBasicInfo' diff --git a/src/pages/publishBall/components/PopupGameplay/PopupGameplay.module.scss b/src/pages/publishBall/components/PopupGameplay/PopupGameplay.module.scss new file mode 100644 index 0000000..7962620 --- /dev/null +++ b/src/pages/publishBall/components/PopupGameplay/PopupGameplay.module.scss @@ -0,0 +1,34 @@ +.optionsList { + padding: 26px 15px 16px 15px; + display: flex; + flex-direction: column; + gap: 6px; + background-color: #fff; +} + +.optionItem { + display: flex; + min-height: 40px; + justify-content: center; + align-items: center; + flex: 1 0 0; + border-radius: 999px; + border: 0.5px solid rgba(0, 0, 0, 0.12); + background: #FFF; +} + + +.optionItem.selected { + border: 0.5px solid rgba(0, 0, 0, 0.06); + color: #fff; + font-size: 14px; + background: #000; + .optionText { + color: #fff; + } +} + +.optionText { + font-size: 14px; + color: #333; +} diff --git a/src/pages/publishBall/components/PopupGameplay/PopupGameplay.tsx b/src/pages/publishBall/components/PopupGameplay/PopupGameplay.tsx new file mode 100644 index 0000000..5bdd5a7 --- /dev/null +++ b/src/pages/publishBall/components/PopupGameplay/PopupGameplay.tsx @@ -0,0 +1,58 @@ +import React, { useState, useEffect } from 'react' +import { View, Text } from '@tarojs/components' +import { CommonPopup } from '../../../../components' +import styles from './PopupGameplay.module.scss' + +interface PopupGameplayProps { + visible: boolean + onClose: () => void + onConfirm: (selectedGameplay: string) => void + selectedGameplay?: string +} + +export default function PopupGameplay({ visible, onClose, onConfirm, selectedGameplay = '不限' }: PopupGameplayProps) { + const [selectedOption, setSelectedOption] = useState(selectedGameplay) + + const options = ['不限', '单打', '双打', '拉球'] + + useEffect(() => { + if (visible && selectedGameplay) { + setSelectedOption(selectedGameplay) + } + }, [visible, selectedGameplay]) + + const handleOptionSelect = (option: string) => { + setSelectedOption(option) + } + + const handleClose = () => { + onClose() + } + + const handleConfirm = () => { + onConfirm(selectedOption) + } + + return ( + + + {options.map((option) => ( + handleOptionSelect(option)} + > + {option} + + ))} + + + ) +} \ No newline at end of file diff --git a/src/pages/publishBall/components/PopupGameplay/index.ts b/src/pages/publishBall/components/PopupGameplay/index.ts new file mode 100644 index 0000000..43948b1 --- /dev/null +++ b/src/pages/publishBall/components/PopupGameplay/index.ts @@ -0,0 +1 @@ +export { default } from './PopupGameplay' diff --git a/src/components/SelectStadium/FLOW.md b/src/pages/publishBall/components/SelectStadium/FLOW.md similarity index 100% rename from src/components/SelectStadium/FLOW.md rename to src/pages/publishBall/components/SelectStadium/FLOW.md diff --git a/src/components/SelectStadium/README.md b/src/pages/publishBall/components/SelectStadium/README.md similarity index 100% rename from src/components/SelectStadium/README.md rename to src/pages/publishBall/components/SelectStadium/README.md diff --git a/src/components/SelectStadium/SelectStadium.scss b/src/pages/publishBall/components/SelectStadium/SelectStadium.scss similarity index 100% rename from src/components/SelectStadium/SelectStadium.scss rename to src/pages/publishBall/components/SelectStadium/SelectStadium.scss diff --git a/src/components/SelectStadium/SelectStadium.tsx b/src/pages/publishBall/components/SelectStadium/SelectStadium.tsx similarity index 99% rename from src/components/SelectStadium/SelectStadium.tsx rename to src/pages/publishBall/components/SelectStadium/SelectStadium.tsx index 119e760..dcc771f 100644 --- a/src/components/SelectStadium/SelectStadium.tsx +++ b/src/pages/publishBall/components/SelectStadium/SelectStadium.tsx @@ -1,9 +1,8 @@ import React, { useState } from 'react' import { View, Text, Input, ScrollView, Image } from '@tarojs/components' -import { Popup } from '@nutui/nutui-react-taro' import Taro from '@tarojs/taro' import StadiumDetail from './StadiumDetail' -import CommonPopup from '../CommonPopup' +import { CommonPopup } from '../../../../components' import './SelectStadium.scss' import images from '@/config/images' diff --git a/src/components/SelectStadium/StadiumDetail.scss b/src/pages/publishBall/components/SelectStadium/StadiumDetail.scss similarity index 100% rename from src/components/SelectStadium/StadiumDetail.scss rename to src/pages/publishBall/components/SelectStadium/StadiumDetail.scss diff --git a/src/components/SelectStadium/StadiumDetail.tsx b/src/pages/publishBall/components/SelectStadium/StadiumDetail.tsx similarity index 100% rename from src/components/SelectStadium/StadiumDetail.tsx rename to src/pages/publishBall/components/SelectStadium/StadiumDetail.tsx diff --git a/src/components/SelectStadium/index.ts b/src/pages/publishBall/components/SelectStadium/index.ts similarity index 100% rename from src/components/SelectStadium/index.ts rename to src/pages/publishBall/components/SelectStadium/index.ts diff --git a/src/pages/publishBall/index.tsx b/src/pages/publishBall/index.tsx index dc7e88d..fb6d2f2 100644 --- a/src/pages/publishBall/index.tsx +++ b/src/pages/publishBall/index.tsx @@ -6,28 +6,52 @@ import PublishForm from './publishForm' import { publishBallFormSchema } from '../../config/formSchema/publishBallFormSchema'; import { PublishBallFormData } from '../../../types/publishBall'; import PublishService from '@/services/publishService'; +import { getNextHourTime, getEndTime } from '@/utils/timeUtils'; import styles from './index.module.scss' import images from '@/config/images' +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: { + current_players: 0, + max_players: 0, + }, + skill_level: { + skill_level_max: 5.0, + skill_level_min: 1.0, + }, + descriptionInfo: { + description: '', + description_tag: [], + }, + is_substitute_supported: false, + is_wechat_contact: false, + wechat_contact: '' +} + const PublishBall: React.FC = () => { const [activityType, setActivityType] = useState('individual') const [formData, setFormData] = useState([ - { - title: '', - timeRange: { - startDate: '2025-11-23', - startTime: '08:00', - endTime: '10:00' - }, - fee: '', - location: '', - gameplay: '', - minParticipants: 1, - maxParticipants: 4, - ntpLevel: [2.0, 4.0], - additionalRequirements: '', - autoDegrade: false - } + defaultFormData ]) // 删除确认弹窗状态 @@ -56,21 +80,12 @@ const PublishBall: React.FC = () => { } const handleAdd = () => { + const newStartTime = getNextHourTime() setFormData(prev => [...prev, { + ...defaultFormData, title: '', - timeRange: { - startDate: '2025-11-23', - startTime: '08:00', - endTime: '10:00' - }, - fee: '', - location: '', - gameplay: '', - minParticipants: 1, - maxParticipants: 4, - ntpLevel: [2.0, 4.0], - additionalRequirements: '', - autoDegrade: false + start_time: newStartTime, + end_time: getEndTime(newStartTime) }]) } diff --git a/src/pages/publishBall/publishForm.tsx b/src/pages/publishBall/publishForm.tsx index cc7e1cc..fa09ab1 100644 --- a/src/pages/publishBall/publishForm.tsx +++ b/src/pages/publishBall/publishForm.tsx @@ -2,8 +2,11 @@ import React, { useState } from 'react' import { View, Text } from '@tarojs/components' import Taro from '@tarojs/taro' -import { ImageUpload, Range, TimeSelector, TextareaTag, SelectStadium, NumberInterval, TitleInput, FormBasicInfo, FormSwitch } from '../../components' -import { type Stadium, type CoverImage } from '../../components/index.types' +import { ImageUpload, Range, TimeSelector, TextareaTag, NumberInterval, TitleTextarea, FormSwitch } from '../../components' +import { SelectStadium } from './components/SelectStadium' +import FormBasicInfo from './components/FormBasicInfo' +import { type CoverImage } from '../../components/index.types' +import { Stadium } from './components/SelectStadium' import { FormFieldConfig, FieldType } from '../../config/formSchema/publishBallFormSchema' import { PublishBallFormData } from '../../../types/publishBall'; @@ -11,7 +14,7 @@ import styles from './index.module.scss' // 组件映射器 const componentMap = { - [FieldType.TEXT]: TitleInput, + [FieldType.TEXT]: TitleTextarea, [FieldType.TIMEINTERVAL]: TimeSelector, [FieldType.RANGE]: Range, [FieldType.TEXTAREATAG]: TextareaTag, @@ -95,7 +98,7 @@ const PublishForm: React.FC<{ const Component = componentMap[item.type] const optionProps = { ...item.props, - ...(item.key === 'additionalRequirements' ? { options: item.options } : {}), + ...(item.type === FieldType.TEXTAREATAG ? { options: item.options } : {}), ...(item.props?.className ? { className: styles[item.props.className] } : {}) } console.log(item.props?.className) @@ -119,16 +122,11 @@ const PublishForm: React.FC<{ {/* 费用地点玩法区域 - 合并白色块 */} - updateFormData('fee', value)} - onLocationChange={(value) => updateFormData('location', value)} - onGameplayChange={(value) => updateFormData('gameplay', value)} - onStadiumSelect={() => setShowStadiumSelector(true)} + value={formData[item.key]} + onChange={(value) => updateFormData(item.key as keyof PublishBallFormData, value)} + {...optionProps} /> diff --git a/src/utils/timeUtils.ts b/src/utils/timeUtils.ts new file mode 100644 index 0000000..afdeca0 --- /dev/null +++ b/src/utils/timeUtils.ts @@ -0,0 +1,44 @@ +import dayjs from 'dayjs' + +/** + * 获取下一个整点时间 + * @returns 格式为 YYYY-MM-DD HH:mm 的字符串 + */ +export const getNextHourTime = (): string => { + const now = dayjs() + const nextHour = now.add(1, 'hour').startOf('hour') + return nextHour.format('YYYY-MM-DD HH:mm') +} + +/** + * 根据开始时间计算结束时间(2小时后) + * @param startTime 开始时间,格式为 YYYY-MM-DD HH:mm + * @returns 格式为 YYYY-MM-DD HH:mm 的字符串 + */ +export const getEndTime = (startTime: string): string => { + const startDateTime = dayjs(startTime) + const endDateTime = startDateTime.add(2, 'hour') + return endDateTime.format('YYYY-MM-DD HH:mm') +} + + +export const getDate = (date: string): string => { + return dayjs(date).format('YYYY年MM月DD日') +} + +export const getTime = (time: string): string => { + const timeObj = dayjs(time) + const hour = timeObj.hour() + const minute = timeObj.minute() + + // 判断是上午还是下午 + const period = hour < 12 ? 'AM' : 'PM' + + // 转换为12小时制 + const hour12 = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour + + // 格式化分钟,保证两位数 + const minuteStr = minute.toString().padStart(2, '0') + + return `${hour12}:${minuteStr} ${period}` +} \ No newline at end of file diff --git a/types/publishBall.ts b/types/publishBall.ts index 578322b..d03f3e7 100644 --- a/types/publishBall.ts +++ b/types/publishBall.ts @@ -1,15 +1,38 @@ -import { TimeRange } from "@/components/index.types" - export interface PublishBallFormData { - title: string - timeRange: TimeRange - fee: string - location: string - gameplay: string - minParticipants: number - maxParticipants: number - ntpLevel: number[] - additionalRequirements: string - autoDegrade: boolean + title: string // 球局标题 + image_list: Array[] // 球局封面 + timeRange: { + start_time: string, + end_time: string + } + activityInfo: { + play_type: string // 玩法类型 + price: number | string // 价格 + venue_id?: number | null // 场地id + location_name?: string // 场地名称 + location?: string // 场地地址 + latitude?: string // 纬度 + longitude?: string // 经度 + court_type?: string // 场地类型 1: 室内 2: 室外 + court_surface?: string // 场地表面 1: 硬地 2: 红土 3: 草地 + venue_description_tag?: Array[] // 场地描述标签 + venue_description?: string // 场地描述 + venue_image_list?: Array[] // 场地图片 + } + players:{ + current_players: number // 当前人数 + max_players: number // 最大人数 + } + skill_level: { + skill_level_max: number // 最高水平要求(NTRP) + skill_level_min: number //最低水平要求(NTRP) + } + descriptionInfo: { + description: string // 备注 + description_tag: Array[] // 备注标签 + } + is_substitute_supported: boolean // 是否支持替补 + is_wechat_contact: boolean // 是否需要微信联系 + wechat_contact: string // 微信联系 } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index b87f811..b4fcd75 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4099,6 +4099,11 @@ data-view-byte-offset@^1.0.1: es-errors "^1.3.0" is-data-view "^1.0.1" +dayjs@^1.11.13: + version "1.11.13" + resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" + integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== + debug@2.6.9: version "2.6.9" resolved "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"