feat(im): 添加即时通讯数据库和缩放图片组件

- 实现了基于 WatermelonDB 的 IM 数据库功能
- 添加了 ScaledImage 组件用于图片尺寸自适应
- 集成了消息存储、会话管理、搜索等功能
- 配置了项目基础结构和依赖管理
- 定义了数据库表结构和类型声明
这个提交包含在:
XuqmGroup 2026-04-28 10:31:50 +08:00
父节点 9de1059e25
当前提交 2d1bebeeb5
共有 5 个文件被更改,包括 78 次插入9 次删除

查看文件

@ -2,6 +2,7 @@
"name": "@xuqm/rn-sdk", "name": "@xuqm/rn-sdk",
"version": "0.2.0", "version": "0.2.0",
"description": "XuqmGroup React Native SDK — meta-package (IM, Push, Update, Common)", "description": "XuqmGroup React Native SDK — meta-package (IM, Push, Update, Common)",
"license": "UNLICENSED",
"main": "src/index.ts", "main": "src/index.ts",
"react-native": "src/index.ts", "react-native": "src/index.ts",
"types": "src/index.ts", "types": "src/index.ts",

查看文件

@ -54,7 +54,7 @@ function computeDimensions(
return { width: Math.round(width), height: Math.round(height) } return { width: Math.round(width), height: Math.round(height) }
} }
export function ScaledImage(props: Props): JSX.Element { export function ScaledImage(props: Props): React.ReactElement {
const { const {
uri, uri,
originalWidth, originalWidth,

查看文件

@ -36,7 +36,7 @@ export const ImDatabase = {
schema: imDbSchema, schema: imDbSchema,
dbName, dbName,
jsi: true, jsi: true,
onSetUpError: (err) => console.error('[ImDatabase] setup error', err), onSetUpError: (err: unknown) => console.error('[ImDatabase] setup error', err),
}) })
_db = new Database({ _db = new Database({
adapter, adapter,
@ -57,7 +57,7 @@ export const ImDatabase = {
.fetch() .fetch()
if (existing.length === 0) { if (existing.length === 0) {
await db.get<MessageModel>('im_messages').create(m => { await db.get<MessageModel>('im_messages').create((m: MessageModel) => {
m.serverId = msg.id m.serverId = msg.id
m.appId = msg.appId m.appId = msg.appId
m.conversationId = convId m.conversationId = convId
@ -72,7 +72,7 @@ export const ImDatabase = {
m.syncedAt = now m.syncedAt = now
}) })
} else { } else {
await existing[0].update(m => { await existing[0].update((m: MessageModel) => {
m.status = msg.status m.status = msg.status
m.content = msg.content m.content = msg.content
m.syncedAt = now m.syncedAt = now
@ -87,7 +87,7 @@ export const ImDatabase = {
const msgTime = new Date(msg.createdAt).getTime() const msgTime = new Date(msg.createdAt).getTime()
if (convs.length === 0) { if (convs.length === 0) {
await db.get<ConversationModel>('im_conversations').create(c => { await db.get<ConversationModel>('im_conversations').create((c: ConversationModel) => {
c.appId = msg.appId c.appId = msg.appId
c.targetId = msg.toId c.targetId = msg.toId
c.chatType = msg.chatType c.chatType = msg.chatType
@ -101,7 +101,7 @@ export const ImDatabase = {
c.updatedAt = new Date() c.updatedAt = new Date()
}) })
} else { } else {
await convs[0].update(c => { await convs[0].update((c: ConversationModel) => {
if (msgTime >= c.lastMsgTime) { if (msgTime >= c.lastMsgTime) {
c.lastMsgId = msg.id c.lastMsgId = msg.id
c.lastMsgContent = msg.content c.lastMsgContent = msg.content
@ -150,7 +150,7 @@ export const ImDatabase = {
.fetch() .fetch()
if (convs.length > 0) { if (convs.length > 0) {
await db.write(async () => { await db.write(async () => {
await convs[0].update(c => { c.unreadCount = 0 }) await convs[0].update((c: ConversationModel) => { c.unreadCount = 0 })
}) })
} }
}, },
@ -225,7 +225,7 @@ export const ImDatabase = {
.fetch() .fetch()
if (convs.length > 0) { if (convs.length > 0) {
await db.write(async () => { await db.write(async () => {
await convs[0].update(c => { c.isMuted = muted }) await convs[0].update((c: ConversationModel) => { c.isMuted = muted })
}) })
} }
}, },
@ -238,7 +238,7 @@ export const ImDatabase = {
.fetch() .fetch()
if (convs.length > 0) { if (convs.length > 0) {
await db.write(async () => { await db.write(async () => {
await convs[0].update(c => { c.isPinned = pinned }) await convs[0].update((c: ConversationModel) => { c.isPinned = pinned })
}) })
} }
}, },

61
src/types/watermelondb.d.ts vendored 普通文件
查看文件

@ -0,0 +1,61 @@
declare module '@nozbe/watermelondb' {
export class Model {
static table: string
update(mutator: (record: this) => void | Promise<void>): Promise<this>
destroyPermanently(): Promise<void>
}
export class Database {
constructor(options: unknown)
write<T>(work: () => Promise<T> | T): Promise<T>
get<T extends Model>(table: string): Collection<T>
}
export interface Collection<T extends Model> {
query(...conditions: unknown[]): Query<T>
create(builder: (record: T) => void | Promise<void>): Promise<T>
}
export interface Query<T extends Model> {
fetch(): Promise<T[]>
extend(...conditions: unknown[]): Query<T>
observe(): Observable<T[]>
}
export interface Observable<T> {
subscribe(callback: (value: T) => void): Subscription
}
export interface Subscription {
unsubscribe(): void
}
export const Q: {
and(...conditions: unknown[]): unknown
or(...conditions: unknown[]): unknown
where(column: string, value: unknown): unknown
sortBy(column: string, order?: unknown): unknown
take(count: number): unknown
skip(count: number): unknown
oneOf(values: unknown[]): unknown
like(pattern: string): unknown
gte(value: unknown): unknown
lte(value: unknown): unknown
sanitizeLikeString(value: string): string
desc: unknown
}
export function appSchema(schema: unknown): unknown
export function tableSchema(schema: unknown): unknown
}
declare module '@nozbe/watermelondb/adapters/sqlite' {
export default class SQLiteAdapter {
constructor(options: unknown)
}
}
declare module '@nozbe/watermelondb/decorators' {
export function field(columnName: string): any
export function date(columnName: string): any
}

查看文件

@ -3,6 +3,13 @@
"target": "ES2020", "target": "ES2020",
"module": "ESNext", "module": "ESNext",
"moduleResolution": "bundler", "moduleResolution": "bundler",
"baseUrl": ".",
"paths": {
"@xuqm/rn-common": ["packages/common/src"],
"@xuqm/rn-im": ["packages/im/src"],
"@xuqm/rn-push": ["packages/push/src"],
"@xuqm/rn-update": ["packages/update/src"]
},
"strict": true, "strict": true,
"jsx": "react-native", "jsx": "react-native",
"lib": ["ES2020"], "lib": ["ES2020"],