Initial commit of akmon project
This commit is contained in:
552
utils/locationService.uts
Normal file
552
utils/locationService.uts
Normal file
@@ -0,0 +1,552 @@
|
||||
/**
|
||||
* 手环位置服务 - 处理基站ID、位置信息、围栏功能
|
||||
*/
|
||||
|
||||
import type { AkReqResponse } from '@/uni_modules/ak-req/index.uts'
|
||||
|
||||
// 基础坐标类型
|
||||
export type LocationCoordinate = {
|
||||
longitude: number
|
||||
latitude: number
|
||||
}
|
||||
|
||||
// 估算位置类型
|
||||
export type EstimatedLocation = {
|
||||
longitude: number
|
||||
latitude: number
|
||||
accuracy: number
|
||||
}
|
||||
|
||||
// 围栏中心点类型
|
||||
export type FenceCenter = {
|
||||
longitude: number
|
||||
latitude: number
|
||||
}
|
||||
|
||||
// 基站信息类型
|
||||
export type BaseStationInfo = {
|
||||
/** 基站ID */
|
||||
id: string
|
||||
/** 基站名称 */
|
||||
name: string
|
||||
/** 基站位置描述 */
|
||||
location: string
|
||||
/** 经度 */
|
||||
longitude: number
|
||||
/** 纬度 */
|
||||
latitude: number
|
||||
/** 信号强度 */
|
||||
signalStrength: number
|
||||
/** 是否在线 */
|
||||
isOnline: boolean
|
||||
/** 覆盖范围(米) */
|
||||
range: number
|
||||
}
|
||||
|
||||
// 位置信息类型
|
||||
export type LocationInfo = {
|
||||
/** 设备ID */
|
||||
deviceId: string
|
||||
/** 当前连接的基站 */
|
||||
baseStation: BaseStationInfo | null
|
||||
/** 估算位置 */
|
||||
estimatedLocation: EstimatedLocation | null
|
||||
/** 最后更新时间 */
|
||||
lastUpdate: string
|
||||
/** 位置状态 */
|
||||
status: 'online' | 'offline' | 'unknown'
|
||||
}
|
||||
|
||||
// 围栏信息类型
|
||||
export type FenceInfo = {
|
||||
/** 围栏ID */
|
||||
id: string
|
||||
/** 围栏名称 */
|
||||
name: string
|
||||
/** 围栏类型 */
|
||||
type: 'circle' | 'polygon'
|
||||
/** 围栏中心点(圆形围栏) */
|
||||
center?: FenceCenter
|
||||
/** 围栏半径(米,圆形围栏) */
|
||||
radius?: number
|
||||
/** 围栏顶点(多边形围栏) */
|
||||
points?: Array<LocationCoordinate>
|
||||
/** 是否激活 */
|
||||
isActive: boolean
|
||||
/** 围栏事件类型 */
|
||||
eventType: 'enter' | 'exit' | 'both'
|
||||
/** 创建时间 */
|
||||
createdAt: string
|
||||
}
|
||||
|
||||
// 位置历史记录类型
|
||||
export type LocationHistoryItem = {
|
||||
/** 记录ID */
|
||||
id: string
|
||||
/** 设备ID */
|
||||
deviceId: string
|
||||
/** 基站信息 */
|
||||
baseStation: BaseStationInfo
|
||||
/** 记录时间 */
|
||||
timestamp: string
|
||||
/** 持续时间(秒) */
|
||||
duration: number
|
||||
/** 位置类型 */
|
||||
locationType: 'basestation' | 'estimated'
|
||||
}
|
||||
|
||||
// 围栏事件类型
|
||||
export type FenceEvent = {
|
||||
/** 事件ID */
|
||||
id: string
|
||||
/** 设备ID */
|
||||
deviceId: string
|
||||
/** 围栏信息 */
|
||||
fence: FenceInfo
|
||||
/** 事件类型 */
|
||||
eventType: 'enter' | 'exit'
|
||||
/** 事件时间 */
|
||||
timestamp: string
|
||||
/** 触发位置 */
|
||||
location: LocationCoordinate
|
||||
/** 是否已读 */
|
||||
isRead: boolean
|
||||
}
|
||||
|
||||
// FenceInfo 的手动 Partial 类型
|
||||
export type PartialFenceInfo = {
|
||||
id?: string
|
||||
name?: string
|
||||
type?: 'circle' | 'polygon'
|
||||
center?: FenceCenter
|
||||
radius?: number
|
||||
points?: Array<LocationCoordinate>
|
||||
isActive?: boolean
|
||||
eventType?: 'enter' | 'exit' | 'both'
|
||||
createdAt?: string
|
||||
}
|
||||
|
||||
// mock generic AkReqResponse for array data
|
||||
export function mockAkArrayResponse<T>(data: T[], status: number = 200): AkReqResponse<Array<T>> {
|
||||
return {
|
||||
status,
|
||||
data,
|
||||
headers: {} as UTSJSONObject,
|
||||
error: null,
|
||||
total: data.length,
|
||||
page: 1,
|
||||
limit: data.length,
|
||||
hasmore: false,
|
||||
origin: null,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 位置服务工厂函数
|
||||
*/
|
||||
export function createLocationResponse<T>(status: number, message: string, data: T[]): AkReqResponse<Array<T>> {
|
||||
return mockAkArrayResponse<T>(data, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* 位置服务错误响应工厂函数
|
||||
*/
|
||||
export function createLocationErrorResponse<T>(message: string): AkReqResponse<Array<T>> {
|
||||
return createLocationResponse<T>(500, message, [])
|
||||
}
|
||||
|
||||
/**
|
||||
* 手环位置服务类
|
||||
*/
|
||||
export class LocationService {
|
||||
/**
|
||||
* 获取设备当前位置信息
|
||||
*/
|
||||
static async getCurrentLocation(deviceId: string): Promise<AkReqResponse<LocationInfo>> {
|
||||
try {
|
||||
// 模拟API调用延迟
|
||||
await new Promise<void>((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve()
|
||||
}, 1000)
|
||||
})
|
||||
|
||||
// 模拟数据
|
||||
const mockBaseStation: BaseStationInfo = {
|
||||
id: 'BS001',
|
||||
name: '教学楼A栋基站',
|
||||
location: '教学楼A栋1层',
|
||||
longitude: 116.397428,
|
||||
latitude: 39.90923,
|
||||
signalStrength: -45,
|
||||
isOnline: true,
|
||||
range: 50
|
||||
}
|
||||
const mockLocation: LocationInfo[] = [{
|
||||
deviceId: deviceId,
|
||||
baseStation: mockBaseStation,
|
||||
estimatedLocation: {
|
||||
longitude: 116.397428,
|
||||
latitude: 39.90923,
|
||||
accuracy: 15
|
||||
},
|
||||
lastUpdate: new Date().toISOString(),
|
||||
status: 'online'
|
||||
}]
|
||||
|
||||
return createLocationResponse(200, '获取位置成功', mockLocation)
|
||||
} catch (error) {
|
||||
console.error('获取设备位置失败:', error)
|
||||
return createLocationErrorResponse('获取位置信息失败')
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 获取可用基站列表
|
||||
*/
|
||||
static async getBaseStations(): Promise<AkReqResponse<BaseStationInfo[]>> {
|
||||
try {
|
||||
await new Promise<void>((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve()
|
||||
}, 800)
|
||||
})
|
||||
|
||||
const mockBaseStations: BaseStationInfo[] = [
|
||||
{
|
||||
id: 'BS001',
|
||||
name: '教学楼A栋基站',
|
||||
location: '教学楼A栋1层',
|
||||
longitude: 116.397428,
|
||||
latitude: 39.90923,
|
||||
signalStrength: -45,
|
||||
isOnline: true,
|
||||
range: 50
|
||||
},
|
||||
{
|
||||
id: 'BS002',
|
||||
name: '教学楼B栋基站',
|
||||
location: '教学楼B栋2层',
|
||||
longitude: 116.398428,
|
||||
latitude: 39.91023,
|
||||
signalStrength: -52,
|
||||
isOnline: true,
|
||||
range: 45
|
||||
},
|
||||
{
|
||||
id: 'BS003',
|
||||
name: '操场基站',
|
||||
location: '学校操场',
|
||||
longitude: 116.399428,
|
||||
latitude: 39.91123,
|
||||
signalStrength: -38,
|
||||
isOnline: true,
|
||||
range: 100
|
||||
},
|
||||
{
|
||||
id: 'BS004',
|
||||
name: '宿舍楼基站',
|
||||
location: '学生宿舍1号楼',
|
||||
longitude: 116.396428,
|
||||
latitude: 39.90823,
|
||||
signalStrength: -60,
|
||||
isOnline: false,
|
||||
range: 40
|
||||
}
|
||||
]
|
||||
|
||||
return createLocationResponse(200, '获取基站列表成功', mockBaseStations)
|
||||
} catch (error) {
|
||||
console.error('获取基站列表失败:', error)
|
||||
return createLocationErrorResponse('获取基站列表失败')
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 获取围栏列表
|
||||
*/
|
||||
static async getFences(deviceId: string): Promise<AkReqResponse<FenceInfo[]>> {
|
||||
try {
|
||||
await new Promise<void>((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve()
|
||||
}, 600)
|
||||
})
|
||||
const mockFences: FenceInfo[] = [ {
|
||||
id: 'FENCE001',
|
||||
name: '校园安全区域',
|
||||
type: 'circle',
|
||||
center: {
|
||||
longitude: 116.397928,
|
||||
latitude: 39.90973
|
||||
},
|
||||
radius: 200,
|
||||
isActive: true,
|
||||
eventType: 'exit',
|
||||
createdAt: '2024-01-15T10:00:00Z'
|
||||
},
|
||||
{
|
||||
id: 'FENCE002',
|
||||
name: '教学区域',
|
||||
type: 'polygon',
|
||||
points: [
|
||||
{ longitude: 116.397000, latitude: 39.909000 },
|
||||
{ longitude: 116.398000, latitude: 39.909000 },
|
||||
{ longitude: 116.398000, latitude: 39.910000 },
|
||||
{ longitude: 116.397000, latitude: 39.910000 }
|
||||
],
|
||||
isActive: true,
|
||||
eventType: 'both',
|
||||
createdAt: '2024-01-16T14:30:00Z'
|
||||
},
|
||||
{
|
||||
id: 'FENCE003',
|
||||
name: '危险区域',
|
||||
type: 'circle',
|
||||
center: {
|
||||
longitude: 116.395428,
|
||||
latitude: 39.90723
|
||||
},
|
||||
radius: 30,
|
||||
isActive: true,
|
||||
eventType: 'enter',
|
||||
createdAt: '2024-01-17T09:15:00Z'
|
||||
}
|
||||
]
|
||||
console.log(mockFences)
|
||||
return createLocationResponse<FenceInfo>(200, '获取围栏列表成功', mockFences)
|
||||
} catch (error) {
|
||||
console.error('获取围栏列表失败:', error)
|
||||
return createLocationErrorResponse('获取围栏列表失败')
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 获取位置历史记录
|
||||
*/
|
||||
static async getLocationHistory(deviceId: string, startDate: string, endDate: string): Promise<AkReqResponse<LocationHistoryItem[]>> {
|
||||
try {
|
||||
await new Promise<void>((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve()
|
||||
}, 1200)
|
||||
})
|
||||
|
||||
const mockHistory: LocationHistoryItem[] = [
|
||||
{
|
||||
id: 'HIST001',
|
||||
deviceId: deviceId,
|
||||
baseStation: {
|
||||
id: 'BS001',
|
||||
name: '教学楼A栋基站',
|
||||
location: '教学楼A栋1层',
|
||||
longitude: 116.397428,
|
||||
latitude: 39.90923,
|
||||
signalStrength: -45,
|
||||
isOnline: true,
|
||||
range: 50
|
||||
},
|
||||
timestamp: '2024-01-20T08:30:00Z',
|
||||
duration: 3600,
|
||||
locationType: 'basestation'
|
||||
},
|
||||
{
|
||||
id: 'HIST002',
|
||||
deviceId: deviceId,
|
||||
baseStation: {
|
||||
id: 'BS003',
|
||||
name: '操场基站',
|
||||
location: '学校操场',
|
||||
longitude: 116.399428,
|
||||
latitude: 39.91123,
|
||||
signalStrength: -38,
|
||||
isOnline: true,
|
||||
range: 100
|
||||
},
|
||||
timestamp: '2024-01-20T10:00:00Z',
|
||||
duration: 2400,
|
||||
locationType: 'basestation'
|
||||
},
|
||||
{
|
||||
id: 'HIST003',
|
||||
deviceId: deviceId,
|
||||
baseStation: {
|
||||
id: 'BS002',
|
||||
name: '教学楼B栋基站',
|
||||
location: '教学楼B栋2层',
|
||||
longitude: 116.398428,
|
||||
latitude: 39.91023,
|
||||
signalStrength: -52,
|
||||
isOnline: true,
|
||||
range: 45
|
||||
},
|
||||
timestamp: '2024-01-20T14:20:00Z',
|
||||
duration: 5400,
|
||||
locationType: 'basestation'
|
||||
}
|
||||
]
|
||||
|
||||
return createLocationResponse(200, '获取位置历史成功', mockHistory)
|
||||
} catch (error) {
|
||||
console.error('获取位置历史失败:', error)
|
||||
return createLocationErrorResponse('获取位置历史失败')
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 获取围栏事件记录
|
||||
*/
|
||||
static async getFenceEvents(deviceId: string, limit: number = 10): Promise<AkReqResponse<FenceEvent[]>> {
|
||||
try {
|
||||
await new Promise<void>((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve()
|
||||
}, 900)
|
||||
})
|
||||
const mockEvents: FenceEvent[] = [ {
|
||||
id: 'EVENT001',
|
||||
deviceId: deviceId,
|
||||
fence: {
|
||||
id: 'FENCE001',
|
||||
name: '校园安全区域',
|
||||
type: 'circle',
|
||||
center: {
|
||||
longitude: 116.397928,
|
||||
latitude: 39.90973
|
||||
},
|
||||
radius: 200,
|
||||
isActive: true,
|
||||
eventType: 'exit',
|
||||
createdAt: '2024-01-15T10:00:00Z'
|
||||
},
|
||||
eventType: 'enter',
|
||||
timestamp: '2024-01-20T07:45:00Z',
|
||||
location: {
|
||||
longitude: 116.397528,
|
||||
latitude: 39.90943
|
||||
},
|
||||
isRead: false
|
||||
},
|
||||
{
|
||||
id: 'EVENT002',
|
||||
deviceId: deviceId,
|
||||
fence: {
|
||||
id: 'FENCE002',
|
||||
name: '教学区域',
|
||||
type: 'polygon',
|
||||
points: [
|
||||
{ longitude: 116.397000, latitude: 39.909000 },
|
||||
{ longitude: 116.398000, latitude: 39.909000 },
|
||||
{ longitude: 116.398000, latitude: 39.910000 },
|
||||
{ longitude: 116.397000, latitude: 39.910000 }
|
||||
],
|
||||
isActive: true,
|
||||
eventType: 'both',
|
||||
createdAt: '2024-01-16T14:30:00Z'
|
||||
},
|
||||
eventType: 'enter',
|
||||
timestamp: '2024-01-20T08:30:00Z',
|
||||
location: {
|
||||
longitude: 116.397500,
|
||||
latitude: 39.909500
|
||||
},
|
||||
isRead: true
|
||||
}
|
||||
]
|
||||
|
||||
return createLocationResponse(200, '获取围栏事件成功', mockEvents)
|
||||
} catch (error) {
|
||||
console.error('获取围栏事件失败:', error)
|
||||
return createLocationErrorResponse('获取围栏事件失败')
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 创建围栏
|
||||
*/
|
||||
static async createFence(fence: PartialFenceInfo): Promise<AkReqResponse<FenceInfo>> {
|
||||
try {
|
||||
await new Promise<void>((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve()
|
||||
}, 1500)
|
||||
})
|
||||
|
||||
const newFence: FenceInfo[] = [{
|
||||
id: `FENCE${Date.now()}`,
|
||||
name: fence.name ?? '新围栏',
|
||||
type: fence.type ?? 'circle',
|
||||
center: fence.center,
|
||||
radius: fence.radius,
|
||||
points: fence.points,
|
||||
isActive: fence.isActive ?? true,
|
||||
eventType: fence.eventType ?? 'both',
|
||||
createdAt: new Date().toISOString()
|
||||
}]
|
||||
|
||||
return createLocationResponse(200, '创建围栏成功', newFence)
|
||||
} catch (error) {
|
||||
console.error('创建围栏失败:', error)
|
||||
return createLocationErrorResponse('创建围栏失败')
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 更新围栏
|
||||
*/
|
||||
static async updateFence(fenceId: string, updates: PartialFenceInfo): Promise<AkReqResponse<FenceInfo>> {
|
||||
try {
|
||||
await new Promise<void>((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve()
|
||||
}, 1200)
|
||||
})
|
||||
|
||||
// 模拟更新成功
|
||||
const updatedFence: FenceInfo[] = [{
|
||||
id: fenceId,
|
||||
name: updates.name ?? '更新的围栏',
|
||||
type: updates.type ?? 'circle',
|
||||
center: updates.center,
|
||||
radius: updates.radius,
|
||||
points: updates.points,
|
||||
isActive: updates.isActive ?? true,
|
||||
eventType: updates.eventType ?? 'both',
|
||||
createdAt: '2024-01-15T10:00:00Z'
|
||||
}]
|
||||
|
||||
return createLocationResponse(200, '更新围栏成功', updatedFence)
|
||||
} catch (error) {
|
||||
console.error('更新围栏失败:', error)
|
||||
return createLocationErrorResponse('更新围栏失败')
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 删除围栏
|
||||
*/
|
||||
static async deleteFence(fenceId: string): Promise<AkReqResponse<Array<boolean>>> {
|
||||
try {
|
||||
await new Promise<void>((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve()
|
||||
}, 800)
|
||||
})
|
||||
|
||||
return createLocationResponse(200, '删除围栏成功', [true])
|
||||
} catch (error) {
|
||||
console.error('删除围栏失败:', error)
|
||||
return createLocationErrorResponse('删除围栏失败')
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 标记围栏事件为已读
|
||||
*/
|
||||
static async markEventAsRead(eventId: string): Promise<AkReqResponse<Array<boolean>>> {
|
||||
try {
|
||||
await new Promise<void>((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve()
|
||||
}, 500)
|
||||
})
|
||||
|
||||
return createLocationResponse(200, '标记事件成功', [true])
|
||||
} catch (error) {
|
||||
console.error('标记事件失败:', error)
|
||||
return createLocationErrorResponse('标记事件失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user