修改发布球局

This commit is contained in:
筱野
2025-09-28 22:52:45 +08:00
parent e5851c1c3b
commit d61243c887
8 changed files with 245 additions and 70 deletions

View File

@@ -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);

View File

@@ -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}

View File

@@ -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,

View File

@@ -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

View File

@@ -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;
} }

View File

@@ -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,10 +572,28 @@ 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` }}>
{/* 活动类型切换 */} {/* 活动类型切换 */}
<View className={styles['activity-type-switch']}> <View className={styles['activity-type-switch']}>
{/* <ActivityTypeSwitch {/* <ActivityTypeSwitch
@@ -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}>

View 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
}
}

View File

@@ -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
} }