Initial commit of akmon project
This commit is contained in:
582
utils/msgDataServiceReal.uts
Normal file
582
utils/msgDataServiceReal.uts
Normal file
@@ -0,0 +1,582 @@
|
||||
/**
|
||||
* 消息数据服务 - 真实 supadb 集成版本
|
||||
* 严格遵循 UTS Android 要求,使用真实的 AkSupa 组件
|
||||
*/
|
||||
|
||||
import supa from '@/components/supadb/aksupainstance.uts'
|
||||
import type { AkReqResponse } from '@/uni_modules/ak-req/index.uts'
|
||||
import type {
|
||||
Message,
|
||||
MessageType,
|
||||
MessageRecipient,
|
||||
MessageGroup,
|
||||
MessageStats,
|
||||
MessageListParams,
|
||||
SendMessageParams,
|
||||
UserOption,
|
||||
MessageSenderType,
|
||||
MessageReceiverType,
|
||||
MessageContentType,
|
||||
MessageStatus,
|
||||
RecipientStatus,
|
||||
DeliveryMethod,
|
||||
GroupType,
|
||||
MemberRole,
|
||||
MemberStatus
|
||||
} from './msgTypes.uts'
|
||||
|
||||
// 定义 GroupMember 类型,如果在 msgTypes.uts 中没有的话
|
||||
type GroupMember = {
|
||||
id : string;
|
||||
group_id : string;
|
||||
user_id : string;
|
||||
role : MemberRole;
|
||||
status : MemberStatus;
|
||||
joined_at : string;
|
||||
updated_at : string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息数据服务- 真实 supadb 版本
|
||||
* 提供消息系统的所有数据操作
|
||||
* 统一使用 aksupainstance.uts
|
||||
*/
|
||||
export class MsgDataServiceReal {
|
||||
|
||||
/**
|
||||
* 获取消息类型列表
|
||||
*/
|
||||
static async getMessageTypes() : Promise<AkReqResponse<Array<MessageType>>> {
|
||||
try {
|
||||
const response = await supa
|
||||
.from('ak_message_types')
|
||||
.select('*', {})
|
||||
.eq('is_active', true)
|
||||
.order('priority', { ascending: false })
|
||||
.executeAs<MessageType>()
|
||||
|
||||
if (response.status >= 200 && response.status < 300 && response.data !== null) {
|
||||
console.log(response)
|
||||
return response
|
||||
}
|
||||
|
||||
// 如果没有数据,返回默认的消息类型
|
||||
return createErrorResponse<Array<MessageType>>([{
|
||||
id: 'default',
|
||||
code: 'default',
|
||||
name: '普通消息',
|
||||
description: '默认消息类型',
|
||||
icon: null,
|
||||
color: '#757575',
|
||||
priority: 50,
|
||||
is_system: false,
|
||||
is_active: true,
|
||||
auto_read_timeout: null,
|
||||
retention_days: 30,
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString()
|
||||
}], '无消息类型数据', 200)
|
||||
} catch (error) {
|
||||
// 出错时也返回默认的消息类型
|
||||
return createErrorResponse<Array<MessageType>>([{
|
||||
id: 'default',
|
||||
code: 'default',
|
||||
name: '普通消息',
|
||||
description: '默认消息类型',
|
||||
icon: null,
|
||||
color: '#757575',
|
||||
priority: 50,
|
||||
is_system: false,
|
||||
is_active: true,
|
||||
auto_read_timeout: null,
|
||||
retention_days: 30,
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString()
|
||||
}], typeof error === 'string' ? error : error?.message ?? '获取消息类型失败', 200)
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 获取消息列表
|
||||
*/
|
||||
static async getMessages(params : MessageListParams) : Promise<AkReqResponse<Array<Message>>> {
|
||||
try {
|
||||
let query = supa
|
||||
.from('ak_messages')
|
||||
.select(`
|
||||
*,
|
||||
message_type:ak_message_types(*),
|
||||
recipients:ak_message_recipients(*)
|
||||
`, {})
|
||||
.eq('is_deleted', false) // 添加筛选条件
|
||||
if (params.message_type != null) {
|
||||
query = query.eq('message_type', params.message_type as string)
|
||||
}
|
||||
if (params.sender_type != null) {
|
||||
query = query.eq('sender_type', params.sender_type as string)
|
||||
}
|
||||
if (params.sender_id != null) {
|
||||
query = query.eq('sender_id', params.sender_id as string)
|
||||
}
|
||||
if (params.receiver_type != null) {
|
||||
query = query.eq('receiver_type', params.receiver_type as string)
|
||||
}
|
||||
if (params.receiver_id != null) {
|
||||
query = query.eq('receiver_id', params.receiver_id as string)
|
||||
}
|
||||
if (params.status != null) {
|
||||
query = query.eq('status', params.status as string)
|
||||
}
|
||||
if (params.is_urgent != null) {
|
||||
query = query.eq('is_urgent', params.is_urgent as boolean)
|
||||
}
|
||||
const keyword = params.search
|
||||
if (keyword != null && keyword !== '') {
|
||||
query = query.or(`title.ilike.%${keyword}%,content.ilike.%${keyword}%`)
|
||||
}
|
||||
const limit = params.limit ?? 20
|
||||
const offset = params.offset ?? 0
|
||||
// 分页和排序
|
||||
const page = Math.floor(offset / limit) + 1
|
||||
const response = await query
|
||||
.order('created_at', { ascending: false })
|
||||
.range(offset, offset + limit - 1)
|
||||
.executeAs<Message>()
|
||||
// .execute()
|
||||
console.log(response)
|
||||
return response
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
return createErrorResponse<Array<UTSJSONObject>>([],
|
||||
typeof error === 'string' ? error : error?.message ?? '获取消息列表失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单条消息详情
|
||||
*/
|
||||
static async getMessageById(id : string) : Promise<AkReqResponse<Message>> {
|
||||
try {
|
||||
const response = await supa
|
||||
.from('ak_messages')
|
||||
.select(`
|
||||
*,
|
||||
message_type:ak_message_types(*),
|
||||
recipients:ak_message_recipients(*)
|
||||
`, {})
|
||||
.eq('id', id)
|
||||
.single()
|
||||
.executeAs<Message>()
|
||||
|
||||
return response
|
||||
} catch (error) {
|
||||
return {
|
||||
status: 500,
|
||||
data: null,
|
||||
error: new UniError(typeof error === 'string' ? error : error?.message ?? '获取消息内容失败'),
|
||||
origin: null,
|
||||
headers: {}
|
||||
} as AkReqResponse<Message>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消<E98081>?
|
||||
*/
|
||||
static async sendMessage(params : SendMessageParams) : Promise<AkReqResponse<Message>> {
|
||||
try {
|
||||
|
||||
|
||||
// 构建消息数据
|
||||
const messageData = {
|
||||
message_type_id: params.message_type_id,
|
||||
sender_type: params.sender_type,
|
||||
sender_id: params.sender_id,
|
||||
sender_name: params.sender_name,
|
||||
receiver_type: params.receiver_type,
|
||||
receiver_id: params.receiver_id,
|
||||
title: params.title,
|
||||
content: params.content,
|
||||
content_type: params.content_type !== null ? params.content_type : 'text',
|
||||
attachments: params.attachments,
|
||||
media_urls: params.media_urls,
|
||||
metadata: params.metadata,
|
||||
is_urgent: params.is_urgent !== null ? params.is_urgent : false,
|
||||
scheduled_at: params.scheduled_at,
|
||||
expires_at: params.expires_at,
|
||||
status: 'pending',
|
||||
is_deleted: false,
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString()
|
||||
}
|
||||
|
||||
// 插入消息
|
||||
const response = await supa
|
||||
.from('ak_messages')
|
||||
.insert(messageData)
|
||||
.single()
|
||||
.executeAs<Message>()
|
||||
|
||||
if (response.status >= 200 && response.status < 300) {
|
||||
const message = response.data as Message
|
||||
|
||||
// 创建接收记录
|
||||
// 批量接收人安全判断
|
||||
const receiversArr = params.receivers ?? []
|
||||
if (Array.isArray(receiversArr) && receiversArr.length > 0) {
|
||||
const recipients = receiversArr.map(receiverId => ({
|
||||
message_id: message.id,
|
||||
receiver_type: params.receiver_type,
|
||||
receiver_id: receiverId,
|
||||
status: 'unread',
|
||||
is_deleted: false,
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString()
|
||||
}))
|
||||
for (const rec of recipients) {
|
||||
await supa
|
||||
.from('ak_message_recipients')
|
||||
.insert(rec)
|
||||
.executeAs<MessageRecipient>()
|
||||
}
|
||||
}
|
||||
|
||||
return response
|
||||
} else {
|
||||
return response
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
status: 500,
|
||||
data: null,
|
||||
error: new UniError(typeof error === 'string' ? error : error?.message ?? '发送消息失败'),
|
||||
headers: {},
|
||||
total: null,
|
||||
page: null,
|
||||
limit: null,
|
||||
hasmore: false,
|
||||
origin: null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记消息为已读
|
||||
*/
|
||||
static async markAsRead(messageId : string, receiverId : string) : Promise<AkReqResponse<boolean>> {
|
||||
try {
|
||||
// 验证参数不能为空
|
||||
if (messageId == null || messageId === '' || receiverId == null || receiverId === '' || receiverId.trim() === '') {
|
||||
return createErrorResponse<boolean>(
|
||||
false,
|
||||
'参数错误:消息ID和接收者ID不能为空'
|
||||
)
|
||||
}
|
||||
|
||||
const response = await supa
|
||||
.from('ak_message_recipients')
|
||||
.update({
|
||||
status: 'read',
|
||||
read_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString()
|
||||
})
|
||||
.eq('message_id', messageId)
|
||||
.eq('recipient_id', receiverId)
|
||||
.executeAs<Array<MessageRecipient>>()
|
||||
|
||||
return {
|
||||
status: response.status,
|
||||
data: Array.isArray(response.data) ,
|
||||
headers: response.headers,
|
||||
error: response.error,
|
||||
total: response.total,
|
||||
page: response.page,
|
||||
limit: response.limit,
|
||||
hasmore: response.hasmore,
|
||||
origin: response.origin
|
||||
}
|
||||
} catch (error) {
|
||||
return createErrorResponse<boolean>(
|
||||
false,
|
||||
typeof error === 'string' ? error : error?.message ?? '标记已读失败'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除消息
|
||||
*/
|
||||
static async deleteMessage(messageId : string, userId : string) : Promise<AkReqResponse<boolean>> {
|
||||
try {
|
||||
// 软删除消息(对发送者)
|
||||
await supa
|
||||
.from('ak_messages')
|
||||
.update({
|
||||
is_deleted: true,
|
||||
updated_at: new Date().toISOString()
|
||||
})
|
||||
.eq('id', messageId)
|
||||
.eq('sender_id', userId)
|
||||
.executeAs<Array<Message>>()
|
||||
|
||||
// 软删除接收记录(对接收者)
|
||||
await supa
|
||||
.from('ak_message_recipients')
|
||||
.update({
|
||||
is_deleted: true,
|
||||
updated_at: new Date().toISOString()
|
||||
})
|
||||
.eq('message_id', messageId)
|
||||
.eq('recipient_id', userId)
|
||||
.executeAs<Array<MessageRecipient>>()
|
||||
const aaa = {
|
||||
status: 200,
|
||||
data: true,
|
||||
error: null,
|
||||
origin: null,
|
||||
headers: {}
|
||||
}
|
||||
return aaa
|
||||
} catch (error) {
|
||||
const aaa = {
|
||||
status: 500,
|
||||
data: false,
|
||||
error: new UniError(typeof error === 'string' ? error : error?.message ?? '删除消息失败'),
|
||||
origin: null,
|
||||
headers: {}
|
||||
}
|
||||
return aaa
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量操作消息
|
||||
*/
|
||||
static async batchOperation(
|
||||
messageIds : Array<string>,
|
||||
operation : string,
|
||||
userId : string
|
||||
) : Promise<AkReqResponse<boolean>> {
|
||||
try {
|
||||
// 验证参数不能为空
|
||||
if (userId == null || userId === '' || userId.trim() === '') {
|
||||
return createErrorResponse<boolean>(
|
||||
false,
|
||||
'参数错误:用户ID不能为空'
|
||||
)
|
||||
}
|
||||
|
||||
if (messageIds == null || messageIds.length === 0) {
|
||||
return createErrorResponse<boolean>(
|
||||
false,
|
||||
'参数错误:消息ID列表不能为空'
|
||||
)
|
||||
}
|
||||
|
||||
switch (operation) {
|
||||
case 'read':
|
||||
await supa
|
||||
.from('ak_message_recipients')
|
||||
.update({
|
||||
status: 'read',
|
||||
read_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString()
|
||||
})
|
||||
.in('message_id', messageIds.map(x => x as any))
|
||||
.eq('recipient_id', userId)
|
||||
.executeAs<Array<MessageRecipient>>()
|
||||
break
|
||||
|
||||
case 'delete':
|
||||
await supa
|
||||
.from('ak_message_recipients')
|
||||
.update({
|
||||
is_deleted: true,
|
||||
updated_at: new Date().toISOString()
|
||||
})
|
||||
.in('message_id', messageIds.map(x => x as any))
|
||||
.eq('recipient_id', userId)
|
||||
.executeAs<Array<MessageRecipient>>()
|
||||
break
|
||||
|
||||
default:
|
||||
return {
|
||||
status: 400,
|
||||
data: false,
|
||||
error: new UniError('不支持的批量操作'),
|
||||
origin: null,
|
||||
headers: {}
|
||||
} as AkReqResponse<boolean>
|
||||
}
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
data: true,
|
||||
error: null,
|
||||
origin: null,
|
||||
headers: {}
|
||||
} as AkReqResponse<boolean>
|
||||
} catch (error) {
|
||||
return {
|
||||
status: 500,
|
||||
data: false,
|
||||
error: new UniError(typeof error === 'string' ? error : error?.message ?? '批量操作失败'),
|
||||
origin: null,
|
||||
headers: {}
|
||||
} as AkReqResponse<boolean>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取消息统计信息
|
||||
*/
|
||||
static async getMessageStats(userId : string) : Promise<AkReqResponse<MessageStats>> {
|
||||
try {
|
||||
// 验证参数不能为空
|
||||
if (userId == null || userId === '' || userId.trim() === '') {
|
||||
return createErrorResponse<MessageStats>(
|
||||
{
|
||||
total_messages: 0,
|
||||
unread_messages: 0,
|
||||
sent_messages: 0,
|
||||
received_messages: 0,
|
||||
urgent_messages: 0,
|
||||
draft_messages: 0
|
||||
},
|
||||
'参数错误:用户ID不能为空'
|
||||
)
|
||||
}
|
||||
|
||||
// 获取未读消息
|
||||
const unreadResponse = await supa
|
||||
.from('ak_message_recipients')
|
||||
.select('id', { count: 'exact' })
|
||||
.eq('recipient_id', userId)
|
||||
.eq('status', 'unread')
|
||||
.eq('is_deleted', false)
|
||||
.executeAs<Array<MessageRecipient>>()
|
||||
|
||||
// 获取总消息数
|
||||
const totalResponse = await supa
|
||||
.from('ak_message_recipients')
|
||||
.select('id', { count: 'exact' })
|
||||
.eq('recipient_id', userId)
|
||||
.eq('is_deleted', false)
|
||||
.executeAs<Array<MessageRecipient>>()
|
||||
|
||||
// 获取紧急消息数
|
||||
const urgentResponse = await supa
|
||||
.from('ak_messages')
|
||||
.select('id', { count: 'exact' })
|
||||
.eq('receiver_id', userId)
|
||||
.eq('is_urgent', true)
|
||||
.eq('is_deleted', false)
|
||||
.executeAs<Array<Message>>()
|
||||
const stats : MessageStats = {
|
||||
total_messages: Array.isArray(totalResponse.data) ? (totalResponse.data as Array<any>).length : 0,
|
||||
unread_messages: Array.isArray(unreadResponse.data) ? (unreadResponse.data as Array<any>).length : 0,
|
||||
urgent_messages: Array.isArray(urgentResponse.data) ? (urgentResponse.data as Array<any>).length : 0,
|
||||
sent_messages: 0, // 可根据业务补充
|
||||
received_messages: 0, // 可根据业务补充
|
||||
draft_messages: 0 // 可根据业务补充
|
||||
}
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
data: stats,
|
||||
error: null,
|
||||
origin: null,
|
||||
headers: {}
|
||||
} as AkReqResponse<MessageStats>
|
||||
} catch (error) {
|
||||
return {
|
||||
status: 500,
|
||||
data: null,
|
||||
error: new UniError(typeof error === 'string' ? error : error?.message ?? '获取消息统计失败'),
|
||||
origin: null,
|
||||
headers: {}
|
||||
} as AkReqResponse<MessageStats>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索用户(用于消息接收者选择)
|
||||
*/
|
||||
static async searchUsers(keyword : string) : Promise<AkReqResponse<Array<UserOption>>> {
|
||||
try {
|
||||
const response = await supa
|
||||
.from('ak_users')
|
||||
.select('id, username, nickname, avatar', { count: 'exact' })
|
||||
.or(`username.ilike.%${keyword}%,nickname.ilike.%${keyword}%`)
|
||||
.limit(20)
|
||||
.executeAs<Array<UserOption>>()
|
||||
|
||||
return response
|
||||
} catch (error) { return {
|
||||
status: 500,
|
||||
data: [] as Array<UserOption>,
|
||||
error: new UniError(typeof error === 'string' ? error : error?.message ?? '搜索失败'),
|
||||
origin: null,
|
||||
headers: {}
|
||||
} as AkReqResponse<Array<UserOption>>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取群组列表
|
||||
*/
|
||||
static async getGroups() : Promise<AkReqResponse<Array<MessageGroup>>> {
|
||||
try {
|
||||
const response = await supa
|
||||
.from('ak_message_groups')
|
||||
.select('*', {})
|
||||
.eq('is_active', true)
|
||||
.executeAs<Array<MessageGroup>>()
|
||||
return response
|
||||
} catch (error) { return {
|
||||
status: 500,
|
||||
data: [] as Array<MessageGroup>,
|
||||
error: new UniError(typeof error === 'string' ? error : error?.message ?? '获取群组失败'),
|
||||
origin: null,
|
||||
headers: {}
|
||||
} as AkReqResponse<Array<MessageGroup>>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取群组成员
|
||||
*/
|
||||
static async getGroupMembers(groupId : string) : Promise<AkReqResponse<Array<GroupMember>>> {
|
||||
try {
|
||||
const response = await supa
|
||||
.from('ak_message_group_members')
|
||||
.select('*', {})
|
||||
.eq('group_id', groupId)
|
||||
.executeAs<Array<GroupMember>>()
|
||||
return response
|
||||
} catch (error) { return {
|
||||
status: 500,
|
||||
data: [] as Array<GroupMember>,
|
||||
error: new UniError(typeof error === 'string' ? error : error?.message ?? '获取群组成员失败'),
|
||||
origin: null,
|
||||
headers: {}
|
||||
} as AkReqResponse<Array<GroupMember>>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建标准错误响应
|
||||
*/
|
||||
function createErrorResponse<T>(data : T, errorMessage : string, status : number = 500) : AkReqResponse<T> {
|
||||
return {
|
||||
status: status,
|
||||
data: data,
|
||||
headers: {},
|
||||
error: new UniError(errorMessage),
|
||||
total: null,
|
||||
page: null,
|
||||
limit: null,
|
||||
hasmore: false,
|
||||
origin: null
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user