diff --git a/cloudbaserc.json b/cloudbaserc.json index 946afb1..a3b8840 100644 --- a/cloudbaserc.json +++ b/cloudbaserc.json @@ -114,6 +114,62 @@ "runtime": "Nodejs20.19", "handler": "index.main", "description": "删除宠物档案" + }, + { + "name": "getMessages", + "timeout": 10, + "runtime": "Nodejs20.19", + "handler": "index.main", + "description": "获取与某用户的聊天消息列表" + }, + { + "name": "sendMessage", + "timeout": 10, + "runtime": "Nodejs20.19", + "handler": "index.main", + "description": "发送私信消息" + }, + { + "name": "getHotTopics", + "timeout": 10, + "runtime": "Nodejs20.19", + "handler": "index.main", + "description": "获取热门话题标签" + }, + { + "name": "searchPosts", + "timeout": 10, + "runtime": "Nodejs20.19", + "handler": "index.main", + "description": "搜索帖子" + }, + { + "name": "searchUsers", + "timeout": 10, + "runtime": "Nodejs20.19", + "handler": "index.main", + "description": "搜索用户" + }, + { + "name": "getStory", + "timeout": 10, + "runtime": "Nodejs20.19", + "handler": "index.main", + "description": "获取用户故事(最近带图动态)" + }, + { + "name": "getNotifications", + "timeout": 10, + "runtime": "Nodejs20.19", + "handler": "index.main", + "description": "获取通知列表(点赞/评论聚合)" + }, + { + "name": "markAllRead", + "timeout": 10, + "runtime": "Nodejs20.19", + "handler": "index.main", + "description": "标记全部通知已读" } ] } diff --git a/cloudfunctions/getHotTopics/index.js b/cloudfunctions/getHotTopics/index.js new file mode 100644 index 0000000..8381259 --- /dev/null +++ b/cloudfunctions/getHotTopics/index.js @@ -0,0 +1,32 @@ +const cloud = require('wx-server-sdk') +cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) +const db = cloud.database() +const SCAN_LIMIT = 200 +const TOP_N = 10 + +exports.main = async (event, context) => { + try { + const res = await db.collection('posts') + .orderBy('createdAt', 'desc') + .limit(SCAN_LIMIT) + .field({ hashtags: true }) + .get() + + const counts = {} + res.data.forEach(p => { + ;(p.hashtags || []).forEach(tag => { + if (!tag) return + counts[tag] = (counts[tag] || 0) + 1 + }) + }) + + const topics = Object.keys(counts) + .map(tag => ({ tag, count: counts[tag] })) + .sort((a, b) => b.count - a.count) + .slice(0, TOP_N) + + return { code: 0, data: topics } + } catch (e) { + return { code: -1, message: e.message } + } +} diff --git a/cloudfunctions/getHotTopics/package.json b/cloudfunctions/getHotTopics/package.json new file mode 100644 index 0000000..4aad8eb --- /dev/null +++ b/cloudfunctions/getHotTopics/package.json @@ -0,0 +1 @@ +{ "name": "getHotTopics", "version": "1.0.0", "main": "index.js", "dependencies": { "wx-server-sdk": "~2.1.2" } } diff --git a/cloudfunctions/getMessages/index.js b/cloudfunctions/getMessages/index.js new file mode 100644 index 0000000..365588d --- /dev/null +++ b/cloudfunctions/getMessages/index.js @@ -0,0 +1,46 @@ +const cloud = require('wx-server-sdk') +cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) +const db = cloud.database() +const _ = db.command +const PAGE_SIZE = 30 + +exports.main = async (event, context) => { + const { OPENID } = cloud.getWXContext() + const { peerId, page = 0 } = event || {} + + try { + const meRes = await db.collection('users').where({ openid: OPENID }).get() + if (meRes.data.length === 0) return { code: -1, message: '用户不存在' } + const myId = meRes.data[0]._id + + let list = [] + if (peerId) { + const skip = page * PAGE_SIZE + const msgRes = await db.collection('messages') + .where(_.or([ + { fromId: myId, toId: peerId }, + { fromId: peerId, toId: myId }, + ])) + .orderBy('createdAt', 'desc') + .skip(skip) + .limit(PAGE_SIZE) + .get() + + list = msgRes.data.reverse().map(m => ({ ...m, isMe: m.fromId === myId })) + + // 把对方发来的未读消息标记为已读 + const unreadIds = msgRes.data.filter(m => m.toId === myId && !m.isRead).map(m => m._id) + if (unreadIds.length) { + await db.collection('messages').where({ _id: _.in(unreadIds) }).update({ data: { isRead: true } }) + } + } + + const unreadRes = await db.collection('messages') + .where({ toId: myId, isRead: _.neq(true) }) + .count() + + return { code: 0, data: { list, unreadCount: unreadRes.total } } + } catch (e) { + return { code: -1, message: e.message } + } +} diff --git a/cloudfunctions/getMessages/package.json b/cloudfunctions/getMessages/package.json new file mode 100644 index 0000000..fbcf41a --- /dev/null +++ b/cloudfunctions/getMessages/package.json @@ -0,0 +1 @@ +{ "name": "getMessages", "version": "1.0.0", "main": "index.js", "dependencies": { "wx-server-sdk": "~2.1.2" } } diff --git a/cloudfunctions/getNotifications/index.js b/cloudfunctions/getNotifications/index.js new file mode 100644 index 0000000..875318c --- /dev/null +++ b/cloudfunctions/getNotifications/index.js @@ -0,0 +1,80 @@ +const cloud = require('wx-server-sdk') +cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) +const db = cloud.database() +const _ = db.command + +// 项目暂未建立独立的通知集合,这里通过聚合"我的动态"收到的点赞 / 评论 +// 实时合成通知列表;已读状态通过用户文档上的 lastReadNotificationsAt 时间戳比对得出 +exports.main = async (event, context) => { + const { OPENID } = cloud.getWXContext() + + try { + const meRes = await db.collection('users').where({ openid: OPENID }).get() + if (meRes.data.length === 0) return { code: 0, data: [] } + const me = meRes.data[0] + const lastRead = me.lastReadNotificationsAt ? new Date(me.lastReadNotificationsAt).getTime() : 0 + + const myPostsRes = await db.collection('posts') + .where({ authorId: OPENID }) + .field({ _id: true }) + .orderBy('createdAt', 'desc') + .limit(50) + .get() + const myPostIds = myPostsRes.data.map(p => p._id) + + const items = [] + + if (myPostIds.length) { + const [likesRes, commentsRes] = await Promise.all([ + db.collection('likes') + .where({ postId: _.in(myPostIds), userId: _.neq(OPENID) }) + .orderBy('createdAt', 'desc') + .limit(20) + .get(), + db.collection('comments') + .where({ postId: _.in(myPostIds), authorId: _.neq(OPENID) }) + .orderBy('createdAt', 'desc') + .limit(20) + .get(), + ]) + + likesRes.data.forEach(l => items.push({ + _id: `like_${l._id}`, + fromId: l.userId, + postId: l.postId, + action: '点赞', + target: '动态', + createdAt: l.createdAt, + })) + + commentsRes.data.forEach(c => items.push({ + _id: `comment_${c._id}`, + fromId: c.authorId, + postId: c.postId, + action: '评论', + target: '动态', + createdAt: c.createdAt, + })) + } + + items.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()) + const sliced = items.slice(0, 30) + + const fromIds = [...new Set(sliced.map(i => i.fromId).filter(Boolean))] + const usersRes = fromIds.length + ? await db.collection('users').where({ openid: _.in(fromIds) }).field({ openid: true, nickName: true }).get() + : { data: [] } + const nickMap = {} + usersRes.data.forEach(u => { nickMap[u.openid] = u.nickName }) + + const result = sliced.map(i => ({ + ...i, + fromNick: nickMap[i.fromId] || '一位用户', + isRead: new Date(i.createdAt).getTime() <= lastRead, + })) + + return { code: 0, data: result } + } catch (e) { + return { code: -1, message: e.message } + } +} diff --git a/cloudfunctions/getNotifications/package.json b/cloudfunctions/getNotifications/package.json new file mode 100644 index 0000000..8e0cb00 --- /dev/null +++ b/cloudfunctions/getNotifications/package.json @@ -0,0 +1 @@ +{ "name": "getNotifications", "version": "1.0.0", "main": "index.js", "dependencies": { "wx-server-sdk": "~2.1.2" } } diff --git a/cloudfunctions/getStory/index.js b/cloudfunctions/getStory/index.js new file mode 100644 index 0000000..5a7c5f6 --- /dev/null +++ b/cloudfunctions/getStory/index.js @@ -0,0 +1,51 @@ +const cloud = require('wx-server-sdk') +cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) +const db = cloud.database() +const _ = db.command +const ONE_DAY_MS = 24 * 3600 * 1000 + +// 项目暂未建立独立的"故事"集合,这里把指定用户最近(24小时内)发布的 +// 带图片动态包装成"故事"展示,作为 Stories 功能的轻量实现 +exports.main = async (event, context) => { + const id = (event && event.id) || '' + if (!id) return { code: -1, message: '缺少用户ID' } + + try { + const since = new Date(Date.now() - ONE_DAY_MS) + let postsRes = await db.collection('posts') + .where({ authorId: id, createdAt: _.gte(since) }) + .orderBy('createdAt', 'desc') + .limit(20) + .get() + + let posts = postsRes.data.filter(p => Array.isArray(p.images) && p.images.length > 0) + + if (posts.length === 0) { + // 兜底:取该用户最近一条带图动态 + const fallbackRes = await db.collection('posts') + .where({ authorId: id }) + .orderBy('createdAt', 'desc') + .limit(20) + .get() + posts = fallbackRes.data.filter(p => Array.isArray(p.images) && p.images.length > 0).slice(0, 1) + } + + if (posts.length === 0) return { code: 0, data: [] } + + const userRes = await db.collection('users').where({ openid: id }).field({ nickName: true }).get() + const authorName = (userRes.data[0] && userRes.data[0].nickName) || '宠物爱好者' + + const stories = posts.map(p => ({ + _id: p._id, + authorId: p.authorId, + authorName, + imageUrl: p.images[0], + text: p.content || '', + createdAt: p.createdAt, + })) + + return { code: 0, data: stories } + } catch (e) { + return { code: -1, message: e.message } + } +} diff --git a/cloudfunctions/getStory/package.json b/cloudfunctions/getStory/package.json new file mode 100644 index 0000000..8e7a5ae --- /dev/null +++ b/cloudfunctions/getStory/package.json @@ -0,0 +1 @@ +{ "name": "getStory", "version": "1.0.0", "main": "index.js", "dependencies": { "wx-server-sdk": "~2.1.2" } } diff --git a/cloudfunctions/markAllRead/index.js b/cloudfunctions/markAllRead/index.js new file mode 100644 index 0000000..2713c14 --- /dev/null +++ b/cloudfunctions/markAllRead/index.js @@ -0,0 +1,19 @@ +const cloud = require('wx-server-sdk') +cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) +const db = cloud.database() + +// 与 getNotifications 配套:把"已读截止时间"写到用户文档上, +// 之后凡是早于该时间的通知都视为已读 +exports.main = async (event, context) => { + const { OPENID } = cloud.getWXContext() + + try { + await db.collection('users') + .where({ openid: OPENID }) + .update({ data: { lastReadNotificationsAt: db.serverDate() } }) + + return { code: 0, data: null } + } catch (e) { + return { code: -1, message: e.message } + } +} diff --git a/cloudfunctions/markAllRead/package.json b/cloudfunctions/markAllRead/package.json new file mode 100644 index 0000000..62d93ad --- /dev/null +++ b/cloudfunctions/markAllRead/package.json @@ -0,0 +1 @@ +{ "name": "markAllRead", "version": "1.0.0", "main": "index.js", "dependencies": { "wx-server-sdk": "~2.1.2" } } diff --git a/cloudfunctions/searchPosts/index.js b/cloudfunctions/searchPosts/index.js new file mode 100644 index 0000000..5a93cba --- /dev/null +++ b/cloudfunctions/searchPosts/index.js @@ -0,0 +1,52 @@ +const cloud = require('wx-server-sdk') +cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) +const db = cloud.database() +const _ = db.command +const RESULT_LIMIT = 20 + +function escapeRegExp(s) { + return String(s).replace(/[.*+?^${}()|[\]\\]/g, '\\$&') +} + +exports.main = async (event, context) => { + const { OPENID } = cloud.getWXContext() + const keyword = String((event && event.keyword) || '').trim() + if (!keyword) return { code: 0, data: [] } + + try { + const re = db.RegExp({ regexp: escapeRegExp(keyword), options: 'i' }) + const postsRes = await db.collection('posts') + .where(_.or([{ content: re }, { hashtags: keyword }])) + .orderBy('createdAt', 'desc') + .limit(RESULT_LIMIT) + .get() + + const posts = postsRes.data + if (posts.length === 0) return { code: 0, data: [] } + + const authorIds = [...new Set(posts.map(p => p.authorId))] + const authorsRes = await db.collection('users') + .where({ openid: _.in(authorIds) }) + .field({ nickName: true, avatarUrl: true, openid: true, pets: true, location: true }) + .get() + const authorMap = {} + authorsRes.data.forEach(u => { authorMap[u.openid] = u }) + + const postIds = posts.map(p => p._id) + const likesRes = await db.collection('likes') + .where({ userId: OPENID, postId: _.in(postIds) }) + .field({ postId: true }) + .get() + const likedSet = new Set(likesRes.data.map(l => l.postId)) + + const enriched = posts.map(p => ({ + ...p, + author: authorMap[p.authorId] || null, + isLiked: likedSet.has(p._id), + })) + + return { code: 0, data: enriched } + } catch (e) { + return { code: -1, message: e.message } + } +} diff --git a/cloudfunctions/searchPosts/package.json b/cloudfunctions/searchPosts/package.json new file mode 100644 index 0000000..e0af826 --- /dev/null +++ b/cloudfunctions/searchPosts/package.json @@ -0,0 +1 @@ +{ "name": "searchPosts", "version": "1.0.0", "main": "index.js", "dependencies": { "wx-server-sdk": "~2.1.2" } } diff --git a/cloudfunctions/searchUsers/index.js b/cloudfunctions/searchUsers/index.js new file mode 100644 index 0000000..540c1a7 --- /dev/null +++ b/cloudfunctions/searchUsers/index.js @@ -0,0 +1,27 @@ +const cloud = require('wx-server-sdk') +cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) +const db = cloud.database() +const _ = db.command +const RESULT_LIMIT = 20 + +function escapeRegExp(s) { + return String(s).replace(/[.*+?^${}()|[\]\\]/g, '\\$&') +} + +exports.main = async (event, context) => { + const keyword = String((event && event.keyword) || '').trim() + if (!keyword) return { code: 0, data: [] } + + try { + const re = db.RegExp({ regexp: escapeRegExp(keyword), options: 'i' }) + const res = await db.collection('users') + .where(_.or([{ nickName: re }, { handle: re }, { location: re }])) + .field({ nickName: true, avatarUrl: true, bio: true, handle: true, location: true }) + .limit(RESULT_LIMIT) + .get() + + return { code: 0, data: res.data } + } catch (e) { + return { code: -1, message: e.message } + } +} diff --git a/cloudfunctions/searchUsers/package.json b/cloudfunctions/searchUsers/package.json new file mode 100644 index 0000000..63fa16b --- /dev/null +++ b/cloudfunctions/searchUsers/package.json @@ -0,0 +1 @@ +{ "name": "searchUsers", "version": "1.0.0", "main": "index.js", "dependencies": { "wx-server-sdk": "~2.1.2" } } diff --git a/cloudfunctions/sendMessage/index.js b/cloudfunctions/sendMessage/index.js new file mode 100644 index 0000000..d4a8bf7 --- /dev/null +++ b/cloudfunctions/sendMessage/index.js @@ -0,0 +1,32 @@ +const cloud = require('wx-server-sdk') +cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) +const db = cloud.database() + +exports.main = async (event, context) => { + const { OPENID } = cloud.getWXContext() + const { toId, content, type = 'text' } = event || {} + + if (!toId || !String(content || '').trim()) { + return { code: -1, message: '参数错误' } + } + + try { + const meRes = await db.collection('users').where({ openid: OPENID }).get() + if (meRes.data.length === 0) return { code: -1, message: '用户不存在' } + const myId = meRes.data[0]._id + + const message = { + fromId: myId, + toId, + content: String(content).trim(), + type, + isRead: false, + createdAt: db.serverDate(), + } + const res = await db.collection('messages').add({ data: message }) + + return { code: 0, data: { _id: res._id, ...message } } + } catch (e) { + return { code: -1, message: e.message } + } +} diff --git a/cloudfunctions/sendMessage/package.json b/cloudfunctions/sendMessage/package.json new file mode 100644 index 0000000..c5657f2 --- /dev/null +++ b/cloudfunctions/sendMessage/package.json @@ -0,0 +1 @@ +{ "name": "sendMessage", "version": "1.0.0", "main": "index.js", "dependencies": { "wx-server-sdk": "~2.1.2" } } diff --git a/miniprogram/app.ts b/miniprogram/app.ts index 1d09648..96683a8 100644 --- a/miniprogram/app.ts +++ b/miniprogram/app.ts @@ -1,5 +1,5 @@ -import { UserProfile, GeoPoint, AppGlobalData } from './types/index' -import { getCachedUser, login } from './utils/auth' +import { AppGlobalData } from './types/index' +import { getCachedUser } from './utils/auth' import { CLOUD_ENV, HEARTBEAT_INTERVAL_MS } from './utils/constants' import { api } from './utils/api' @@ -44,16 +44,6 @@ App<{ globalData: AppGlobalData }>({ this._stopLocationHeartbeat() }, - async _initLogin() { - try { - const userInfo = await login() - this.globalData.userInfo = userInfo - this.globalData.isLoggedIn = true - } catch (e) { - console.error('Login failed', e) - } - }, - _initLocation() { wx.getLocation({ type: 'gcj02', diff --git a/miniprogram/pages/chat/chat.ts b/miniprogram/pages/chat/chat.ts index 090c8e0..ddef9b4 100644 --- a/miniprogram/pages/chat/chat.ts +++ b/miniprogram/pages/chat/chat.ts @@ -18,6 +18,7 @@ Page({ onLoad(query: { userId?: string }) { const info = wx.getSystemInfoSync() this.setData({ statusBarHeight: info.statusBarHeight, peerId: query.userId || '' }) + this.loadPeerInfo() this.loadMessages() this.subscribeRealtime() }, @@ -26,9 +27,18 @@ Page({ this._watcher?.close() }, - async loadMessages() { + async loadPeerInfo() { + if (!this.data.peerId) return try { - const res = await api.getMessages() + const user = await api.getUserProfile(this.data.peerId) + this.setData({ peerName: user.nickName || '宠物爱好者' }) + } catch {} + }, + + async loadMessages() { + if (!this.data.peerId) return + try { + const res = await api.getMessages(this.data.peerId) const msgs = res.list.map((m: any) => ({ ...m, isMe: m.fromId === app.globalData?.userInfo?._id, diff --git a/miniprogram/pages/notifications/notifications.ts b/miniprogram/pages/notifications/notifications.ts index dd1a1dc..9ceb143 100644 --- a/miniprogram/pages/notifications/notifications.ts +++ b/miniprogram/pages/notifications/notifications.ts @@ -1,3 +1,4 @@ +import { api } from '../../utils/api' import { getAvatarGradient, formatTime } from '../../utils/format' Page({ @@ -11,13 +12,13 @@ Page({ async loadNotifications() { try { - const res = await wx.cloud.callFunction({ name: 'getNotifications', data: {} }) as any - const list = (res.result?.data || []).map((n: any) => ({ + const list = await api.getNotifications() + const enriched = (list || []).map((n: any) => ({ ...n, gradient: getAvatarGradient(n.fromId || ''), timeText: formatTime(n.createdAt), })) - this.setData({ list }) + this.setData({ list: enriched }) } catch {} }, @@ -27,7 +28,7 @@ Page({ }, onReadAll() { - wx.cloud.callFunction({ name: 'markAllRead', data: {} }).catch(() => {}) + api.markAllRead().catch(() => {}) const list = this.data.list.map((n: any) => ({ ...n, isRead: true })) this.setData({ list }) }, diff --git a/miniprogram/pages/search/search.ts b/miniprogram/pages/search/search.ts index 63863a4..c5923fc 100644 --- a/miniprogram/pages/search/search.ts +++ b/miniprogram/pages/search/search.ts @@ -1,3 +1,4 @@ +import { api } from '../../utils/api' import { getAvatarGradient } from '../../utils/format' Page({ @@ -19,8 +20,8 @@ Page({ async loadHotTopics() { try { - const res = await wx.cloud.callFunction({ name: 'getHotTopics', data: {} }) as any - this.setData({ hotTopics: res.result?.data || [] }) + const topics = await api.getHotTopics() + this.setData({ hotTopics: topics || [] }) } catch {} }, @@ -38,12 +39,12 @@ Page({ this.setData({ loading: true }) try { const [posts, users] = await Promise.all([ - wx.cloud.callFunction({ name: 'searchPosts', data: { keyword: kw } }) as any, - wx.cloud.callFunction({ name: 'searchUsers', data: { keyword: kw } }) as any, + api.searchPosts(kw), + api.searchUsers(kw), ]) this.setData({ - postResults: posts.result?.data || [], - userResults: (users.result?.data || []).map((u: any) => ({ + postResults: posts || [], + userResults: (users || []).map((u: any) => ({ ...u, gradient: getAvatarGradient(u._id), })), diff --git a/miniprogram/pages/story/story.ts b/miniprogram/pages/story/story.ts index 08326ed..e62f3dd 100644 --- a/miniprogram/pages/story/story.ts +++ b/miniprogram/pages/story/story.ts @@ -1,3 +1,4 @@ +import { api } from '../../utils/api' import { getAvatarGradient, formatTime } from '../../utils/format' const DURATION = 5000 @@ -22,15 +23,18 @@ Page({ async loadStory(id: string) { try { - const res = await wx.cloud.callFunction({ name: 'getStory', data: { id } }) as any - const stories = (res.result?.data || []).map((s: any) => ({ + const list = await api.getStory(id) + const stories = (list || []).map((s: any) => ({ ...s, gradient: getAvatarGradient(s.authorId), timeText: formatTime(s.createdAt), })) this.setData({ stories, currentStory: stories[0] || {} }) - this.startProgress() - } catch {} + if (stories.length) this.startProgress() + else wx.navigateBack() + } catch { + wx.navigateBack() + } }, startProgress() { diff --git a/miniprogram/types/index.ts b/miniprogram/types/index.ts index e2869f0..1f6d3d4 100644 --- a/miniprogram/types/index.ts +++ b/miniprogram/types/index.ts @@ -71,17 +71,6 @@ export interface Comment { createdAt: string } -export interface Message { - _id: string - fromId: string - from?: UserProfile - toId: string - content: string - type: 'greeting' | 'text' | 'image' - isRead: boolean - createdAt: string -} - export interface NearbyUser { userId: string user: UserProfile @@ -93,14 +82,6 @@ export interface NearbyUser { location: GeoPoint } -export interface TabBarItem { - pagePath: string - text: string - icon: string - activeIcon: string - selected: boolean -} - export interface NavBarInfo { statusBarHeight: number navbarHeight: number diff --git a/miniprogram/utils/api.ts b/miniprogram/utils/api.ts index 89afc9c..c29aae3 100644 --- a/miniprogram/utils/api.ts +++ b/miniprogram/utils/api.ts @@ -1,4 +1,4 @@ -import { Post, UserProfile, NearbyUser, Pet } from '../types/index' +import { Post, UserProfile, NearbyUser, Pet, Comment } from '../types/index' type CloudResult = { result: { code: number; data: T; message?: string } } @@ -31,9 +31,6 @@ export const api = { petId?: string }) => call('createPost', params), - deletePost: (postId: string) => - call('deletePost', { postId }), - likePost: (postId: string) => call<{ liked: boolean; count: number }>('likePost', { postId }), @@ -58,11 +55,11 @@ export const api = { getFollowList: (type: 'following' | 'followers', userId?: string) => call('getFollowList', { type, userId }), - getMessages: (page = 0) => - call<{ list: any[]; unreadCount: number }>('getMessages', { page }), + getMessages: (peerId: string, page = 0) => + call<{ list: any[]; unreadCount: number }>('getMessages', { peerId, page }), sendMessage: (toId: string, content: string, type = 'text') => - call('sendMessage', { toId, content, type }), + call<{ _id: string }>('sendMessage', { toId, content, type }), updatePet: (pet: Partial & { _id?: string }) => call('updatePet', { pet }), @@ -70,15 +67,21 @@ export const api = { deletePet: (petId: string) => call('deletePet', { petId }), - uploadImage: async (filePath: string): Promise => { - const ext = filePath.split('.').pop() || 'jpg' - const cloudPath = `posts/${Date.now()}_${Math.random().toString(36).slice(2)}.${ext}` - const res = await wx.cloud.uploadFile({ cloudPath, filePath }) - return res.fileID - }, + getHotTopics: () => + call<{ tag: string; count: number }[]>('getHotTopics'), - getFileURL: async (fileID: string): Promise => { - const res = await wx.cloud.getTempFileURL({ fileList: [fileID] }) - return res.fileList[0]?.tempFileURL || fileID - }, + searchPosts: (keyword: string) => + call('searchPosts', { keyword }), + + searchUsers: (keyword: string) => + call('searchUsers', { keyword }), + + getStory: (id: string) => + call('getStory', { id }), + + getNotifications: () => + call('getNotifications'), + + markAllRead: () => + call('markAllRead'), } diff --git a/miniprogram/utils/auth.ts b/miniprogram/utils/auth.ts index 0f20045..662d164 100644 --- a/miniprogram/utils/auth.ts +++ b/miniprogram/utils/auth.ts @@ -1,7 +1,6 @@ import { UserProfile } from '../types/index' import { api } from './api' -const TOKEN_KEY = 'wangquan_token' const USER_KEY = 'wangquan_user' export async function login(): Promise { @@ -19,11 +18,6 @@ export function getCachedUser(): UserProfile | null { } } -export function clearAuth(): void { - wx.removeStorageSync(TOKEN_KEY) - wx.removeStorageSync(USER_KEY) -} - export async function requireLocation(): Promise<{ latitude: number; longitude: number }> { return new Promise((resolve, reject) => { wx.getLocation({ diff --git a/miniprogram/utils/constants.ts b/miniprogram/utils/constants.ts index c5d0e3c..1b768b5 100644 --- a/miniprogram/utils/constants.ts +++ b/miniprogram/utils/constants.ts @@ -1,28 +1,5 @@ export const CLOUD_ENV = 'cloud1-d4g697lte499543d8' -export const COLORS = { - pink: '#ff4f91', - orange: '#ff9f1c', - yellow: '#ffe15a', - green: '#2fd37a', - mint: '#67e8c9', - blue: '#4d8dff', - violet: '#8c5cff', - ink: '#272235', - bgPrimary: '#fff9fb', - textPrimary: '#272235', - textSecondary: '#6a6178', - textTertiary: '#9b8fa8', -} - -export const AVATAR_GRADIENTS = [ - 'linear-gradient(135deg, #ffd6e8, #fff1a6)', - 'linear-gradient(135deg, #ffe7a0, #b7f4d2)', - 'linear-gradient(135deg, #c9f7df, #d9d2ff)', - 'linear-gradient(135deg, #cfe8ff, #ffd6e8)', - 'linear-gradient(135deg, #e3d8ff, #ffd6e8)', -] - export const MOOD_OPTIONS = [ { label: '开心 😄', value: 'happy' }, { label: '累了 😮‍💨', value: 'tired' }, diff --git a/miniprogram/utils/format.ts b/miniprogram/utils/format.ts index 7c6ca32..2ebd44e 100644 --- a/miniprogram/utils/format.ts +++ b/miniprogram/utils/format.ts @@ -61,12 +61,3 @@ export function getPetEmoji(species: string, breed?: string): string { } return (breed && dogBreedEmoji[breed]) || '🐶' } - -export function calcDistance(lat1: number, lng1: number, lat2: number, lng2: number): number { - const R = 6371000 - const dLat = (lat2 - lat1) * Math.PI / 180 - const dLng = (lng2 - lng1) * Math.PI / 180 - const a = Math.sin(dLat / 2) ** 2 + - Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * Math.sin(dLng / 2) ** 2 - return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)) -}