507 lines
15 KiB
Plaintext
507 lines
15 KiB
Plaintext
/**
|
||
* 传感器数据服务 - 使用 executeAs<T> 方式进行类型转换
|
||
* 减少UI层的类型转换问题
|
||
*/
|
||
|
||
import supa from '@/components/supadb/aksupainstance.uts'
|
||
import type { AkReqResponse } from '@/uni_modules/ak-req/index.uts'
|
||
import type {
|
||
SensorMeasurement,
|
||
SensorAnalysisResult,
|
||
DeviceInfo
|
||
} from './types.uts'
|
||
|
||
// Helper function to create error response factories
|
||
function createErrorResponseFactory<T>(defaults: T) {
|
||
return (message: string): AkReqResponse<T> => ({
|
||
status: 500,
|
||
data: defaults,
|
||
headers: {},
|
||
error: new UniError('SenseDataService', -1, message),
|
||
total: null,
|
||
page: null,
|
||
limit: null,
|
||
hasmore: null,
|
||
origin: null
|
||
});
|
||
}
|
||
|
||
// 保留原 createErrorResponse 以兼容其它调用(如有)
|
||
function createErrorResponse<T>(data: T, message: string): AkReqResponse<T> {
|
||
return createErrorResponseFactory<T>(data)(message);
|
||
}
|
||
|
||
// 查询参数类型
|
||
export type SensorDataParams = {
|
||
device_id ?: string | null
|
||
user_id ?: string | null
|
||
measurement_type ?: string | null
|
||
start_date ?: string | null
|
||
end_date ?: string | null
|
||
limit ?: number | null
|
||
offset ?: number | null
|
||
}
|
||
|
||
export type DeviceParams = {
|
||
user_id ?: string | null
|
||
device_type ?: string | null
|
||
status ?: string | null
|
||
}
|
||
|
||
/**
|
||
* 传感器数据服务类
|
||
*/
|
||
export class SenseDataService {
|
||
/**
|
||
* 获取传感器测量数据列表
|
||
*/
|
||
static async getMeasurements(params : SensorDataParams) : Promise<AkReqResponse<Array<SensorMeasurement>>> {
|
||
try {
|
||
let query = supa
|
||
.from('ss_sensor_measurements')
|
||
.select('*', {})
|
||
.order('measured_at', { ascending: false })
|
||
// 添加筛选条件
|
||
const deviceId = params.device_id
|
||
if (deviceId != null) {
|
||
query = query.eq('device_id', deviceId)
|
||
}
|
||
const userId = params.user_id
|
||
if (userId != null && userId !== '') {
|
||
query = query.eq('user_id', userId)
|
||
}
|
||
const measurementType = params.measurement_type
|
||
if (measurementType != null) {
|
||
query = query.eq('measurement_type', measurementType)
|
||
}
|
||
const startDate = params.start_date
|
||
if (startDate != null) {
|
||
query = query.gte('measured_at', startDate)
|
||
}
|
||
const endDate = params.end_date
|
||
if (endDate != null) {
|
||
query = query.lte('measured_at', endDate)
|
||
} // 分页
|
||
const limit = params.limit ?? 20
|
||
const offset = params.offset ?? 0
|
||
console.log(limit, offset)
|
||
|
||
// 先设置 limit,这会自动计算并设置对应的 range
|
||
query = query.limit(limit)
|
||
|
||
// 如果有 offset,需要重新调整 range
|
||
if (offset > 0) {
|
||
query = query.range(offset, offset + limit - 1)
|
||
}
|
||
|
||
// 如果 limit 为 1,使用 single() 方法优化查询
|
||
if (limit == 1) {
|
||
query = query.single()
|
||
}
|
||
const response = await query.executeAs<SensorMeasurement>()
|
||
|
||
return response
|
||
} catch (error) {
|
||
const errorMsg = typeof error === 'string' ? error : error?.message ?? '获取传感器数据失败';
|
||
const empty: SensorMeasurement = {
|
||
id: '', device_id: '', user_id: '', measurement_type: '', measured_at: '', unit: '', raw_data: new UTSJSONObject(), created_at: ''
|
||
};
|
||
const errorSensorMeasurement = createErrorResponseFactory(empty);
|
||
const errorSensorMeasurementArr = createErrorResponseFactory([] as SensorMeasurement[]);
|
||
if ((params.limit ?? 20) === 1) {
|
||
return errorSensorMeasurement(errorMsg);
|
||
} else {
|
||
return errorSensorMeasurementArr(errorMsg);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取单条传感器测量数据
|
||
*/
|
||
static async getMeasurementById(id : string) : Promise<AkReqResponse<SensorMeasurement>> {
|
||
try {
|
||
const response = await supa
|
||
.from('ss_sensor_measurements')
|
||
.select('*', {})
|
||
.eq('id', id)
|
||
.single()
|
||
.executeAs<SensorMeasurement>()
|
||
|
||
return response
|
||
} catch (error) {
|
||
const errorMsg = typeof error === 'string' ? error : error?.message ?? '获取传感器数据详情失败';
|
||
const empty: SensorMeasurement = {
|
||
id: '', device_id: '', user_id: '', measurement_type: '', measured_at: '', unit: '', raw_data: new UTSJSONObject(), created_at: ''
|
||
};
|
||
return createErrorResponseFactory(empty)(errorMsg);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取最新的传感器测量数据(单条记录)
|
||
*/
|
||
static async getLatestMeasurement(params : SensorDataParams) : Promise<AkReqResponse<SensorMeasurement>> {
|
||
try {
|
||
let query = supa
|
||
.from('ss_sensor_measurements')
|
||
.select('*', {})
|
||
.order('measured_at', { ascending: false })
|
||
|
||
// 添加筛选条件
|
||
const deviceId = params.device_id
|
||
if (deviceId != null) {
|
||
query = query.eq('device_id', deviceId)
|
||
}
|
||
const userId = params.user_id
|
||
if (userId != null) {
|
||
query = query.eq('user_id', userId)
|
||
}
|
||
const measurementType = params.measurement_type
|
||
if (measurementType != null) {
|
||
query = query.eq('measurement_type', measurementType)
|
||
}
|
||
|
||
// 使用 single() 方法获取单条最新记录
|
||
const response = await query.single().executeAs<SensorMeasurement>()
|
||
|
||
|
||
return response
|
||
|
||
} catch (error) {
|
||
const errorMsg = typeof error === 'string' ? error : error?.message ?? '获取最新传感器数据失败';
|
||
const empty: SensorMeasurement = {
|
||
id: '', device_id: '', user_id: '', measurement_type: '', measured_at: '', unit: '', raw_data: new UTSJSONObject(), created_at: ''
|
||
};
|
||
return createErrorResponseFactory(empty)(errorMsg);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取设备列表
|
||
*/
|
||
static async getDevices(params : DeviceParams) : Promise<AkReqResponse<Array<DeviceInfo>>> {
|
||
try {
|
||
let query = supa
|
||
.from('ak_devices')
|
||
.select('*', {})
|
||
.order('bind_time', { ascending: false })
|
||
// 添加筛选条件
|
||
const userId = params.user_id
|
||
if (userId != null) {
|
||
query = query.eq('user_id', userId)
|
||
}
|
||
const deviceType = params.device_type
|
||
if (deviceType != null) {
|
||
query = query.eq('device_type', deviceType)
|
||
}
|
||
const status = params.status
|
||
if (status != null) {
|
||
query = query.eq('status', status)
|
||
}
|
||
|
||
const response = await query.executeAs<DeviceInfo>()
|
||
|
||
|
||
return response
|
||
|
||
|
||
} catch (error) {
|
||
const errorMsg = typeof error === 'string' ? error : error?.message ?? '获取设备列表失败';
|
||
return createErrorResponseFactory([] as DeviceInfo[])(errorMsg);
|
||
}
|
||
}
|
||
/**
|
||
* 获取设备详情
|
||
*/
|
||
static async getDeviceById(id : string) : Promise<AkReqResponse<Array<DeviceInfo>>> {
|
||
try {
|
||
const response = await supa
|
||
.from('ak_devices')
|
||
.select('*', {})
|
||
.eq('id', id)
|
||
.single()
|
||
.executeAs<DeviceInfo>()
|
||
|
||
console.log(response)
|
||
return response
|
||
} catch (error) {
|
||
const errorMsg = typeof error === 'string' ? error : error?.message ?? '获取设备详情失败';
|
||
const empty: DeviceInfo = {
|
||
id: '', user_id: '', device_type: '', device_name: '', device_mac: '', bind_time: '', status: '', extra: new UTSJSONObject()
|
||
};
|
||
return createErrorResponseFactory(empty)(errorMsg);
|
||
}
|
||
}
|
||
/**
|
||
* 获取分析结果列表
|
||
*/
|
||
static async getAnalysisResults(user_id : string, analysis_type ?: string | null) : Promise<AkReqResponse<Array<SensorAnalysisResult>>> {
|
||
try {
|
||
let query = supa
|
||
.from('ak_sensor_analysis')
|
||
.select('*', {})
|
||
.eq('user_id', user_id)
|
||
.order('created_at', { ascending: false })
|
||
const analysisType = analysis_type
|
||
if (analysisType != null) {
|
||
query = query.eq('analysis_type', analysisType)
|
||
}
|
||
|
||
const response = await query.executeAs<SensorAnalysisResult>()
|
||
return response
|
||
|
||
} catch (error) {
|
||
const errorMsg = typeof error === 'string' ? error : error?.message ?? '获取分析结果失败';
|
||
return createErrorResponseFactory([] as SensorAnalysisResult[])(errorMsg);
|
||
}
|
||
}/**
|
||
* 创建传感器测量数据 - 支持单个或批量
|
||
*/
|
||
static async createMeasurement(data : UTSJSONObject | Array<UTSJSONObject>) : Promise<AkReqResponse<SensorMeasurement | Array<SensorMeasurement>>> {
|
||
return await this.insertMeasurementData(data)
|
||
}/**
|
||
* 批量创建传感器测量数据(用于模拟器)
|
||
* @deprecated 使用 createMeasurement 方法,它现在支持批量插入
|
||
*/
|
||
static async createMeasurements(dataList : Array<UTSJSONObject>) : Promise<AkReqResponse<Array<SensorMeasurement>>> {
|
||
const result = await this.createMeasurement(dataList)
|
||
return result as AkReqResponse<Array<SensorMeasurement>>
|
||
}
|
||
/**
|
||
* 绑定设备
|
||
*/
|
||
static async bindDevice(deviceData : UTSJSONObject) : Promise<AkReqResponse<DeviceInfo>> {
|
||
try {
|
||
const data = new UTSJSONObject()
|
||
// 复制传入的数据
|
||
const keys = UTSJSONObject.keys(data)
|
||
for (let i = 0; i < keys.length; i++) {
|
||
const key = keys[i]
|
||
data.set(key, deviceData.get(key))
|
||
}
|
||
data.set('bind_time', new Date().toISOString())
|
||
data.set('status', 'online')
|
||
const response = await supa
|
||
.from('ak_devices')
|
||
.insert(data)
|
||
.select('*', {})
|
||
.single()
|
||
.executeAs<DeviceInfo>()
|
||
|
||
|
||
return response
|
||
} catch (error) {
|
||
const errorMsg = typeof error === 'string' ? error : error?.message ?? '绑定设备失败';
|
||
const empty: DeviceInfo = {
|
||
id: '', user_id: '', device_type: '', device_name: '', device_mac: '', bind_time: '', status: '', extra: new UTSJSONObject()
|
||
};
|
||
return createErrorResponseFactory(empty)(errorMsg);
|
||
}
|
||
}
|
||
/**
|
||
* 更新设备状态
|
||
*/
|
||
static async updateDeviceStatus(device_id : string, status : string) : Promise<AkReqResponse<DeviceInfo>> {
|
||
try {
|
||
const response = await supa
|
||
.from('ak_devices')
|
||
.update({ status: status })
|
||
.eq('id', device_id)
|
||
.select('*', {})
|
||
.single()
|
||
.executeAs<DeviceInfo>()
|
||
|
||
|
||
return response
|
||
} catch (error) {
|
||
const errorMsg = typeof error === 'string' ? error : error?.message ?? '更新设备状态失败';
|
||
const empty: DeviceInfo = {
|
||
id: '', user_id: '', device_type: '', device_name: '', device_mac: '', bind_time: '', status: '', extra: new UTSJSONObject()
|
||
};
|
||
return createErrorResponseFactory(empty)(errorMsg);
|
||
}
|
||
}
|
||
/**
|
||
* 解绑设备
|
||
*/
|
||
static async unbindDevice(device_id : string) : Promise<AkReqResponse<boolean>> {
|
||
try {
|
||
const response = await supa
|
||
.from('ak_devices')
|
||
.delete()
|
||
.eq('id', device_id)
|
||
.execute()
|
||
|
||
if (response.error === null) {
|
||
return {
|
||
status: 200,
|
||
data: true,
|
||
headers: {},
|
||
error: null,
|
||
total: null,
|
||
page: null,
|
||
limit: null,
|
||
hasmore: null,
|
||
origin: null
|
||
}
|
||
} else {
|
||
return createErrorResponseFactory(false)(response.error?.message ?? '设备解绑失败');
|
||
}
|
||
} catch (error) {
|
||
const errorMsg = typeof error === 'string' ? error : error?.message ?? '设备解绑失败';
|
||
return createErrorResponseFactory(false)(errorMsg);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 更新设备信息
|
||
*/
|
||
static async updateDevice(device_id : string, deviceData : UTSJSONObject) : Promise<AkReqResponse<DeviceInfo>> {
|
||
try {
|
||
const response = await supa
|
||
.from('ak_devices')
|
||
.update(deviceData)
|
||
.eq('id', device_id)
|
||
.select('*', {})
|
||
.single()
|
||
.executeAs<DeviceInfo>()
|
||
|
||
return response
|
||
} catch (error) {
|
||
const errorMsg = typeof error === 'string' ? error : error?.message ?? '更新设备信息失败';
|
||
const empty: DeviceInfo = {
|
||
id: '', user_id: '', device_type: '', device_name: '', device_mac: '', bind_time: '', status: '', extra: new UTSJSONObject()
|
||
};
|
||
return createErrorResponseFactory(empty)(errorMsg);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 统一的插入方法 - 支持单个或批量插入
|
||
* @param data 单个对象或对象数组
|
||
* @returns 插入结果
|
||
*/
|
||
static async insertMeasurements(data : UTSJSONObject | Array<UTSJSONObject>) : Promise<AkReqResponse<SensorMeasurement | Array<SensorMeasurement>>> {
|
||
try {
|
||
let processedData : UTSJSONObject | Array<UTSJSONObject>
|
||
let isBatch = false
|
||
|
||
if (Array.isArray(data)) {
|
||
// 批量插入
|
||
isBatch = true
|
||
const measurementDataList : Array<UTSJSONObject> = []
|
||
|
||
for (let i = 0; i < data.length; i++) {
|
||
const item = data[i]
|
||
const measurementData = new UTSJSONObject()
|
||
// 复制传入的数据
|
||
const keys = UTSJSONObject.keys(item)
|
||
for (let j = 0; j < keys.length; j++) {
|
||
const key = keys[j]
|
||
measurementData.set(key, item.get(key))
|
||
}
|
||
measurementData.set('created_at', new Date().toISOString())
|
||
measurementDataList.push(measurementData)
|
||
}
|
||
processedData = measurementDataList
|
||
} else {
|
||
// 单个插入
|
||
const measurementData = new UTSJSONObject()
|
||
// 复制传入的数据
|
||
const keys = UTSJSONObject.keys(data)
|
||
for (let i = 0; i < keys.length; i++) {
|
||
const key = keys[i]
|
||
measurementData.set(key, data.get(key))
|
||
}
|
||
measurementData.set('created_at', new Date().toISOString())
|
||
processedData = measurementData
|
||
}
|
||
let query = supa
|
||
.from('ss_sensor_measurements')
|
||
.insert(processedData)
|
||
.select('*', {})
|
||
|
||
// 根据是否批量决定是否使用 single()
|
||
if (!isBatch) {
|
||
query = query.single()
|
||
}
|
||
|
||
if (isBatch) {
|
||
const response = await query.executeAs<SensorMeasurement>()
|
||
return response
|
||
} else {
|
||
const response = await query.executeAs<SensorMeasurement>()
|
||
|
||
return response
|
||
}
|
||
} catch (error) {
|
||
const errorMsg = typeof error === 'string' ? error : error?.message ?? (Array.isArray(data) ? '批量创建传感器数据失败' : '创建传感器数据失败');
|
||
const empty: SensorMeasurement = {
|
||
id: '', device_id: '', user_id: '', measurement_type: '', measured_at: '', unit: '', raw_data: new UTSJSONObject(), created_at: ''
|
||
};
|
||
const errorSensorMeasurement = createErrorResponseFactory(empty);
|
||
const errorSensorMeasurementArr = createErrorResponseFactory([] as SensorMeasurement[]);
|
||
if (Array.isArray(data)) {
|
||
return errorSensorMeasurementArr(errorMsg) as AkReqResponse<SensorMeasurement | Array<SensorMeasurement>>;
|
||
} else {
|
||
return errorSensorMeasurement(errorMsg) as AkReqResponse<SensorMeasurement | Array<SensorMeasurement>>;
|
||
}
|
||
}
|
||
}
|
||
/**
|
||
* 传感器测量数据插入方法 - 支持单个或批量插入
|
||
* @param data 单个对象或对象数组
|
||
* @returns 插入结果
|
||
*/
|
||
static async insertMeasurementData(data : UTSJSONObject | Array<UTSJSONObject>) : Promise<AkReqResponse<Array<SensorMeasurement>>> {
|
||
try {
|
||
let processedData : UTSJSONObject | Array<UTSJSONObject>
|
||
let isBatch = Array.isArray(data)
|
||
|
||
if (isBatch) {
|
||
// 批量插入
|
||
const dataList : Array<UTSJSONObject> = []
|
||
const dataArray = data as Array<UTSJSONObject>
|
||
|
||
for (let i = 0; i < dataArray.length; i++) {
|
||
const item = dataArray[i]
|
||
const processedItem = new UTSJSONObject()
|
||
// 复制传入的数据
|
||
const keys = UTSJSONObject.keys(item)
|
||
for (let j = 0; j < keys.length; j++) {
|
||
const key = keys[j]
|
||
processedItem.set(key, item.get(key))
|
||
}
|
||
processedItem.set('created_at', new Date().toISOString())
|
||
dataList.push(processedItem)
|
||
}
|
||
processedData = dataList
|
||
} else {
|
||
// 单个插入
|
||
const singleData = data as UTSJSONObject
|
||
const processedItem = new UTSJSONObject()
|
||
// 复制传入的数据
|
||
const keys = UTSJSONObject.keys(singleData)
|
||
for (let i = 0; i < keys.length; i++) {
|
||
const key = keys[i]
|
||
processedItem.set(key, singleData.get(key))
|
||
}
|
||
processedItem.set('created_at', new Date().toISOString())
|
||
processedData = processedItem
|
||
}
|
||
let query = supa
|
||
.from('ss_sensor_measurements')
|
||
.insert(processedData)
|
||
|
||
|
||
const response = await query.executeAs<SensorMeasurement>()
|
||
|
||
return response
|
||
|
||
} catch (error) {
|
||
const errorMsg = typeof error === 'string' ? error : error?.message ?? '插入传感器数据失败';
|
||
return createErrorResponseFactory([] as SensorMeasurement[])(errorMsg) as AkReqResponse<SensorMeasurement | Array<SensorMeasurement>>;
|
||
}
|
||
}
|
||
} |