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