341 lines
11 KiB
TypeScript

// 地理位置逆编码
import { fetchApi } from '@/lib/server-api-util';
import * as ImagePicker from 'expo-image-picker';
import * as Location from 'expo-location';
import * as Notifications from 'expo-notifications';
import * as SecureStore from 'expo-secure-store';
import { Alert, Linking, Platform } from 'react-native';
interface Address {
id: number;
name: string;
// Add other address properties as needed
}
// 配置通知处理器
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
shouldPlaySound: true,
shouldSetBadge: false,
shouldShowBanner: true,
shouldShowList: true,
}),
});
// 逆编码
export const reverseGeocode = async (latitude: number, longitude: number) => {
try {
const addressResults = await fetchApi<Address[]>(`/area/gecoding?latitude=${latitude}&longitude=${longitude}`);
console.log('地址:', addressResults);
for (let address of addressResults) {
console.log('地址:', address);
if (Platform.OS === 'web') {
localStorage.setItem('location', JSON.stringify(address));
} else {
SecureStore.setItemAsync('location', JSON.stringify(address));
}
return address;
}
} catch (error) {
console.log('逆地理编码失败:', error);
}
};
// 获取位置权限
export const getLocationPermission = async () => {
const { status } = await Location.getForegroundPermissionsAsync();
if (status !== 'granted') {
// Alert.alert('需要位置权限', '请允许访问位置以继续');
return false;
}
return true;
};
// 请求位置权限
export const requestLocationPermission = async () => {
try {
// 1. 先检查当前权限状态
const { status, canAskAgain } = await Location.getForegroundPermissionsAsync();
console.log('当前权限状态:', { status, canAskAgain });
console.log("canAskAgain", canAskAgain);
// 2. 如果已经有权限,直接返回
if (status === 'granted') {
return true;
}
// 3. 如果用户之前选择了"拒绝且不再询问"
if (status === 'denied' && !canAskAgain) {
// 显示提示,引导用户去设置
const openSettings = await new Promise(resolve => {
Alert.alert(
'需要位置权限',
'您之前拒绝了位置权限。要使用此功能,请在设置中启用位置权限。',
[
{
text: '取消',
style: 'cancel',
onPress: () => resolve(false)
},
{
text: '去设置',
onPress: () => resolve(true)
}
]
);
});
if (openSettings) {
// 打开应用设置
await Linking.openSettings();
}
return false;
}
// 4. 如果是第一次请求或可以再次询问,则请求权限
console.log('请求位置权限...');
const { status: newStatus } = await Location.requestForegroundPermissionsAsync();
console.log('新权限状态:', newStatus);
if (newStatus !== 'granted') {
Alert.alert('需要位置权限', '请允许访问位置以使用此功能');
return false;
}
return true;
} catch (error) {
console.error('请求位置权限时出错:', error);
Alert.alert('错误', '请求位置权限时出错');
return false;
}
};
// 获取媒体库权限
export const getPermissions = async () => {
if (Platform.OS !== 'web') {
const { status: mediaStatus } = await ImagePicker.getMediaLibraryPermissionsAsync();
if (mediaStatus !== 'granted') {
// Alert.alert('需要媒体库权限', '请允许访问媒体库以继续');
return false;
}
return true;
}
return true;
};
// 请求媒体库权限
export const requestPermissions = async () => {
if (Platform.OS !== 'web') {
const mediaStatus = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (!mediaStatus.granted) {
// Alert.alert('需要媒体库权限', '请允许访问媒体库以继续');
return false;
}
return true;
}
return true;
};
/**
* 检查相册/媒体库权限
* @returns 返回权限状态对象
*/
export const checkMediaLibraryPermission = async (): Promise<{
hasPermission: boolean;
canAskAgain: boolean;
status: ImagePicker.PermissionStatus;
}> => {
if (Platform.OS === 'web') {
return { hasPermission: true, canAskAgain: true, status: 'granted' };
}
const { status, canAskAgain } = await ImagePicker.getMediaLibraryPermissionsAsync();
return {
hasPermission: status === 'granted',
canAskAgain,
status
};
};
/**
* 请求相册/媒体库权限
* @param showAlert 是否在无权限时显示提示
* @returns 返回是否已授权
*/
export const requestMediaLibraryPermission = async (showAlert: boolean = true): Promise<boolean> => {
if (Platform.OS === 'web') {
return true;
}
try {
// 1. 检查当前权限状态
const { status: existingStatus, canAskAgain } = await checkMediaLibraryPermission();
// 2. 如果已经有权限,直接返回
if (existingStatus === 'granted') {
return true;
}
// 3. 如果之前被拒绝且不能再次询问
if (existingStatus === 'denied' && !canAskAgain) {
if (showAlert) {
const openSettings = await new Promise<boolean>(resolve => {
Alert.alert(
'需要媒体库权限',
'您之前拒绝了媒体库访问权限。要选择照片,请在设置中启用媒体库权限。',
[
{ text: '取消', style: 'cancel', onPress: () => resolve(false) },
{ text: '去设置', onPress: () => resolve(true) }
]
);
});
if (openSettings) {
await Linking.openSettings();
}
}
return false;
}
// 4. 请求权限
const { status: newStatus } = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (newStatus !== 'granted' && showAlert) {
Alert.alert('需要媒体库权限', '请允许访问媒体库以方便后续操作');
}
return newStatus === 'granted';
} catch (error) {
console.error('请求媒体库权限时出错:', error);
if (showAlert) {
Alert.alert('错误', '请求媒体库权限时出错');
}
return false;
}
};
// 检查通知权限
export const checkNotificationPermission = async () => {
const { status } = await Notifications.getPermissionsAsync();
console.log('当前通知权限状态:', status);
return status === 'granted';
};
// 请求通知权限
export const requestNotificationPermission = async () => {
try {
// 1. 先检查当前权限状态
const { status, canAskAgain } = await Notifications.getPermissionsAsync();
console.log('当前通知权限状态:', { status, canAskAgain });
// 2. 如果已经有权限,直接返回
if (status === 'granted') {
return true;
}
// 3. 如果用户之前选择了"拒绝且不再询问"
if (status === 'denied' && !canAskAgain) {
// 显示提示,引导用户去设置
const openSettings = await new Promise(resolve => {
Alert.alert(
'需要通知权限',
'您之前拒绝了通知权限。要使用此功能,请在设置中启用通知权限。',
[
{
text: '取消',
style: 'cancel',
onPress: () => resolve(false)
},
{
text: '去设置',
onPress: () => resolve(true)
}
]
);
});
if (openSettings) {
// 打开应用设置
await Linking.openSettings();
}
return false;
}
// 4. 如果是第一次请求或可以再次询问,则请求权限
console.log('请求通知权限...');
const { status: newStatus } = await Notifications.requestPermissionsAsync();
console.log('新通知权限状态:', newStatus);
if (newStatus !== 'granted') {
Alert.alert('需要通知权限', '请允许通知以使用此功能');
return false;
}
return true;
} catch (error) {
console.error('请求通知权限时出错:', error);
Alert.alert('错误', '请求通知权限时出错');
return false;
}
};
// 发送本地通知的辅助函数
export const sendLocalNotification = async (title: string, body: string, data: Record<string, any> = {}) => {
try {
const hasPermission = await checkNotificationPermission();
if (!hasPermission) {
const granted = await requestNotificationPermission();
if (!granted) {
return false;
}
}
await Notifications.scheduleNotificationAsync({
content: {
title,
body,
data,
priority: 'high',
},
trigger: null, // 立即触发
});
return true;
} catch (error) {
console.error('发送通知时出错:', error);
return false;
}
};
// 获取定位信息 -- 最子集元素
export function findInnermostElement(data: any[], targetName: string): { name: string; value: any } | null {
let result: { name: string; value: any } | null = null;
function search(nodes: any[]): boolean {
for (const node of nodes) {
if (node.name === targetName) {
result = { name: node.name, value: node.value };
// Keep searching to see if there's a deeper match
let foundDeeper = false;
if (node.children && node.children.length > 0) {
foundDeeper = search(node.children);
}
// If no deeper match was found, this is the innermost one
if (!foundDeeper) {
return true;
}
} else if (node.children && node.children.length > 0) {
const found = search(node.children);
if (found) return true;
}
}
return false;
}
search(data);
return result;
}