367 lines
16 KiB
Markdown
367 lines
16 KiB
Markdown
# TopFans Frontend 接口调用总览
|
||
|
||
> 范围:`frontend` 源码(排除 `unpackage/dist` 编译产物)。
|
||
|
||
## 1. 请求基础设施
|
||
|
||
- **统一入口**:`frontend/utils/api.js` 的 `request(options)`,底层使用 `uni.request`。
|
||
- **Base URL**:`http://101.132.250.62:8080`(硬编码)。
|
||
- **鉴权注入**:
|
||
- 登录/注册接口(`/api/v1/auth/login`、`/api/v1/auth/register`)不注入 token。
|
||
- 其余接口自动从 `uni.getStorageSync('access_token')` 注入 `Authorization: Bearer <token>`。
|
||
- **统一响应解析**:
|
||
- HTTP `401`:清理 `access_token`/`user`,`reLaunch` 到登录页,`reject(Error('登录已过期,请重新登录'))`。
|
||
- HTTP `200` 且有 `res.data.code`:
|
||
- `code === 200`:`resolve(res.data)`。
|
||
- `code === 401/400/403`:同样清会话并跳登录。
|
||
- 其他业务码:`reject(Error(res.data.message || '请求失败'))`。
|
||
- 其他 HTTP 状态:`reject(Error(res.data?.message || 请求失败(statusCode)))`。
|
||
- **超时/重试**:未设置统一 `timeout`,无自动重试机制。
|
||
|
||
---
|
||
|
||
## 2. API 清单(函数名 / 参数 / 响应解析 / 用途)
|
||
|
||
### 2.1 认证与账号
|
||
|
||
#### `loginApi(mobile, password)`
|
||
- **Method/Path**:`POST /api/v1/auth/login`
|
||
- **参数**:`{ mobile, password }`
|
||
- **调用位置**:
|
||
- `store/modules/user.js` -> `actions.login`
|
||
- `pages/login/login.vue` -> `handleLogin`(触发 `store.dispatch('user/login')`)
|
||
- **响应解析**:
|
||
- `res.code === 200 && res.data` 成功。
|
||
- 读取 `res.data.access_token`、`res.data.user` 写入本地缓存与 store。
|
||
- 若 `user.avatar_url` 存在,继续调用 `getOssPresignedUrlApi` 取 `res.data.url` 并本地缓存头像。
|
||
- **用途**:登录并初始化会话(token、用户信息、头像缓存)。
|
||
|
||
#### `registerApi(mobile, password, star_id, nickname)`
|
||
- **Method/Path**:`POST /api/v1/auth/register`
|
||
- **参数**:`{ mobile, password, star_id, nickname }`
|
||
- **调用位置**:
|
||
- `store/modules/user.js` -> `actions.register`
|
||
- `pages/profile/selectRole.vue` -> `handleNext`(触发 `store.dispatch('user/register')`)
|
||
- **响应解析**:
|
||
- 成功同登录流程:读取 `access_token` 与 `user`,并尝试头像预缓存。
|
||
- 对 `409`(昵称冲突)做显式分支,向上抛 `{ code: 409, message }`。
|
||
- **用途**:注册并建立登录态。
|
||
|
||
#### `getUserProfileApi()`
|
||
- **Method/Path**:`GET /api/v1/auth/me`
|
||
- **参数**:无
|
||
- **调用位置**:
|
||
- `pages/profile/profile.vue` -> `fetchUserInfo`
|
||
- **响应解析**:
|
||
- 读取 `res.data` 字段:`uid`、`nickname`、`avatar_url`、`current_identity`、`assets_num`、`slot_limit`、`starbook_limit`、`blockchain_address` 等。
|
||
- 页面侧将 `current_identity` 转换为缓存结构 `fan_identity`,并回写本地 `user`。
|
||
- **用途**:个人中心刷新用户主数据(以服务端为准)。
|
||
|
||
#### `updateNicknameApi(nickname)`
|
||
- **Method/Path**:`PUT /api/v1/me/nickname`
|
||
- **参数**:`{ nickname }`
|
||
- **调用位置**:
|
||
- `pages/profile/profile.vue` -> `confirmChangeNickname`
|
||
- **响应解析**:检查 `res.code === 200` 后触发 `fetchUserInfo(true)` 全量刷新。
|
||
- **用途**:修改当前身份昵称。
|
||
|
||
#### `updatePasswordApi(oldPassword, newPassword)`
|
||
- **Method/Path**:`POST /api/v1/account/password`
|
||
- **参数**:`{ old_password, new_password }`
|
||
- **调用位置**:
|
||
- `pages/profile/profile.vue` -> `confirmChangePassword`
|
||
- **响应解析**:`res.code === 200` 后提示成功并强制登出、清缓存、跳登录页。
|
||
- **用途**:密码修改与会话重置。
|
||
|
||
#### `deleteAccountApi()`
|
||
- **Method/Path**:`POST /api/user/delete-account`
|
||
- **参数**:无
|
||
- **调用位置**:
|
||
- `pages/profile/profile.vue` -> `confirmDeleteAccount`
|
||
- **响应解析**:`result.code === 200` 后执行登出流程并跳登录页。
|
||
- **用途**:注销账号。
|
||
|
||
#### `updateUserInfoApi(nickname)`
|
||
- **Method/Path**:`POST /api/user/update`
|
||
- **参数**:`{ nickname }`
|
||
- **调用位置**:当前源码未发现调用。
|
||
- **用途**:历史/预留接口(当前未接入)。
|
||
|
||
---
|
||
|
||
### 2.2 社交(好友关系)
|
||
|
||
#### `friendListApi(page = 1, pageSize = 10)`
|
||
- **Method/Path**:`GET /api/v1/social/friends?page={page}&page_size={pageSize}`
|
||
- **参数**:分页参数
|
||
- **调用位置**:
|
||
- `pages/components/FriendsContent.vue` -> `loadFriendList`
|
||
- **响应解析**:
|
||
- 读取 `res.data.items`、`res.data.total`。
|
||
- 字段映射:`friend_id -> user_id`,`friend_nickname -> nickname`,`friend_fan_level -> fan_level`,`friend_avatar -> avatar_url`。
|
||
- 头像会再经 `getFriendAvatarRealUrl()` 调 `getOssPresignedUrlApi` 转真实 URL。
|
||
- **用途**:好友列表页及分页加载。
|
||
|
||
#### `searchUserApi(friendUserId)`
|
||
- **Method/Path**:`GET /api/v1/social/search-user?friend_user_id={friendUserId}`
|
||
- **参数**:目标用户 ID(UID)
|
||
- **调用位置**:
|
||
- `pages/components/FriendsContent.vue` -> `watch(searchUid, ...)` 防抖回调
|
||
- **响应解析**:
|
||
- 成功读取 `res.data` 并解析 `res.data.avatar_url` 为预签名 URL。
|
||
- 失败时对 `404` 走“用户不存在”分支。
|
||
- **用途**:按 UID 搜索可添加的用户。
|
||
|
||
#### `sendFriendRequestApi(friendUserId)`
|
||
- **Method/Path**:`POST /api/v1/social/friend-requests`
|
||
- **参数**:`{ friend_user_id }`
|
||
- **调用位置**:
|
||
- `pages/components/FriendsContent.vue` -> `confirmAddFriend`
|
||
- **响应解析**:调用成功后刷新“已发送请求”列表。
|
||
- **用途**:发送好友申请。
|
||
|
||
#### `getSentFriendRequestsApi(page = 1, pageSize = 10)`
|
||
- **Method/Path**:`GET /api/v1/social/friend-requests?type=sent&status=pending&page={page}&page_size={pageSize}`
|
||
- **参数**:分页参数
|
||
- **调用位置**:
|
||
- `pages/components/FriendsContent.vue` -> `fetchSentRequests`
|
||
- **响应解析**:
|
||
- 读取 `res.data.items`。
|
||
- 解析 `to_user_avatar_url` 为预签名 URL 后渲染。
|
||
- **用途**:我的已发送申请列表。
|
||
|
||
#### `getReceivedFriendRequestsApi(page = 1, pageSize = 10)`
|
||
- **Method/Path**:`GET /api/v1/social/friend-requests?type=received&status=pending&page={page}&page_size={pageSize}`
|
||
- **参数**:分页参数
|
||
- **调用位置**:
|
||
- `pages/components/FriendsContent.vue` -> `loadReceivedRequests`
|
||
- **响应解析**:
|
||
- 读取 `res.data.items` 分页追加。
|
||
- 解析 `from_user_avatar_url` 为预签名 URL。
|
||
- **用途**:收到的好友请求列表。
|
||
|
||
#### `handleFriendRequestApi(requestId, action)`
|
||
- **Method/Path**:`POST /api/v1/social/friend-requests/handle`
|
||
- **参数**:`{ request_id, action }`,`action ∈ {accept, reject}`
|
||
- **调用位置**:
|
||
- `pages/components/FriendsContent.vue` -> `handleAcceptRequest`
|
||
- `pages/components/FriendsContent.vue` -> `handleRejectRequest`
|
||
- **响应解析**:成功后本地移除对应请求项。
|
||
- **用途**:接受/拒绝好友请求。
|
||
|
||
#### `deleteFriendApi(friendUserId)`
|
||
- **Method/Path**:`DELETE /api/v1/social/friends`
|
||
- **参数**:`{ friend_user_id }`
|
||
- **调用位置**:
|
||
- `pages/components/FriendsContent.vue` -> `confirmDeleteFriend`
|
||
- **响应解析**:成功后本地删除好友项并更新计数。
|
||
- **用途**:解除好友关系。
|
||
|
||
---
|
||
|
||
### 2.3 身份(粉丝身份)
|
||
|
||
#### `getFanIdentitiesApi()`
|
||
- **Method/Path**:`GET /api/v1/fan-identities`
|
||
- **参数**:无
|
||
- **调用位置**:
|
||
- `pages/profile/profile.vue` -> `handleSwitchRole`
|
||
- **响应解析**:读取 `res.data.items` 作为可选明星列表。
|
||
- **用途**:拉取可新增的粉丝身份候选。
|
||
|
||
#### `addFanIdentityApi(starId, nickname)`
|
||
- **Method/Path**:`POST /api/v1/my/fan-identities`
|
||
- **参数**:`{ star_id, nickname }`
|
||
- **调用位置**:
|
||
- `pages/profile/profile.vue` -> `confirmAddIdentity`
|
||
- **响应解析**:`res.code === 200` 后刷新用户信息。
|
||
- **用途**:新增某明星身份。
|
||
|
||
#### `getMyFanIdentitiesApi()`
|
||
- **Method/Path**:`GET /api/v1/my/fan-identities`
|
||
- **参数**:无
|
||
- **调用位置**:
|
||
- `pages/profile/profile.vue` -> `handleFanTagClick`
|
||
- **响应解析**:读取 `res.data.items` 与 `res.data.current_star_id`。
|
||
- **用途**:身份切换前加载身份列表与当前身份。
|
||
|
||
#### `switchFanIdentityApi(newStarId)`
|
||
- **Method/Path**:`POST /api/v1/my/fan-identities/switch`
|
||
- **参数**:`{ new_star_id }`
|
||
- **调用位置**:
|
||
- `pages/profile/profile.vue` -> `handleSwitchIdentity`
|
||
- **响应解析**:
|
||
- 读取 `res.data.access_token` 覆盖本地 token。
|
||
- 读取 `res.data.current_identity`(`identity_id`、`identity_name`、`tag`、`level`)刷新 UI 与缓存。
|
||
- **用途**:切换当前生效身份并刷新会话上下文。
|
||
|
||
---
|
||
|
||
### 2.4 资产/NFT(星册、详情、点赞)
|
||
|
||
#### `getMyAssetsApi(page = 1, pageSize = 20)`
|
||
- **Method/Path**:`GET /api/v1/assets/me/items?page={page}&page_size={pageSize}`
|
||
- **参数**:分页参数
|
||
- **调用位置**:
|
||
- `pages/components/StarbookContent.vue` -> `loadAssetsList`
|
||
- `pages/exhibition/exhibition.vue` -> `handleAddAssetClick`
|
||
- **响应解析**:
|
||
- 读取 `response.data.items`。
|
||
- 常用字段:`asset_id`、`name`、`cover_url`、`tx_hash`、`like_count`、`status`。
|
||
- `cover_url` 会通过 `getAssetCoverRealUrl()` -> `getOssPresignedUrlApi(type=asset)` 转真实访问 URL。
|
||
- **用途**:我的藏品列表(星册页、展馆上架弹窗)。
|
||
|
||
#### `getAssetDetailApi(assetId)`
|
||
- **Method/Path**:`GET /api/v1/assets/{assetId}`
|
||
- **参数**:`assetId`
|
||
- **调用位置**:
|
||
- `pages/components/StarbookContent.vue` -> `handleCardClick`
|
||
- `pages/exhibition/exhibition.vue` -> `handleNftClick`
|
||
- **响应解析**:
|
||
- 读取 `response.data.asset` 作为详情对象。
|
||
- 点赞态兼容读取:`asset.is_liked`,部分调用还兜底 `response.data.is_liked`。
|
||
- **用途**:点击藏品卡片时拉取完整详情。
|
||
|
||
#### `likeAssetApi(assetId)`
|
||
- **Method/Path**:`POST /api/v1/social/assets/{assetId}/like`
|
||
- **参数**:`assetId`
|
||
- **调用位置**:
|
||
- `pages/components/NftDetailModal.vue` -> `handleLike`(点赞分支)
|
||
- **响应解析**:`response.code === 200` 后本地 `isLiked=true`、`likeCount+1`。
|
||
- **用途**:点赞藏品。
|
||
|
||
#### `unlikeAssetApi(assetId)`
|
||
- **Method/Path**:`DELETE /api/v1/social/assets/{assetId}/like`
|
||
- **参数**:`assetId`
|
||
- **调用位置**:
|
||
- `pages/components/NftDetailModal.vue` -> `handleLike`(取消点赞分支)
|
||
- **响应解析**:`response.code === 200` 后本地 `isLiked=false`、`likeCount-1`。
|
||
- **用途**:取消点赞。
|
||
|
||
---
|
||
|
||
### 2.5 展馆(槽位、上架、下架)
|
||
|
||
#### `getMyGalleriesApi()`
|
||
- **Method/Path**:`GET /api/v1/mygalleries`
|
||
- **参数**:无
|
||
- **调用位置**:
|
||
- `pages/exhibition/exhibition.vue` -> `loadGallerySlots`(`isMyGallery === true` 分支)
|
||
- **响应解析**:
|
||
- 读取 `response.data.gallery_owner_id`、`response.data.slots`。
|
||
- `slots` 按 `visibility(public/private)` 分板,并读取 `slot.asset`(`asset_id`、`cover_url`、`like_count`、`remain_time` 等)。
|
||
- **用途**:加载当前用户展馆槽位状态。
|
||
|
||
#### `getUserGalleriesApi(targetUid)`
|
||
- **Method/Path**:`GET /api/v1/galleries/{targetUid}`
|
||
- **参数**:目标用户 UID
|
||
- **调用位置**:
|
||
- `pages/exhibition/exhibition.vue` -> `loadGallerySlots`(`isMyGallery === false` 分支)
|
||
- **响应解析**:与 `getMyGalleriesApi` 同结构解析。
|
||
- **用途**:加载目标用户展馆。
|
||
|
||
#### `placeAssetToGalleryApi(assetId, galleryOwnerId, slotId)`
|
||
- **Method/Path**:`POST /api/v1/galleries/place`
|
||
- **参数**:`{ asset_id, gallery_owner_id, slot_id }`
|
||
- **调用位置**:
|
||
- `pages/exhibition/exhibition.vue` -> `confirmPlaceAsset`
|
||
- **响应解析**:`response.code === 200` 后关闭弹窗并重新拉取槽位数据。
|
||
- **用途**:上架藏品到指定展位槽位。
|
||
|
||
#### `removeAssetFromGalleryApi(slotId)`
|
||
- **Method/Path**:`DELETE /api/v1/galleries/slots/{slotId}/asset`
|
||
- **参数**:`slotId`
|
||
- **调用位置**:
|
||
- `pages/exhibition/exhibition.vue` -> `confirmRemoveAsset`
|
||
- **响应解析**:`response.code === 200` 后刷新展馆槽位。
|
||
- **用途**:下架槽位中的藏品。
|
||
|
||
---
|
||
|
||
### 2.6 OSS(上传签名 / 预签名读取 / 头像更新)
|
||
|
||
#### `getOssSignatureApi(type)`
|
||
- **Method/Path**:`GET /api/v1/assets/oss/signature?type={type}`
|
||
- **参数**:`type`(实际使用:`avatar`、`asset`)
|
||
- **调用位置**:
|
||
- `pages/profile/profile.vue` -> `uploadAvatarToOss`(`type='avatar'`)
|
||
- `pages/components/CastloveContent.vue` -> `uploadImageToOss`(`type='asset'`)
|
||
- **响应解析**:
|
||
- 头像上传与素材上传都会读取:
|
||
- `host`, `dir`, `policy`, `x_oss_credential`, `x_oss_date`, `security_token`, `signature`, `x_oss_signature_version`。
|
||
- `type=asset` 时额外读取 `signRes.data.order_id`(铸造订单草稿 ID)。
|
||
- **用途**:向 OSS 直传前获取签名凭证。
|
||
|
||
#### `getOssPresignedUrlApi(fileName, expires = 3600, type = 'avatar')`
|
||
- **Method/Path**:`GET /api/v1/assets/oss/presigned-url?file_name={encodeURIComponent(fileName)}&expires={expires}&type={type}`
|
||
- **参数**:文件名/路径、有效期、类型
|
||
- **调用位置**:
|
||
- `store/modules/user.js` -> `actions.login`、`actions.register`
|
||
- `pages/profile/profile.vue` -> `handleAvatarUpdateSuccess`
|
||
- `pages/components/Avatar.vue` -> `fetchOwnAvatarWithCache`
|
||
- `utils/assetImageHelper.js` -> `getAssetCoverRealUrl`、`getFriendAvatarRealUrl`
|
||
- **响应解析**:通用读取 `res.data.url`;失败时回退默认图或空值。
|
||
- **用途**:将 OSS 对象标识转换为可读 URL(头像、藏品封面)。
|
||
|
||
#### `updateAvatarApi(avatarUrl)`
|
||
- **Method/Path**:`PUT /api/v1/me/avatar`
|
||
- **参数**:`{ avatar_url }`
|
||
- **调用位置**:
|
||
- `pages/profile/profile.vue` -> `uploadAvatarToOss`(OSS 上传成功后)
|
||
- **响应解析**:`updateRes.code === 200` 后更新本地 user 缓存、触发 `avatarUpdated` 事件并刷新组件。
|
||
- **用途**:头像上传成功后回写用户头像地址。
|
||
|
||
---
|
||
|
||
### 2.7 铸造(Castlove)
|
||
|
||
#### `createMintOrderApi(orderData)`
|
||
- **Method/Path**:`POST /api/v1/assets/mints`
|
||
- **参数**:`orderData`(页面构造字段)
|
||
- `name`, `event`, `description`, `material_type`, `material_url`, `rarity`, `tags`, `order_id`
|
||
- **调用位置**:
|
||
- `pages/components/CastloveContent.vue` -> `handleConfirm`
|
||
- **响应解析**:`response.code === 200` 后视为铸造成功,保存临时展示数据并跳转成功页。
|
||
- **用途**:提交铸造订单。
|
||
|
||
#### `deleteMintOrderApi(orderId)`
|
||
- **Method/Path**:`DELETE /api/v1/assets/mints/{orderId}`
|
||
- **参数**:`orderId`
|
||
- **调用位置**:
|
||
- `pages/components/CastloveContent.vue` -> `handleBack`(用户确认返回时清理未完成订单)
|
||
- **响应解析**:仅调用,不依赖返回体字段(失败仅记录日志,不阻断返回流程)。
|
||
- **用途**:清理中断铸造产生的草稿订单。
|
||
|
||
---
|
||
|
||
## 3. 非封装直连网络调用(不经过 `request()`)
|
||
|
||
### `uni.uploadFile`(OSS 直传)
|
||
- **位置**:
|
||
- `pages/profile/profile.vue` -> `uploadAvatarToOss`
|
||
- `pages/components/CastloveContent.vue` -> `uploadImageToOss`
|
||
- **前置**:先调 `getOssSignatureApi` 获取签名字段。
|
||
- **成功判定**:`uploadRes.statusCode === 200 || 204`。
|
||
- **后续动作**:
|
||
- 头像上传:调用 `updateAvatarApi` 回写业务系统头像地址。
|
||
- 藏品素材上传:生成 `uploadedImageUrl`,用于 `createMintOrderApi`。
|
||
- **说明**:不走 `request()`,因此不受其统一鉴权/错误码分流逻辑约束。
|
||
|
||
### `uni.downloadFile`(头像文件缓存)
|
||
- **位置**:
|
||
- `utils/avatarCache.js` -> `downloadAndCacheAvatar`
|
||
- **调用链**:`getOssPresignedUrlApi -> downloadAndCacheAvatar(avatarUrl, realUrl) -> uni.downloadFile`
|
||
- **成功判定**:`res.statusCode === 200`
|
||
- **用途**:将头像下载到本地并 `saveFile`,提升后续展示性能与稳定性。
|
||
|
||
---
|
||
|
||
## 4. 调用覆盖与观察
|
||
|
||
- `utils/api.js` 共导出 **31** 个 API 函数。
|
||
- 其中 **30 个已在源码业务层使用**,`updateUserInfoApi` 当前未发现调用。
|
||
- 响应处理范式基本统一:
|
||
- 成功分支:`res.code === 200` + 按需读取 `res.data.*`
|
||
- 失败分支:依赖 `throw Error(message)`,页面显示 `error.message`。
|
||
|