Merge branch 'master' of http://115.190.64.57:8000/xiaozhang/zhibo into IM-gift
This commit is contained in:
commit
3535009dba
167
0-待完成接入接口.md
Normal file
167
0-待完成接入接口.md
Normal file
|
|
@ -0,0 +1,167 @@
|
||||||
|
# 待完成接入接口清单
|
||||||
|
|
||||||
|
> 更新时间: 2024-12-30
|
||||||
|
|
||||||
|
## 📊 总体情况
|
||||||
|
|
||||||
|
| 类别 | 后端接口数 | Android已接入 | 待接入 |
|
||||||
|
|------|-----------|--------------|--------|
|
||||||
|
| 总计 | 131 | ~85 | ~46 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ 已接入模块 (无需处理)
|
||||||
|
|
||||||
|
| 模块 | 接口数 | 状态 |
|
||||||
|
|------|--------|------|
|
||||||
|
| 用户认证 | 4 | ✅ 全部接入 |
|
||||||
|
| 用户信息 | 2 | ✅ 全部接入 |
|
||||||
|
| 直播间 | 6 | ✅ 全部接入 |
|
||||||
|
| 直播弹幕 | 2 | ✅ 全部接入 |
|
||||||
|
| 礼物打赏 | 5 | ✅ 全部接入 |
|
||||||
|
| 私聊会话 | 8 | ✅ 全部接入 |
|
||||||
|
| 好友管理 | 9 | ✅ 全部接入 |
|
||||||
|
| 文件上传 | 2 | ✅ 全部接入 |
|
||||||
|
| 在线状态 | 5 | ✅ 全部接入 |
|
||||||
|
| 离线消息 | 3 | ✅ 全部接入 |
|
||||||
|
| 消息表情回应 | 4 | ✅ 全部接入 |
|
||||||
|
| 关注功能 | 7 | ✅ 全部接入 |
|
||||||
|
| 作品管理 | 13 | ✅ 全部接入 |
|
||||||
|
| 搜索功能 | 9 | ✅ 全部接入 |
|
||||||
|
| 支付集成 | 4 | ✅ 全部接入 |
|
||||||
|
| 通话功能 | 10 | ✅ 全部接入 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ❌ 待接入模块
|
||||||
|
|
||||||
|
### 1. 群组管理 (10个接口) - 🔴 高优先级
|
||||||
|
|
||||||
|
后端已完成,Android端未定义接口。
|
||||||
|
|
||||||
|
| 接口 | 路径 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| 创建群组 | `POST /api/front/groups/create` | 创建新群组 |
|
||||||
|
| 群组列表 | `GET /api/front/groups/list` | 获取我的群组 |
|
||||||
|
| 群组详情 | `GET /api/front/groups/{groupId}` | 获取群组信息 |
|
||||||
|
| 更新群组 | `PUT /api/front/groups/{groupId}` | 修改群组信息 |
|
||||||
|
| 解散群组 | `DELETE /api/front/groups/{groupId}` | 解散群组 |
|
||||||
|
| 添加成员 | `POST /api/front/groups/{groupId}/members` | 邀请成员 |
|
||||||
|
| 移除成员 | `DELETE /api/front/groups/{groupId}/members/{userId}` | 踢出成员 |
|
||||||
|
| 成员列表 | `GET /api/front/groups/{groupId}/members` | 获取成员 |
|
||||||
|
| 退出群组 | `POST /api/front/groups/{groupId}/leave` | 主动退群 |
|
||||||
|
| 转让群主 | `POST /api/front/groups/{groupId}/transfer` | 转让群主 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. 群组消息 (4个接口) - 🔴 高优先级
|
||||||
|
|
||||||
|
| 接口 | 路径 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| 发送群消息 | `POST /api/front/groups/{groupId}/messages` | 发送消息 |
|
||||||
|
| 群消息历史 | `GET /api/front/groups/{groupId}/messages` | 获取历史 |
|
||||||
|
| 撤回消息 | `DELETE /api/front/groups/{groupId}/messages/{messageId}` | 撤回消息 |
|
||||||
|
| 转发消息 | `POST /api/front/groups/{groupId}/messages/{messageId}/forward` | 转发消息 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. 消息搜索 (3个接口) - 🟡 中优先级
|
||||||
|
|
||||||
|
| 接口 | 路径 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| 搜索会话 | `GET /api/front/messages/search/conversations` | 搜索会话 |
|
||||||
|
| 搜索消息 | `GET /api/front/messages/search/messages` | 搜索消息内容 |
|
||||||
|
| 全局搜索 | `GET /api/front/messages/search/global` | 全局搜索 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. 评论功能 (8个接口) - 🟡 中优先级
|
||||||
|
|
||||||
|
| 接口 | 路径 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| 发布评论 | `POST /api/front/works/comment/publish` | 发布评论 |
|
||||||
|
| 评论列表 | `GET /api/front/works/comment/list/{worksId}` | 获取评论 |
|
||||||
|
| 点赞评论 | `POST /api/front/works/comment/like/{commentId}` | 点赞 |
|
||||||
|
| 取消点赞 | `POST /api/front/works/comment/unlike/{commentId}` | 取消点赞 |
|
||||||
|
| 删除评论 | `POST /api/front/works/comment/delete/{commentId}` | 删除评论 |
|
||||||
|
| 回复列表 | `GET /api/front/works/comment/reply/list/{commentId}` | 获取回复 |
|
||||||
|
| 评论详情 | `GET /api/front/works/comment/detail/{commentId}` | 评论详情 |
|
||||||
|
| 检查点赞 | `GET /api/front/works/comment/check-liked/{commentId}` | 检查状态 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5. 通知推送 (9个接口) - 🟡 中优先级
|
||||||
|
|
||||||
|
| 接口 | 路径 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| 通知列表 | `GET /api/front/notification/list` | 获取通知 |
|
||||||
|
| 未读数量 | `GET /api/front/notification/unread-count` | 未读数 |
|
||||||
|
| 标记已读 | `POST /api/front/notification/mark-read/{id}` | 单条已读 |
|
||||||
|
| 全部已读 | `POST /api/front/notification/mark-all-read` | 全部已读 |
|
||||||
|
| 注册FCM | `POST /api/front/notification/fcm/register` | 注册推送 |
|
||||||
|
| 移除FCM | `POST /api/front/notification/fcm/remove` | 移除推送 |
|
||||||
|
| 删除通知 | `DELETE /api/front/notification/{id}` | 删除单条 |
|
||||||
|
| 清空通知 | `DELETE /api/front/notification/clear-all` | 清空全部 |
|
||||||
|
| 按类型统计 | `GET /api/front/notification/unread-count-by-type` | 分类统计 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 6. 分类管理 (7个接口) - 🟢 低优先级
|
||||||
|
|
||||||
|
| 接口 | 路径 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| 直播间分类 | `GET /api/front/category/live-room` | 直播分类 |
|
||||||
|
| 作品分类 | `GET /api/front/category/work` | 作品分类 |
|
||||||
|
| 分类列表 | `GET /api/front/category/list` | 全部分类 |
|
||||||
|
| 分类详情 | `GET /api/front/category/{id}` | 分类详情 |
|
||||||
|
| 分类统计 | `GET /api/front/category/statistics` | 统计数据 |
|
||||||
|
| 热门分类 | `GET /api/front/category/hot` | 热门分类 |
|
||||||
|
| 子分类 | `GET /api/front/category/{parentId}/children` | 子分类 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 7. 文件上传补充 (3个接口) - 🟢 低优先级
|
||||||
|
|
||||||
|
| 接口 | 路径 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| 通用图片上传 | `POST /api/upload/image` | 通用图片 |
|
||||||
|
| 通用文件上传 | `POST /api/upload/file` | 通用文件 |
|
||||||
|
| 语音上传 | `POST /api/upload/chat/voice` | 语音消息 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 8. 直播间补充 (4个接口) - 🟢 低优先级
|
||||||
|
|
||||||
|
| 接口 | 路径 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| 开始直播 | `POST /api/front/live/room/{id}/start` | 开播 |
|
||||||
|
| 结束直播 | `POST /api/front/live/room/{id}/stop` | 停播 |
|
||||||
|
| 观众列表 | `GET /api/rooms/{roomId}/viewers` | 观众列表 |
|
||||||
|
| 手动广播人数 | `POST /api/live/online/broadcast/{roomId}` | 广播人数 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 接入优先级建议
|
||||||
|
|
||||||
|
### 第一优先级 (核心社交)
|
||||||
|
1. **群组管理** - 10个接口
|
||||||
|
2. **群组消息** - 4个接口
|
||||||
|
|
||||||
|
### 第二优先级 (内容互动)
|
||||||
|
3. **评论功能** - 8个接口
|
||||||
|
4. **通知推送** - 9个接口
|
||||||
|
|
||||||
|
### 第三优先级 (辅助功能)
|
||||||
|
5. **消息搜索** - 3个接口
|
||||||
|
6. **分类管理** - 7个接口
|
||||||
|
7. **文件上传补充** - 3个接口
|
||||||
|
8. **直播间补充** - 4个接口
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 备注
|
||||||
|
|
||||||
|
- 后端接口已全部完成 (131个)
|
||||||
|
- Android端已接入约85个接口
|
||||||
|
- 待接入约46个接口
|
||||||
|
- 核心功能已基本完成,待接入的主要是群组和辅助功能
|
||||||
|
|
@ -10,7 +10,27 @@ export function sessionDetailApi(id) {
|
||||||
return request({ url: '/admin/session/detail/' + id, method: 'get' })
|
return request({ url: '/admin/session/detail/' + id, method: 'get' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 会话消息列表
|
||||||
|
export function sessionMessagesApi(conversationId, params) {
|
||||||
|
return request({ url: '/admin/session/' + conversationId + '/messages', method: 'get', params })
|
||||||
|
}
|
||||||
|
|
||||||
// 删除会话
|
// 删除会话
|
||||||
export function sessionDeleteApi(id) {
|
export function sessionDeleteApi(id) {
|
||||||
return request({ url: '/admin/session/delete/' + id, method: 'post' })
|
return request({ url: '/admin/session/delete/' + id, method: 'post' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 删除消息
|
||||||
|
export function sessionMessageDeleteApi(messageId) {
|
||||||
|
return request({ url: '/admin/session/message/delete/' + messageId, method: 'post' })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 撤回消息
|
||||||
|
export function sessionMessageRecallApi(messageId) {
|
||||||
|
return request({ url: '/admin/session/message/recall/' + messageId, method: 'post' })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 会话统计
|
||||||
|
export function sessionStatisticsApi() {
|
||||||
|
return request({ url: '/admin/session/statistics', method: 'get' })
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,164 +1,602 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="divBox">
|
<div class="divBox relative">
|
||||||
<el-card shadow="never" class="ivu-mt">
|
<el-card :bordered="false" shadow="never" class="ivu-mt" :body-style="{ padding: 0 }">
|
||||||
<div class="padding-add">
|
<div class="padding-add">
|
||||||
<!-- 搜索表单 -->
|
<el-form inline size="small" :model="queryForm" ref="queryForm" label-width="90px">
|
||||||
<el-form :inline="true" :model="searchForm" size="small" class="mb20">
|
<div class="acea-row search-form row-between">
|
||||||
<el-form-item label="发送方昵称">
|
<div class="search-form-box">
|
||||||
<el-input v-model="searchForm.senderNickname" placeholder="请输入发送方昵称" clearable class="selWidth" />
|
<el-form-item label="发送方昵称:">
|
||||||
|
<el-input v-model="queryForm.senderNickname" placeholder="请输入发送方昵称" clearable class="selWidth" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="发送方电话">
|
<el-form-item label="发送方电话:">
|
||||||
<el-input v-model="searchForm.senderPhone" placeholder="请输入发送方电话" clearable class="selWidth" />
|
<el-input v-model="queryForm.senderPhone" placeholder="请输入发送方电话" clearable class="selWidth" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="分类时间">
|
<el-form-item label="时间选择:">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
v-model="searchForm.startTime"
|
v-model="dateRange"
|
||||||
type="datetime"
|
align="right"
|
||||||
placeholder="开始时间"
|
unlink-panels
|
||||||
value-format="yyyy-MM-dd HH:mm:ss"
|
value-format="yyyy-MM-dd HH:mm:ss"
|
||||||
|
format="yyyy-MM-dd"
|
||||||
|
size="small"
|
||||||
|
type="daterange"
|
||||||
|
placeholder="选择时间范围"
|
||||||
class="selWidth"
|
class="selWidth"
|
||||||
|
@change="onDateChange"
|
||||||
|
start-placeholder="开始时间"
|
||||||
|
end-placeholder="结束时间"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="起止时间">
|
</div>
|
||||||
<el-date-picker
|
<el-form-item class="search-form-sub">
|
||||||
v-model="searchForm.endTime"
|
<el-button type="primary" icon="el-icon-search" @click="handleSearch">搜索</el-button>
|
||||||
type="datetime"
|
<el-button @click="handleReset" size="small">重置</el-button>
|
||||||
placeholder="结束时间"
|
|
||||||
value-format="yyyy-MM-dd HH:mm:ss"
|
|
||||||
class="selWidth"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item>
|
|
||||||
<el-button type="primary" @click="handleSearch">搜索</el-button>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
</div>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
<!-- 数据表格 -->
|
<el-card class="box-card mt14">
|
||||||
<el-table v-loading="loading" :data="tableData" border size="small">
|
<div slot="header" class="clearfix">
|
||||||
<el-table-column prop="id" label="id" width="80" align="center" />
|
<span class="card-title">会话管理</span>
|
||||||
<el-table-column label="发送者头像" width="100" align="center">
|
<div class="header-right">
|
||||||
<template slot-scope="scope">
|
<el-tag type="info">总会话数:{{ statistics.totalConversations || 0 }}</el-tag>
|
||||||
<el-image
|
<el-tag type="success" class="ml10">总消息数:{{ statistics.totalMessages || 0 }}</el-tag>
|
||||||
v-if="scope.row.sender_avatar"
|
<el-tag type="warning" class="ml10">今日消息:{{ statistics.todayMessages || 0 }}</el-tag>
|
||||||
:src="scope.row.sender_avatar"
|
</div>
|
||||||
:preview-src-list="[scope.row.sender_avatar]"
|
</div>
|
||||||
style="width: 50px; height: 50px; cursor: pointer"
|
|
||||||
fit="cover"
|
<el-table
|
||||||
/>
|
ref="table"
|
||||||
|
v-loading="loading"
|
||||||
|
:data="tableData"
|
||||||
|
style="width: 100%"
|
||||||
|
size="mini"
|
||||||
|
highlight-current-row
|
||||||
|
>
|
||||||
|
<el-table-column type="expand">
|
||||||
|
<template slot-scope="props">
|
||||||
|
<div class="message-preview" v-loading="props.row.messagesLoading">
|
||||||
|
<div class="message-header">
|
||||||
|
<span>最近消息记录</span>
|
||||||
|
<el-button type="text" size="mini" @click="loadMessages(props.row)">刷新</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="message-list" v-if="props.row.messages && props.row.messages.length">
|
||||||
|
<div
|
||||||
|
class="message-item"
|
||||||
|
v-for="msg in props.row.messages"
|
||||||
|
:key="msg.id"
|
||||||
|
:class="{ 'message-right': msg.senderId === props.row.user1_id }"
|
||||||
|
>
|
||||||
|
<div class="message-sender">{{ msg.senderName || '用户' + msg.senderId }}</div>
|
||||||
|
<div class="message-content">{{ msg.content }}</div>
|
||||||
|
<div class="message-time">{{ msg.createTime }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-empty v-else description="暂无消息记录" :image-size="60"></el-empty>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="sender_nickname" label="发送者昵称" width="120" align="center" />
|
<el-table-column prop="id" label="会话ID" width="80" />
|
||||||
<el-table-column prop="sender_phone" label="发送者电话" width="130" align="center" />
|
<el-table-column label="发送者" min-width="150">
|
||||||
<el-table-column label="对方头像" width="100" align="center">
|
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-image
|
<div class="user-info">
|
||||||
v-if="scope.row.receiver_avatar"
|
<el-avatar :size="32" :src="scope.row.sender_avatar" icon="el-icon-user"></el-avatar>
|
||||||
:src="scope.row.receiver_avatar"
|
<div class="user-detail">
|
||||||
:preview-src-list="[scope.row.receiver_avatar]"
|
<span class="user-name">{{ scope.row.sender_nickname || '用户' + scope.row.user1_id }}</span>
|
||||||
style="width: 50px; height: 50px; cursor: pointer"
|
<span class="user-id">{{ scope.row.sender_phone || 'ID: ' + scope.row.user1_id }}</span>
|
||||||
fit="cover"
|
</div>
|
||||||
/>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="receiver_nickname" label="对方昵称" width="120" align="center" />
|
<el-table-column label="对方" min-width="150">
|
||||||
<el-table-column prop="receiver_phone" label="对方昵称电话" width="130" align="center" />
|
|
||||||
<el-table-column prop="create_time" label="创建时间" width="160" align="center" />
|
|
||||||
<el-table-column label="操作" width="100" align="center" fixed="right">
|
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button type="text" size="small" @click="handleDelete(scope.row.id)">删除</el-button>
|
<div class="user-info">
|
||||||
|
<el-avatar :size="32" :src="scope.row.receiver_avatar" icon="el-icon-user"></el-avatar>
|
||||||
|
<div class="user-detail">
|
||||||
|
<span class="user-name">{{ scope.row.receiver_nickname || '用户' + scope.row.user2_id }}</span>
|
||||||
|
<span class="user-id">{{ scope.row.receiver_phone || 'ID: ' + scope.row.user2_id }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="last_message" label="最后消息" min-width="200" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="last_message_time" label="最后消息时间" width="160" />
|
||||||
|
<el-table-column label="消息数" width="80">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-tag size="mini">{{ scope.row.message_count || 0 }}</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="create_time" label="创建时间" width="160" />
|
||||||
|
<el-table-column label="操作" width="120" fixed="right">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button type="text" size="mini" @click="viewMessages(scope.row)">查看</el-button>
|
||||||
|
<el-divider direction="vertical"></el-divider>
|
||||||
|
<el-popconfirm title="确定删除该会话及所有消息吗?" @confirm="deleteConversation(scope.row)">
|
||||||
|
<el-button slot="reference" type="text" size="mini" class="text-danger">删除</el-button>
|
||||||
|
</el-popconfirm>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<!-- 分页 -->
|
<div class="block">
|
||||||
<div class="acea-row row-center page mt20">
|
|
||||||
<span class="mr10">共 {{ total }} 条</span>
|
|
||||||
<el-pagination
|
<el-pagination
|
||||||
:current-page="page"
|
|
||||||
:page-sizes="[10, 20, 50, 100]"
|
:page-sizes="[10, 20, 50, 100]"
|
||||||
:page-size="limit"
|
:page-size="queryForm.limit"
|
||||||
|
:current-page="queryForm.page"
|
||||||
|
layout="total, sizes, prev, pager, next, jumper"
|
||||||
:total="total"
|
:total="total"
|
||||||
layout="prev, pager, next, sizes, jumper"
|
|
||||||
@size-change="handleSizeChange"
|
@size-change="handleSizeChange"
|
||||||
@current-change="handleCurrentChange"
|
@current-change="handlePageChange"
|
||||||
|
background
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 消息详情对话框 -->
|
||||||
|
<el-dialog
|
||||||
|
:title="'会话详情 - ' + (currentConversation ? currentConversation.id : '')"
|
||||||
|
:visible.sync="dialogVisible"
|
||||||
|
width="700px"
|
||||||
|
top="5vh"
|
||||||
|
>
|
||||||
|
<div class="dialog-users" v-if="currentConversation">
|
||||||
|
<div class="dialog-user">
|
||||||
|
<el-avatar :size="48" :src="currentConversation.sender_avatar" icon="el-icon-user"></el-avatar>
|
||||||
|
<div>
|
||||||
|
<div class="user-name">{{ currentConversation.sender_nickname || '用户' + currentConversation.user1_id }}</div>
|
||||||
|
<div class="user-id">{{ currentConversation.sender_phone || 'ID: ' + currentConversation.user1_id }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="dialog-arrow">
|
||||||
|
<i class="el-icon-sort"></i>
|
||||||
|
</div>
|
||||||
|
<div class="dialog-user">
|
||||||
|
<el-avatar :size="48" :src="currentConversation.receiver_avatar" icon="el-icon-user"></el-avatar>
|
||||||
|
<div>
|
||||||
|
<div class="user-name">{{ currentConversation.receiver_nickname || '用户' + currentConversation.user2_id }}</div>
|
||||||
|
<div class="user-id">{{ currentConversation.receiver_phone || 'ID: ' + currentConversation.user2_id }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="dialog-messages" v-loading="messagesLoading">
|
||||||
|
<div
|
||||||
|
class="dialog-message"
|
||||||
|
v-for="msg in currentMessages"
|
||||||
|
:key="msg.id"
|
||||||
|
:class="{ 'message-from-user1': currentConversation && msg.senderId === currentConversation.user1_id }"
|
||||||
|
>
|
||||||
|
<div class="msg-avatar">
|
||||||
|
<el-avatar
|
||||||
|
:size="36"
|
||||||
|
:src="getMessageAvatar(msg)"
|
||||||
|
icon="el-icon-user"
|
||||||
|
></el-avatar>
|
||||||
|
</div>
|
||||||
|
<div class="msg-body">
|
||||||
|
<div class="msg-header">
|
||||||
|
<span class="msg-sender">{{ msg.senderName || '用户' + msg.senderId }}</span>
|
||||||
|
<el-tag v-if="msg.isRecalled" type="warning" size="mini" class="recalled-tag">已撤回</el-tag>
|
||||||
|
<span class="msg-time">{{ msg.createTime }}</span>
|
||||||
|
<el-popconfirm
|
||||||
|
v-if="!msg.isRecalled"
|
||||||
|
title="确定要撤回这条消息吗?"
|
||||||
|
@confirm="recallMessage(msg)"
|
||||||
|
class="msg-recall"
|
||||||
|
>
|
||||||
|
<el-button slot="reference" type="text" size="mini" class="recall-btn">撤回</el-button>
|
||||||
|
</el-popconfirm>
|
||||||
|
</div>
|
||||||
|
<!-- 如果消息已撤回,显示原始内容 -->
|
||||||
|
<div v-if="msg.isRecalled && msg.originalContent" class="msg-content recalled-content">
|
||||||
|
<div class="original-label">原始内容:</div>
|
||||||
|
<div class="original-text">{{ msg.originalContent }}</div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="msg-content">{{ msg.content }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-empty v-if="!messagesLoading && currentMessages.length === 0" description="暂无消息记录"></el-empty>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="dialog-pagination" v-if="messageTotal > messagePageSize">
|
||||||
|
<el-pagination
|
||||||
|
small
|
||||||
|
layout="prev, pager, next"
|
||||||
|
:total="messageTotal"
|
||||||
|
:page-size="messagePageSize"
|
||||||
|
:current-page="messagePage"
|
||||||
|
@current-change="handleMessagePageChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { sessionListApi, sessionDeleteApi } from '@/api/session';
|
import { sessionListApi, sessionMessagesApi, sessionDeleteApi, sessionStatisticsApi, sessionMessageRecallApi } from '@/api/session';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'SessionList',
|
name: 'SessionList',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
loading: false,
|
loading: false,
|
||||||
searchForm: {
|
tableData: [],
|
||||||
|
total: 0,
|
||||||
|
queryForm: {
|
||||||
senderNickname: '',
|
senderNickname: '',
|
||||||
senderPhone: '',
|
senderPhone: '',
|
||||||
startTime: '',
|
startTime: '',
|
||||||
endTime: '',
|
endTime: '',
|
||||||
},
|
|
||||||
tableData: [],
|
|
||||||
page: 1,
|
page: 1,
|
||||||
limit: 10,
|
limit: 10,
|
||||||
total: 0,
|
},
|
||||||
|
dateRange: [],
|
||||||
|
statistics: {
|
||||||
|
totalConversations: 0,
|
||||||
|
totalMessages: 0,
|
||||||
|
todayMessages: 0,
|
||||||
|
},
|
||||||
|
dialogVisible: false,
|
||||||
|
currentConversation: null,
|
||||||
|
currentMessages: [],
|
||||||
|
messagesLoading: false,
|
||||||
|
messagePage: 1,
|
||||||
|
messagePageSize: 20,
|
||||||
|
messageTotal: 0,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.getList();
|
this.getList();
|
||||||
|
this.getStatistics();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getList() {
|
async getList() {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
sessionListApi({
|
try {
|
||||||
...this.searchForm,
|
const res = await sessionListApi(this.queryForm);
|
||||||
page: this.page,
|
this.tableData = (res.list || []).map(item => ({
|
||||||
limit: this.limit
|
...item,
|
||||||
})
|
messages: [],
|
||||||
.then((res) => {
|
messagesLoading: false,
|
||||||
this.tableData = res.data.list || [];
|
}));
|
||||||
this.total = res.data.total || 0;
|
this.total = res.total || 0;
|
||||||
this.loading = false;
|
} catch (error) {
|
||||||
})
|
console.error('获取会话列表失败:', error);
|
||||||
.catch(() => {
|
this.$message.error('获取会话列表失败');
|
||||||
|
} finally {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async getStatistics() {
|
||||||
|
try {
|
||||||
|
const res = await sessionStatisticsApi();
|
||||||
|
this.statistics = res || {};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取统计数据失败:', error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async loadMessages(row) {
|
||||||
|
row.messagesLoading = true;
|
||||||
|
try {
|
||||||
|
const res = await sessionMessagesApi(row.id, { page: 1, pageSize: 5 });
|
||||||
|
row.messages = res.list || [];
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载消息失败:', error);
|
||||||
|
} finally {
|
||||||
|
row.messagesLoading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async viewMessages(row) {
|
||||||
|
this.currentConversation = row;
|
||||||
|
this.dialogVisible = true;
|
||||||
|
this.messagePage = 1;
|
||||||
|
await this.loadDialogMessages();
|
||||||
|
},
|
||||||
|
async loadDialogMessages() {
|
||||||
|
if (!this.currentConversation) return;
|
||||||
|
this.messagesLoading = true;
|
||||||
|
try {
|
||||||
|
const res = await sessionMessagesApi(this.currentConversation.id, {
|
||||||
|
page: this.messagePage,
|
||||||
|
pageSize: this.messagePageSize,
|
||||||
});
|
});
|
||||||
|
this.currentMessages = res.list || [];
|
||||||
|
this.messageTotal = res.total || 0;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载消息失败:', error);
|
||||||
|
this.$message.error('加载消息失败');
|
||||||
|
} finally {
|
||||||
|
this.messagesLoading = false;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
handleSearch() {
|
async deleteConversation(row) {
|
||||||
this.page = 1;
|
try {
|
||||||
this.getList();
|
await sessionDeleteApi(row.id);
|
||||||
},
|
|
||||||
handleSizeChange(val) {
|
|
||||||
this.limit = val;
|
|
||||||
this.page = 1;
|
|
||||||
this.getList();
|
|
||||||
},
|
|
||||||
handleCurrentChange(val) {
|
|
||||||
this.page = val;
|
|
||||||
this.getList();
|
|
||||||
},
|
|
||||||
handleDelete(id) {
|
|
||||||
this.$confirm('确定要删除该会话吗?', '提示', {
|
|
||||||
confirmButtonText: '确定',
|
|
||||||
cancelButtonText: '取消',
|
|
||||||
type: 'warning'
|
|
||||||
}).then(() => {
|
|
||||||
sessionDeleteApi(id).then(() => {
|
|
||||||
this.$message.success('删除成功');
|
this.$message.success('删除成功');
|
||||||
this.getList();
|
this.getList();
|
||||||
});
|
this.getStatistics();
|
||||||
});
|
} catch (error) {
|
||||||
|
console.error('删除会话失败:', error);
|
||||||
|
this.$message.error('删除失败');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async recallMessage(msg) {
|
||||||
|
try {
|
||||||
|
await sessionMessageRecallApi(msg.id);
|
||||||
|
this.$message.success('撤回成功');
|
||||||
|
// 刷新消息列表
|
||||||
|
await this.loadDialogMessages();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('撤回消息失败:', error);
|
||||||
|
this.$message.error('撤回失败');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleSearch() {
|
||||||
|
this.queryForm.page = 1;
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
handleReset() {
|
||||||
|
this.queryForm = {
|
||||||
|
senderNickname: '',
|
||||||
|
senderPhone: '',
|
||||||
|
startTime: '',
|
||||||
|
endTime: '',
|
||||||
|
page: 1,
|
||||||
|
limit: 10,
|
||||||
|
};
|
||||||
|
this.dateRange = [];
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
onDateChange(val) {
|
||||||
|
if (val && val.length === 2) {
|
||||||
|
this.queryForm.startTime = val[0];
|
||||||
|
this.queryForm.endTime = val[1];
|
||||||
|
} else {
|
||||||
|
this.queryForm.startTime = '';
|
||||||
|
this.queryForm.endTime = '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleSizeChange(val) {
|
||||||
|
this.queryForm.limit = val;
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
handlePageChange(val) {
|
||||||
|
this.queryForm.page = val;
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
handleMessagePageChange(val) {
|
||||||
|
this.messagePage = val;
|
||||||
|
this.loadDialogMessages();
|
||||||
|
},
|
||||||
|
getMessageAvatar(msg) {
|
||||||
|
if (!this.currentConversation) return '';
|
||||||
|
if (msg.senderId === this.currentConversation.user1_id) {
|
||||||
|
return this.currentConversation.sender_avatar || '';
|
||||||
|
}
|
||||||
|
return this.currentConversation.receiver_avatar || '';
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style lang="scss" scoped>
|
||||||
|
.padding-add {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
.selWidth {
|
.selWidth {
|
||||||
width: 180px;
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt14 {
|
||||||
|
margin-top: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ml10 {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-right {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-detail {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-name {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-id {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-danger {
|
||||||
|
color: #f56c6c !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-preview {
|
||||||
|
padding: 10px 20px;
|
||||||
|
background: #fafafa;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #606266;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-list {
|
||||||
|
max-height: 200px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-item {
|
||||||
|
padding: 8px 12px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
border-left: 3px solid #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-item.message-right {
|
||||||
|
border-left-color: #67c23a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-sender {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #909399;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-content {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #303133;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-time {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #c0c4cc;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-users {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 20px;
|
||||||
|
padding: 20px;
|
||||||
|
background: #f5f7fa;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-user {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-arrow {
|
||||||
|
font-size: 24px;
|
||||||
|
color: #909399;
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-messages {
|
||||||
|
max-height: 400px;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-message {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding: 10px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-message.message-from-user1 {
|
||||||
|
background: #ecf5ff;
|
||||||
|
border-color: #b3d8ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.msg-avatar {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.msg-body {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.msg-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.msg-sender {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.msg-time {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #909399;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recall-btn {
|
||||||
|
color: #f56c6c !important;
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.msg-content {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
line-height: 1.5;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recalled-tag {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recalled-content {
|
||||||
|
background: #fff3e0;
|
||||||
|
padding: 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border-left: 3px solid #ff9800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.original-label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #ff9800;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.original-text {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-pagination {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block {
|
||||||
|
margin-top: 20px;
|
||||||
|
text-align: right;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -10,80 +10,302 @@ import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 会话管理控制器(社交互动模块)
|
||||||
|
* 与私聊管理使用相同的数据表:eb_conversation 和 eb_private_message
|
||||||
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("api/admin/session")
|
@RequestMapping("api/admin/session")
|
||||||
@Api(tags = "会话管理")
|
@Api(tags = "社交互动 - 会话管理")
|
||||||
@Validated
|
@Validated
|
||||||
public class SessionController {
|
public class SessionController {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private JdbcTemplate jdbcTemplate;
|
private JdbcTemplate jdbcTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取会话列表
|
||||||
|
*/
|
||||||
@ApiOperation(value = "会话列表")
|
@ApiOperation(value = "会话列表")
|
||||||
@RequestMapping(value = "/list", method = RequestMethod.GET)
|
@GetMapping("/list")
|
||||||
public CommonResult<CommonPage<Map<String, Object>>> getList(
|
public CommonResult<CommonPage<Map<String, Object>>> getList(
|
||||||
@RequestParam(value = "senderNickname", required = false) String senderNickname,
|
@RequestParam(value = "senderNickname", required = false) String senderNickname,
|
||||||
@RequestParam(value = "senderPhone", required = false) String senderPhone,
|
@RequestParam(value = "senderPhone", required = false) String senderPhone,
|
||||||
|
@RequestParam(value = "keyword", required = false) String keyword,
|
||||||
@RequestParam(value = "startTime", required = false) String startTime,
|
@RequestParam(value = "startTime", required = false) String startTime,
|
||||||
@RequestParam(value = "endTime", required = false) String endTime,
|
@RequestParam(value = "endTime", required = false) String endTime,
|
||||||
@RequestParam(value = "page", defaultValue = "1") Integer page,
|
@RequestParam(value = "page", defaultValue = "1") Integer page,
|
||||||
@RequestParam(value = "limit", defaultValue = "10") Integer limit) {
|
@RequestParam(value = "limit", defaultValue = "10") Integer limit) {
|
||||||
|
|
||||||
StringBuilder sql = new StringBuilder("SELECT * FROM eb_session WHERE 1=1");
|
StringBuilder sql = new StringBuilder();
|
||||||
StringBuilder countSql = new StringBuilder("SELECT COUNT(*) FROM eb_session WHERE 1=1");
|
sql.append("SELECT c.id, c.user1_id, c.user2_id, c.last_message, c.last_message_time, c.create_time, ");
|
||||||
|
sql.append("u1.nickname as sender_nickname, u1.avatar as sender_avatar, u1.phone as sender_phone, ");
|
||||||
|
sql.append("u2.nickname as receiver_nickname, u2.avatar as receiver_avatar, u2.phone as receiver_phone, ");
|
||||||
|
sql.append("(SELECT COUNT(*) FROM eb_private_message WHERE conversation_id = c.id) as message_count ");
|
||||||
|
sql.append("FROM eb_conversation c ");
|
||||||
|
sql.append("LEFT JOIN eb_user u1 ON c.user1_id = u1.uid ");
|
||||||
|
sql.append("LEFT JOIN eb_user u2 ON c.user2_id = u2.uid ");
|
||||||
|
sql.append("WHERE 1=1 ");
|
||||||
|
|
||||||
if (senderNickname != null && !senderNickname.isEmpty()) {
|
StringBuilder countSql = new StringBuilder();
|
||||||
String safeName = senderNickname.replace("'", "''");
|
countSql.append("SELECT COUNT(*) FROM eb_conversation c ");
|
||||||
sql.append(" AND sender_nickname LIKE '%").append(safeName).append("%'");
|
countSql.append("LEFT JOIN eb_user u1 ON c.user1_id = u1.uid ");
|
||||||
countSql.append(" AND sender_nickname LIKE '%").append(safeName).append("%'");
|
countSql.append("LEFT JOIN eb_user u2 ON c.user2_id = u2.uid ");
|
||||||
}
|
countSql.append("WHERE 1=1 ");
|
||||||
if (senderPhone != null && !senderPhone.isEmpty()) {
|
|
||||||
String safePhone = senderPhone.replace("'", "''");
|
// 发送方昵称搜索
|
||||||
sql.append(" AND sender_phone LIKE '%").append(safePhone).append("%'");
|
if (senderNickname != null && !senderNickname.trim().isEmpty()) {
|
||||||
countSql.append(" AND sender_phone LIKE '%").append(safePhone).append("%'");
|
String condition = " AND (u1.nickname LIKE '%" + senderNickname.replace("'", "''") + "%' OR u2.nickname LIKE '%" + senderNickname.replace("'", "''") + "%') ";
|
||||||
}
|
sql.append(condition);
|
||||||
if (startTime != null && !startTime.isEmpty()) {
|
countSql.append(condition);
|
||||||
sql.append(" AND create_time >= '").append(startTime).append("'");
|
|
||||||
countSql.append(" AND create_time >= '").append(startTime).append("'");
|
|
||||||
}
|
|
||||||
if (endTime != null && !endTime.isEmpty()) {
|
|
||||||
sql.append(" AND create_time <= '").append(endTime).append("'");
|
|
||||||
countSql.append(" AND create_time <= '").append(endTime).append("'");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sql.append(" ORDER BY id DESC");
|
// 发送方电话搜索
|
||||||
Long total = jdbcTemplate.queryForObject(countSql.toString(), Long.class);
|
if (senderPhone != null && !senderPhone.trim().isEmpty()) {
|
||||||
|
String condition = " AND (u1.phone LIKE '%" + senderPhone.replace("'", "''") + "%' OR u2.phone LIKE '%" + senderPhone.replace("'", "''") + "%') ";
|
||||||
|
sql.append(condition);
|
||||||
|
countSql.append(condition);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关键词搜索(兼容私聊管理的参数)
|
||||||
|
if (keyword != null && !keyword.trim().isEmpty()) {
|
||||||
|
String condition = " AND (u1.nickname LIKE '%" + keyword + "%' OR u2.nickname LIKE '%" + keyword + "%' "
|
||||||
|
+ "OR c.user1_id = '" + keyword + "' OR c.user2_id = '" + keyword + "') ";
|
||||||
|
sql.append(condition);
|
||||||
|
countSql.append(condition);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 时间范围
|
||||||
|
if (startTime != null && !startTime.trim().isEmpty()) {
|
||||||
|
String condition = " AND c.create_time >= '" + startTime + "' ";
|
||||||
|
sql.append(condition);
|
||||||
|
countSql.append(condition);
|
||||||
|
}
|
||||||
|
if (endTime != null && !endTime.trim().isEmpty()) {
|
||||||
|
String condition = " AND c.create_time <= '" + endTime + "' ";
|
||||||
|
sql.append(condition);
|
||||||
|
countSql.append(condition);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 排序
|
||||||
|
sql.append("ORDER BY c.last_message_time DESC ");
|
||||||
|
|
||||||
|
// 统计总数
|
||||||
|
Long total = 0L;
|
||||||
|
try {
|
||||||
|
total = jdbcTemplate.queryForObject(countSql.toString(), Long.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("查询会话总数失败: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分页
|
||||||
int offset = (page - 1) * limit;
|
int offset = (page - 1) * limit;
|
||||||
sql.append("LIMIT ").append(offset).append(", ").append(limit);
|
sql.append("LIMIT ").append(offset).append(", ").append(limit);
|
||||||
List<Map<String, Object>> list = jdbcTemplate.queryForList(sql.toString());
|
|
||||||
|
List<Map<String, Object>> list;
|
||||||
|
try {
|
||||||
|
list = jdbcTemplate.queryForList(sql.toString());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("查询会话列表失败: {}", e.getMessage());
|
||||||
|
list = java.util.Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
CommonPage<Map<String, Object>> result = new CommonPage<>();
|
CommonPage<Map<String, Object>> result = new CommonPage<>();
|
||||||
result.setList(list);
|
result.setList(list);
|
||||||
result.setTotal(total);
|
result.setTotal(total != null ? total : 0L);
|
||||||
result.setPage(page);
|
result.setPage(page);
|
||||||
result.setLimit(limit);
|
result.setLimit(limit);
|
||||||
result.setTotalPage((int) Math.ceil((double) total / limit));
|
result.setTotalPage((int) Math.ceil((double) (total != null ? total : 0) / limit));
|
||||||
|
|
||||||
return CommonResult.success(result);
|
return CommonResult.success(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取会话详情
|
||||||
|
*/
|
||||||
@ApiOperation(value = "会话详情")
|
@ApiOperation(value = "会话详情")
|
||||||
@RequestMapping(value = "/detail/{id}", method = RequestMethod.GET)
|
@GetMapping("/detail/{id}")
|
||||||
public CommonResult<Map<String, Object>> getDetail(@PathVariable Integer id) {
|
public CommonResult<Map<String, Object>> getDetail(@PathVariable Long id) {
|
||||||
String sql = "SELECT * FROM eb_session WHERE id = ?";
|
try {
|
||||||
Map<String, Object> detail = jdbcTemplate.queryForMap(sql, id);
|
StringBuilder sql = new StringBuilder();
|
||||||
|
sql.append("SELECT c.*, ");
|
||||||
|
sql.append("u1.nickname as sender_nickname, u1.avatar as sender_avatar, u1.phone as sender_phone, ");
|
||||||
|
sql.append("u2.nickname as receiver_nickname, u2.avatar as receiver_avatar, u2.phone as receiver_phone ");
|
||||||
|
sql.append("FROM eb_conversation c ");
|
||||||
|
sql.append("LEFT JOIN eb_user u1 ON c.user1_id = u1.uid ");
|
||||||
|
sql.append("LEFT JOIN eb_user u2 ON c.user2_id = u2.uid ");
|
||||||
|
sql.append("WHERE c.id = ?");
|
||||||
|
|
||||||
|
Map<String, Object> detail = jdbcTemplate.queryForMap(sql.toString(), id);
|
||||||
return CommonResult.success(detail);
|
return CommonResult.success(detail);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("获取会话详情失败: {}", e.getMessage());
|
||||||
|
return CommonResult.failed("获取会话详情失败");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取会话消息列表
|
||||||
|
*/
|
||||||
|
@ApiOperation(value = "会话消息列表")
|
||||||
|
@GetMapping("/{conversationId}/messages")
|
||||||
|
public CommonResult<CommonPage<Map<String, Object>>> getMessages(
|
||||||
|
@PathVariable Long conversationId,
|
||||||
|
@RequestParam(value = "page", defaultValue = "1") Integer page,
|
||||||
|
@RequestParam(value = "pageSize", defaultValue = "20") Integer pageSize) {
|
||||||
|
|
||||||
|
StringBuilder sql = new StringBuilder();
|
||||||
|
sql.append("SELECT m.*, u.nickname as sender_name, u.avatar as sender_avatar ");
|
||||||
|
sql.append("FROM eb_private_message m ");
|
||||||
|
sql.append("LEFT JOIN eb_user u ON m.sender_id = u.uid ");
|
||||||
|
sql.append("WHERE m.conversation_id = ? ");
|
||||||
|
sql.append("ORDER BY m.create_time DESC ");
|
||||||
|
|
||||||
|
Long total = 0L;
|
||||||
|
try {
|
||||||
|
String countSql = "SELECT COUNT(*) FROM eb_private_message WHERE conversation_id = ?";
|
||||||
|
total = jdbcTemplate.queryForObject(countSql, Long.class, conversationId);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("查询消息总数失败: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
int offset = (page - 1) * pageSize;
|
||||||
|
sql.append("LIMIT ").append(offset).append(", ").append(pageSize);
|
||||||
|
|
||||||
|
List<Map<String, Object>> list;
|
||||||
|
try {
|
||||||
|
list = jdbcTemplate.queryForList(sql.toString(), conversationId);
|
||||||
|
// 转换字段名
|
||||||
|
list.forEach(item -> {
|
||||||
|
item.put("senderId", item.get("sender_id"));
|
||||||
|
item.put("receiverId", item.get("receiver_id"));
|
||||||
|
item.put("senderName", item.get("sender_name"));
|
||||||
|
item.put("senderAvatar", item.get("sender_avatar"));
|
||||||
|
item.put("messageType", item.get("message_type"));
|
||||||
|
item.put("createTime", item.get("create_time"));
|
||||||
|
item.put("isRecalled", item.get("is_recalled"));
|
||||||
|
item.put("originalContent", item.get("original_content"));
|
||||||
|
item.put("recallTime", item.get("recall_time"));
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("查询消息列表失败: {}", e.getMessage());
|
||||||
|
list = java.util.Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
CommonPage<Map<String, Object>> result = new CommonPage<>();
|
||||||
|
result.setList(list);
|
||||||
|
result.setTotal(total != null ? total : 0L);
|
||||||
|
result.setPage(page);
|
||||||
|
result.setLimit(pageSize);
|
||||||
|
result.setTotalPage((int) Math.ceil((double) (total != null ? total : 0) / pageSize));
|
||||||
|
|
||||||
|
return CommonResult.success(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除会话(包括所有消息)
|
||||||
|
*/
|
||||||
@ApiOperation(value = "删除会话")
|
@ApiOperation(value = "删除会话")
|
||||||
@RequestMapping(value = "/delete/{id}", method = RequestMethod.POST)
|
@PostMapping("/delete/{id}")
|
||||||
public CommonResult<String> delete(@PathVariable Integer id) {
|
public CommonResult<String> delete(@PathVariable Long id) {
|
||||||
jdbcTemplate.update("DELETE FROM eb_session WHERE id = ?", id);
|
try {
|
||||||
|
// 先删除消息
|
||||||
|
jdbcTemplate.update("DELETE FROM eb_private_message WHERE conversation_id = ?", id);
|
||||||
|
// 删除会话
|
||||||
|
jdbcTemplate.update("DELETE FROM eb_conversation WHERE id = ?", id);
|
||||||
return CommonResult.success("删除成功");
|
return CommonResult.success("删除成功");
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("删除会话失败: {}", e.getMessage());
|
||||||
|
return CommonResult.failed("删除失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除单条消息
|
||||||
|
*/
|
||||||
|
@ApiOperation(value = "删除消息")
|
||||||
|
@PostMapping("/message/delete/{messageId}")
|
||||||
|
public CommonResult<String> deleteMessage(@PathVariable Long messageId) {
|
||||||
|
try {
|
||||||
|
jdbcTemplate.update("DELETE FROM eb_private_message WHERE id = ?", messageId);
|
||||||
|
return CommonResult.success("删除成功");
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("删除消息失败: {}", e.getMessage());
|
||||||
|
return CommonResult.failed("删除失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 撤回消息(管理员可以撤回任意消息)
|
||||||
|
*/
|
||||||
|
@ApiOperation(value = "撤回消息")
|
||||||
|
@PostMapping("/message/recall/{messageId}")
|
||||||
|
public CommonResult<String> recallMessage(@PathVariable Long messageId) {
|
||||||
|
try {
|
||||||
|
// 先获取原始消息内容
|
||||||
|
Map<String, Object> message = jdbcTemplate.queryForMap(
|
||||||
|
"SELECT content FROM eb_private_message WHERE id = ?", messageId);
|
||||||
|
String originalContent = (String) message.get("content");
|
||||||
|
|
||||||
|
// 保存原始内容并标记为撤回
|
||||||
|
int updated = jdbcTemplate.update(
|
||||||
|
"UPDATE eb_private_message SET is_recalled = 1, original_content = ?, recall_time = NOW(), content = '[消息已被管理员撤回]' WHERE id = ?",
|
||||||
|
originalContent, messageId
|
||||||
|
);
|
||||||
|
if (updated > 0) {
|
||||||
|
return CommonResult.success("撤回成功");
|
||||||
|
} else {
|
||||||
|
return CommonResult.failed("消息不存在");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("撤回消息失败: {}", e.getMessage());
|
||||||
|
return CommonResult.failed("撤回失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取会话统计数据
|
||||||
|
*/
|
||||||
|
@ApiOperation(value = "会话统计")
|
||||||
|
@GetMapping("/statistics")
|
||||||
|
public CommonResult<Map<String, Object>> getStatistics() {
|
||||||
|
Map<String, Object> stats = new HashMap<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 总会话数
|
||||||
|
Long totalConversations = jdbcTemplate.queryForObject(
|
||||||
|
"SELECT COUNT(*) FROM eb_conversation", Long.class);
|
||||||
|
stats.put("totalConversations", totalConversations != null ? totalConversations : 0);
|
||||||
|
|
||||||
|
// 总消息数
|
||||||
|
Long totalMessages = jdbcTemplate.queryForObject(
|
||||||
|
"SELECT COUNT(*) FROM eb_private_message", Long.class);
|
||||||
|
stats.put("totalMessages", totalMessages != null ? totalMessages : 0);
|
||||||
|
|
||||||
|
// 今日消息数
|
||||||
|
Long todayMessages = jdbcTemplate.queryForObject(
|
||||||
|
"SELECT COUNT(*) FROM eb_private_message WHERE DATE(create_time) = CURDATE()", Long.class);
|
||||||
|
stats.put("todayMessages", todayMessages != null ? todayMessages : 0);
|
||||||
|
|
||||||
|
// 活跃会话数(最近7天有消息的会话)
|
||||||
|
Long activeConversations = jdbcTemplate.queryForObject(
|
||||||
|
"SELECT COUNT(DISTINCT conversation_id) FROM eb_private_message WHERE create_time >= DATE_SUB(NOW(), INTERVAL 7 DAY)",
|
||||||
|
Long.class);
|
||||||
|
stats.put("activeConversations", activeConversations != null ? activeConversations : 0);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("获取统计数据失败: {}", e.getMessage());
|
||||||
|
stats.put("totalConversations", 0);
|
||||||
|
stats.put("totalMessages", 0);
|
||||||
|
stats.put("todayMessages", 0);
|
||||||
|
stats.put("activeConversations", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CommonResult.success(stats);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,4 +90,12 @@ public class PrivateMessage implements Serializable {
|
||||||
@ApiModelProperty(value = "是否已撤回")
|
@ApiModelProperty(value = "是否已撤回")
|
||||||
@Column(name = "is_recalled", columnDefinition = "TINYINT(1) DEFAULT 0")
|
@Column(name = "is_recalled", columnDefinition = "TINYINT(1) DEFAULT 0")
|
||||||
private Boolean isRecalled;
|
private Boolean isRecalled;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "原始消息内容(撤回前)")
|
||||||
|
@Column(name = "original_content", columnDefinition = "TEXT")
|
||||||
|
private String originalContent;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "撤回时间")
|
||||||
|
@Column(name = "recall_time")
|
||||||
|
private Date recallTime;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -229,3 +229,4 @@ public class CallController {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -146,4 +146,15 @@ public class ConversationController {
|
||||||
Integer userId = userService.getUserIdException();
|
Integer userId = userService.getUserIdException();
|
||||||
return CommonResult.success(conversationService.deleteMessage(id, userId));
|
return CommonResult.success(conversationService.deleteMessage(id, userId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 撤回消息
|
||||||
|
*/
|
||||||
|
@ApiOperation(value = "撤回消息")
|
||||||
|
@ApiImplicitParam(name = "id", value = "消息ID", required = true)
|
||||||
|
@PostMapping("/messages/{id}/recall")
|
||||||
|
public CommonResult<Boolean> recallMessage(@PathVariable Long id) {
|
||||||
|
Integer userId = userService.getUserIdException();
|
||||||
|
return CommonResult.success(conversationService.recallMessage(id, userId));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -473,10 +473,12 @@ public class ConversationServiceImpl extends ServiceImpl<ConversationDao, Conver
|
||||||
if (diffMinutes > 2) {
|
if (diffMinutes > 2) {
|
||||||
throw new CrmebException("消息发送超过2分钟,无法撤回");
|
throw new CrmebException("消息发送超过2分钟,无法撤回");
|
||||||
}
|
}
|
||||||
// 标记消息为已撤回
|
// 保存原始内容,然后标记消息为已撤回
|
||||||
LambdaUpdateWrapper<PrivateMessage> uw = new LambdaUpdateWrapper<>();
|
LambdaUpdateWrapper<PrivateMessage> uw = new LambdaUpdateWrapper<>();
|
||||||
uw.eq(PrivateMessage::getId, messageId)
|
uw.eq(PrivateMessage::getId, messageId)
|
||||||
.set(PrivateMessage::getIsRecalled, true)
|
.set(PrivateMessage::getIsRecalled, true)
|
||||||
|
.set(PrivateMessage::getOriginalContent, message.getContent()) // 保存原始内容
|
||||||
|
.set(PrivateMessage::getRecallTime, new Date()) // 记录撤回时间
|
||||||
.set(PrivateMessage::getContent, "[消息已撤回]");
|
.set(PrivateMessage::getContent, "[消息已撤回]");
|
||||||
return privateMessageDao.update(null, uw) > 0;
|
return privateMessageDao.update(null, uw) > 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
8
Zhibo/zhibo-h/sql/add_recall_fields.sql
Normal file
8
Zhibo/zhibo-h/sql/add_recall_fields.sql
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
-- 为私信消息表添加撤回相关字段
|
||||||
|
-- 执行此脚本前请备份数据库
|
||||||
|
|
||||||
|
-- 添加原始内容字段(保存撤回前的消息内容)
|
||||||
|
ALTER TABLE eb_private_message ADD COLUMN original_content TEXT COMMENT '原始消息内容(撤回前)';
|
||||||
|
|
||||||
|
-- 添加撤回时间字段
|
||||||
|
ALTER TABLE eb_private_message ADD COLUMN recall_time DATETIME COMMENT '撤回时间';
|
||||||
BIN
android-app/app/release-key.jks
Normal file
BIN
android-app/app/release-key.jks
Normal file
Binary file not shown.
|
|
@ -25,6 +25,7 @@ public class ChatMessage {
|
||||||
private long timestamp;
|
private long timestamp;
|
||||||
private boolean isSystemMessage;
|
private boolean isSystemMessage;
|
||||||
private boolean isGiftMessage; // 是否是礼物消息
|
private boolean isGiftMessage; // 是否是礼物消息
|
||||||
|
private boolean isOutgoing; // 是否是自己发送的消息
|
||||||
private MessageStatus status;
|
private MessageStatus status;
|
||||||
private String avatarUrl; // 发送者头像 URL,后续从后端获取
|
private String avatarUrl; // 发送者头像 URL,后续从后端获取
|
||||||
|
|
||||||
|
|
@ -49,7 +50,8 @@ public class ChatMessage {
|
||||||
this.isGiftMessage = false;
|
this.isGiftMessage = false;
|
||||||
this.messageType = MessageType.TEXT;
|
this.messageType = MessageType.TEXT;
|
||||||
// 如果是自己发送的消息,初始状态为发送中
|
// 如果是自己发送的消息,初始状态为发送中
|
||||||
this.status = "我".equals(username) ? MessageStatus.SENDING : MessageStatus.SENT;
|
this.isOutgoing = "我".equals(username);
|
||||||
|
this.status = this.isOutgoing ? MessageStatus.SENDING : MessageStatus.SENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 系统消息构造函数
|
// 系统消息构造函数
|
||||||
|
|
@ -86,6 +88,20 @@ public class ChatMessage {
|
||||||
this.isSystemMessage = isSystemMessage;
|
this.isSystemMessage = isSystemMessage;
|
||||||
this.status = status;
|
this.status = status;
|
||||||
this.messageType = MessageType.TEXT;
|
this.messageType = MessageType.TEXT;
|
||||||
|
this.isOutgoing = "我".equals(username);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 完整构造函数(从后端数据构造,带 isOutgoing 参数)
|
||||||
|
public ChatMessage(String messageId, String username, String message, long timestamp,
|
||||||
|
boolean isSystemMessage, MessageStatus status, boolean isOutgoing) {
|
||||||
|
this.messageId = messageId;
|
||||||
|
this.username = username;
|
||||||
|
this.message = message;
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
this.isSystemMessage = isSystemMessage;
|
||||||
|
this.status = status;
|
||||||
|
this.messageType = MessageType.TEXT;
|
||||||
|
this.isOutgoing = isOutgoing;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 图片消息构造函数
|
// 图片消息构造函数
|
||||||
|
|
@ -140,6 +156,14 @@ public class ChatMessage {
|
||||||
isGiftMessage = giftMessage;
|
isGiftMessage = giftMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isOutgoing() {
|
||||||
|
return isOutgoing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOutgoing(boolean outgoing) {
|
||||||
|
isOutgoing = outgoing;
|
||||||
|
}
|
||||||
|
|
||||||
public MessageStatus getStatus() {
|
public MessageStatus getStatus() {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,9 @@ public class ConversationActivity extends AppCompatActivity {
|
||||||
setupMessages();
|
setupMessages();
|
||||||
setupInput();
|
setupInput();
|
||||||
|
|
||||||
|
// 确保输入框显示正确的提示文本
|
||||||
|
binding.messageInput.setHint("输入消息...");
|
||||||
|
|
||||||
// 标记会话为已读
|
// 标记会话为已读
|
||||||
if (initialUnreadCount > 0 && conversationId != null) {
|
if (initialUnreadCount > 0 && conversationId != null) {
|
||||||
markConversationAsRead();
|
markConversationAsRead();
|
||||||
|
|
@ -181,7 +184,8 @@ public class ConversationActivity extends AppCompatActivity {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String url = ApiConfig.getBaseUrl() + "/api/front/user/info";
|
// 使用正确的用户信息接口
|
||||||
|
String url = ApiConfig.getBaseUrl() + "/api/front/user";
|
||||||
Log.d(TAG, "获取用户信息: " + url);
|
Log.d(TAG, "获取用户信息: " + url);
|
||||||
|
|
||||||
Request request = new Request.Builder()
|
Request request = new Request.Builder()
|
||||||
|
|
@ -205,14 +209,31 @@ public class ConversationActivity extends AppCompatActivity {
|
||||||
if (json.optInt("code", -1) == 200) {
|
if (json.optInt("code", -1) == 200) {
|
||||||
JSONObject data = json.optJSONObject("data");
|
JSONObject data = json.optJSONObject("data");
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
|
// 尝试多种方式获取用户ID
|
||||||
int uid = data.optInt("uid", 0);
|
int uid = data.optInt("uid", 0);
|
||||||
|
if (uid == 0) {
|
||||||
|
uid = data.optInt("id", 0);
|
||||||
|
}
|
||||||
|
if (uid == 0) {
|
||||||
|
// 尝试从字符串解析
|
||||||
|
String uidStr = data.optString("uid", "");
|
||||||
|
if (!uidStr.isEmpty()) {
|
||||||
|
try {
|
||||||
|
uid = (int) Double.parseDouble(uidStr);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
Log.e(TAG, "解析uid失败: " + uidStr, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (uid > 0) {
|
if (uid > 0) {
|
||||||
currentUserId = String.valueOf(uid);
|
currentUserId = String.valueOf(uid);
|
||||||
// 保存到 AuthStore
|
// 保存到 AuthStore
|
||||||
AuthStore.setUserInfo(ConversationActivity.this, currentUserId, data.optString("nickname", ""));
|
AuthStore.setUserInfo(ConversationActivity.this, currentUserId, data.optString("nickname", data.optString("nikeName", "")));
|
||||||
Log.d(TAG, "从服务器获取到用户ID: " + currentUserId);
|
Log.d(TAG, "从服务器获取到用户ID: " + currentUserId);
|
||||||
// 重新加载消息以正确显示
|
// 重新加载消息以正确显示
|
||||||
runOnUiThread(() -> loadMessagesFromServer());
|
runOnUiThread(() -> loadMessagesFromServer());
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "无法从响应中获取用户ID: " + body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -308,8 +329,28 @@ public class ConversationActivity extends AppCompatActivity {
|
||||||
|
|
||||||
boolean isMine = false;
|
boolean isMine = false;
|
||||||
if (myUserId != null && !myUserId.isEmpty() && senderId > 0) {
|
if (myUserId != null && !myUserId.isEmpty() && senderId > 0) {
|
||||||
|
// 处理可能的浮点数格式(如 "1.0" vs "1")
|
||||||
|
try {
|
||||||
|
int myUid = (int) Double.parseDouble(myUserId);
|
||||||
|
isMine = (myUid == senderId);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
isMine = myUserId.equals(String.valueOf(senderId));
|
isMine = myUserId.equals(String.valueOf(senderId));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果 senderId 为 0,尝试从 senderId 字段获取
|
||||||
|
if (senderId == 0) {
|
||||||
|
senderId = item.optInt("senderId", 0);
|
||||||
|
if (myUserId != null && !myUserId.isEmpty() && senderId > 0) {
|
||||||
|
try {
|
||||||
|
int myUid = (int) Double.parseDouble(myUserId);
|
||||||
|
isMine = (myUid == senderId);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
isMine = myUserId.equals(String.valueOf(senderId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Log.d(TAG, "消息判断: myUserId=" + myUserId + ", senderId=" + senderId + ", isMine=" + isMine);
|
Log.d(TAG, "消息判断: myUserId=" + myUserId + ", senderId=" + senderId + ", isMine=" + isMine);
|
||||||
|
|
||||||
String displayName = isMine ? "我" : username;
|
String displayName = isMine ? "我" : username;
|
||||||
|
|
@ -327,6 +368,7 @@ public class ConversationActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
ChatMessage chatMessage = new ChatMessage(messageId, displayName, message, timestamp, isSystem, msgStatus);
|
ChatMessage chatMessage = new ChatMessage(messageId, displayName, message, timestamp, isSystem, msgStatus);
|
||||||
|
chatMessage.setOutgoing(isMine); // 关键:设置消息方向,确保自己发送的消息显示在右侧
|
||||||
chatMessage.setAvatarUrl(avatarUrl);
|
chatMessage.setAvatarUrl(avatarUrl);
|
||||||
return chatMessage;
|
return chatMessage;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
@ -375,9 +417,16 @@ public class ConversationActivity extends AppCompatActivity {
|
||||||
PopupMenu popupMenu = new PopupMenu(this, anchorView);
|
PopupMenu popupMenu = new PopupMenu(this, anchorView);
|
||||||
popupMenu.getMenu().add(0, 0, 0, "复制");
|
popupMenu.getMenu().add(0, 0, 0, "复制");
|
||||||
popupMenu.getMenu().add(0, 2, 0, "表情回应");
|
popupMenu.getMenu().add(0, 2, 0, "表情回应");
|
||||||
// 只有自己发送的消息才能删除
|
// 只有自己发送的消息才能删除和撤回
|
||||||
if ("我".equals(message.getUsername())) {
|
if ("我".equals(message.getUsername()) || message.isOutgoing()) {
|
||||||
popupMenu.getMenu().add(0, 1, 0, "删除");
|
popupMenu.getMenu().add(0, 1, 0, "删除");
|
||||||
|
// 检查是否在2分钟内,可以撤回
|
||||||
|
long messageTime = message.getTimestamp();
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
long diffMinutes = (now - messageTime) / (1000 * 60);
|
||||||
|
if (diffMinutes <= 2) {
|
||||||
|
popupMenu.getMenu().add(0, 3, 0, "撤回");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
popupMenu.setOnMenuItemClickListener(item -> {
|
popupMenu.setOnMenuItemClickListener(item -> {
|
||||||
|
|
@ -390,6 +439,9 @@ public class ConversationActivity extends AppCompatActivity {
|
||||||
} else if (item.getItemId() == 2) {
|
} else if (item.getItemId() == 2) {
|
||||||
showEmojiPicker(message);
|
showEmojiPicker(message);
|
||||||
return true;
|
return true;
|
||||||
|
} else if (item.getItemId() == 3) {
|
||||||
|
recallMessage(message, position);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
@ -458,6 +510,68 @@ public class ConversationActivity extends AppCompatActivity {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 撤回消息
|
||||||
|
*/
|
||||||
|
private void recallMessage(ChatMessage message, int position) {
|
||||||
|
if (position < 0 || position >= messages.size()) return;
|
||||||
|
|
||||||
|
new AlertDialog.Builder(this)
|
||||||
|
.setTitle("撤回消息")
|
||||||
|
.setMessage("确定要撤回这条消息吗?")
|
||||||
|
.setPositiveButton("撤回", (dialog, which) -> recallMessageFromServer(message, position))
|
||||||
|
.setNegativeButton("取消", null)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用服务器撤回消息接口
|
||||||
|
*/
|
||||||
|
private void recallMessageFromServer(ChatMessage message, int position) {
|
||||||
|
String token = AuthStore.getToken(this);
|
||||||
|
if (token == null) return;
|
||||||
|
|
||||||
|
String messageId = message.getMessageId();
|
||||||
|
String url = ApiConfig.getBaseUrl() + "/api/front/conversations/messages/" + messageId + "/recall";
|
||||||
|
Log.d(TAG, "撤回消息: " + url);
|
||||||
|
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(url)
|
||||||
|
.addHeader("Authori-zation", token)
|
||||||
|
.post(RequestBody.create("", MediaType.parse("application/json")))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
httpClient.newCall(request).enqueue(new Callback() {
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call call, IOException e) {
|
||||||
|
Log.e(TAG, "撤回消息失败", e);
|
||||||
|
runOnUiThread(() -> Snackbar.make(binding.getRoot(), "撤回失败", Snackbar.LENGTH_SHORT).show());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call call, Response response) throws IOException {
|
||||||
|
String body = response.body() != null ? response.body().string() : "";
|
||||||
|
Log.d(TAG, "撤回消息响应: " + body);
|
||||||
|
runOnUiThread(() -> {
|
||||||
|
try {
|
||||||
|
JSONObject json = new JSONObject(body);
|
||||||
|
if (json.optInt("code", -1) == 200) {
|
||||||
|
// 更新本地消息显示为已撤回
|
||||||
|
message.setMessage("[消息已撤回]");
|
||||||
|
adapter.notifyItemChanged(position);
|
||||||
|
Snackbar.make(binding.getRoot(), "消息已撤回", Snackbar.LENGTH_SHORT).show();
|
||||||
|
} else {
|
||||||
|
String errorMsg = json.optString("message", "撤回失败");
|
||||||
|
Snackbar.make(binding.getRoot(), errorMsg, Snackbar.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "解析撤回响应失败", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void setupInput() {
|
private void setupInput() {
|
||||||
binding.sendButton.setOnClickListener(new DebounceClickListener(300) {
|
binding.sendButton.setOnClickListener(new DebounceClickListener(300) {
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,8 @@ public class ConversationMessagesAdapter extends ListAdapter<ChatMessage, Recycl
|
||||||
ChatMessage msg = getItem(position);
|
ChatMessage msg = getItem(position);
|
||||||
if (msg == null) return TYPE_TEXT_INCOMING;
|
if (msg == null) return TYPE_TEXT_INCOMING;
|
||||||
|
|
||||||
boolean isOutgoing = "我".equals(msg.getUsername());
|
// 优先使用 isOutgoing 字段,如果没有设置则回退到检查用户名
|
||||||
|
boolean isOutgoing = msg.isOutgoing() || "我".equals(msg.getUsername());
|
||||||
ChatMessage.MessageType type = msg.getMessageType();
|
ChatMessage.MessageType type = msg.getMessageType();
|
||||||
|
|
||||||
if (type == null) type = ChatMessage.MessageType.TEXT;
|
if (type == null) type = ChatMessage.MessageType.TEXT;
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import com.example.livestreaming.databinding.ActivityFansListBinding;
|
||||||
import com.example.livestreaming.net.ApiResponse;
|
import com.example.livestreaming.net.ApiResponse;
|
||||||
import com.example.livestreaming.net.ApiService;
|
import com.example.livestreaming.net.ApiService;
|
||||||
import com.example.livestreaming.net.PageResponse;
|
import com.example.livestreaming.net.PageResponse;
|
||||||
import com.example.livestreaming.net.RetrofitClient;
|
import com.example.livestreaming.net.ApiClient;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -58,7 +58,7 @@ public class FansListActivity extends AppCompatActivity {
|
||||||
if (isLoading) return;
|
if (isLoading) return;
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
|
|
||||||
ApiService apiService = RetrofitClient.getInstance(this).getApiService();
|
ApiService apiService = ApiClient.getService(this);
|
||||||
Call<ApiResponse<PageResponse<Map<String, Object>>>> call = apiService.getFollowersList(currentPage, 20);
|
Call<ApiResponse<PageResponse<Map<String, Object>>>> call = apiService.getFollowersList(currentPage, 20);
|
||||||
|
|
||||||
call.enqueue(new Callback<ApiResponse<PageResponse<Map<String, Object>>>>() {
|
call.enqueue(new Callback<ApiResponse<PageResponse<Map<String, Object>>>>() {
|
||||||
|
|
@ -96,7 +96,7 @@ public class FansListActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(FansListActivity.this,
|
Toast.makeText(FansListActivity.this,
|
||||||
apiResponse.getMsg() != null ? apiResponse.getMsg() : "获取粉丝列表失败",
|
apiResponse.getMessage() != null ? apiResponse.getMessage() : "获取粉丝列表失败",
|
||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import com.example.livestreaming.databinding.ActivityFollowingListBinding;
|
||||||
import com.example.livestreaming.net.ApiResponse;
|
import com.example.livestreaming.net.ApiResponse;
|
||||||
import com.example.livestreaming.net.ApiService;
|
import com.example.livestreaming.net.ApiService;
|
||||||
import com.example.livestreaming.net.PageResponse;
|
import com.example.livestreaming.net.PageResponse;
|
||||||
import com.example.livestreaming.net.RetrofitClient;
|
import com.example.livestreaming.net.ApiClient;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -58,7 +58,7 @@ public class FollowingListActivity extends AppCompatActivity {
|
||||||
if (isLoading) return;
|
if (isLoading) return;
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
|
|
||||||
ApiService apiService = RetrofitClient.getInstance(this).getApiService();
|
ApiService apiService = ApiClient.getService(this);
|
||||||
Call<ApiResponse<PageResponse<Map<String, Object>>>> call = apiService.getFollowingList(currentPage, 20);
|
Call<ApiResponse<PageResponse<Map<String, Object>>>> call = apiService.getFollowingList(currentPage, 20);
|
||||||
|
|
||||||
call.enqueue(new Callback<ApiResponse<PageResponse<Map<String, Object>>>>() {
|
call.enqueue(new Callback<ApiResponse<PageResponse<Map<String, Object>>>>() {
|
||||||
|
|
@ -94,7 +94,7 @@ public class FollowingListActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(FollowingListActivity.this,
|
Toast.makeText(FollowingListActivity.this,
|
||||||
apiResponse.getMsg() != null ? apiResponse.getMsg() : "获取关注列表失败",
|
apiResponse.getMessage() != null ? apiResponse.getMessage() : "获取关注列表失败",
|
||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -679,7 +679,7 @@ public class ProfileActivity extends AppCompatActivity {
|
||||||
*/
|
*/
|
||||||
private void loadFollowStats() {
|
private void loadFollowStats() {
|
||||||
com.example.livestreaming.net.ApiService apiService =
|
com.example.livestreaming.net.ApiService apiService =
|
||||||
com.example.livestreaming.net.RetrofitClient.getInstance(this).getApiService();
|
com.example.livestreaming.net.ApiClient.getService(this);
|
||||||
retrofit2.Call<com.example.livestreaming.net.ApiResponse<java.util.Map<String, Object>>> call =
|
retrofit2.Call<com.example.livestreaming.net.ApiResponse<java.util.Map<String, Object>>> call =
|
||||||
apiService.getFollowStats(null); // null表示查询当前用户
|
apiService.getFollowStats(null); // null表示查询当前用户
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -638,7 +638,7 @@ public class PublishWorkActivity extends AppCompatActivity {
|
||||||
RequestBody model = RequestBody.create(okhttp3.MediaType.parse("text/plain"), "works");
|
RequestBody model = RequestBody.create(okhttp3.MediaType.parse("text/plain"), "works");
|
||||||
RequestBody pid = RequestBody.create(okhttp3.MediaType.parse("text/plain"), "0");
|
RequestBody pid = RequestBody.create(okhttp3.MediaType.parse("text/plain"), "0");
|
||||||
|
|
||||||
ApiService apiService = ApiClient.getApiService(this);
|
ApiService apiService = ApiClient.getService(this);
|
||||||
Call<ApiResponse<FileUploadResponse>> call = apiService.uploadImage(body, model, pid);
|
Call<ApiResponse<FileUploadResponse>> call = apiService.uploadImage(body, model, pid);
|
||||||
|
|
||||||
call.enqueue(new retrofit2.Callback<ApiResponse<FileUploadResponse>>() {
|
call.enqueue(new retrofit2.Callback<ApiResponse<FileUploadResponse>>() {
|
||||||
|
|
@ -649,7 +649,7 @@ public class PublishWorkActivity extends AppCompatActivity {
|
||||||
if (apiResponse.getCode() == 200 && apiResponse.getData() != null) {
|
if (apiResponse.getCode() == 200 && apiResponse.getData() != null) {
|
||||||
callback.onSuccess(apiResponse.getData().getUrl());
|
callback.onSuccess(apiResponse.getData().getUrl());
|
||||||
} else {
|
} else {
|
||||||
callback.onFailure(apiResponse.getMsg() != null ? apiResponse.getMsg() : "上传失败");
|
callback.onFailure(apiResponse.getMessage() != null ? apiResponse.getMessage() : "上传失败");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
callback.onFailure("上传失败");
|
callback.onFailure("上传失败");
|
||||||
|
|
@ -687,7 +687,7 @@ public class PublishWorkActivity extends AppCompatActivity {
|
||||||
RequestBody model = RequestBody.create(okhttp3.MediaType.parse("text/plain"), "works");
|
RequestBody model = RequestBody.create(okhttp3.MediaType.parse("text/plain"), "works");
|
||||||
RequestBody pid = RequestBody.create(okhttp3.MediaType.parse("text/plain"), "0");
|
RequestBody pid = RequestBody.create(okhttp3.MediaType.parse("text/plain"), "0");
|
||||||
|
|
||||||
ApiService apiService = ApiClient.getApiService(this);
|
ApiService apiService = ApiClient.getService(this);
|
||||||
Call<ApiResponse<FileUploadResponse>> call = apiService.uploadVideo(body, model, pid);
|
Call<ApiResponse<FileUploadResponse>> call = apiService.uploadVideo(body, model, pid);
|
||||||
|
|
||||||
call.enqueue(new retrofit2.Callback<ApiResponse<FileUploadResponse>>() {
|
call.enqueue(new retrofit2.Callback<ApiResponse<FileUploadResponse>>() {
|
||||||
|
|
@ -698,7 +698,7 @@ public class PublishWorkActivity extends AppCompatActivity {
|
||||||
if (apiResponse.getCode() == 200 && apiResponse.getData() != null) {
|
if (apiResponse.getCode() == 200 && apiResponse.getData() != null) {
|
||||||
callback.onSuccess(apiResponse.getData().getUrl());
|
callback.onSuccess(apiResponse.getData().getUrl());
|
||||||
} else {
|
} else {
|
||||||
callback.onFailure(apiResponse.getMsg() != null ? apiResponse.getMsg() : "上传失败");
|
callback.onFailure(apiResponse.getMessage() != null ? apiResponse.getMessage() : "上传失败");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
callback.onFailure("上传失败");
|
callback.onFailure("上传失败");
|
||||||
|
|
@ -762,7 +762,7 @@ public class PublishWorkActivity extends AppCompatActivity {
|
||||||
request.setVideoUrl(videoUrl);
|
request.setVideoUrl(videoUrl);
|
||||||
request.setImageUrls(imageUrls);
|
request.setImageUrls(imageUrls);
|
||||||
|
|
||||||
ApiService apiService = ApiClient.getApiService(this);
|
ApiService apiService = ApiClient.getService(this);
|
||||||
Call<ApiResponse<Long>> call = apiService.publishWork(request);
|
Call<ApiResponse<Long>> call = apiService.publishWork(request);
|
||||||
|
|
||||||
call.enqueue(new retrofit2.Callback<ApiResponse<Long>>() {
|
call.enqueue(new retrofit2.Callback<ApiResponse<Long>>() {
|
||||||
|
|
@ -777,7 +777,7 @@ public class PublishWorkActivity extends AppCompatActivity {
|
||||||
finish();
|
finish();
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(PublishWorkActivity.this,
|
Toast.makeText(PublishWorkActivity.this,
|
||||||
apiResponse.getMsg() != null ? apiResponse.getMsg() : "发布失败",
|
apiResponse.getMessage() != null ? apiResponse.getMessage() : "发布失败",
|
||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -31,12 +31,15 @@ import com.example.livestreaming.net.ApiService;
|
||||||
import com.example.livestreaming.net.AuthStore;
|
import com.example.livestreaming.net.AuthStore;
|
||||||
import com.example.livestreaming.net.CreateRechargeRequest;
|
import com.example.livestreaming.net.CreateRechargeRequest;
|
||||||
import com.example.livestreaming.net.CreateRechargeResponse;
|
import com.example.livestreaming.net.CreateRechargeResponse;
|
||||||
|
import com.example.livestreaming.net.GiftResponse;
|
||||||
import com.example.livestreaming.net.OrderPayRequest;
|
import com.example.livestreaming.net.OrderPayRequest;
|
||||||
import com.example.livestreaming.net.OrderPayResultResponse;
|
import com.example.livestreaming.net.OrderPayResultResponse;
|
||||||
import com.example.livestreaming.net.RechargeOptionResponse;
|
import com.example.livestreaming.net.RechargeOptionResponse;
|
||||||
import com.example.livestreaming.net.RetrofitClient;
|
|
||||||
import com.example.livestreaming.net.Room;
|
import com.example.livestreaming.net.Room;
|
||||||
|
import com.example.livestreaming.net.SendGiftRequest;
|
||||||
|
import com.example.livestreaming.net.SendGiftResponse;
|
||||||
import com.example.livestreaming.net.StreamConfig;
|
import com.example.livestreaming.net.StreamConfig;
|
||||||
|
import com.example.livestreaming.net.UserBalanceResponse;
|
||||||
import com.example.livestreaming.ShareUtils;
|
import com.example.livestreaming.ShareUtils;
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
|
|
@ -45,7 +48,9 @@ import tv.danmaku.ijk.media.player.IMediaPlayer;
|
||||||
import tv.danmaku.ijk.media.player.IjkMediaPlayer;
|
import tv.danmaku.ijk.media.player.IjkMediaPlayer;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
|
|
@ -362,8 +367,9 @@ public class RoomDetailActivity extends AppCompatActivity {
|
||||||
stopOnlineReconnect();
|
stopOnlineReconnect();
|
||||||
|
|
||||||
// 构建WebSocket URL,添加clientId参数
|
// 构建WebSocket URL,添加clientId参数
|
||||||
String clientId = AuthStore.getUserId(this) > 0 ?
|
String userIdStr = AuthStore.getUserId(this);
|
||||||
String.valueOf(AuthStore.getUserId(this)) :
|
String clientId = (userIdStr != null && !userIdStr.isEmpty()) ?
|
||||||
|
userIdStr :
|
||||||
"guest_" + System.currentTimeMillis();
|
"guest_" + System.currentTimeMillis();
|
||||||
String wsUrl = WS_ONLINE_BASE_URL + roomId + "?clientId=" + clientId;
|
String wsUrl = WS_ONLINE_BASE_URL + roomId + "?clientId=" + clientId;
|
||||||
|
|
||||||
|
|
@ -1203,7 +1209,7 @@ public class RoomDetailActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
android.util.Log.d("RoomDetail", "成功加载 " + availableGifts.size() + " 个礼物");
|
android.util.Log.d("RoomDetail", "成功加载 " + availableGifts.size() + " 个礼物");
|
||||||
} else {
|
} else {
|
||||||
android.util.Log.w("RoomDetail", "加载礼物列表失败: " + apiResponse.getMsg());
|
android.util.Log.w("RoomDetail", "加载礼物列表失败: " + apiResponse.getMessage());
|
||||||
setDefaultGifts();
|
setDefaultGifts();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1384,7 +1390,7 @@ public class RoomDetailActivity extends AppCompatActivity {
|
||||||
* 加载充值选项列表
|
* 加载充值选项列表
|
||||||
*/
|
*/
|
||||||
private void loadRechargeOptions(RechargeAdapter adapter, View dialogView) {
|
private void loadRechargeOptions(RechargeAdapter adapter, View dialogView) {
|
||||||
ApiService apiService = RetrofitClient.getInstance(this).getApiService();
|
ApiService apiService = ApiClient.getService(this);
|
||||||
Call<ApiResponse<List<RechargeOptionResponse>>> call = apiService.getRechargeOptions();
|
Call<ApiResponse<List<RechargeOptionResponse>>> call = apiService.getRechargeOptions();
|
||||||
|
|
||||||
call.enqueue(new Callback<ApiResponse<List<RechargeOptionResponse>>>() {
|
call.enqueue(new Callback<ApiResponse<List<RechargeOptionResponse>>>() {
|
||||||
|
|
@ -1407,7 +1413,7 @@ public class RoomDetailActivity extends AppCompatActivity {
|
||||||
adapter.setOptions(options);
|
adapter.setOptions(options);
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(RoomDetailActivity.this,
|
Toast.makeText(RoomDetailActivity.this,
|
||||||
"加载充值选项失败: " + apiResponse.getMsg(),
|
"加载充值选项失败: " + apiResponse.getMessage(),
|
||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
// 使用默认选项
|
// 使用默认选项
|
||||||
setDefaultRechargeOptions(adapter);
|
setDefaultRechargeOptions(adapter);
|
||||||
|
|
@ -1450,7 +1456,7 @@ public class RoomDetailActivity extends AppCompatActivity {
|
||||||
* 创建充值订单
|
* 创建充值订单
|
||||||
*/
|
*/
|
||||||
private void createRechargeOrder(RechargeOption selectedOption, androidx.appcompat.app.AlertDialog rechargeDialog) {
|
private void createRechargeOrder(RechargeOption selectedOption, androidx.appcompat.app.AlertDialog rechargeDialog) {
|
||||||
ApiService apiService = RetrofitClient.getInstance(this).getApiService();
|
ApiService apiService = ApiClient.getService(this);
|
||||||
|
|
||||||
CreateRechargeRequest request = new CreateRechargeRequest(
|
CreateRechargeRequest request = new CreateRechargeRequest(
|
||||||
Integer.parseInt(selectedOption.getId()),
|
Integer.parseInt(selectedOption.getId()),
|
||||||
|
|
@ -1475,7 +1481,7 @@ public class RoomDetailActivity extends AppCompatActivity {
|
||||||
showPaymentMethodDialog(orderId, selectedOption, rechargeDialog);
|
showPaymentMethodDialog(orderId, selectedOption, rechargeDialog);
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(RoomDetailActivity.this,
|
Toast.makeText(RoomDetailActivity.this,
|
||||||
"创建充值订单失败: " + apiResponse.getMsg(),
|
"创建充值订单失败: " + apiResponse.getMessage(),
|
||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1536,7 +1542,7 @@ public class RoomDetailActivity extends AppCompatActivity {
|
||||||
*/
|
*/
|
||||||
private void processPayment(String orderId, String payType, String payChannel,
|
private void processPayment(String orderId, String payType, String payChannel,
|
||||||
RechargeOption selectedOption, androidx.appcompat.app.AlertDialog rechargeDialog) {
|
RechargeOption selectedOption, androidx.appcompat.app.AlertDialog rechargeDialog) {
|
||||||
ApiService apiService = RetrofitClient.getInstance(this).getApiService();
|
ApiService apiService = ApiClient.getService(this);
|
||||||
|
|
||||||
OrderPayRequest payRequest = new OrderPayRequest(orderId, payType, payChannel);
|
OrderPayRequest payRequest = new OrderPayRequest(orderId, payType, payChannel);
|
||||||
Call<ApiResponse<OrderPayResultResponse>> call = apiService.payment(payRequest);
|
Call<ApiResponse<OrderPayResultResponse>> call = apiService.payment(payRequest);
|
||||||
|
|
@ -1565,7 +1571,7 @@ public class RoomDetailActivity extends AppCompatActivity {
|
||||||
simulateRechargeSuccess(selectedOption, rechargeDialog);
|
simulateRechargeSuccess(selectedOption, rechargeDialog);
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(RoomDetailActivity.this,
|
Toast.makeText(RoomDetailActivity.this,
|
||||||
"支付失败: " + apiResponse.getMsg(),
|
"支付失败: " + apiResponse.getMessage(),
|
||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1651,10 +1657,13 @@ public class RoomDetailActivity extends AppCompatActivity {
|
||||||
|
|
||||||
ApiService apiService = ApiClient.getService(getApplicationContext());
|
ApiService apiService = ApiClient.getService(getApplicationContext());
|
||||||
|
|
||||||
SendGiftRequest request = new SendGiftRequest();
|
// 获取主播ID(使用房间ID作为主播ID,或者从房间信息中获取)
|
||||||
request.setRoomId(Integer.parseInt(roomId));
|
Integer streamerId = Integer.parseInt(roomId);
|
||||||
request.setGiftId(Integer.parseInt(selectedGift.getId()));
|
SendGiftRequest request = new SendGiftRequest(
|
||||||
request.setCount(count);
|
Integer.parseInt(selectedGift.getId()),
|
||||||
|
streamerId,
|
||||||
|
count
|
||||||
|
);
|
||||||
|
|
||||||
Call<ApiResponse<SendGiftResponse>> call = apiService.sendRoomGift(roomId, request);
|
Call<ApiResponse<SendGiftResponse>> call = apiService.sendRoomGift(roomId, request);
|
||||||
|
|
||||||
|
|
@ -1689,7 +1698,7 @@ public class RoomDetailActivity extends AppCompatActivity {
|
||||||
giftCountText.setText("1");
|
giftCountText.setText("1");
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(RoomDetailActivity.this,
|
Toast.makeText(RoomDetailActivity.this,
|
||||||
"赠送失败: " + apiResponse.getMsg(),
|
"赠送失败: " + apiResponse.getMessage(),
|
||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1719,7 +1728,7 @@ public class RoomDetailActivity extends AppCompatActivity {
|
||||||
ApiService apiService = ApiClient.getService(getApplicationContext());
|
ApiService apiService = ApiClient.getService(getApplicationContext());
|
||||||
|
|
||||||
java.util.Map<String, Object> body = new java.util.HashMap<>();
|
java.util.Map<String, Object> body = new java.util.HashMap<>();
|
||||||
body.put("streamerId", room.getStreamerId());
|
body.put("streamerId", roomId); // 使用房间ID作为主播ID
|
||||||
body.put("action", "follow");
|
body.put("action", "follow");
|
||||||
|
|
||||||
Call<ApiResponse<Map<String, Object>>> call = apiService.followStreamer(body);
|
Call<ApiResponse<Map<String, Object>>> call = apiService.followStreamer(body);
|
||||||
|
|
@ -1736,7 +1745,7 @@ public class RoomDetailActivity extends AppCompatActivity {
|
||||||
binding.followButton.setEnabled(false);
|
binding.followButton.setEnabled(false);
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(RoomDetailActivity.this,
|
Toast.makeText(RoomDetailActivity.this,
|
||||||
"关注失败: " + apiResponse.getMsg(),
|
"关注失败: " + apiResponse.getMessage(),
|
||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1785,7 +1794,7 @@ public class RoomDetailActivity extends AppCompatActivity {
|
||||||
fetchRoom();
|
fetchRoom();
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(RoomDetailActivity.this,
|
Toast.makeText(RoomDetailActivity.this,
|
||||||
"开始直播失败: " + apiResponse.getMsg(),
|
"开始直播失败: " + apiResponse.getMessage(),
|
||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1839,7 +1848,7 @@ public class RoomDetailActivity extends AppCompatActivity {
|
||||||
fetchRoom();
|
fetchRoom();
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(RoomDetailActivity.this,
|
Toast.makeText(RoomDetailActivity.this,
|
||||||
"结束直播失败: " + apiResponse.getMsg(),
|
"结束直播失败: " + apiResponse.getMessage(),
|
||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import com.example.livestreaming.net.ApiResponse;
|
||||||
import com.example.livestreaming.net.ApiService;
|
import com.example.livestreaming.net.ApiService;
|
||||||
import com.example.livestreaming.net.HotSearchResponse;
|
import com.example.livestreaming.net.HotSearchResponse;
|
||||||
import com.example.livestreaming.net.PageResponse;
|
import com.example.livestreaming.net.PageResponse;
|
||||||
import com.example.livestreaming.net.RetrofitClient;
|
import com.example.livestreaming.net.ApiClient;
|
||||||
import com.example.livestreaming.net.Room;
|
import com.example.livestreaming.net.Room;
|
||||||
import com.example.livestreaming.net.SearchHistoryResponse;
|
import com.example.livestreaming.net.SearchHistoryResponse;
|
||||||
|
|
||||||
|
|
@ -151,7 +151,7 @@ public class SearchActivity extends AppCompatActivity {
|
||||||
|
|
||||||
Log.d(TAG, "执行搜索: " + keyword);
|
Log.d(TAG, "执行搜索: " + keyword);
|
||||||
|
|
||||||
ApiService apiService = RetrofitClient.getInstance(this).getApiService();
|
ApiService apiService = ApiClient.getService(this);
|
||||||
Call<ApiResponse<PageResponse<Map<String, Object>>>> call =
|
Call<ApiResponse<PageResponse<Map<String, Object>>>> call =
|
||||||
apiService.searchLiveRooms(keyword, null, null, 1, 20);
|
apiService.searchLiveRooms(keyword, null, null, 1, 20);
|
||||||
|
|
||||||
|
|
@ -191,9 +191,9 @@ public class SearchActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(SearchActivity.this,
|
Toast.makeText(SearchActivity.this,
|
||||||
"搜索失败: " + apiResponse.getMsg(),
|
"搜索失败: " + apiResponse.getMessage(),
|
||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
Log.e(TAG, "搜索失败: " + apiResponse.getMsg());
|
Log.e(TAG, "搜索失败: " + apiResponse.getMessage());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(SearchActivity.this,
|
Toast.makeText(SearchActivity.this,
|
||||||
|
|
@ -253,7 +253,7 @@ public class SearchActivity extends AppCompatActivity {
|
||||||
private void loadHotSearch() {
|
private void loadHotSearch() {
|
||||||
Log.d(TAG, "加载热门搜索");
|
Log.d(TAG, "加载热门搜索");
|
||||||
|
|
||||||
ApiService apiService = RetrofitClient.getInstance(this).getApiService();
|
ApiService apiService = ApiClient.getService(this);
|
||||||
Call<ApiResponse<List<HotSearchResponse>>> call = apiService.getHotSearch(2, 10); // 2-直播间
|
Call<ApiResponse<List<HotSearchResponse>>> call = apiService.getHotSearch(2, 10); // 2-直播间
|
||||||
|
|
||||||
call.enqueue(new Callback<ApiResponse<List<HotSearchResponse>>>() {
|
call.enqueue(new Callback<ApiResponse<List<HotSearchResponse>>>() {
|
||||||
|
|
@ -282,7 +282,7 @@ public class SearchActivity extends AppCompatActivity {
|
||||||
* 加载搜索建议(可选功能)
|
* 加载搜索建议(可选功能)
|
||||||
*/
|
*/
|
||||||
private void loadSearchSuggestions(String keyword) {
|
private void loadSearchSuggestions(String keyword) {
|
||||||
ApiService apiService = RetrofitClient.getInstance(this).getApiService();
|
ApiService apiService = ApiClient.getService(this);
|
||||||
Call<ApiResponse<List<String>>> call = apiService.getSearchSuggestions(keyword, 2, 10); // 2-直播间
|
Call<ApiResponse<List<String>>> call = apiService.getSearchSuggestions(keyword, 2, 10); // 2-直播间
|
||||||
|
|
||||||
call.enqueue(new Callback<ApiResponse<List<String>>>() {
|
call.enqueue(new Callback<ApiResponse<List<String>>>() {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import androidx.recyclerview.widget.GridLayoutManager;
|
||||||
import com.example.livestreaming.databinding.ActivityUserProfileReadOnlyBinding;
|
import com.example.livestreaming.databinding.ActivityUserProfileReadOnlyBinding;
|
||||||
import com.example.livestreaming.net.ApiResponse;
|
import com.example.livestreaming.net.ApiResponse;
|
||||||
import com.example.livestreaming.net.ApiService;
|
import com.example.livestreaming.net.ApiService;
|
||||||
import com.example.livestreaming.net.RetrofitClient;
|
import com.example.livestreaming.net.ApiClient;
|
||||||
import com.google.android.material.tabs.TabLayout;
|
import com.google.android.material.tabs.TabLayout;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
@ -101,7 +101,7 @@ public class UserProfileReadOnlyActivity extends AppCompatActivity {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int userId = Integer.parseInt(currentUserId);
|
int userId = Integer.parseInt(currentUserId);
|
||||||
ApiService apiService = RetrofitClient.getInstance(this).getApiService();
|
ApiService apiService = ApiClient.getService(this);
|
||||||
Call<ApiResponse<Map<String, Object>>> call = apiService.checkFollowStatus(userId);
|
Call<ApiResponse<Map<String, Object>>> call = apiService.checkFollowStatus(userId);
|
||||||
|
|
||||||
call.enqueue(new Callback<ApiResponse<Map<String, Object>>>() {
|
call.enqueue(new Callback<ApiResponse<Map<String, Object>>>() {
|
||||||
|
|
@ -137,7 +137,7 @@ public class UserProfileReadOnlyActivity extends AppCompatActivity {
|
||||||
Map<String, Object> requestBody = new HashMap<>();
|
Map<String, Object> requestBody = new HashMap<>();
|
||||||
requestBody.put("userId", userId);
|
requestBody.put("userId", userId);
|
||||||
|
|
||||||
ApiService apiService = RetrofitClient.getInstance(this).getApiService();
|
ApiService apiService = ApiClient.getService(this);
|
||||||
Call<ApiResponse<Map<String, Object>>> call = apiService.followUser(requestBody);
|
Call<ApiResponse<Map<String, Object>>> call = apiService.followUser(requestBody);
|
||||||
|
|
||||||
call.enqueue(new Callback<ApiResponse<Map<String, Object>>>() {
|
call.enqueue(new Callback<ApiResponse<Map<String, Object>>>() {
|
||||||
|
|
@ -152,7 +152,7 @@ public class UserProfileReadOnlyActivity extends AppCompatActivity {
|
||||||
Toast.makeText(UserProfileReadOnlyActivity.this, "关注成功", Toast.LENGTH_SHORT).show();
|
Toast.makeText(UserProfileReadOnlyActivity.this, "关注成功", Toast.LENGTH_SHORT).show();
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(UserProfileReadOnlyActivity.this,
|
Toast.makeText(UserProfileReadOnlyActivity.this,
|
||||||
apiResponse.getMsg() != null ? apiResponse.getMsg() : "关注失败",
|
apiResponse.getMessage() != null ? apiResponse.getMessage() : "关注失败",
|
||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -179,7 +179,7 @@ public class UserProfileReadOnlyActivity extends AppCompatActivity {
|
||||||
Map<String, Object> requestBody = new HashMap<>();
|
Map<String, Object> requestBody = new HashMap<>();
|
||||||
requestBody.put("userId", userId);
|
requestBody.put("userId", userId);
|
||||||
|
|
||||||
ApiService apiService = RetrofitClient.getInstance(this).getApiService();
|
ApiService apiService = ApiClient.getService(this);
|
||||||
Call<ApiResponse<Map<String, Object>>> call = apiService.unfollowUser(requestBody);
|
Call<ApiResponse<Map<String, Object>>> call = apiService.unfollowUser(requestBody);
|
||||||
|
|
||||||
call.enqueue(new Callback<ApiResponse<Map<String, Object>>>() {
|
call.enqueue(new Callback<ApiResponse<Map<String, Object>>>() {
|
||||||
|
|
@ -194,7 +194,7 @@ public class UserProfileReadOnlyActivity extends AppCompatActivity {
|
||||||
Toast.makeText(UserProfileReadOnlyActivity.this, "取消关注成功", Toast.LENGTH_SHORT).show();
|
Toast.makeText(UserProfileReadOnlyActivity.this, "取消关注成功", Toast.LENGTH_SHORT).show();
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(UserProfileReadOnlyActivity.this,
|
Toast.makeText(UserProfileReadOnlyActivity.this,
|
||||||
apiResponse.getMsg() != null ? apiResponse.getMsg() : "取消关注失败",
|
apiResponse.getMessage() != null ? apiResponse.getMessage() : "取消关注失败",
|
||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -224,17 +224,6 @@ public class UserProfileReadOnlyActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateFollowButton() {
|
|
||||||
if (binding == null) return;
|
|
||||||
if (isFollowing) {
|
|
||||||
binding.addFriendButton.setText("已关注");
|
|
||||||
binding.addFriendButton.setAlpha(0.7f);
|
|
||||||
} else {
|
|
||||||
binding.addFriendButton.setText("关注");
|
|
||||||
binding.addFriendButton.setAlpha(1f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupTabsAndWorks() {
|
private void setupTabsAndWorks() {
|
||||||
if (binding == null) return;
|
if (binding == null) return;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -443,7 +443,7 @@ public class WorkDetailActivity extends AppCompatActivity {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
long worksId = Long.parseLong(workItem.getId());
|
long worksId = Long.parseLong(workItem.getId());
|
||||||
ApiService apiService = ApiClient.getApiService(this);
|
ApiService apiService = ApiClient.getService(this);
|
||||||
|
|
||||||
Call<ApiResponse<Boolean>> call;
|
Call<ApiResponse<Boolean>> call;
|
||||||
if (isLiked) {
|
if (isLiked) {
|
||||||
|
|
@ -480,7 +480,7 @@ public class WorkDetailActivity extends AppCompatActivity {
|
||||||
workItem.setLikeCount(oldCount);
|
workItem.setLikeCount(oldCount);
|
||||||
updateLikeButton();
|
updateLikeButton();
|
||||||
Toast.makeText(WorkDetailActivity.this,
|
Toast.makeText(WorkDetailActivity.this,
|
||||||
apiResponse.getMsg() != null ? apiResponse.getMsg() : "操作失败",
|
apiResponse.getMessage() != null ? apiResponse.getMessage() : "操作失败",
|
||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -514,7 +514,7 @@ public class WorkDetailActivity extends AppCompatActivity {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
long worksId = Long.parseLong(workItem.getId());
|
long worksId = Long.parseLong(workItem.getId());
|
||||||
ApiService apiService = ApiClient.getApiService(this);
|
ApiService apiService = ApiClient.getService(this);
|
||||||
|
|
||||||
Call<ApiResponse<Boolean>> call;
|
Call<ApiResponse<Boolean>> call;
|
||||||
if (isFavorited) {
|
if (isFavorited) {
|
||||||
|
|
@ -544,7 +544,7 @@ public class WorkDetailActivity extends AppCompatActivity {
|
||||||
isFavorited = oldFavorited;
|
isFavorited = oldFavorited;
|
||||||
updateFavoriteButton();
|
updateFavoriteButton();
|
||||||
Toast.makeText(WorkDetailActivity.this,
|
Toast.makeText(WorkDetailActivity.this,
|
||||||
apiResponse.getMsg() != null ? apiResponse.getMsg() : "操作失败",
|
apiResponse.getMessage() != null ? apiResponse.getMessage() : "操作失败",
|
||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -699,7 +699,7 @@ public class WorkDetailActivity extends AppCompatActivity {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
long worksId = Long.parseLong(workItem.getId());
|
long worksId = Long.parseLong(workItem.getId());
|
||||||
ApiService apiService = ApiClient.getApiService(this);
|
ApiService apiService = ApiClient.getService(this);
|
||||||
Call<ApiResponse<Boolean>> call = apiService.deleteWork(worksId);
|
Call<ApiResponse<Boolean>> call = apiService.deleteWork(worksId);
|
||||||
|
|
||||||
call.enqueue(new retrofit2.Callback<ApiResponse<Boolean>>() {
|
call.enqueue(new retrofit2.Callback<ApiResponse<Boolean>>() {
|
||||||
|
|
@ -712,7 +712,7 @@ public class WorkDetailActivity extends AppCompatActivity {
|
||||||
finish();
|
finish();
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(WorkDetailActivity.this,
|
Toast.makeText(WorkDetailActivity.this,
|
||||||
apiResponse.getMsg() != null ? apiResponse.getMsg() : "删除失败",
|
apiResponse.getMessage() != null ? apiResponse.getMessage() : "删除失败",
|
||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -787,7 +787,7 @@ public class WorkDetailActivity extends AppCompatActivity {
|
||||||
try {
|
try {
|
||||||
long worksId = Long.parseLong(workId);
|
long worksId = Long.parseLong(workId);
|
||||||
|
|
||||||
ApiService apiService = ApiClient.getApiService(this);
|
ApiService apiService = ApiClient.getService(this);
|
||||||
Call<ApiResponse<WorksResponse>> call = apiService.getWorkDetail(worksId);
|
Call<ApiResponse<WorksResponse>> call = apiService.getWorkDetail(worksId);
|
||||||
|
|
||||||
call.enqueue(new retrofit2.Callback<ApiResponse<WorksResponse>>() {
|
call.enqueue(new retrofit2.Callback<ApiResponse<WorksResponse>>() {
|
||||||
|
|
@ -813,7 +813,7 @@ public class WorkDetailActivity extends AppCompatActivity {
|
||||||
setupActionButton();
|
setupActionButton();
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(WorkDetailActivity.this,
|
Toast.makeText(WorkDetailActivity.this,
|
||||||
apiResponse.getMsg() != null ? apiResponse.getMsg() : "获取作品详情失败",
|
apiResponse.getMessage() != null ? apiResponse.getMessage() : "获取作品详情失败",
|
||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -379,12 +379,6 @@ public interface ApiService {
|
||||||
|
|
||||||
// ==================== 支付集成 ====================
|
// ==================== 支付集成 ====================
|
||||||
|
|
||||||
@GET("api/front/gift/recharge/options")
|
|
||||||
Call<ApiResponse<List<RechargeOptionResponse>>> getRechargeOptions();
|
|
||||||
|
|
||||||
@POST("api/front/gift/recharge/create")
|
|
||||||
Call<ApiResponse<CreateRechargeResponse>> createRecharge(@Body CreateRechargeRequest body);
|
|
||||||
|
|
||||||
@GET("api/front/pay/alipay/queryPayResult")
|
@GET("api/front/pay/alipay/queryPayResult")
|
||||||
Call<ApiResponse<Boolean>> queryAliPayResult(@Query("orderNo") String orderNo);
|
Call<ApiResponse<Boolean>> queryAliPayResult(@Query("orderNo") String orderNo);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent">
|
app:layout_constraintStart_toStartOf="parent">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<EditText
|
||||||
android:id="@+id/messageInput"
|
android:id="@+id/messageInput"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
|
|
@ -136,7 +136,10 @@
|
||||||
android:paddingStart="12dp"
|
android:paddingStart="12dp"
|
||||||
android:paddingEnd="12dp"
|
android:paddingEnd="12dp"
|
||||||
android:textColor="#111111"
|
android:textColor="#111111"
|
||||||
android:textSize="14sp" />
|
android:textColorHint="#999999"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:importantForAutofill="no"
|
||||||
|
android:autofillHints="" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/sendButton"
|
android:id="@+id/sendButton"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user