feat: 分包

This commit is contained in:
2025-09-12 16:28:46 +08:00
parent 19701bd246
commit ee0b5763de
39 changed files with 75 additions and 64 deletions

View File

@@ -0,0 +1,92 @@
@use '~@/scss/images.scss' as img;
@use '~@/scss/themeColor.scss' as theme;
// FormBasicInfo 组件样式
.form-basic-info{
background: white;
border-radius: 16px;
width: 100%;
// 费用项目
.form-item {
display: flex;
align-items: center;
justify-content: space-between;
height: 44px;
padding-left: 12px;
&:last-child{
.form-wrapper{
border-bottom: none;
}
}
.form-label {
display: flex;
align-items: center;
font-size: 14px;
padding-right: 14px;
.lable-icon {
width: 16px;
height: 16px;
}
text {
font-size: 16px;
color: #333;
font-weight: 500;
}
}
.form-wrapper{
display: flex;
justify-content: space-between;
flex: 1;
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
align-items: center;
.form-item-label{
display: flex;
}
.form-right-wrapper{
display: flex;
padding-right: 12px;
height: 44px;
line-height: 44px;
align-items: center;
.title-placeholder{
font-size: 14px;
color: theme.$textarea-placeholder-color;
font-weight: 400;
}
.h5-input{
font-size: 14px;
color: #333;
font-weight: 500;
width: 50px;
text-align: right;
margin-right: 8px;
}
.unit{
font-size: 14px;
color: theme.$primary-color;
}
.right-text{
color: theme.$textarea-placeholder-color;
font-size: 14px;
padding-right: 8px;
width: 200px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
text-align: right;
&.selected{
color: #000;
}
}
.arrow{
width: 16px;
height: 16px;
margin-left: 4px;
}
}
}
}
}

View File

@@ -0,0 +1,195 @@
import React, { useState, useCallback, useEffect } from 'react'
import { View, Text, Input, Image } from '@tarojs/components'
import PopupGameplay from '../PopupGameplay'
import img from '@/config/images';
import { FormFieldConfig } from '@/config/formSchema/publishBallFormSchema';
import SelectStadium from '../SelectStadium/SelectStadium'
import { Stadium } from '../SelectStadium/StadiumDetail'
import './FormBasicInfo.scss'
type PlayGame = {
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<string>[] // 场地描述标签
venue_description?: string // 场地描述
venue_image_list?: Array<string>[] // 场地图片
}
interface FormBasicInfoProps {
value: PlayGame
onChange: (value: any) => void
children: FormFieldConfig[]
}
const FormBasicInfo: React.FC<FormBasicInfoProps> = ({
value,
onChange,
children
}) => {
const [gameplayVisible, setGameplayVisible] = useState(false)
const [showStadiumSelector, setShowStadiumSelector] = useState(false)
const [playGame, setPlayGame] = useState<{label: string, value: string }[]>([])
const handleGameplaySelect = () => {
setGameplayVisible(true)
}
const handleGameplayConfirm = (selectedGameplay: string) => {
onChange({...value, [children[2].prop]: selectedGameplay})
setGameplayVisible(false)
}
const handleGameplayClose = () => {
setGameplayVisible(false)
}
// 处理场馆选择
const handleStadiumSelect = (stadium: Stadium | null) => {
console.log(stadium,'stadiumstadium');
const { address, name, latitude, longitude, court_type, court_surface, description, description_tag, venue_image_list} = stadium || {};
onChange({...value,
venue_id: stadium?.id,
location_name: name,
location: address,
latitude,
longitude,
court_type,
court_surface,
venue_description: description,
venue_description_tag: description_tag,
venue_image_list
})
setShowStadiumSelector(false)
}
const handleChange = useCallback((key: string, costValue: any) => {
// 价格输入限制¥0.009999.99
console.log(costValue, 'valuevalue');
if (key === children[0]?.prop) {
// 允许清空
if (costValue === '') {
onChange({...value, [key]: ''});
return;
}
// 只允许数字和一个小数点
const filteredValue = costValue.replace(/[^\d.]/g, '');
// 确保只有一个小数点
const parts = filteredValue.split('.');
if (parts.length > 2) {
return; // 不更新,保持原值
}
// 限制小数点后最多2位
if (parts.length === 2 && parts[1].length > 2) {
return; // 不更新,保持原值
}
const numValue = parseFloat(filteredValue);
if (isNaN(numValue)) {
onChange({...value, [key]: ''});
return;
}
if (numValue < 0) {
onChange({...value, [key]: '0'});
return;
}
if (numValue > 9999.99) {
onChange({...value, [key]: '9999.99'});
return;
}
// 使用过滤后的值
onChange({...value, [key]: filteredValue});
return;
}
onChange({...value, [key]: costValue})
}, [onChange, children])
useEffect(() => {
if (children.length > 2) {
const options = children[2]?.options || [];
setPlayGame(options)
}
}, [children])
useEffect(() => {
console.log(value, 'valuevalue');
}, [value])
const renderChildren = () => {
return children.map((child: any, index: number) => {
return <View className='form-item'>
<View className='form-label'>
<Image className='lable-icon' src={img[child.iconType]} />
</View>
{
index === 0 && (<View className='form-wrapper'>
<Text className='form-item-label'>{child.label}</Text>
<View className='form-right-wrapper'>
<Input
className='fee-input'
placeholder='请输入'
placeholderClass='title-placeholder'
type='digit'
maxlength={7}
value={value[child.prop]}
onInput={(e) => handleChange(child.prop, e.detail.value)}
/>
<Text className='unit'>/</Text>
</View>
</View>)
}
{
index === 1 && (<View className='form-wrapper'>
<Text className='form-item-label'>{child.label}</Text>
<View className='form-right-wrapper' onClick={() => setShowStadiumSelector(true)}>
<Text className={`right-text ${value[child.prop] ? 'selected' : ''}`}>
{value[child.prop] ? value[child.prop] : '请选择'}
</Text>
<Image src={img.ICON_ARROW_RIGHT} className='arrow'/>
</View>
</View>)
}
{
index === 2 && ( <View className='form-wrapper'>
<Text className='form-item-label'>{child.label}</Text>
<View className='form-right-wrapper' onClick={handleGameplaySelect}>
<Text className={`right-text ${value[child.prop] ? 'selected' : ''}`}>
{value[child.prop] ? value[child.prop] : '请选择'}
</Text>
<Image src={img.ICON_ARROW_RIGHT} className='arrow'/>
</View>
</View>)
}
</View>
})
}
return (
<View className='form-basic-info'>
{/* 费用 */}
{renderChildren()}
{/* 玩法选择弹窗 */}
<PopupGameplay
visible={gameplayVisible}
onClose={handleGameplayClose}
onConfirm={handleGameplayConfirm}
value={value[children[2].prop]}
options={playGame}
/>
{/* 场馆选择弹窗 */}
<SelectStadium
visible={showStadiumSelector}
onClose={() => setShowStadiumSelector(false)}
onConfirm={handleStadiumSelect}
/>
</View>
)
}
export default FormBasicInfo

View File

@@ -0,0 +1 @@
export { default } from './FormBasicInfo'