项目从akmon迁入到mall

This commit is contained in:
comlibmb
2026-01-21 12:12:22 +08:00
parent cf8236e175
commit d7f95f7fa5
165 changed files with 69160 additions and 0 deletions

14
utils/i18nfun.uts Normal file
View File

@@ -0,0 +1,14 @@
import i18n from '@/i18n/index.uts'
// 包装一个带参数智能判断的 t 函数,支持缺省值
export function tt(key: string, values: any | null = null, locale: string | null = null): string {
const isLocale = typeof values === 'string'
const _values = isLocale ? null : values
const _locale = isLocale ? values : locale
return i18n.global.t(key, _values, _locale)
}
// 示例用法
// tSmart('prev')
// tSmart('prev', 'en-US')
// tSmart('prev', {name: '张三'})

457
utils/store.uts Normal file
View File

@@ -0,0 +1,457 @@
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)
}
}
}

159
utils/utils.uts Normal file
View File

@@ -0,0 +1,159 @@
// 通用 UTSJSONObject 转任意 type 的函数
// UTS 2024
import i18n from '../i18n/index.uts';
/**
* 切换应用语言设置
* @param locale 语言代码,如 'zh-CN' 或 'en-US'
*/
export function switchLocale(locale: string) {
// 设置存储
uni.setStorageSync('uVueI18nLocale', locale);
// 设置 i18n 语言
try {
i18n.global.locale.value = locale;
} catch (err) {
console.error('Failed to switch locale:', err);
}
}
/**
* 获取当前语言设置
* @returns 当前语言代码
*/
export function getCurrentLocale(): string {
const locale = uni.getStorageSync('uVueI18nLocale') as string;
if (locale == null || locale == '') {
return 'zh-CN';
}
return locale;
}
/**
* 确保语言设置正确初始化
*/
export function ensureLocaleInitialized() {
const currentLocale = getCurrentLocale();
if (currentLocale == null || currentLocale == '') {
switchLocale('zh-CN');
}
}
/**
* 将任意错误对象转换为标准的 UniError
* @param error 任意类型的错误对象
* @param defaultMessage 默认错误消息
* @returns 标准化的 UniError 对象
*/
export function toUniError(error: any, defaultMessage: string = '操作失败'): UniError {
// 如果已经是 UniError直接返回
if (error instanceof UniError) {
return error
}
let errorMessage = defaultMessage
let errorCode = -1
try {
// 如果是普通 Error 对象
if (error instanceof Error) {
errorMessage = error.message != null && error.message != '' ? error.message : defaultMessage
}
// 如果是字符串
else if (typeof error === 'string') {
errorMessage = error
} // 如果是对象,尝试提取错误信息
else if (error != null && typeof error === 'object') {
const errorObj = error as UTSJSONObject
let message: string = ''
// 逐个检查字段,避免使用 || 操作符
if (errorObj['message'] != null) {
const msgValue = errorObj['message']
if (typeof msgValue === 'string') {
message = msgValue
}
} else if (errorObj['errMsg'] != null) {
const msgValue = errorObj['errMsg']
if (typeof msgValue === 'string') {
message = msgValue
}
} else if (errorObj['error'] != null) {
const msgValue = errorObj['error']
if (typeof msgValue === 'string') {
message = msgValue
}
} else if (errorObj['details'] != null) {
const msgValue = errorObj['details']
if (typeof msgValue === 'string') {
message = msgValue
}
} else if (errorObj['msg'] != null) {
const msgValue = errorObj['msg']
if (typeof msgValue === 'string') {
message = msgValue
}
}
if (message != '') {
errorMessage = message
}
// 尝试提取错误码
let code: number = 0
if (errorObj['code'] != null) {
const codeValue = errorObj['code']
if (typeof codeValue === 'number') {
code = codeValue
}
} else if (errorObj['errCode'] != null) {
const codeValue = errorObj['errCode']
if (typeof codeValue === 'number') {
code = codeValue
}
} else if (errorObj['status'] != null) {
const codeValue = errorObj['status']
if (typeof codeValue === 'number') {
code = codeValue
}
}
if (code != 0) {
errorCode = code
}
}
} catch (e) {
console.error('Error converting to UniError:', e)
errorMessage = defaultMessage
}
// 创建标准 UniError
const uniError = new UniError('AppError', errorCode, errorMessage)
return uniError
}
/**
* 响应式状态管理
* @returns 响应式状态对象
*/
export function responsiveState() {
const screenInfo = uni.getSystemInfoSync()
const screenWidth = screenInfo.screenWidth
return {
isLargeScreen: screenWidth >= 768,
isSmallScreen: screenWidth < 576,
screenWidth: screenWidth,
cardColumns: screenWidth >= 768 ? 3 : screenWidth >= 576 ? 2 : 1
}
}
/**
* 兼容 UTS Android 的剪贴板写入
* @param text 要写入剪贴板的文本
*/
export function setClipboard(text: string): void {
// #ifdef WEB
uni.setClipboardData({ data: text });
// #endif
}