合并代码
This commit is contained in:
@@ -5,6 +5,7 @@ import Taro from '@tarojs/taro'
|
||||
// 导入API服务
|
||||
import demoApi from '../../services/demoApi'
|
||||
import commonApi from '../../services/commonApi'
|
||||
import PublishMenu from '../../components/PublishMenu'
|
||||
import {
|
||||
useUserStats,
|
||||
useUserActions
|
||||
@@ -286,6 +287,13 @@ function Index() {
|
||||
<Text className='tip-item'>• 请求失败时会自动使用模拟数据</Text>
|
||||
</View>
|
||||
</View>
|
||||
<PublishMenu
|
||||
onPersonalPublish={() => {
|
||||
Taro.navigateTo({
|
||||
url: '/pages/publishBall/index'
|
||||
})
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
// import MapPlugin from "src/components/MapDisplay/mapPlugin";
|
||||
import MapDisplay from "src/components/MapDisplay";
|
||||
export default function MapDisplayPage() {
|
||||
return <MapDisplay />
|
||||
}
|
||||
@@ -13,7 +13,7 @@ export interface Stadium {
|
||||
id?: string
|
||||
name: string
|
||||
address?: string
|
||||
istance?: string
|
||||
distance_km?: number | null | undefined
|
||||
longitude?: number
|
||||
latitude?: number
|
||||
}
|
||||
@@ -78,6 +78,15 @@ const SelectStadium: React.FC<SelectStadiumProps> = ({
|
||||
setShowDetail(true)
|
||||
}
|
||||
|
||||
const calculateDistance = (stadium: Stadium) => {
|
||||
const distance_km = stadium.distance_km
|
||||
if (!distance_km) return ''
|
||||
if (distance_km && distance_km > 1) {
|
||||
return distance_km.toFixed(1) + 'km'
|
||||
}
|
||||
return (distance_km * 1000).toFixed(0) + 'm'
|
||||
}
|
||||
|
||||
|
||||
// 处理搜索框输入
|
||||
const handleSearchInput = (e: any) => {
|
||||
@@ -253,7 +262,7 @@ const SelectStadium: React.FC<SelectStadiumProps> = ({
|
||||
handleItemLocation(stadium)
|
||||
}}
|
||||
>
|
||||
{stadium.istance} ·
|
||||
{calculateDistance(stadium)} ·
|
||||
</Text>
|
||||
<Text
|
||||
className='stadium-address-text'
|
||||
|
||||
@@ -13,7 +13,7 @@ export interface Stadium {
|
||||
address?: string
|
||||
longitude?: number
|
||||
latitude?: number
|
||||
istance?: string
|
||||
distance_km?: number | null
|
||||
court_type?: string
|
||||
court_surface?: string
|
||||
description?: string
|
||||
@@ -99,7 +99,7 @@ const StadiumDetail = forwardRef<StadiumDetailRef, StadiumDetailProps>(({
|
||||
address: stadium.address,
|
||||
latitude: stadium.longitude,
|
||||
longitude: stadium.latitude,
|
||||
istance: stadium.istance,
|
||||
istance: stadium.distance_km,
|
||||
court_type: court_type[0] || '',
|
||||
court_surface: court_surface[0] || '',
|
||||
additionalInfo: '',
|
||||
@@ -116,6 +116,13 @@ const StadiumDetail = forwardRef<StadiumDetailRef, StadiumDetailProps>(({
|
||||
setFormData: (data: any) => setFormData(data)
|
||||
}), [formData, stadium])
|
||||
|
||||
const calculateDistance = (distance_km: number | null) => {
|
||||
if (!distance_km) return ''
|
||||
if (distance_km && distance_km > 1) {
|
||||
return distance_km.toFixed(1) + 'km'
|
||||
}
|
||||
return (distance_km * 1000).toFixed(0) + 'm'
|
||||
}
|
||||
|
||||
|
||||
const handleMapLocation = () => {
|
||||
@@ -127,7 +134,8 @@ const StadiumDetail = forwardRef<StadiumDetailRef, StadiumDetailProps>(({
|
||||
name: res.name,
|
||||
address: res.address,
|
||||
latitude: res.longitude,
|
||||
longitude: res.latitude
|
||||
longitude: res.latitude,
|
||||
istance: null
|
||||
})
|
||||
},
|
||||
fail: (err) => {
|
||||
@@ -165,7 +173,7 @@ const StadiumDetail = forwardRef<StadiumDetailRef, StadiumDetailProps>(({
|
||||
<View className='stadium-item-right'>
|
||||
<View className='stadium-name'>{formData.name}</View>
|
||||
<View className='stadium-address'>
|
||||
<Text>{formData.istance} · </Text>
|
||||
<Text>{calculateDistance(formData.istance || null)} · </Text>
|
||||
<Text>{formData.address}</Text>
|
||||
<Image src={images.ICON_ARRORW_SMALL} className='stadium-map-icon' />
|
||||
</View>
|
||||
|
||||
@@ -25,7 +25,8 @@
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
color: rgba(60, 60, 67, 0.50);
|
||||
|
||||
font-size: 14px;
|
||||
|
||||
&-icon{
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
@@ -230,74 +231,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 删除确认弹窗
|
||||
.delete-modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 10000;
|
||||
|
||||
&__content {
|
||||
background: white;
|
||||
border-radius: 16px;
|
||||
padding: 24px;
|
||||
margin: 0 32px;
|
||||
max-width: 320px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__title {
|
||||
display: block;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: theme.$primary-color;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
&__desc {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
color: rgba(60, 60, 67, 0.6);
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
&__actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
|
||||
.delete-modal__btn {
|
||||
flex: 1;
|
||||
height: 44px;
|
||||
border-radius: 12px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:first-child {
|
||||
background: rgba(0, 0, 0, 0.04);
|
||||
color: rgba(60, 60, 67, 0.8);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
background: #FF3B30;
|
||||
color: white;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 旋转动画
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import React, { useState } from 'react'
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import { View, Text, Button, Image } from '@tarojs/components'
|
||||
import Taro from '@tarojs/taro'
|
||||
import ActivityTypeSwitch, { type ActivityType } from '../../components/ActivityTypeSwitch'
|
||||
import { type ActivityType } from '../../components/ActivityTypeSwitch'
|
||||
// import ActivityTypeSwitch, { type ActivityType } from '../../components/ActivityTypeSwitch'
|
||||
import CommonDialog from '../../components/CommonDialog'
|
||||
import PublishForm from './publishForm'
|
||||
import { publishBallFormSchema } from '../../config/formSchema/publishBallFormSchema';
|
||||
import { PublishBallFormData } from '../../../types/publishBall';
|
||||
@@ -44,6 +46,29 @@ const defaultFormData: PublishBallFormData = {
|
||||
|
||||
const PublishBall: React.FC = () => {
|
||||
const [activityType, setActivityType] = useState<ActivityType>('individual')
|
||||
|
||||
// 获取页面参数并设置导航标题
|
||||
useEffect(() => {
|
||||
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)
|
||||
// 根据type设置导航标题
|
||||
if (type === 'group') {
|
||||
Taro.setNavigationBarTitle({
|
||||
title: '发布畅打活动'
|
||||
})
|
||||
} else {
|
||||
Taro.setNavigationBarTitle({
|
||||
title: '发布'
|
||||
})
|
||||
}
|
||||
}
|
||||
handleActivityTypeChange(type)
|
||||
}
|
||||
}, [])
|
||||
const [formData, setFormData] = useState<PublishBallFormData[]>([
|
||||
defaultFormData
|
||||
])
|
||||
@@ -69,10 +94,13 @@ const PublishBall: React.FC = () => {
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 处理活动类型变化
|
||||
const handleActivityTypeChange = (type: ActivityType) => {
|
||||
setActivityType(type)
|
||||
if (type === 'group') {
|
||||
setFormData([defaultFormData])
|
||||
} else {
|
||||
setFormData([defaultFormData])
|
||||
}
|
||||
}
|
||||
|
||||
const handleAdd = () => {
|
||||
@@ -80,8 +108,10 @@ const PublishBall: React.FC = () => {
|
||||
setFormData(prev => [...prev, {
|
||||
...defaultFormData,
|
||||
title: '',
|
||||
start_time: newStartTime,
|
||||
end_time: getEndTime(newStartTime)
|
||||
timeRange: {
|
||||
start_time: newStartTime,
|
||||
end_time: getEndTime(newStartTime)
|
||||
}
|
||||
}])
|
||||
}
|
||||
|
||||
@@ -131,7 +161,7 @@ const PublishBall: React.FC = () => {
|
||||
const validateFormData = (formData: PublishBallFormData) => {
|
||||
const { activityInfo, image_list, title } = formData;
|
||||
const { play_type, price, location_name } = activityInfo;
|
||||
if (!image_list.length) {
|
||||
if (!image_list?.length) {
|
||||
Taro.showToast({
|
||||
title: `请上传活动封面`,
|
||||
icon: 'none'
|
||||
@@ -145,21 +175,21 @@ const PublishBall: React.FC = () => {
|
||||
})
|
||||
return false
|
||||
}
|
||||
if (!price) {
|
||||
if (!price || (typeof price === 'number' && price <= 0) || (typeof price === 'string' && !price.trim())) {
|
||||
Taro.showToast({
|
||||
title: `请输入费用`,
|
||||
icon: 'none'
|
||||
})
|
||||
return false
|
||||
}
|
||||
if (!play_type) {
|
||||
if (!play_type || !play_type.trim()) {
|
||||
Taro.showToast({
|
||||
title: `请选择玩法类型`,
|
||||
icon: 'none'
|
||||
})
|
||||
return false
|
||||
}
|
||||
if (!location_name) {
|
||||
if (!location_name || !location_name.trim()) {
|
||||
Taro.showToast({
|
||||
title: `请选择场地`,
|
||||
icon: 'none'
|
||||
@@ -202,16 +232,46 @@ const PublishBall: React.FC = () => {
|
||||
})
|
||||
}
|
||||
}
|
||||
if (activityType === 'group') {
|
||||
const isValid = formData.every(item => validateFormData(item))
|
||||
if (!isValid) {
|
||||
return
|
||||
}
|
||||
formData.forEach(async (item) => {
|
||||
const { activityInfo, descriptionInfo, timeRange, players, skill_level, ...rest } = item;
|
||||
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]
|
||||
}
|
||||
const res = await PublishService.create_play_pmoothly(options);
|
||||
if (res.code === 0 && res.data) {
|
||||
Taro.showToast({
|
||||
title: '发布成功',
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
console.log(formData, 'formData');
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<View className={styles['publish-ball']}>
|
||||
{/* 活动类型切换 */}
|
||||
<View className={styles['activity-type-switch']}>
|
||||
<ActivityTypeSwitch
|
||||
{/* <ActivityTypeSwitch
|
||||
value={activityType}
|
||||
onChange={handleActivityTypeChange}
|
||||
/>
|
||||
/> */}
|
||||
</View>
|
||||
|
||||
<View className={styles['publish-ball__scroll']}>
|
||||
@@ -263,28 +323,15 @@ const PublishBall: React.FC = () => {
|
||||
</View>
|
||||
|
||||
{/* 删除确认弹窗 */}
|
||||
{deleteConfirm.visible && (
|
||||
<View className={styles['delete-modal']}>
|
||||
<View className={styles['delete-modal__content']}>
|
||||
<Text className={styles['delete-modal__title']}>确认移除该场次?</Text>
|
||||
<Text className={styles['delete-modal__desc']}>该操作不可恢复</Text>
|
||||
<View className={styles['delete-modal__actions']}>
|
||||
<Button
|
||||
className={styles['delete-modal__btn']}
|
||||
onClick={closeDeleteConfirm}
|
||||
>
|
||||
再想想
|
||||
</Button>
|
||||
<Button
|
||||
className={styles['delete-modal__btn']}
|
||||
onClick={confirmDelete}
|
||||
>
|
||||
确认移除
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
<CommonDialog
|
||||
visible={deleteConfirm.visible}
|
||||
cancelText="再想想"
|
||||
confirmText="确认移除"
|
||||
onCancel={closeDeleteConfirm}
|
||||
onConfirm={confirmDelete}
|
||||
contentTitle="确认移除该场次?"
|
||||
contentDesc="该操作不可恢复"
|
||||
/>
|
||||
|
||||
{/* 完成按钮 */}
|
||||
<View className={styles['submit-section']}>
|
||||
|
||||
@@ -84,8 +84,36 @@ const PublishForm: React.FC<{
|
||||
})
|
||||
}
|
||||
|
||||
const getNTRPText = (ntrp: [number, number]) => {
|
||||
const [min, max] = ntrp
|
||||
if (min === 1.0 && max === 5.0) {
|
||||
return '不限'
|
||||
}
|
||||
if (min === 5.0 && max === 5.0) {
|
||||
return '5.0 及以上'
|
||||
}
|
||||
if (min === 1.0 && max === 1.0) {
|
||||
return `${min.toFixed(1)}`
|
||||
}
|
||||
if (min > 1.0 && max === 5.0) {
|
||||
return `${min.toFixed(1)} 以上`
|
||||
}
|
||||
if (min === 1.0 && max < 5.0) {
|
||||
return `${max.toFixed(1)} 以下`
|
||||
}
|
||||
if (min > 1.0 && max < 5.0) {
|
||||
return `${min.toFixed(1)} - ${max.toFixed(1)}之间`
|
||||
}
|
||||
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
const renderSummary = (item: FormFieldConfig) => {
|
||||
if (item.props?.showSummary) {
|
||||
if (item.prop === 'skill_level') {
|
||||
return <Text className={styles['section-summary']}>{getNTRPText(formData.skill_level)}</Text>
|
||||
}
|
||||
return <Text className={styles['section-summary']}>{item.props?.summary}</Text>
|
||||
}
|
||||
return null
|
||||
|
||||
Reference in New Issue
Block a user