修改发布球局
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
z-index: 999;
|
z-index: 9;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: #FAFAFA;
|
background-color: #FAFAFA;
|
||||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import styles from './index.module.scss'
|
|||||||
import uploadFiles from '@/services/uploadFiles'
|
import uploadFiles from '@/services/uploadFiles'
|
||||||
import publishService from '@/services/publishService'
|
import publishService from '@/services/publishService'
|
||||||
import { usePublishBallActions } from '@/store/publishBallStore'
|
import { usePublishBallActions } from '@/store/publishBallStore'
|
||||||
|
import { useKeyboardHeight } from '@/store/keyboardStore'
|
||||||
import images from '@/config/images'
|
import images from '@/config/images'
|
||||||
|
|
||||||
export interface AiImportPopupProps {
|
export interface AiImportPopupProps {
|
||||||
@@ -23,13 +24,14 @@ const AiImportPopup: React.FC<AiImportPopupProps> = ({
|
|||||||
const [uploadFailCount, setUploadFailCount] = useState(0)
|
const [uploadFailCount, setUploadFailCount] = useState(0)
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [uploadLoading, setUploadLoading] = useState(false)
|
const [uploadLoading, setUploadLoading] = useState(false)
|
||||||
const [keyboardHeight, setKeyboardHeight] = useState(0)
|
|
||||||
const [isKeyboardVisible, setIsKeyboardVisible] = useState(false)
|
|
||||||
const maxFailCount = 3
|
const maxFailCount = 3
|
||||||
|
|
||||||
// 获取 actions(在组件顶层调用 Hook)
|
// 获取 actions(在组件顶层调用 Hook)
|
||||||
const { setPublishData } = usePublishBallActions()
|
const { setPublishData } = usePublishBallActions()
|
||||||
|
|
||||||
|
// 使用全局键盘状态
|
||||||
|
const { keyboardHeight, isKeyboardVisible, addListener, initializeKeyboardListener } = useKeyboardHeight()
|
||||||
|
|
||||||
const textIdentification = async (text: string) => {
|
const textIdentification = async (text: string) => {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
const res = await publishService.extract_tennis_activity({text})
|
const res = await publishService.extract_tennis_activity({text})
|
||||||
@@ -51,8 +53,6 @@ const AiImportPopup: React.FC<AiImportPopupProps> = ({
|
|||||||
setUploadFailCount(0)
|
setUploadFailCount(0)
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
setUploadLoading(false)
|
setUploadLoading(false)
|
||||||
setKeyboardHeight(0)
|
|
||||||
setIsKeyboardVisible(false)
|
|
||||||
}
|
}
|
||||||
const handlePasteAndRecognize = async () => {
|
const handlePasteAndRecognize = async () => {
|
||||||
if (text) {
|
if (text) {
|
||||||
@@ -109,31 +109,20 @@ const AiImportPopup: React.FC<AiImportPopupProps> = ({
|
|||||||
setText(e.detail.value)
|
setText(e.detail.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 监听键盘高度变化,保持弹窗贴合底部
|
// 使用全局键盘状态监听
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
Taro.onKeyboardHeightChange?.((res: any) => {
|
// 初始化全局键盘监听器
|
||||||
const height = Number(res?.height || 0)
|
initializeKeyboardListener()
|
||||||
if (height > 0) {
|
|
||||||
setIsKeyboardVisible(true)
|
// 添加本地监听器
|
||||||
setKeyboardHeight(height)
|
const removeListener = addListener((height, visible) => {
|
||||||
} else {
|
console.log('AiImportPopup 收到键盘变化:', height, visible)
|
||||||
setIsKeyboardVisible(false)
|
|
||||||
setKeyboardHeight(0)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
// Taro 里 onKeyboardHeightChange 返回的不是取消函数,这里通过置零兜底
|
removeListener()
|
||||||
setIsKeyboardVisible(false)
|
|
||||||
setKeyboardHeight(0)
|
|
||||||
// 微信小程序环境可调用 offKeyboardHeightChange,如存在则尝试注销
|
|
||||||
// @ts-ignore
|
|
||||||
if (typeof Taro.offKeyboardHeightChange === 'function') {
|
|
||||||
// @ts-ignore
|
|
||||||
Taro.offKeyboardHeightChange()
|
|
||||||
}
|
}
|
||||||
}
|
}, [initializeKeyboardListener, addListener])
|
||||||
}, [])
|
|
||||||
|
|
||||||
const handleImageRecognition = async () => {
|
const handleImageRecognition = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -217,8 +206,8 @@ const AiImportPopup: React.FC<AiImportPopupProps> = ({
|
|||||||
className={styles.textArea}
|
className={styles.textArea}
|
||||||
value={text}
|
value={text}
|
||||||
onInput={handleTextChange}
|
onInput={handleTextChange}
|
||||||
onFocus={() => setIsKeyboardVisible(true)}
|
onFocus={() => {}}
|
||||||
onBlur={() => setIsKeyboardVisible(false)}
|
onBlur={() => {}}
|
||||||
placeholder="在此「粘贴识别」或输入文本,智能拆分球局时间、费用、地点和其他信息,并帮你智能生成球局标题"
|
placeholder="在此「粘贴识别」或输入文本,智能拆分球局时间、费用、地点和其他信息,并帮你智能生成球局标题"
|
||||||
maxlength={100}
|
maxlength={100}
|
||||||
showConfirmBar={false}
|
showConfirmBar={false}
|
||||||
|
|||||||
@@ -50,9 +50,9 @@ const FormBasicInfo: React.FC<FormBasicInfoProps> = ({
|
|||||||
// 处理场馆选择
|
// 处理场馆选择
|
||||||
const handleStadiumSelect = (stadium: Stadium | null) => {
|
const handleStadiumSelect = (stadium: Stadium | null) => {
|
||||||
console.log(stadium,'stadiumstadium');
|
console.log(stadium,'stadiumstadium');
|
||||||
const { address, name, latitude, longitude, court_type, court_surface, description, description_tag, venue_image_list} = stadium || {};
|
const { address, name, venue_id, latitude, longitude, court_type, court_surface, description, description_tag, venue_image_list} = stadium || {};
|
||||||
onChange({...value,
|
onChange({...value,
|
||||||
venue_id: stadium?.id,
|
venue_id,
|
||||||
location_name: name,
|
location_name: name,
|
||||||
location: address,
|
location: address,
|
||||||
latitude,
|
latitude,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import './StadiumDetail.scss'
|
|||||||
|
|
||||||
export interface Stadium {
|
export interface Stadium {
|
||||||
id?: string
|
id?: string
|
||||||
|
venue_id?: string
|
||||||
name: string
|
name: string
|
||||||
address?: string
|
address?: string
|
||||||
longitude?: number
|
longitude?: number
|
||||||
|
|||||||
@@ -1,5 +1,15 @@
|
|||||||
@use '~@/scss/themeColor.scss' as theme;
|
@use '~@/scss/themeColor.scss' as theme;
|
||||||
|
|
||||||
|
.publish-ball-container{
|
||||||
|
position: relative;
|
||||||
|
&.publish-ball-container-keyboard{
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
}
|
||||||
.publish-ball {
|
.publish-ball {
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
@@ -167,12 +177,8 @@
|
|||||||
|
|
||||||
// 提交区域
|
// 提交区域
|
||||||
.submit-section {
|
.submit-section {
|
||||||
position: fixed;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
padding: 16px;
|
|
||||||
|
|
||||||
|
padding: 16px;
|
||||||
.submit-btn {
|
.submit-btn {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
color: white;
|
color: white;
|
||||||
@@ -260,5 +266,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.publish-ball-navbar{
|
.publish-ball-navbar{
|
||||||
|
position: fixed !important;
|
||||||
|
top: 0 !important;
|
||||||
|
left: 0 !important;
|
||||||
|
z-index: 9999 !important;
|
||||||
|
width: 100% !important;
|
||||||
box-shadow: none!important;
|
box-shadow: none!important;
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect, useRef } from 'react'
|
||||||
import { View, Text, Button, Image } from '@tarojs/components'
|
import { View, Text, Button, Image } from '@tarojs/components'
|
||||||
import { Checkbox } from '@nutui/nutui-react-taro'
|
import { Checkbox } from '@nutui/nutui-react-taro'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
@@ -17,6 +17,7 @@ import images from '@/config/images'
|
|||||||
import { useUserInfo } from '@/store/userStore'
|
import { useUserInfo } from '@/store/userStore'
|
||||||
import styles from './index.module.scss'
|
import styles from './index.module.scss'
|
||||||
import { usePublishBallData } from '@/store/publishBallStore'
|
import { usePublishBallData } from '@/store/publishBallStore'
|
||||||
|
import { useKeyboardHeight } from '@/store/keyboardStore'
|
||||||
import DetailService from "@/services/detailService";
|
import DetailService from "@/services/detailService";
|
||||||
|
|
||||||
const defaultFormData: PublishBallFormData = {
|
const defaultFormData: PublishBallFormData = {
|
||||||
@@ -65,12 +66,17 @@ const PublishBall: React.FC = () => {
|
|||||||
const userInfo = useUserInfo();
|
const userInfo = useUserInfo();
|
||||||
const publishAiData = usePublishBallData()
|
const publishAiData = usePublishBallData()
|
||||||
const { statusNavbarHeightInfo } = useGlobalState();
|
const { statusNavbarHeightInfo } = useGlobalState();
|
||||||
|
|
||||||
|
// 使用全局键盘状态
|
||||||
|
const { keyboardHeight, isKeyboardVisible, addListener, initializeKeyboardListener } = useKeyboardHeight()
|
||||||
// 获取页面参数并设置导航标题
|
// 获取页面参数并设置导航标题
|
||||||
const [optionsConfig, setOptionsConfig] = useState<FormFieldConfig[]>(publishBallFormSchema)
|
const [optionsConfig, setOptionsConfig] = useState<FormFieldConfig[]>(publishBallFormSchema)
|
||||||
console.log(userInfo, 'userInfo');
|
console.log(userInfo, 'userInfo');
|
||||||
const [formData, setFormData] = useState<PublishBallFormData[]>([defaultFormData])
|
const [formData, setFormData] = useState<PublishBallFormData[]>([defaultFormData])
|
||||||
const [checked, setChecked] = useState(true)
|
const [checked, setChecked] = useState(true)
|
||||||
const [titleBar, setTitleBar] = useState('发布')
|
const [titleBar, setTitleBar] = useState('发布')
|
||||||
|
const scrollViewRef = useRef<any>(null)
|
||||||
|
|
||||||
// 删除确认弹窗状态
|
// 删除确认弹窗状态
|
||||||
const [deleteConfirm, setDeleteConfirm] = useState<{
|
const [deleteConfirm, setDeleteConfirm] = useState<{
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
@@ -172,8 +178,10 @@ const PublishBall: React.FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const validateFormData = (formData: PublishBallFormData, isOnSubmit: boolean = false) => {
|
const validateFormData = (formData: PublishBallFormData, isOnSubmit: boolean = false) => {
|
||||||
const { activityInfo, title, timeRange, image_list } = formData;
|
const { activityInfo, title, timeRange, image_list, players, current_players } = formData;
|
||||||
const { play_type, price, location_name } = activityInfo;
|
const { play_type, price, location_name } = activityInfo;
|
||||||
|
|
||||||
|
const { max } = players;
|
||||||
if (!image_list?.length && activityType === 'group') {
|
if (!image_list?.length && activityType === 'group') {
|
||||||
if (!isOnSubmit) {
|
if (!isOnSubmit) {
|
||||||
Taro.showToast({
|
Taro.showToast({
|
||||||
@@ -223,6 +231,7 @@ const PublishBall: React.FC = () => {
|
|||||||
if (timeRange?.start_time && timeRange?.end_time) {
|
if (timeRange?.start_time && timeRange?.end_time) {
|
||||||
const start = dayjs(timeRange.start_time)
|
const start = dayjs(timeRange.start_time)
|
||||||
const end = dayjs(timeRange.end_time)
|
const end = dayjs(timeRange.end_time)
|
||||||
|
const currentTime = dayjs()
|
||||||
if (!end.isAfter(start)) {
|
if (!end.isAfter(start)) {
|
||||||
if (!isOnSubmit) {
|
if (!isOnSubmit) {
|
||||||
Taro.showToast({
|
Taro.showToast({
|
||||||
@@ -241,6 +250,33 @@ const PublishBall: React.FC = () => {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if (start.isBefore(currentTime)) {
|
||||||
|
if (!isOnSubmit) {
|
||||||
|
Taro.showToast({
|
||||||
|
title: `开始时间需晚于当前时间`,
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (end.isBefore(currentTime)) {
|
||||||
|
if (!isOnSubmit) {
|
||||||
|
Taro.showToast({
|
||||||
|
title: `结束时间需晚于当前时间`,
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (current_players && (current_players > max)) {
|
||||||
|
if (!isOnSubmit) {
|
||||||
|
Taro.showToast({
|
||||||
|
title: `最大人数不能小于当前参与人数${current_players}`,
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@@ -269,7 +305,7 @@ const PublishBall: React.FC = () => {
|
|||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const { activityInfo, descriptionInfo, timeRange, players, skill_level, image_list, wechat, ...rest } = formData[0];
|
const { activityInfo, descriptionInfo,is_substitute_supported, timeRange, players, skill_level, image_list, wechat, id, ...rest } = formData[0];
|
||||||
const { min, max, organizer_joined } = players;
|
const { min, max, organizer_joined } = players;
|
||||||
const options = {
|
const options = {
|
||||||
...rest,
|
...rest,
|
||||||
@@ -278,12 +314,14 @@ const PublishBall: React.FC = () => {
|
|||||||
...timeRange,
|
...timeRange,
|
||||||
max_players: max,
|
max_players: max,
|
||||||
min_players: min,
|
min_players: min,
|
||||||
organizer_joined,
|
organizer_joined: organizer_joined === true ? 1 : 0,
|
||||||
skill_level_min: skill_level[0],
|
skill_level_min: skill_level[0],
|
||||||
skill_level_max: skill_level[1],
|
skill_level_max: skill_level[1],
|
||||||
image_list: image_list.map(item => item.url),
|
image_list: image_list.map(item => item.url),
|
||||||
is_wechat_contact: wechat.is_wechat_contact,
|
is_wechat_contact: wechat.is_wechat_contact ? 1 : 0,
|
||||||
wechat_contact: wechat.wechat_contact || wechat.default_wechat_contact,
|
wechat_contact: wechat.wechat_contact || wechat.default_wechat_contact,
|
||||||
|
is_substitute_supported: is_substitute_supported ? '1' : '0',
|
||||||
|
...(republish === '0' ? { id } : {}),
|
||||||
}
|
}
|
||||||
const res = republish === '0' ? await PublishService.gamesUpdate(options) : await PublishService.createPersonal(options);
|
const res = republish === '0' ? await PublishService.gamesUpdate(options) : await PublishService.createPersonal(options);
|
||||||
const successText = republish === '0' ? '更新成功' : '发布成功';
|
const successText = republish === '0' ? '更新成功' : '发布成功';
|
||||||
@@ -295,9 +333,10 @@ const PublishBall: React.FC = () => {
|
|||||||
delay(1000)
|
delay(1000)
|
||||||
// 如果是个人球局,则跳转到详情页,并自动分享
|
// 如果是个人球局,则跳转到详情页,并自动分享
|
||||||
// 如果是畅打,则跳转第一个球局详情页,并自动分享 @刘杰
|
// 如果是畅打,则跳转第一个球局详情页,并自动分享 @刘杰
|
||||||
|
const id = (res as any).data?.id;
|
||||||
Taro.navigateTo({
|
Taro.navigateTo({
|
||||||
// @ts-expect-error: id
|
// @ts-expect-error: id
|
||||||
url: `/game_pages/detail/index?id=${(res as any).data?.id || 1}&from=publish&autoShare=1`
|
url: `/game_pages/detail/index?id=${id || 1}&from=publish&autoShare=1`
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Taro.showToast({
|
Taro.showToast({
|
||||||
@@ -319,7 +358,7 @@ const PublishBall: React.FC = () => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
const options = formData.map((item) => {
|
const options = formData.map((item) => {
|
||||||
const { activityInfo, descriptionInfo, timeRange, players, skill_level, ...rest } = item;
|
const { activityInfo, descriptionInfo, timeRange, players, skill_level, is_substitute_supported, id, ...rest } = item;
|
||||||
const { min, max, organizer_joined } = players;
|
const { min, max, organizer_joined } = players;
|
||||||
return {
|
return {
|
||||||
...rest,
|
...rest,
|
||||||
@@ -328,10 +367,12 @@ const PublishBall: React.FC = () => {
|
|||||||
...timeRange,
|
...timeRange,
|
||||||
max_players: max,
|
max_players: max,
|
||||||
min_players: min,
|
min_players: min,
|
||||||
organizer_joined,
|
organizer_joined: organizer_joined === true ? 1 : 0,
|
||||||
skill_level_min: skill_level[0],
|
skill_level_min: skill_level[0],
|
||||||
skill_level_max: skill_level[1],
|
skill_level_max: skill_level[1],
|
||||||
image_list: item.image_list.map(img => img.url)
|
is_substitute_supported: is_substitute_supported ? '1' : '0',
|
||||||
|
image_list: item.image_list.map(img => img.url),
|
||||||
|
...(republish === '0' ? { id } : {}),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const successText = republish === '0' ? '更新成功' : '发布成功';
|
const successText = republish === '0' ? '更新成功' : '发布成功';
|
||||||
@@ -344,9 +385,10 @@ const PublishBall: React.FC = () => {
|
|||||||
delay(1000)
|
delay(1000)
|
||||||
// 如果是个人球局,则跳转到详情页,并自动分享
|
// 如果是个人球局,则跳转到详情页,并自动分享
|
||||||
// 如果是畅打,则跳转第一个球局详情页,并自动分享 @刘杰
|
// 如果是畅打,则跳转第一个球局详情页,并自动分享 @刘杰
|
||||||
|
const id = republish === '0' ? (res as any).data?.id : (res as any).data?.[0]?.id;
|
||||||
Taro.navigateTo({
|
Taro.navigateTo({
|
||||||
// @ts-expect-error: id
|
// @ts-expect-error: id
|
||||||
url: `/game_pages/detail/index?id=${(res as any).data?.[0]?.id || 1}&from=publish&autoShare=1`
|
url: `/game_pages/detail/index?id=${id || 1}&from=publish&autoShare=1`
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Taro.showToast({
|
Taro.showToast({
|
||||||
@@ -357,13 +399,17 @@ const PublishBall: React.FC = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mergeWithDefault = (data: any): PublishBallFormData => {
|
const mergeWithDefault = (data: any, isDetail: boolean = false): PublishBallFormData => {
|
||||||
const userPhone = (userInfo as any)?.phone || ''
|
// ai导入与详情数据处理
|
||||||
const { start_time, end_time, play_type, price, venue_id, location_name, location, latitude,
|
const { start_time, end_time, play_type, price, venue_id, location_name, location, latitude,
|
||||||
longitude, court_type, court_surface, venue_description_tag, venue_description, venue_image_list,
|
longitude, court_type, court_surface, venue_description_tag, venue_description, venue_image_list,
|
||||||
description, description_tag, max_players, min_players, skill_level_max, skill_level_min,
|
description, description_tag, max_players, min_players, skill_level_max, skill_level_min,
|
||||||
venueDtl
|
venueDtl, wechat_contact, image_list, id: publish_id, is_wechat_contact,
|
||||||
|
is_substitute_supported, title, current_players, organizer_joined
|
||||||
} = data;
|
} = data;
|
||||||
|
const level_max = skill_level_max ? Number(skill_level_max) : 5.0;
|
||||||
|
const level_min = skill_level_min ? Number(skill_level_min) : 1.0;
|
||||||
|
const userPhone = wechat_contact || (userInfo as any)?.phone || ''
|
||||||
let activityInfo = {};
|
let activityInfo = {};
|
||||||
if (venueDtl) {
|
if (venueDtl) {
|
||||||
const { latitude, longitude,venue_type, surface_type, facilities, name, id } = venueDtl;
|
const { latitude, longitude,venue_type, surface_type, facilities, name, id } = venueDtl;
|
||||||
@@ -377,9 +423,25 @@ const PublishBall: React.FC = () => {
|
|||||||
venue_id: id
|
venue_id: id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (isDetail) {
|
||||||
|
activityInfo = {
|
||||||
|
venue_id,
|
||||||
|
location_name,
|
||||||
|
location,
|
||||||
|
latitude,
|
||||||
|
longitude,
|
||||||
|
court_type,
|
||||||
|
court_surface,
|
||||||
|
venue_description_tag,
|
||||||
|
venue_description,
|
||||||
|
venue_image_list
|
||||||
|
}
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
...defaultFormData,
|
...defaultFormData,
|
||||||
...data,
|
title,
|
||||||
|
...(is_substitute_supported === '0' ? { is_substitute_supported: false } : {}),
|
||||||
|
...(publish_id ? { id: publish_id } : {}),
|
||||||
timeRange: {
|
timeRange: {
|
||||||
...defaultFormData.timeRange,
|
...defaultFormData.timeRange,
|
||||||
start_time,
|
start_time,
|
||||||
@@ -389,16 +451,6 @@ const PublishBall: React.FC = () => {
|
|||||||
...defaultFormData.activityInfo,
|
...defaultFormData.activityInfo,
|
||||||
...(play_type ? { play_type } : {}),
|
...(play_type ? { play_type } : {}),
|
||||||
...((price) ? { price } : {}),
|
...((price) ? { price } : {}),
|
||||||
...(venue_id ? { venue_id } : {}),
|
|
||||||
...(location_name ? { location_name } : {}),
|
|
||||||
...(location ? { location } : {}),
|
|
||||||
...(latitude ? { latitude } : {}),
|
|
||||||
...(longitude ? { longitude } : {}),
|
|
||||||
...(court_type ? { court_type } : {}),
|
|
||||||
...(court_surface ? { court_surface } : {}),
|
|
||||||
...(venue_description_tag ? { venue_description_tag } : {}),
|
|
||||||
...(venue_description ? { venue_description } : {}),
|
|
||||||
...(venue_image_list ? { venue_image_list } : {}),
|
|
||||||
...activityInfo
|
...activityInfo
|
||||||
},
|
},
|
||||||
descriptionInfo: {
|
descriptionInfo: {
|
||||||
@@ -406,9 +458,12 @@ const PublishBall: React.FC = () => {
|
|||||||
...(description ? { description } : {}),
|
...(description ? { description } : {}),
|
||||||
...(description_tag ? { description_tag } : {}),
|
...(description_tag ? { description_tag } : {}),
|
||||||
},
|
},
|
||||||
...(skill_level_max && skill_level_min ? { skill_level: [skill_level_min, skill_level_max] } : {}),
|
...(level_max && level_min ? { skill_level: [level_min, level_max] } : {}),
|
||||||
...(max_players && min_players ? { players: { min: min_players, max: max_players, organizer_joined: true } } : {}),
|
...(max_players && min_players ? { players: { min: min_players, max: max_players, organizer_joined: organizer_joined === 0 ? false : true } } : {}),
|
||||||
wechat: { ...defaultFormData.wechat, default_wechat_contact: userPhone }
|
wechat: { ...defaultFormData.wechat, default_wechat_contact: userPhone, is_wechat_contact: is_wechat_contact === 0 ? false : true},
|
||||||
|
image_list: image_list?.map(item => ({ url: item, id: item })) || [],
|
||||||
|
...(current_players ? { current_players } : {}),
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -483,9 +538,9 @@ const PublishBall: React.FC = () => {
|
|||||||
try {
|
try {
|
||||||
const res = await DetailService.getDetail(Number(gameId));
|
const res = await DetailService.getDetail(Number(gameId));
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
const merged = mergeWithDefault(res.data)
|
const merged = mergeWithDefault(res.data, true)
|
||||||
setFormData([merged])
|
setFormData([merged])
|
||||||
if (merged.activityInfo.play_type === '个人球局') {
|
if (res.data.game_type === '个人球局') {
|
||||||
setTitleBar('发布')
|
setTitleBar('发布')
|
||||||
setActivityType('individual')
|
setActivityType('individual')
|
||||||
} else {
|
} else {
|
||||||
@@ -494,8 +549,10 @@ const PublishBall: React.FC = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.message === '球局不存在') {
|
Taro.showToast({
|
||||||
}
|
title: e.message,
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const onCheckedChange = (checked: boolean) => {
|
const onCheckedChange = (checked: boolean) => {
|
||||||
@@ -515,8 +572,26 @@ const PublishBall: React.FC = () => {
|
|||||||
initFormData()
|
initFormData()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
// 使用全局键盘状态监听
|
||||||
|
useEffect(() => {
|
||||||
|
// 初始化全局键盘监听器
|
||||||
|
initializeKeyboardListener()
|
||||||
|
|
||||||
|
// 添加本地监听器
|
||||||
|
const removeListener = addListener((height, visible) => {
|
||||||
|
console.log('PublishBall 收到键盘变化:', height, visible)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
removeListener()
|
||||||
|
}
|
||||||
|
}, [initializeKeyboardListener, addListener])
|
||||||
|
|
||||||
|
console.log(isKeyboardVisible, 'isKeyboardVisible');
|
||||||
|
console.log(keyboardHeight, 'keyboardHeight');
|
||||||
return (
|
return (
|
||||||
<View>
|
<View className={`${styles['publish-ball-container']} ${isKeyboardVisible ? styles['publish-ball-container-keyboard'] : ''}`} style={{ bottom: isKeyboardVisible ? `${keyboardHeight - 124}px` : 0 }}>
|
||||||
<GeneralNavbar title={titleBar} backgroundColor="#FAFAFA" className={styles['publish-ball-navbar']} />
|
<GeneralNavbar title={titleBar} backgroundColor="#FAFAFA" className={styles['publish-ball-navbar']} />
|
||||||
<View className={styles['publish-ball']} style={{ paddingTop: `${statusNavbarHeightInfo.totalHeight}px` }}>
|
<View className={styles['publish-ball']} style={{ paddingTop: `${statusNavbarHeightInfo.totalHeight}px` }}>
|
||||||
{/* 活动类型切换 */}
|
{/* 活动类型切换 */}
|
||||||
@@ -527,7 +602,7 @@ const PublishBall: React.FC = () => {
|
|||||||
/> */}
|
/> */}
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View className={styles['publish-ball__scroll']} style={{ height: `calc(100vh - ${statusNavbarHeightInfo.totalHeight+120}px)` }}>
|
<View className={styles['publish-ball__scroll']} style={{ height: `calc(100vh - ${statusNavbarHeightInfo.totalHeight+120}px)`, overflow: 'auto' }}>
|
||||||
{
|
{
|
||||||
formData.map((item, index) => (
|
formData.map((item, index) => (
|
||||||
<View key={index}>
|
<View key={index}>
|
||||||
|
|||||||
98
src/store/keyboardStore.ts
Normal file
98
src/store/keyboardStore.ts
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
import { create } from 'zustand'
|
||||||
|
import Taro from '@tarojs/taro'
|
||||||
|
|
||||||
|
interface KeyboardState {
|
||||||
|
keyboardHeight: number
|
||||||
|
isKeyboardVisible: boolean
|
||||||
|
listeners: Set<(height: number, visible: boolean) => void>
|
||||||
|
isInitialized: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface KeyboardActions {
|
||||||
|
setKeyboardHeight: (height: number) => void
|
||||||
|
setKeyboardVisible: (visible: boolean) => void
|
||||||
|
addListener: (listener: (height: number, visible: boolean) => void) => () => void
|
||||||
|
initializeKeyboardListener: () => void
|
||||||
|
cleanup: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
type KeyboardStore = KeyboardState & KeyboardActions
|
||||||
|
|
||||||
|
export const useKeyboardStore = create<KeyboardStore>((set, get) => ({
|
||||||
|
keyboardHeight: 0,
|
||||||
|
isKeyboardVisible: false,
|
||||||
|
listeners: new Set(),
|
||||||
|
isInitialized: false,
|
||||||
|
|
||||||
|
setKeyboardHeight: (height: number) => {
|
||||||
|
set({ keyboardHeight: height })
|
||||||
|
const { listeners } = get()
|
||||||
|
listeners.forEach(listener => listener(height, get().isKeyboardVisible))
|
||||||
|
},
|
||||||
|
|
||||||
|
setKeyboardVisible: (visible: boolean) => {
|
||||||
|
set({ isKeyboardVisible: visible })
|
||||||
|
const { listeners } = get()
|
||||||
|
listeners.forEach(listener => listener(get().keyboardHeight, visible))
|
||||||
|
},
|
||||||
|
|
||||||
|
addListener: (listener: (height: number, visible: boolean) => void) => {
|
||||||
|
const { listeners } = get()
|
||||||
|
listeners.add(listener)
|
||||||
|
|
||||||
|
// 返回取消监听的函数
|
||||||
|
return () => {
|
||||||
|
listeners.delete(listener)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
initializeKeyboardListener: () => {
|
||||||
|
const { isInitialized } = get()
|
||||||
|
if (isInitialized) return
|
||||||
|
|
||||||
|
console.log('初始化全局键盘监听器')
|
||||||
|
|
||||||
|
Taro.onKeyboardHeightChange?.((res: any) => {
|
||||||
|
const height = Number(res?.height || 0)
|
||||||
|
console.log('全局键盘高度变化:', height)
|
||||||
|
|
||||||
|
const store = get()
|
||||||
|
if (height > 0) {
|
||||||
|
store.setKeyboardVisible(true)
|
||||||
|
store.setKeyboardHeight(height)
|
||||||
|
} else {
|
||||||
|
store.setKeyboardVisible(false)
|
||||||
|
store.setKeyboardHeight(0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
set({ isInitialized: true })
|
||||||
|
},
|
||||||
|
|
||||||
|
cleanup: () => {
|
||||||
|
console.log('清理全局键盘监听器')
|
||||||
|
// @ts-ignore
|
||||||
|
if (typeof Taro.offKeyboardHeightChange === 'function') {
|
||||||
|
// @ts-ignore
|
||||||
|
Taro.offKeyboardHeightChange()
|
||||||
|
}
|
||||||
|
set({
|
||||||
|
isInitialized: false,
|
||||||
|
keyboardHeight: 0,
|
||||||
|
isKeyboardVisible: false,
|
||||||
|
listeners: new Set()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
// 导出便捷的 hooks
|
||||||
|
export const useKeyboardHeight = () => {
|
||||||
|
const { keyboardHeight, isKeyboardVisible, addListener, initializeKeyboardListener } = useKeyboardStore()
|
||||||
|
|
||||||
|
return {
|
||||||
|
keyboardHeight,
|
||||||
|
isKeyboardVisible,
|
||||||
|
addListener,
|
||||||
|
initializeKeyboardListener
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,5 +35,6 @@ export interface PublishBallFormData {
|
|||||||
is_wechat_contact: boolean // 是否需要微信联系
|
is_wechat_contact: boolean // 是否需要微信联系
|
||||||
default_wechat_contact: string // 默认微信联系
|
default_wechat_contact: string // 默认微信联系
|
||||||
wechat_contact: string // 微信联系
|
wechat_contact: string // 微信联系
|
||||||
}
|
},
|
||||||
|
[key: string]: any
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user