Files
akmon/utils/store.uts
2026-01-20 08:04:15 +08:00

457 lines
12 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import supa, { supaReady } from '@/components/supadb/aksupainstance.uts'
import type { UserProfile, UserStats } from '@/pages/user/types.uts'
import type { DeviceInfo } from '@/pages/sense/types.uts'
import { SenseDataService, type DeviceParams } from '@/pages/sense/senseDataService.uts'
import { reactive } from 'vue'
import { ensureUserProfile } from './sapi.uts'
// 设备状态类型
export type DeviceState = {
devices : Array<DeviceInfo>
currentDevice : DeviceInfo | null
isLoading : boolean
lastUpdated : number | null
}
//定义一个大写的State类型
export type State = {
globalNum : number
userProfile ?: UserProfile
isLoggedIn : boolean // 新增字段
deviceState : DeviceState // 新增设备状态
// 如有需要,可增加更多属性
}
// 实例化为state
export const state = reactive({
globalNum: 0,
userProfile: { username: '', email: '' },
isLoggedIn: false,
deviceState: {
devices: [],
currentDevice: null,
isLoading: false,
lastUpdated: null
} as DeviceState
} as State)
// 定义修改属性值的方法
export const setGlobalNum = (num : number) => {
state.globalNum = num
}
// 新增:设置登录状态的方法
export const setIsLoggedIn = (val : boolean) => {
state.isLoggedIn = val
}
// 定义全局设置用户信息的方法
export const setUserProfile = (profile : UserProfile) => {
state.userProfile = profile
}
// 获取当前用户信息(含补全 profile
export async function getCurrentUser() : Promise<UserProfile | null> {
try {
await supaReady
} catch (_) {}
const sessionInfo = supa.getSession()
if (sessionInfo.user == null) {
state.userProfile = { username: '', email: '' }
state.isLoggedIn = false // 未登录
return null
}
const userId = sessionInfo.user?.getString("id")
if (userId == null) {
state.userProfile = { username: '', email: '' }
state.isLoggedIn = false // 未登录
return null
} // 查询 ak_users 表补全 profile
const res = await supa.from('ak_users').select('*', {}).eq('id', userId).execute()
console.log(res)
if (res.status >= 200 && res.status < 300 && (res.data != null)) {
let user : UTSJSONObject | null = null;
const data = res.data as any;
if (Array.isArray(data)) {
if (data.length > 0) {
user = data[0] as UTSJSONObject;
}
} else if (data != null) {
user = data as UTSJSONObject;
} console.log(user)
if (user == null) {
console.log('用户资料为空,尝试创建基础资料...') // 如果用户资料为空,尝试创建基础用户资料
const sessionUser = sessionInfo.user
if (sessionUser != null) {
const createdProfile = await ensureUserProfile(sessionUser)
if (createdProfile != null) {
state.userProfile = createdProfile
state.isLoggedIn = true
return createdProfile
} else {
console.error('创建用户资料失败')
state.userProfile = { username: '', email: '' }
state.isLoggedIn = false
return null
}
} else {
console.error('会话用户信息为空')
state.userProfile = { username: '', email: '' }
state.isLoggedIn = false
return null
}
}
console.log(user)
// 直接用 getString/getNumber无需兜底属性
const profile : UserProfile = {
id: user.getString('id'),
username: user.getString('username') ?? "",
email: user.getString('email') ?? "",
gender: user.getString('gender'),
birthday: user.getString('birthday'),
height_cm: user.getNumber('height_cm'),
weight_kg: user.getNumber('weight_kg'),
bio: user.getString('bio'),
avatar_url: user.getString('avatar_url'),
preferred_language: user.getString('preferred_language'),
role: user.getString('role'),
school_id: user.getString('school_id'),
grade_id: user.getString('grade_id'),
class_id: user.getString('class_id')
}
state.userProfile = profile
state.isLoggedIn = true // 登录成功
return profile
} else {
state.userProfile = { username: '', email: '' }
state.isLoggedIn = false // 未登录
return null
}
}
// 登出并清空用户信息
export function logout() {
supa.signOut()
state.userProfile = { username: '', email: '' }
state.isLoggedIn = false // 登出
}
// 获取当前用户ID优先级state.userProfile.id > session > localStorage
export function getCurrentUserId() : string {
try {
const profile = state.userProfile
if (profile != null && profile.id != null) {
const profileId = profile.id
if (profileId != null) {
return profileId
}
}
} catch (e) { }
try {
const session = supa.getSession()
if (session != null) {
const curuser = session.user
const userId = curuser?.getString('id')
if (userId != null) return userId
}
} catch (e) { }
return ''
}
// 获取当前用户的class_id
export function getCurrentUserClassId() : string | null {
try {
const profile = state.userProfile
if (profile != null && profile.class_id != null) {
return profile.class_id
}
} catch (e) {
console.error('获取用户class_id失败:', e)
}
return null
}
// User store API for component compatibility
export function getUserStore() {
return {
getUserId() : string | null {
const sessionInfo = supa.getSession()
return sessionInfo.user?.getString("id") ?? null
},
getUserName() : string | null {
return state.userProfile?.username ?? null
},
getUserRole() : string | null {
// Default role logic - can be enhanced based on your needs
const sessionInfo = supa.getSession()
if (sessionInfo.user == null) return null
// You can add role detection logic here
// For now, return a default role
return 'teacher' // or determine from user profile/database
},
getProfile() : UserProfile | null {
return state.userProfile
}
}
}
// ========== 设备状态管理方法 ==========
/**
* 设置设备加载状态
*/
export const setDeviceLoading = (loading : boolean) => {
state.deviceState.isLoading = loading
}
/**
* 设置设备列表
*/
export const setDevices = (devices : Array<DeviceInfo>) => {
state.deviceState.devices = devices
state.deviceState.lastUpdated = Date.now()
}
/**
* 添加设备到列表
*/
export const addDevice = (device : DeviceInfo) => {
const existingIndex = state.deviceState.devices.findIndex(d => d.id === device.id)
if (existingIndex >= 0) {
// 更新现有设备
state.deviceState.devices[existingIndex] = device
} else {
// 添加新设备
state.deviceState.devices.push(device)
}
state.deviceState.lastUpdated = Date.now()
}
/**
* 从列表中移除设备
*/
export const removeDevice = (deviceId : string) => {
const index = state.deviceState.devices.findIndex(d => d.id === deviceId)
if (index >= 0) {
state.deviceState.devices.splice(index, 1)
// 如果移除的是当前设备,清空当前设备
if (state.deviceState.currentDevice?.id === deviceId) {
state.deviceState.currentDevice = null
}
state.deviceState.lastUpdated = Date.now()
}
}
/**
* 更新设备信息
*/
export const updateDevice = (device : DeviceInfo) => {
const index = state.deviceState.devices.findIndex(d => d.id === device.id)
if (index >= 0) {
state.deviceState.devices[index] = device
// 如果更新的是当前设备,也更新当前设备
if (state.deviceState.currentDevice?.id === device.id) {
state.deviceState.currentDevice = device
}
state.deviceState.lastUpdated = Date.now()
}
}
/**
* 设置当前选中的设备
*/
export const setCurrentDevice = (device : DeviceInfo | null) => {
state.deviceState.currentDevice = device
}
/**
* 根据设备ID获取设备信息
*/
export const getDeviceById = (deviceId : string) : DeviceInfo | null => {
return state.deviceState.devices.find(d => d.id === deviceId) ?? null
}
/**
* 获取在线设备列表
*/
export const getOnlineDevices = () : Array<DeviceInfo> => {
return state.deviceState.devices.filter(d => d.status === 'online')
}
/**
* 从服务器加载设备列表
*/
export const loadDevices = async (forceRefresh : boolean) : Promise<boolean> => {
const userId = getCurrentUserId()
if (userId == null || userId === '') {
console.log('用户未登录,无法加载设备列表')
return false
}
// 如果不是强制刷新且数据较新5分钟内直接返回
const now = Date.now()
const lastUpdated = state.deviceState.lastUpdated
if (forceRefresh == false && lastUpdated != null && (now - lastUpdated < 5 * 60 * 1000)) {
console.log('设备数据较新,跳过刷新')
return true
}
setDeviceLoading(true)
try {
const result = await SenseDataService.getDevices({ user_id: userId })
if (result.error === null && result.data != null) {
const devices = result.data as Array<DeviceInfo>
setDevices(devices)
console.log(`加载设备列表成功,共${devices.length}个设备`)
return true
} else {
console.log('加载设备列表失败:', result.error?.message ?? '未知错误')
return false
}
} catch (error) {
console.log('加载设备列表异常:', error)
return false
} finally {
setDeviceLoading(false)
}
}
/**
* 从服务器加载设备列表 - 带默认参数的重载版本
*/
export const loadDevicesWithDefault = async () : Promise<boolean> => {
return await loadDevices(false)
}
/**
* 绑定新设备
*/
export const bindNewDevice = async (deviceData : UTSJSONObject) : Promise<boolean> => {
const userId = getCurrentUserId()
if (userId == null) {
console.log('用户未登录,无法绑定设备')
return false
}
// 确保设备数据中包含用户ID
deviceData.set('user_id', userId)
try {
const result = await SenseDataService.bindDevice(deviceData)
if (result.error === null && result.data != null) {
// 添加到本地状态
addDevice(result.data as DeviceInfo)
const deviceName = (result.data as DeviceInfo).device_name ?? '未知设备'
console.log('设备绑定成功:', deviceName)
return true
} else {
console.log('设备绑定失败:', result.error?.message ?? '未知错误')
return false
}
} catch (error) {
console.log('设备绑定异常:', error)
return false
}
}
/**
* 解绑设备
*/
export const unbindDevice = async (deviceId : string) : Promise<boolean> => {
try {
const result = await SenseDataService.unbindDevice(deviceId)
if (result.error === null) {
// 从本地状态中移除
removeDevice(deviceId)
console.log('设备解绑成功')
return true
} else {
console.log('设备解绑失败:', result.error?.message ?? '未知错误')
return false
}
} catch (error) {
console.log('设备解绑异常:', error)
return false
}
}
/**
* 更新设备配置
*/
export const updateDeviceConfig = async (deviceId : string, configData : UTSJSONObject) : Promise<boolean> => {
try {
const result = await SenseDataService.updateDevice(deviceId, configData)
if (result.error === null && result.data != null) {
// 更新本地状态
updateDevice(result.data as DeviceInfo)
console.log('设备配置更新成功')
return true
} else {
console.log('设备配置更新失败:', result.error?.message ?? '未知错误')
return false
}
} catch (error) {
console.log('设备配置更新异常:', error)
return false
}
}
// ========== 设备管理 API ==========
/**
* 获取设备管理相关的API
*/
export function getDeviceStore() {
return {
// 获取设备状态
getDevices() : Array<DeviceInfo> {
return state.deviceState.devices
},
getCurrentDevice() : DeviceInfo | null {
return state.deviceState.currentDevice
},
isLoading() : boolean {
return state.deviceState.isLoading
},
getLastUpdated() : number | null {
return state.deviceState.lastUpdated
},
// 设备操作方法
async loadDevices(forceRefresh : boolean) : Promise<boolean> {
return await loadDevices(forceRefresh)
},
async refreshDevices() : Promise<boolean> {
return await loadDevicesWithDefault()
},
async bindDevice(deviceData : UTSJSONObject) : Promise<boolean> {
return await bindNewDevice(deviceData)
},
async unbindDevice(deviceId : string) : Promise<boolean> {
return await unbindDevice(deviceId)
},
async updateDevice(deviceId : string, configData : UTSJSONObject) : Promise<boolean> {
return await updateDeviceConfig(deviceId, configData)
},
// 设备查询方法
getDeviceById(deviceId : string) : DeviceInfo | null {
return getDeviceById(deviceId)
},
getOnlineDevices() : Array<DeviceInfo> {
return getOnlineDevices()
},
// 设备选择
setCurrentDevice(device : DeviceInfo | null) {
setCurrentDevice(device)
}
}
}