From e5176f4f5f57d95903297701c9ed3763fbc9adda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=AD=B1=E9=87=8E?= Date: Thu, 21 Aug 2025 23:00:21 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=9C=B0=E7=82=B9=E9=80=89?= =?UTF-8?q?=E6=8B=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/CommonPopup/CommonPopup.tsx | 2 +- src/components/CommonPopup/index.module.scss | 23 ++- src/components/FormSwitch/FormSwitch.tsx | 10 +- src/components/FormSwitch/index.scss | 8 +- .../SelectStadium/SelectStadium.scss | 171 ++++++++++------- .../SelectStadium/SelectStadium.tsx | 118 +++++++++--- .../SelectStadium/StadiumDetail.scss | 71 ++++--- .../SelectStadium/StadiumDetail.tsx | 181 ++++++++++++------ src/components/TextareaTag/TextareaTag.scss | 6 +- src/components/TextareaTag/TextareaTag.tsx | 27 +-- .../formSchema/publishBallFormSchema.ts | 7 +- src/config/images.js | 5 + ...n-arror-small.svg => icon-arrow-small.svg} | 0 13 files changed, 406 insertions(+), 223 deletions(-) rename src/static/publishBall/{icon-arror-small.svg => icon-arrow-small.svg} (100%) diff --git a/src/components/CommonPopup/CommonPopup.tsx b/src/components/CommonPopup/CommonPopup.tsx index e3f75ef..a8dbeef 100644 --- a/src/components/CommonPopup/CommonPopup.tsx +++ b/src/components/CommonPopup/CommonPopup.tsx @@ -25,7 +25,7 @@ const CommonPopup: React.FC = ({ onClose, className, title, - showHeader = true, + showHeader = false, hideFooter = false, cancelText = '返回', confirmText = '完成', diff --git a/src/components/CommonPopup/index.module.scss b/src/components/CommonPopup/index.module.scss index 0b38b73..bc5b33b 100644 --- a/src/components/CommonPopup/index.module.scss +++ b/src/components/CommonPopup/index.module.scss @@ -3,7 +3,7 @@ .common-popup { padding: 0; box-sizing: border-box; - max-height: 80vh; + max-height: calc(100vh - 10px); display: flex; flex-direction: column; background-color: theme.$page-background-color; @@ -20,17 +20,18 @@ } .common-popup__body { - padding: 16px; overflow: auto; -webkit-overflow-scrolling: touch; flex: 1 1 auto; } .common-popup__footer { - padding: 12px 16px; + padding: 8px 10px 0 10px; display: flex; - gap: 12px; - border-top: 1px solid #f0f1f5; + gap: 8px; + background: #FFF; + padding-bottom: env(safe-area-inset-bottom); + } .common-popup__btn { @@ -41,9 +42,21 @@ background: #f5f6f7; color: #1f2329; border: none; + width: 154px; + height: 36px; + border-radius: 12px; + border: 0.5px solid rgba(0, 0, 0, 0.06); + background: #fff; + padding: 4px 10px; } .common-popup__btn-confirm { /* 使用按钮组件的 primary 样式 */ + width: 154px; + height: 36px; + border: 0.5px solid rgba(0, 0, 0, 0.06); + background: #000; + border-radius: 12px; + padding: 4px 10px; } } \ No newline at end of file diff --git a/src/components/FormSwitch/FormSwitch.tsx b/src/components/FormSwitch/FormSwitch.tsx index 65953e6..fdf9cd8 100644 --- a/src/components/FormSwitch/FormSwitch.tsx +++ b/src/components/FormSwitch/FormSwitch.tsx @@ -26,6 +26,11 @@ const FormSwitch: React.FC = ({ value, onChange, subTitle, info {showTip && setShowTip(false)} />} + {subTitle} { @@ -43,11 +48,6 @@ const FormSwitch: React.FC = ({ value, onChange, subTitle, info ) } - diff --git a/src/components/FormSwitch/index.scss b/src/components/FormSwitch/index.scss index 9e50057..d6f2e73 100644 --- a/src/components/FormSwitch/index.scss +++ b/src/components/FormSwitch/index.scss @@ -8,8 +8,8 @@ .auto-degrade-item { display: flex; align-items: center; - justify-content: space-between; width: 100%; + gap: 8px; .auto-degrade-content { display: flex; align-items: center; @@ -62,10 +62,8 @@ } .auto-degrade-checkbox { - .nut-checkbox-icon { - width: 14px; - height: 14px; - } + width: 18px; + height: 18px; } } } diff --git a/src/components/SelectStadium/SelectStadium.scss b/src/components/SelectStadium/SelectStadium.scss index 47405e3..90c9292 100644 --- a/src/components/SelectStadium/SelectStadium.scss +++ b/src/components/SelectStadium/SelectStadium.scss @@ -1,17 +1,8 @@ -.select-stadium-popup { - .nut-popup { - max-height: 85vh; - overflow: hidden; - - .nut-popup__content { - overflow: hidden; - } - } -} + .select-stadium { width: 100%; - height: 85vh; + height: calc(100vh - 10px); background: #f5f5f5; display: flex; flex-direction: column; @@ -21,19 +12,46 @@ // 搜索区域 .search-section { background: #f5f5f5; - padding: 16px; + padding: 26px 15px 0px 15px; .search-wrapper { - background: white; - border-radius: 12px; - padding: 12px 16px; display: flex; align-items: center; gap: 8px; - .search-icon { + .search-bar { font-size: 16px; - color: #999; + display: flex; + height: 44px; + padding: 0 12px; + align-items: center; + gap: 10px; + flex: 1; + border-radius: 999px; + border: 0.5px solid rgba(0, 0, 0, 0.06); + background: #FFF; + box-shadow: 0 4px 48px 0 rgba(0, 0, 0, 0.08); + .search-icon { + width: 20px; + height: 20px; + } + + .clear-btn { + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + border-radius: 50%; + cursor: pointer; + &:active { + background: rgba(0, 0, 0, 0.04); + } + .clear-icon { + width: 20px; + height: 20px; + } + } } .search-input { @@ -43,26 +61,32 @@ border: none; outline: none; background: transparent; + .search-placeholder{ + color: rgba(60, 60, 67, 0.60); + } } .map-btn { - width: 32px; - height: 32px; - border-radius: 16px; - background: #f0f8ff; display: flex; + height: 44px; + padding: 0 12px; align-items: center; - justify-content: center; - cursor: pointer; - transition: background-color 0.2s; - + gap: 2px; + border-radius: 999px; + border: 0.5px solid rgba(0, 0, 0, 0.06); + background: #FFF; + box-shadow: 0 4px 48px 0 rgba(0, 0, 0, 0.08); + box-sizing: border-box; &:active { background: #e0f0ff; } - .map-icon { + width: 20px; + height: 20px; + } + .map-text { font-size: 16px; - color: #007AFF; + color: #000; } } } @@ -70,34 +94,42 @@ // 热门球场区域 .hot-section { - background: #f5f5f5; - padding: 0 16px 16px 16px; + padding: 23px 20px 10px 20px; .hot-header { display: flex; align-items: center; - gap: 30px; .hot-title { font-size: 16px; font-weight: 600; - color: #333; + color: #000; + } + .hot-stadium-line{ + height: 6px; + width: 1px; + background: rgba(22, 24, 35, 0.12); + margin: 0 12px;; } .booking-section { display: flex; align-items: center; - gap: 8px; + color: rgba(0, 0, 0, 0.50); + gap: 4px; .booking-title { - font-size: 16px; - font-weight: 600; - color: #333; + font-size: 15px; } .booking-status { - font-size: 12px; - color: #999; + display: flex; + padding: 2px 5px; + align-items: center; + gap: 4px; + border-radius: 999px; + border: 0.5px solid rgba(0, 0, 0, 0.16); + background: #FFF; } } } @@ -107,44 +139,51 @@ .stadium-list { flex: 1; width: auto; - padding: 0 16px; overflow-y: auto; -webkit-overflow-scrolling: touch; .stadium-item { - border-radius: 20px; - height: 40px; - margin-bottom: 6px; + padding: 16px 20px; display: flex; align-items: center; - justify-content: center; - color: #000; position: relative; - border: 1px solid rgba(0, 0, 0, 0.12); - &:last-child { - margin-bottom: 0; - } - - &.selected { - background: #f0f8ff; - - &::after { - content: '✓'; - position: absolute; - right: 16px; - top: 50%; - transform: translateY(-50%); - color: #007AFF; - font-size: 16px; - font-weight: bold; + gap: 12px; + .stadium-item-left{ + display: flex; + padding: 14px; + justify-content: center; + align-items: center; + border-radius: 12px; + border: 0.5px solid rgba(0, 0, 0, 0.08); + background: rgba(0, 0, 0, 0.06); + .stadium-icon{ + width: 20px; + height: 20px; } } - - .stadium-name { - font-size: 16px; - color: #333; - line-height: 1.4; - padding-right: 30px; + .stadium-item-right{ + flex: 1; + display: flex; + flex-direction: column; + gap: 4px; + .stadium-name{ + font-size: 16px; + color: #000; + font-weight: 600; + line-height: 24px; + display: flex; + } + .stadium-address{ + display: flex; + align-items: center; + gap: 4px; + color: rgba(0, 0, 0, 0.80); + font-size: 12px; + } + .stadium-map-icon{ + width: 10px; + height: 10px; + } } } } diff --git a/src/components/SelectStadium/SelectStadium.tsx b/src/components/SelectStadium/SelectStadium.tsx index f61dbe3..ed08bc6 100644 --- a/src/components/SelectStadium/SelectStadium.tsx +++ b/src/components/SelectStadium/SelectStadium.tsx @@ -1,15 +1,19 @@ import React, { useState } from 'react' -import { View, Text, Input, ScrollView } from '@tarojs/components' +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 './SelectStadium.scss' +import images from '@/config/images' export interface Stadium { - id: string + id?: string name: string address?: string + istance?: string + longitude?: number + latitude?: number } interface SelectStadiumProps { @@ -19,15 +23,15 @@ interface SelectStadiumProps { } const stadiumList: Stadium[] = [ - { id: '1', name: '静安网球馆', address: '静安区' }, - { id: '2', name: '芦湾体育馆', address: '芦湾区' }, - { id: '3', name: '静安网球馆', address: '静安区' }, - { id: '4', name: '徐汇游泳中心', address: '徐汇区' }, - { id: '5', name: '汇龙新城小区', address: '新城区' }, - { id: '6', name: '翠湖御苑小区', address: '翠湖区' }, - { id: '7', name: '仁恒河滨花园网球场', address: '浦东新区' }, - { id: '8', name: 'Our Tennis 东江球场', address: '浦东新区' }, - { id: '9', name: '上海琦梦网球俱乐部', address: '浦东新区' } + { id: '1', name: '静安网球馆', address: '浦东新区东园路18号', istance: '100米' , longitude: 121.4367, latitude: 31.2304}, + { id: '2', name: '芦湾体育馆', address: '浦东新区东园路18号', istance: '100米' , longitude: 121.4367, latitude: 31.2304 }, + { id: '3', name: '静安网球馆', address: '浦东新区东园路18号', istance: '100米' , longitude: 121.4367, latitude: 31.2304 }, + { id: '4', name: '徐汇游泳中心', address: '浦东新区东园路18号', istance: '100米' , longitude: 121.4367, latitude: 31.2304 }, + { id: '5', name: '汇龙新城小区', address: '浦东新区东园路18号', istance: '100米' , longitude: 121.4367, latitude: 31.2304 }, + { id: '6', name: '翠湖御苑小区', address: '浦东新区东园路18号', istance: '100米' , longitude: 121.4367, latitude: 31.2304 }, + { id: '7', name: '仁恒河滨花园网球场', address: '浦东新区东园路18号', istance: '100米' , longitude: 121.4367, latitude: 31.2304 }, + { id: '8', name: 'Our Tennis 东江球场', address: '浦东新区东园路18号', istance: '100米' , longitude: 121.4367, latitude: 31.2304 }, + { id: '9', name: '上海琦梦网球俱乐部', address: '浦东新区东园路18号', istance: '100米' , longitude: 121.4367, latitude: 31.2304 } ] const SelectStadium: React.FC = ({ @@ -68,12 +72,13 @@ const SelectStadium: React.FC = ({ Taro.chooseLocation({ success: (res) => { console.log('选择位置成功:', res) - // 可以根据位置信息搜索附近的场馆 - // 这里可以调用相关API获取附近场馆信息 - Taro.showToast({ - title: '位置选择成功', - icon: 'success' + setSelectedStadium({ + name: res.name, + address: res.address, + longitude: res.longitude, + latitude: res.latitude }) + setShowDetail(true) }, fail: (err) => { console.error('选择位置失败:', err) @@ -112,23 +117,31 @@ const SelectStadium: React.FC = ({ setSearchValue('') } + + const markSearchText = (text: string) => { + return text.replace(searchValue, `${searchValue}`) + } + // 如果显示详情页面 if (showDetail && selectedStadium) { return ( - - + ) } @@ -136,6 +149,7 @@ const SelectStadium: React.FC = ({ return ( = ({ {/* 搜索框 */} - 🔍 - - - 📍 + + + + {searchValue && ( + setSearchValue('')}> + + + )} + { + !searchValue && ( + + + 地图 + + ) + } @@ -167,6 +194,7 @@ const SelectStadium: React.FC = ({ 热门球场 + 预定球场 敬请期待 @@ -182,9 +210,37 @@ const SelectStadium: React.FC = ({ className={`stadium-item ${selectedStadium?.id === stadium.id ? 'selected' : ''}`} onClick={() => handleStadiumSelect(stadium)} > - {stadium.name} + + + + + + + {stadium.istance} · + {stadium.address} + + + + ))} + { + searchValue && ( handleMapLocation()} + > + + + + + 没有找到球场?去地图定位 + + 腾讯地图 + + + + ) + } diff --git a/src/components/SelectStadium/StadiumDetail.scss b/src/components/SelectStadium/StadiumDetail.scss index 7b6517e..c366a0a 100644 --- a/src/components/SelectStadium/StadiumDetail.scss +++ b/src/components/SelectStadium/StadiumDetail.scss @@ -9,40 +9,59 @@ padding-bottom: env(safe-area-inset-bottom); // 已选球场 - .selected-venue-section { - padding: 20px 16px 16px 16px; - border-bottom: 1px solid #e5e5e5; - flex-shrink: 0; - - .section-title { - font-size: 16px; - font-weight: 600; - color: #333; - margin-bottom: 12px; - display: block; - } - - .venue-button { - background: #333; - border-radius: 24px; - padding: 12px 24px; - display: inline-block; - - .venue-name { - color: white; - font-size: 16px; - font-weight: 500; + // 场馆列表 + .stadium-item { + padding: 32px 20px 16px 20px; + display: flex; + align-items: center; + position: relative; + gap: 12px; + .stadium-item-left{ + display: flex; + padding: 14px; + justify-content: center; + align-items: center; + border-radius: 12px; + border: 0.5px solid rgba(0, 0, 0, 0.08); + background: rgba(0, 0, 0, 0.06); + .stadium-icon{ + width: 20px; + height: 20px; + } + } + .stadium-item-right{ + flex: 1; + display: flex; + flex-direction: column; + gap: 4px; + .stadium-name{ + font-size: 16px; + color: #000; + font-weight: 600; + line-height: 24px; + display: flex; + } + .stadium-address{ + display: flex; + align-items: center; + gap: 4px; + color: rgba(0, 0, 0, 0.80); + font-size: 12px; + } + .stadium-map-icon{ + width: 10px; + height: 10px; + } } } - } // 场地类型 .venue-type-section { - padding: 16px; border-bottom: 1px solid #e5e5e5; flex-shrink: 0; .section-title { + padding: 18px 20px 10px 20px; font-size: 16px; font-weight: 600; color: #333; @@ -53,7 +72,7 @@ .option-buttons { display: flex; gap: 12px; - + padding: 0 15px; .option-btn { padding: 8px 16px; border-radius: 20px; diff --git a/src/components/SelectStadium/StadiumDetail.tsx b/src/components/SelectStadium/StadiumDetail.tsx index e6db410..dc2e217 100644 --- a/src/components/SelectStadium/StadiumDetail.tsx +++ b/src/components/SelectStadium/StadiumDetail.tsx @@ -1,9 +1,12 @@ -import React, { useState } from 'react' -import { View, Text, Input } from '@tarojs/components' +import React, { useState, useCallback } from 'react' +import { View, Text, Image } from '@tarojs/components' +import images from '@/config/images' import './StadiumDetail.scss' +import TextareaTag from '@/components/TextareaTag' +import CoverImageUpload, { type CoverImage } from '@/components/CoverImageUpload' export interface Stadium { - id: string + id?: string name: string address?: string } @@ -14,6 +17,29 @@ interface StadiumDetailProps { onConfirm: (stadium: Stadium, venueType: string, groundMaterial: string, additionalInfo: string) => void } +const stadiumInfo = [ + { + label: '场地类型', + options: ['室内', '室外', '室外雨棚'], + type: 'tags' + }, + { + label: '地面材质', + options: ['硬地', '红土', '草地'], + type: 'tags' + }, + { + label: '场地信息补充', + options: ['1号场', '2号场', '3号场', '4号场', '有空调', '6号场'], + type: 'textareaTag' + }, + { + label: '场地预定截图', + options: ['有其他场地信息可备注'], + type: 'image' + } +] + const StadiumDetail: React.FC = ({ stadium, onBack, @@ -22,78 +48,107 @@ const StadiumDetail: React.FC = ({ const [venueType, setVenueType] = useState('室内') const [groundMaterial, setGroundMaterial] = useState('硬地') const [additionalInfo, setAdditionalInfo] = useState('') - - const venueTypes = ['室内', '室外', '室外雨棚'] - const groundMaterials = ['硬地', '红土', '草地'] + const [imagesList, setImagesList] = useState([]) const handleConfirm = () => { onConfirm(stadium, venueType, groundMaterial, additionalInfo) } + const handleMapLocation = () => { + + } + + const getSelectedByLabel = useCallback((label: string) => { + if (label === '场地类型') return venueType + if (label === '地面材质') return groundMaterial + return '' + }, [venueType, groundMaterial]) + + const setSelectedByLabel = useCallback((label: string, value: string) => { + if (label === '场地类型') { + setVenueType(value) + } else if (label === '地面材质') { + setGroundMaterial(value) + } + }, []) + + console.log(stadium,'stadiumstadium'); return ( {/* 已选球场 */} - - 已选球场 - - {stadium.name} + handleMapLocation()} + > + + - - - {/* 场地类型 */} - - 场地类型 - - {venueTypes.map((type) => ( - setVenueType(type)} - > - {type} - - ))} - - - - {/* 地面材质 */} - - 地面材质 - - {groundMaterials.map((material) => ( - setGroundMaterial(material)} - > - {material} - - ))} - - - - {/* 场地信息补充 */} - - 场地信息补充 - setAdditionalInfo(e.detail.value)} - /> - - - {/* 底部按钮 */} - - - - 取消 - - - 完成 + + {stadium.name} + + {stadium.address} + + + {stadiumInfo.map((item) => { + if (item.type === 'tags') { + const selected = getSelectedByLabel(item.label) + return ( + + {item.label} + + {item.options.map((opt) => ( + setSelectedByLabel(item.label, opt)} + > + {opt} + + ))} + + + ) + } + + if (item.type === 'textareaTag') { + return ( + + {item.label} + + ({ label: o, value: o }))} + /> + + + + ) + } + + if (item.type === 'image') { + return ( + + {item.label} + + + + + + ) + } + + return null + })} ) } diff --git a/src/components/TextareaTag/TextareaTag.scss b/src/components/TextareaTag/TextareaTag.scss index 602f7dc..5bfb696 100644 --- a/src/components/TextareaTag/TextareaTag.scss +++ b/src/components/TextareaTag/TextareaTag.scss @@ -2,11 +2,10 @@ .textarea-tag { background: white; border-radius: 16px; - padding: 10px 16px 5px 10px; + padding: 10px 16px; width: 100%; .input-wrapper { - padding-bottom: 10px; - + margin-top: 8px; .additional-input { width: 100%; height: 46px; @@ -37,7 +36,6 @@ gap: 6px; .nut-checkbox{ margin-right: 0; - margin-bottom: 5px; .nut-checkbox-button{ border: 1px solid theme.$primary-border-color; color: theme.$primary-color; diff --git a/src/components/TextareaTag/TextareaTag.tsx b/src/components/TextareaTag/TextareaTag.tsx index 98ae9bb..f8f0d6e 100644 --- a/src/components/TextareaTag/TextareaTag.tsx +++ b/src/components/TextareaTag/TextareaTag.tsx @@ -45,19 +45,6 @@ const TextareaTag: React.FC = ({ return ( - {/* 输入框 */} - -