docs: Phase 2c 设计文档 + 实施计划 + 项目进度更新
- 新增 Phase 2c 设计文档(群聊与已读回执) - 新增 Phase 2c 实施计划(14 个 Task) - 更新 CURRENT_STATUS.md 反映 Phase 2c 规划 - 更新 project-context.mdc 新增 Phase 2c 进度和模块信息 Made-with: Cursor
This commit is contained in:
@@ -18,10 +18,10 @@ alwaysApply: true
|
|||||||
- **Phase 2a(WebSocket 实时通讯与联系人管理)**:✅ 全部完成(13 个 Task + 后期 Bug 修复 3 项)
|
- **Phase 2a(WebSocket 实时通讯与联系人管理)**:✅ 全部完成(13 个 Task + 后期 Bug 修复 3 项)
|
||||||
- **Phase 2b(即时通讯消息系统)**:✅ 全部完成(10 个 Task + 代码审查修复 7 项 + 用户测试修复 8 项),设计文档 `docs/plans/2026-03-03-phase2b-design.md`
|
- **Phase 2b(即时通讯消息系统)**:✅ 全部完成(10 个 Task + 代码审查修复 7 项 + 用户测试修复 8 项),设计文档 `docs/plans/2026-03-03-phase2b-design.md`
|
||||||
- 分支:`feature/phase2b-instant-messaging`
|
- 分支:`feature/phase2b-instant-messaging`
|
||||||
- 代码审查修复:ClearHistory 个人视图、Redis 负数保护、N+1 查询优化、全文索引搜索、撤回更新预览、推送补全 sender 信息
|
- **Phase 2c(群聊与已读回执)**:📋 设计完成,待实施(14 个 Task),设计文档 `docs/plans/2026-03-04-phase2c-design.md`,实施计划 `docs/plans/2026-03-04-phase2c-implementation.plan.md`
|
||||||
- 用户测试修复:好友申请/接受唯一约束、Redis 在线状态残留清理、WS 全局初始化、管理端字段修正、好友列表在线状态初始值、聊天页布局约束
|
- 分支:`feature/phase2c-group-read-receipt`(待创建)
|
||||||
- **Phase 2c(群聊与增强)**:待规划设计
|
- 范围:群聊全功能(三级角色/禁言/@提醒/群公告/入群审批)+ 已读回执(单聊会话级 + 群聊消息级)+ MinIO 文件存储 + 管理端群聊管理
|
||||||
- **跨模块通信模式**:已建立接口注入标准(ws.FriendIDsGetter / im.FriendChecker / im.UserInfoGetter → contact.FriendshipDAO,im.OfflineMessagePusher → ws.Handler,contact.OnlineChecker → ws.OnlineService)
|
- **跨模块通信模式**:已建立接口注入标准(ws.FriendIDsGetter / im.FriendChecker / im.UserInfoGetter → contact.FriendshipDAO,im.OfflineMessagePusher → ws.Handler,contact.OnlineChecker → ws.OnlineService),Phase 2c 新增 im.GroupMemberChecker / im.GroupInfoGetter → group.GroupDAO
|
||||||
|
|
||||||
## 项目概述
|
## 项目概述
|
||||||
|
|
||||||
@@ -31,6 +31,7 @@ EchoChat 是一个实时音视频通讯平台,包含三个子项目:
|
|||||||
- `admin/` — 后台管理端(Vue 3.5+ + Element Plus + Pinia 3.x)
|
- `admin/` — 后台管理端(Vue 3.5+ + Element Plus + Pinia 3.x)
|
||||||
|
|
||||||
已实现模块:auth(认证)、contact(联系人)、ws(WebSocket)、admin(管理端)、im(即时通讯)
|
已实现模块:auth(认证)、contact(联系人)、ws(WebSocket)、admin(管理端)、im(即时通讯)
|
||||||
|
Phase 2c 待实现模块:group(群聊管理)、file(文件上传/MinIO)+ im 扩展(已读回执)
|
||||||
|
|
||||||
## 核心开发规则
|
## 核心开发规则
|
||||||
|
|
||||||
|
|||||||
626
docs/plans/2026-03-04-phase2c-design.md
Normal file
626
docs/plans/2026-03-04-phase2c-design.md
Normal file
@@ -0,0 +1,626 @@
|
|||||||
|
# Phase 2c 设计文档:群聊与已读回执
|
||||||
|
|
||||||
|
> **状态:** 📋 设计完成,待实施
|
||||||
|
> **分支:** `feature/phase2c-group-read-receipt`
|
||||||
|
> **前置依赖:** Phase 2b 全部完成(单聊即时通讯)
|
||||||
|
> **最后更新:** 2026-03-04
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、设计目标
|
||||||
|
|
||||||
|
基于 Phase 2b 的单聊 IM 基础设施,实现群聊核心功能和已读回执系统,同时引入 MinIO 文件存储服务作为基础设施扩展。
|
||||||
|
|
||||||
|
**核心交付物:**
|
||||||
|
- 群聊管理(创建/加入/退出/解散/搜索/角色管理/禁言/公告)
|
||||||
|
- 群消息收发(复用 im.message.* 事件 + @提醒 + 管理员撤回)
|
||||||
|
- 已读回执(单聊会话级 + 群聊消息级 + 实时推送 + 详情查看)
|
||||||
|
- MinIO 文件存储(Docker 容器 + Go SDK + 通用上传 API)
|
||||||
|
- 管理端群聊管理(群列表/详情/解散/移除成员)
|
||||||
|
- 前端 9 个新页面 + 群聊 Store + API 封装
|
||||||
|
|
||||||
|
**不包含(留待后续阶段):**
|
||||||
|
- 图片/语音/文件消息
|
||||||
|
- 管理端消息管理
|
||||||
|
- 消息类型扩展
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、需求决策记录
|
||||||
|
|
||||||
|
### 2.1 群聊功能决策
|
||||||
|
|
||||||
|
| 决策项 | 选定方案 | 说明 |
|
||||||
|
|--------|----------|------|
|
||||||
|
| 创建方式 | 选好友 + 搜索用户 ID 拉人 | 非好友也可拉入群 |
|
||||||
|
| 成员上限 | 200 人(默认) | im_groups.max_members 可配置 |
|
||||||
|
| 角色体系 | 三级:群主(2) + 管理员(1) + 普通成员(0) | 微信模式 |
|
||||||
|
| 管理操作 | 全功能 | 改群名/头像/公告、拉人/踢人、禁言/全体禁言、转让群主、解散、设管理员 |
|
||||||
|
| 入群方式 | 被拉入(无需审批)+ 主动申请(需审批) | 群主/管理员审批 |
|
||||||
|
| 退出机制 | 主动退出 + 显示系统消息 | "XX 退出/加入/被移出了群聊" |
|
||||||
|
| 历史消息 | 钉钉模式 | 新成员可查看所有历史消息 |
|
||||||
|
| 群搜索 | 全局搜索公开群 + 自己的群 | 默认可搜索,群主可设为不可搜索 |
|
||||||
|
| 群头像 | 默认图标 + 群主手动上传 | 使用 MinIO 存储 |
|
||||||
|
| 群昵称 | 成员可设置群内昵称 | 仅在该群内显示 |
|
||||||
|
| 免打扰 | 微信模式 | 仍计未读(灰色数字),不推送通知 |
|
||||||
|
| @提醒 | @某人 + @所有人 | 所有成员可 @所有人,输入 @ 弹出成员选择 |
|
||||||
|
| @通知 | 会话列表标记 | 显示 "[N条] @了我" |
|
||||||
|
| 正在输入 | 群聊不显示 | 仅单聊保留 |
|
||||||
|
| 消息撤回 | 成员 2 分钟,管理员无时限 | 群主/管理员可撤回任何人消息 |
|
||||||
|
| 撤回展示 | 区分操作者 | "管理员 XX 撤回了 YY 的一条消息" |
|
||||||
|
| 群公告 | 需要 | 群主/管理员发布,发布时推送系统消息通知全员 |
|
||||||
|
|
||||||
|
### 2.2 已读回执决策
|
||||||
|
|
||||||
|
| 决策项 | 选定方案 | 说明 |
|
||||||
|
|--------|----------|------|
|
||||||
|
| 单聊粒度 | 会话级别 | 复用 last_read_msg_id,消息 ID ≤ 该值即已读 |
|
||||||
|
| 群聊粒度 | 消息级别 | im_message_reads 表记录每人每条消息的已读 |
|
||||||
|
| 展示方式 | 钉钉模式 | 单聊 "已读/未读",群聊 "X人已读" 可点击查看列表 |
|
||||||
|
| 存储方案 | 纯 PostgreSQL | im_message_reads 表(联合主键 message_id + user_id) |
|
||||||
|
| 推送策略 | 差异化 | 单聊实时推送已读变化,群聊仅推送已读计数变化 |
|
||||||
|
| 详情查看 | REST 按需拉取 | 点击 "X人已读" 时 GET /api/v1/im/messages/:id/reads |
|
||||||
|
|
||||||
|
### 2.3 基础设施决策
|
||||||
|
|
||||||
|
| 决策项 | 选定方案 | 说明 |
|
||||||
|
|--------|----------|------|
|
||||||
|
| 文件存储 | MinIO(Docker 镜像) | 通用上传 API,后续消息类型扩展可复用 |
|
||||||
|
| 前端架构 | 群聊独立页面体系 | 不复用单聊页面,完全独立 |
|
||||||
|
| 会话列表 | 分 Tab | 单聊 Tab + 群聊 Tab |
|
||||||
|
| WS 事件 | 消息复用 + 管理独立 | im.message.* 复用,group.* 新增 |
|
||||||
|
| 消息搜索 | 统一全局搜索 | 单聊 + 群聊消息在同一搜索结果中 |
|
||||||
|
| 分支策略 | 从 phase2b 拉新分支 | feature/phase2c-group-read-receipt |
|
||||||
|
| 管理端 | 群列表 + 详情 + 解散 + 移除 | 4 个管理 API + 2 个前端页面 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、架构设计
|
||||||
|
|
||||||
|
### 3.1 新增模块
|
||||||
|
|
||||||
|
| 模块 | 位置 | 职责 |
|
||||||
|
|------|------|------|
|
||||||
|
| group | app/group/ | 群聊管理(创建/加入/退出/角色/禁言/搜索/审批) |
|
||||||
|
| file | app/file/ | 文件上传(MinIO SDK 封装 + 通用上传 API) |
|
||||||
|
| storage | pkg/storage/ | MinIO 客户端初始化 + 配置 |
|
||||||
|
|
||||||
|
### 3.2 模块目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
backend/go-service/
|
||||||
|
├── app/
|
||||||
|
│ ├── group/ # [新增] 群聊管理模块
|
||||||
|
│ │ ├── controller/
|
||||||
|
│ │ │ └── group_controller.go # REST API 控制器(~15 个接口)
|
||||||
|
│ │ ├── service/
|
||||||
|
│ │ │ └── group_service.go # 群创建/管理/审批/搜索业务逻辑
|
||||||
|
│ │ ├── dao/
|
||||||
|
│ │ │ └── group_dao.go # im_groups + 成员角色 + 入群申请 CRUD
|
||||||
|
│ │ ├── handler/
|
||||||
|
│ │ │ └── group_handler.go # WS 群管理事件处理
|
||||||
|
│ │ ├── model/
|
||||||
|
│ │ │ ├── group.go # im_groups 模型
|
||||||
|
│ │ │ └── join_request.go # im_group_join_requests 模型
|
||||||
|
│ │ ├── router.go
|
||||||
|
│ │ └── provider.go
|
||||||
|
│ ├── file/ # [新增] 文件上传模块
|
||||||
|
│ │ ├── controller/
|
||||||
|
│ │ │ └── file_controller.go # POST /api/v1/upload
|
||||||
|
│ │ ├── service/
|
||||||
|
│ │ │ └── file_service.go # MinIO 上传/删除封装
|
||||||
|
│ │ ├── router.go
|
||||||
|
│ │ └── provider.go
|
||||||
|
│ ├── im/ # [扩展]
|
||||||
|
│ │ ├── dao/
|
||||||
|
│ │ │ └── read_dao.go # [新增] im_message_reads 操作
|
||||||
|
│ │ ├── model/
|
||||||
|
│ │ │ └── message_read.go # [新增] im_message_reads 模型
|
||||||
|
│ │ └── service/
|
||||||
|
│ │ └── im_service.go # [扩展] 群消息/已读回执/管理员撤回
|
||||||
|
│ └── constants/
|
||||||
|
│ └── group.go # [新增] 群聊相关常量
|
||||||
|
├── pkg/
|
||||||
|
│ └── storage/
|
||||||
|
│ └── minio.go # [新增] MinIO 客户端初始化
|
||||||
|
|
||||||
|
frontend/src/
|
||||||
|
├── pages/
|
||||||
|
│ ├── group/ # [新增] 群聊页面(独立体系)
|
||||||
|
│ │ ├── index.vue # 群聊会话列表
|
||||||
|
│ │ ├── conversation.vue # 群聊对话页
|
||||||
|
│ │ ├── create.vue # 创建群聊
|
||||||
|
│ │ ├── settings.vue # 群聊设置
|
||||||
|
│ │ ├── members.vue # 群成员列表
|
||||||
|
│ │ ├── invite.vue # 邀请入群
|
||||||
|
│ │ ├── join-requests.vue # 入群申请审批
|
||||||
|
│ │ └── search.vue # 搜索公开群
|
||||||
|
│ └── chat/
|
||||||
|
│ └── read-detail.vue # [新增] 已读回执详情页
|
||||||
|
├── store/
|
||||||
|
│ └── group.js # [新增] 群聊 Pinia Store
|
||||||
|
├── api/
|
||||||
|
│ ├── group.js # [新增] 群聊 API
|
||||||
|
│ └── file.js # [新增] 文件上传 API
|
||||||
|
|
||||||
|
admin/src/
|
||||||
|
├── views/
|
||||||
|
│ └── group/ # [新增] 管理端群聊管理
|
||||||
|
│ ├── list.vue # 群列表
|
||||||
|
│ └── detail.vue # 群详情(含成员管理)
|
||||||
|
├── api/
|
||||||
|
│ └── group.js # [新增] 管理端群聊 API
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.3 跨模块接口注入
|
||||||
|
|
||||||
|
延续 Phase 2a/2b 的接口注入模式,通过 Wire Bind 在 `app/provider/wire.go` 中统一绑定。
|
||||||
|
|
||||||
|
| 接口 | 定义模块 | 实现方 | 用途 |
|
||||||
|
|------|----------|--------|------|
|
||||||
|
| GroupMemberChecker | im/service | group/dao.GroupDAO | 检查用户是否为群成员 |
|
||||||
|
| GroupInfoGetter | im/service | group/dao.GroupDAO | 获取群信息(名称/头像/成员数) |
|
||||||
|
| GroupRoleChecker | im/service | group/dao.GroupDAO | 检查用户群角色(管理员撤回权限) |
|
||||||
|
| 已有接口 | - | - | FriendChecker / UserInfoGetter / FriendIDsGetter 等继续复用 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、数据库设计
|
||||||
|
|
||||||
|
### 4.1 新增表
|
||||||
|
|
||||||
|
#### im_groups(群聊信息表)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE im_groups (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
conversation_id BIGINT NOT NULL UNIQUE REFERENCES im_conversations(id),
|
||||||
|
name VARCHAR(100) NOT NULL DEFAULT '',
|
||||||
|
avatar VARCHAR(500) DEFAULT '',
|
||||||
|
owner_id BIGINT NOT NULL,
|
||||||
|
notice TEXT DEFAULT '',
|
||||||
|
max_members INT NOT NULL DEFAULT 200,
|
||||||
|
is_searchable BOOLEAN NOT NULL DEFAULT TRUE,
|
||||||
|
is_all_muted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
status SMALLINT NOT NULL DEFAULT 1,
|
||||||
|
created_at TIMESTAMP(0) NOT NULL DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMP(0) NOT NULL DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE im_groups IS '群聊信息表';
|
||||||
|
COMMENT ON COLUMN im_groups.id IS '群唯一标识';
|
||||||
|
COMMENT ON COLUMN im_groups.conversation_id IS '关联 im_conversations.id';
|
||||||
|
COMMENT ON COLUMN im_groups.name IS '群名称';
|
||||||
|
COMMENT ON COLUMN im_groups.avatar IS '群头像 URL(MinIO)';
|
||||||
|
COMMENT ON COLUMN im_groups.owner_id IS '群主用户 ID';
|
||||||
|
COMMENT ON COLUMN im_groups.notice IS '群公告内容';
|
||||||
|
COMMENT ON COLUMN im_groups.max_members IS '最大成员数,默认 200';
|
||||||
|
COMMENT ON COLUMN im_groups.is_searchable IS '是否可被搜索发现';
|
||||||
|
COMMENT ON COLUMN im_groups.is_all_muted IS '是否全体禁言';
|
||||||
|
COMMENT ON COLUMN im_groups.status IS '群状态:1=正常,2=已解散';
|
||||||
|
|
||||||
|
CREATE INDEX idx_im_groups_owner ON im_groups(owner_id);
|
||||||
|
CREATE INDEX idx_im_groups_name ON im_groups USING gin(to_tsvector('simple', name));
|
||||||
|
```
|
||||||
|
|
||||||
|
#### im_group_join_requests(入群申请表)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE im_group_join_requests (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
group_id BIGINT NOT NULL REFERENCES im_groups(id),
|
||||||
|
user_id BIGINT NOT NULL,
|
||||||
|
message TEXT DEFAULT '',
|
||||||
|
reviewer_id BIGINT DEFAULT NULL,
|
||||||
|
status SMALLINT NOT NULL DEFAULT 0,
|
||||||
|
created_at TIMESTAMP(0) NOT NULL DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMP(0) NOT NULL DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE im_group_join_requests IS '入群申请表';
|
||||||
|
COMMENT ON COLUMN im_group_join_requests.id IS '申请唯一标识';
|
||||||
|
COMMENT ON COLUMN im_group_join_requests.group_id IS '目标群 ID';
|
||||||
|
COMMENT ON COLUMN im_group_join_requests.user_id IS '申请人用户 ID';
|
||||||
|
COMMENT ON COLUMN im_group_join_requests.message IS '申请附言';
|
||||||
|
COMMENT ON COLUMN im_group_join_requests.reviewer_id IS '审批人用户 ID';
|
||||||
|
COMMENT ON COLUMN im_group_join_requests.status IS '状态:0=待审批,1=通过,2=拒绝';
|
||||||
|
|
||||||
|
CREATE INDEX idx_group_join_req_group ON im_group_join_requests(group_id, status);
|
||||||
|
CREATE INDEX idx_group_join_req_user ON im_group_join_requests(user_id);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### im_message_reads(消息已读记录表)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE im_message_reads (
|
||||||
|
message_id BIGINT NOT NULL,
|
||||||
|
user_id BIGINT NOT NULL,
|
||||||
|
read_at TIMESTAMP(0) NOT NULL DEFAULT NOW(),
|
||||||
|
PRIMARY KEY (message_id, user_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE im_message_reads IS '群聊消息已读记录表(消息级别)';
|
||||||
|
COMMENT ON COLUMN im_message_reads.message_id IS '消息 ID';
|
||||||
|
COMMENT ON COLUMN im_message_reads.user_id IS '已读用户 ID';
|
||||||
|
COMMENT ON COLUMN im_message_reads.read_at IS '已读时间';
|
||||||
|
|
||||||
|
CREATE INDEX idx_msg_reads_user ON im_message_reads(user_id, read_at);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 扩展现有表
|
||||||
|
|
||||||
|
#### im_conversation_members — 新增 5 个字段
|
||||||
|
|
||||||
|
```sql
|
||||||
|
ALTER TABLE im_conversation_members
|
||||||
|
ADD COLUMN role SMALLINT NOT NULL DEFAULT 0,
|
||||||
|
ADD COLUMN nickname VARCHAR(50) DEFAULT '',
|
||||||
|
ADD COLUMN is_muted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
ADD COLUMN is_do_not_disturb BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
ADD COLUMN joined_at TIMESTAMP(0) DEFAULT NULL;
|
||||||
|
|
||||||
|
COMMENT ON COLUMN im_conversation_members.role IS '成员角色:0=普通成员,1=管理员,2=群主';
|
||||||
|
COMMENT ON COLUMN im_conversation_members.nickname IS '群内昵称(仅群聊有效)';
|
||||||
|
COMMENT ON COLUMN im_conversation_members.is_muted IS '是否被禁言';
|
||||||
|
COMMENT ON COLUMN im_conversation_members.is_do_not_disturb IS '是否消息免打扰(微信模式:仍计未读但灰色显示)';
|
||||||
|
COMMENT ON COLUMN im_conversation_members.joined_at IS '加入群聊时间';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### im_messages — 新增 1 个字段
|
||||||
|
|
||||||
|
```sql
|
||||||
|
ALTER TABLE im_messages
|
||||||
|
ADD COLUMN at_user_ids BIGINT[] DEFAULT NULL;
|
||||||
|
|
||||||
|
COMMENT ON COLUMN im_messages.at_user_ids IS '@提醒用户 ID 列表,NULL=无@,包含 0 表示 @所有人';
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.3 数据库表关系图
|
||||||
|
|
||||||
|
```
|
||||||
|
im_conversations (type=2 群聊)
|
||||||
|
│ 1:1
|
||||||
|
├── im_groups (群信息:名称/头像/公告/群主)
|
||||||
|
│ │ 1:N
|
||||||
|
│ └── im_group_join_requests (入群申请)
|
||||||
|
│ 1:N
|
||||||
|
├── im_conversation_members (成员:+role/nickname/is_muted/is_do_not_disturb)
|
||||||
|
│ 1:N
|
||||||
|
└── im_messages (消息:+at_user_ids)
|
||||||
|
│ 1:N
|
||||||
|
└── im_message_reads (群聊消息已读记录)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、API 设计
|
||||||
|
|
||||||
|
### 5.1 群聊 REST API(16 个)
|
||||||
|
|
||||||
|
| # | 方法 | 路径 | 描述 | 权限 |
|
||||||
|
|---|------|------|------|------|
|
||||||
|
| 1 | POST | /api/v1/groups | 创建群聊 | 登录用户 |
|
||||||
|
| 2 | GET | /api/v1/groups/:id | 群详情 | 群成员 |
|
||||||
|
| 3 | PUT | /api/v1/groups/:id | 更新群信息 | 群主/管理员 |
|
||||||
|
| 4 | DELETE | /api/v1/groups/:id | 解散群聊 | 群主 |
|
||||||
|
| 5 | GET | /api/v1/groups/:id/members | 成员列表 | 群成员 |
|
||||||
|
| 6 | POST | /api/v1/groups/:id/members | 邀请/拉人入群 | 群主/管理员 |
|
||||||
|
| 7 | DELETE | /api/v1/groups/:id/members/:uid | 踢人 | 群主/管理员 |
|
||||||
|
| 8 | PUT | /api/v1/groups/:id/members/:uid/role | 设置/取消管理员 | 群主 |
|
||||||
|
| 9 | PUT | /api/v1/groups/:id/members/:uid/mute | 禁言/解除禁言 | 群主/管理员 |
|
||||||
|
| 10 | POST | /api/v1/groups/:id/leave | 退出群聊 | 群成员 |
|
||||||
|
| 11 | PUT | /api/v1/groups/:id/transfer | 转让群主 | 群主 |
|
||||||
|
| 12 | PUT | /api/v1/groups/:id/members/me/nickname | 修改群昵称 | 群成员 |
|
||||||
|
| 13 | POST | /api/v1/groups/:id/join-requests | 申请入群 | 登录用户 |
|
||||||
|
| 14 | GET | /api/v1/groups/:id/join-requests | 入群申请列表 | 群主/管理员 |
|
||||||
|
| 15 | PUT | /api/v1/groups/:id/join-requests/:rid | 审批入群申请 | 群主/管理员 |
|
||||||
|
| 16 | GET | /api/v1/groups/search | 搜索公开群 | 登录用户 |
|
||||||
|
|
||||||
|
### 5.2 已读回执 REST API(2 个)
|
||||||
|
|
||||||
|
| # | 方法 | 路径 | 描述 |
|
||||||
|
|---|------|------|------|
|
||||||
|
| 1 | GET | /api/v1/im/messages/:id/reads | 消息已读详情(谁读了,分页) |
|
||||||
|
| 2 | GET | /api/v1/im/messages/:id/read-count | 消息已读/未读计数 |
|
||||||
|
|
||||||
|
### 5.3 文件上传 REST API(1 个)
|
||||||
|
|
||||||
|
| # | 方法 | 路径 | 描述 |
|
||||||
|
|---|------|------|------|
|
||||||
|
| 1 | POST | /api/v1/upload | 通用文件上传(返回 MinIO URL) |
|
||||||
|
|
||||||
|
### 5.4 管理端 REST API(4 个)
|
||||||
|
|
||||||
|
| # | 方法 | 路径 | 描述 |
|
||||||
|
|---|------|------|------|
|
||||||
|
| 1 | GET | /api/v1/admin/groups | 群列表(分页 + 筛选) |
|
||||||
|
| 2 | GET | /api/v1/admin/groups/:id | 群详情(含成员列表) |
|
||||||
|
| 3 | DELETE | /api/v1/admin/groups/:id | 管理员解散群 |
|
||||||
|
| 4 | DELETE | /api/v1/admin/groups/:id/members/:uid | 管理员移除成员 |
|
||||||
|
|
||||||
|
### 5.5 WebSocket 事件
|
||||||
|
|
||||||
|
#### 消息事件(复用 im.message.*,扩展群聊支持)
|
||||||
|
|
||||||
|
| 事件 | 方向 | 变更说明 |
|
||||||
|
|------|------|----------|
|
||||||
|
| im.message.send | C→S | data 新增 at_user_ids 字段 |
|
||||||
|
| im.message.send.ack | S→C | 无变化 |
|
||||||
|
| im.message.new | S→C | data 新增 conv_type、at_user_ids 字段 |
|
||||||
|
| im.message.recall | C→S | 群聊时管理员可撤回他人消息(无时限) |
|
||||||
|
| im.message.recalled | S→C | 群聊时区分 "管理员 XX 撤回了 YY 的消息" |
|
||||||
|
|
||||||
|
#### 已读回执事件(新增)
|
||||||
|
|
||||||
|
| 事件 | 方向 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| im.message.read | C→S | 上报已读:单聊走 last_read_msg_id,群聊写 im_message_reads |
|
||||||
|
| im.message.read.ack | S→C | 单聊:实时推送已读状态给消息发送者 |
|
||||||
|
| im.message.read.count | S→C | 群聊:推送已读计数变化 {msg_id, read_count} |
|
||||||
|
|
||||||
|
#### 群管理事件(新增 group.* 系列)
|
||||||
|
|
||||||
|
| 事件 | 方向 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| group.member.join | S→C | 成员加入通知(含系统消息 "XX 加入了群聊") |
|
||||||
|
| group.member.leave | S→C | 成员退出通知(含系统消息 "XX 退出了群聊") |
|
||||||
|
| group.member.kicked | S→C | 成员被踢通知(含系统消息 "XX 被移出了群聊") |
|
||||||
|
| group.info.update | S→C | 群信息变更通知(名称/头像) |
|
||||||
|
| group.notice.update | S→C | 群公告变更通知(含系统消息) |
|
||||||
|
| group.dissolved | S→C | 群解散通知 |
|
||||||
|
| group.mute.update | S→C | 禁言状态变更通知(个人/全体) |
|
||||||
|
| group.join.request | S→C | 新入群申请(推送给群主/管理员) |
|
||||||
|
| group.join.approved | S→C | 入群申请通过(推送给申请人) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、核心业务流程
|
||||||
|
|
||||||
|
### 6.1 创建群聊
|
||||||
|
|
||||||
|
```
|
||||||
|
1. 用户选择好友 + 搜索用户 ID → 确定初始成员列表
|
||||||
|
2. POST /api/v1/groups {name, member_ids[]}
|
||||||
|
3. GroupService:
|
||||||
|
a. 创建 im_conversations (type=2)
|
||||||
|
b. 创建 im_groups (关联 conversation_id)
|
||||||
|
c. 批量创建 im_conversation_members (创建者 role=2 群主, 其余 role=0)
|
||||||
|
d. 插入系统消息 "XX 创建了群聊,邀请了 A、B、C 加入"
|
||||||
|
e. PubSub 推送 group.member.join 给所有初始成员
|
||||||
|
4. 返回群信息 + 会话 ID
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.2 群消息发送
|
||||||
|
|
||||||
|
```
|
||||||
|
1. 发送者 WS: im.message.send {conversation_id, content, at_user_ids}
|
||||||
|
2. IMService.SendMessage:
|
||||||
|
a. 查询 im_conversations.type → 群聊分支
|
||||||
|
b. 校验群成员身份 + 禁言检查(is_muted / is_all_muted,管理员豁免全体禁言)
|
||||||
|
c. 写入 im_messages (含 at_user_ids)
|
||||||
|
d. 更新 im_conversations.last_msg_*
|
||||||
|
e. 遍历群成员:
|
||||||
|
- 排除发送者
|
||||||
|
- 非免打扰成员:递增 unread_count + Redis 全局未读
|
||||||
|
- 免打扰成员:递增 unread_count,不递增 Redis 全局未读
|
||||||
|
- 被 @的成员:记录 @计数(可存 im_conversation_members 或 Redis)
|
||||||
|
f. PubSub.PublishToUsers → 推送 im.message.new 给所有在线成员
|
||||||
|
3. 发送者收到 im.message.send.ack
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.3 已读回执(单聊)
|
||||||
|
|
||||||
|
```
|
||||||
|
1. 用户打开单聊会话
|
||||||
|
2. 前端 WS: im.message.read {conversation_id}
|
||||||
|
3. IMService:
|
||||||
|
a. 获取会话最新消息 ID → 更新 last_read_msg_id
|
||||||
|
b. 清零 unread_count + Redis 全局未读
|
||||||
|
c. PubSub 推送 im.message.read.ack 给对方
|
||||||
|
{conversation_id, reader_id, last_read_msg_id}
|
||||||
|
4. 对方前端收到后,对 ID ≤ last_read_msg_id 的自己发送的消息标记为 "已读"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.4 已读回执(群聊)
|
||||||
|
|
||||||
|
```
|
||||||
|
1. 用户打开群聊会话,前端获取可视区域消息 ID 列表
|
||||||
|
2. 前端 WS: im.message.read {conversation_id, message_ids[]}
|
||||||
|
3. IMService:
|
||||||
|
a. 批量写入 im_message_reads (ON CONFLICT DO NOTHING)
|
||||||
|
b. 更新 last_read_msg_id + 清零 unread_count
|
||||||
|
c. 查询受影响消息的 sender_id(去重)
|
||||||
|
d. 对每个 sender_id 推送 im.message.read.count
|
||||||
|
{msg_id, read_count, total_members}
|
||||||
|
4. 发送者前端更新 "X人已读" 显示
|
||||||
|
5. 用户点击 "X人已读" → GET /api/v1/im/messages/:id/reads → 显示详情列表
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.5 @提醒流程
|
||||||
|
|
||||||
|
```
|
||||||
|
1. 发送者在输入框键入 @ → 弹出成员选择列表
|
||||||
|
2. 选择成员(或 @所有人)→ 消息中插入 @昵称 标记
|
||||||
|
3. 发送消息时 at_user_ids 包含被 @用户的 ID(0 表示 @所有人)
|
||||||
|
4. 接收方前端:
|
||||||
|
a. 收到 im.message.new 检查 at_user_ids
|
||||||
|
b. 如果包含自己的 ID 或 0 → 标记该会话 "被@"
|
||||||
|
c. 会话列表显示 "[N条] @了我"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 七、前端页面规划
|
||||||
|
|
||||||
|
### 7.1 新增页面(9 个)
|
||||||
|
|
||||||
|
| 页面 | 路径 | 功能描述 |
|
||||||
|
|------|------|----------|
|
||||||
|
| 群聊会话列表 | pages/group/index.vue | 群聊 Tab 页,显示群会话列表 |
|
||||||
|
| 群聊对话页 | pages/group/conversation.vue | 群消息展示 + 发送 + @选择器 |
|
||||||
|
| 创建群聊 | pages/group/create.vue | 选好友 + 搜索用户 + 填群名 |
|
||||||
|
| 群设置 | pages/group/settings.vue | 群信息/公告/成员概览/免打扰/退群/解散 |
|
||||||
|
| 群成员列表 | pages/group/members.vue | 完整成员列表 + 角色标识 + 管理操作 |
|
||||||
|
| 邀请入群 | pages/group/invite.vue | 搜索用户 ID 拉人入群 |
|
||||||
|
| 入群审批 | pages/group/join-requests.vue | 群主/管理员审批入群申请 |
|
||||||
|
| 搜索群聊 | pages/group/search.vue | 搜索公开群 + 申请加入 |
|
||||||
|
| 已读详情 | pages/chat/read-detail.vue | 已读/未读人员列表(单聊+群聊共用) |
|
||||||
|
|
||||||
|
### 7.2 修改现有页面
|
||||||
|
|
||||||
|
| 页面 | 修改内容 |
|
||||||
|
|------|----------|
|
||||||
|
| pages/chat/index.vue | 改为 Tab 切换:单聊 Tab + 群聊 Tab |
|
||||||
|
| pages/chat/conversation.vue | 添加单聊已读状态展示("已读"/"未读") |
|
||||||
|
| pages/chat/search.vue | 全局搜索扩展支持群聊消息结果 |
|
||||||
|
| components/CustomTabBar.vue | TabBar 适配群聊入口 |
|
||||||
|
|
||||||
|
### 7.3 管理端新增页面(2 个)
|
||||||
|
|
||||||
|
| 页面 | 路径 | 功能描述 |
|
||||||
|
|------|------|----------|
|
||||||
|
| 群列表 | admin/src/views/group/list.vue | 群列表(搜索/分页/状态筛选) |
|
||||||
|
| 群详情 | admin/src/views/group/detail.vue | 群信息 + 成员列表 + 解散/移除操作 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 八、Docker Compose 变更
|
||||||
|
|
||||||
|
在 `deploy/docker/docker-compose.dev.yml` 中新增 MinIO 服务:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
minio:
|
||||||
|
image: minio/minio:latest
|
||||||
|
command: server /data --console-address ":9001"
|
||||||
|
ports:
|
||||||
|
- "9000:9000"
|
||||||
|
- "9001:9001"
|
||||||
|
environment:
|
||||||
|
MINIO_ROOT_USER: echochat
|
||||||
|
MINIO_ROOT_PASSWORD: echochat123456
|
||||||
|
volumes:
|
||||||
|
- minio_data:/data
|
||||||
|
restart: unless-stopped
|
||||||
|
```
|
||||||
|
|
||||||
|
Go 后端 `config.yaml` 新增:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
minio:
|
||||||
|
endpoint: "localhost:9000"
|
||||||
|
access_key: "echochat"
|
||||||
|
secret_key: "echochat123456"
|
||||||
|
bucket: "echochat"
|
||||||
|
use_ssl: false
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 九、常量定义规划
|
||||||
|
|
||||||
|
```go
|
||||||
|
// app/constants/group.go
|
||||||
|
|
||||||
|
// 群成员角色
|
||||||
|
const (
|
||||||
|
GroupRoleMember = 0 // 普通成员
|
||||||
|
GroupRoleAdmin = 1 // 管理员
|
||||||
|
GroupRoleOwner = 2 // 群主
|
||||||
|
)
|
||||||
|
|
||||||
|
// 群状态
|
||||||
|
const (
|
||||||
|
GroupStatusActive = 1 // 正常
|
||||||
|
GroupStatusDissolved = 2 // 已解散
|
||||||
|
)
|
||||||
|
|
||||||
|
// 入群申请状态
|
||||||
|
const (
|
||||||
|
JoinRequestPending = 0 // 待审批
|
||||||
|
JoinRequestApproved = 1 // 已通过
|
||||||
|
JoinRequestRejected = 2 // 已拒绝
|
||||||
|
)
|
||||||
|
|
||||||
|
// 系统消息类型(im_messages.type 扩展)
|
||||||
|
const (
|
||||||
|
MessageTypeSystem = 10 // 系统通知消息
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十、DTO 扩展规划
|
||||||
|
|
||||||
|
### 10.1 群聊 DTO
|
||||||
|
|
||||||
|
```go
|
||||||
|
// CreateGroupRequest 创建群聊请求
|
||||||
|
type CreateGroupRequest struct {
|
||||||
|
Name string `json:"name" binding:"required"`
|
||||||
|
MemberIDs []int64 `json:"member_ids" binding:"required,min=1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupDTO 群详情
|
||||||
|
type GroupDTO struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
ConversationID int64 `json:"conversation_id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Avatar string `json:"avatar"`
|
||||||
|
OwnerID int64 `json:"owner_id"`
|
||||||
|
OwnerNickname string `json:"owner_nickname"`
|
||||||
|
Notice string `json:"notice"`
|
||||||
|
MemberCount int `json:"member_count"`
|
||||||
|
MaxMembers int `json:"max_members"`
|
||||||
|
IsSearchable bool `json:"is_searchable"`
|
||||||
|
IsAllMuted bool `json:"is_all_muted"`
|
||||||
|
Status int `json:"status"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupMemberDTO 群成员信息
|
||||||
|
type GroupMemberDTO struct {
|
||||||
|
UserID int64 `json:"user_id"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Nickname string `json:"nickname"` // 群昵称(优先)或全局昵称
|
||||||
|
Avatar string `json:"avatar"`
|
||||||
|
Role int `json:"role"`
|
||||||
|
IsMuted bool `json:"is_muted"`
|
||||||
|
IsOnline bool `json:"is_online"`
|
||||||
|
JoinedAt string `json:"joined_at"`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 10.2 已读回执 DTO
|
||||||
|
|
||||||
|
```go
|
||||||
|
// ReadDetailDTO 消息已读详情
|
||||||
|
type ReadDetailDTO struct {
|
||||||
|
UserID int64 `json:"user_id"`
|
||||||
|
Nickname string `json:"nickname"`
|
||||||
|
Avatar string `json:"avatar"`
|
||||||
|
ReadAt string `json:"read_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadCountDTO 消息已读计数
|
||||||
|
type ReadCountDTO struct {
|
||||||
|
MessageID int64 `json:"message_id"`
|
||||||
|
ReadCount int `json:"read_count"`
|
||||||
|
UnreadCount int `json:"unread_count"`
|
||||||
|
TotalMembers int `json:"total_members"`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 10.3 ConversationDTO 扩展
|
||||||
|
|
||||||
|
```go
|
||||||
|
// ConversationDTO 扩展:增加群聊字段
|
||||||
|
type ConversationDTO struct {
|
||||||
|
// 原有字段...
|
||||||
|
GroupID *int64 `json:"group_id,omitempty"` // 群聊时的群 ID
|
||||||
|
GroupName string `json:"group_name,omitempty"` // 群名称
|
||||||
|
GroupAvatar string `json:"group_avatar,omitempty"` // 群头像
|
||||||
|
MemberCount int `json:"member_count,omitempty"` // 群成员数
|
||||||
|
IsDoNotDisturb bool `json:"is_do_not_disturb"` // 是否免打扰
|
||||||
|
AtMeCount int `json:"at_me_count,omitempty"` // 被@计数
|
||||||
|
}
|
||||||
|
```
|
||||||
562
docs/plans/2026-03-04-phase2c-implementation.plan.md
Normal file
562
docs/plans/2026-03-04-phase2c-implementation.plan.md
Normal file
@@ -0,0 +1,562 @@
|
|||||||
|
# Phase 2c 实施计划:群聊与已读回执
|
||||||
|
|
||||||
|
> **状态:** 📋 待执行
|
||||||
|
> **设计文档:** `docs/plans/2026-03-04-phase2c-design.md`
|
||||||
|
> **分支:** `feature/phase2c-group-read-receipt`
|
||||||
|
> **预计 Task 数:** 14 个
|
||||||
|
> **最后更新:** 2026-03-04
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 总览
|
||||||
|
|
||||||
|
| Task | 阶段 | 描述 | 依赖 | 状态 |
|
||||||
|
|------|------|------|------|------|
|
||||||
|
| Task 0 | 基础设施 | MinIO Docker + SDK + 通用上传 API | 无 | 📋 |
|
||||||
|
| Task 1 | 基础设施 | 数据库迁移 + Model + 常量定义 | 无 | 📋 |
|
||||||
|
| Task 2 | 群聊后端 | Group DAO 层 | Task 1 | 📋 |
|
||||||
|
| Task 3 | 群聊后端 | Group Service 业务逻辑 | Task 2 | 📋 |
|
||||||
|
| Task 4 | 群聊后端 | Group Controller + Router + Wire | Task 3 | 📋 |
|
||||||
|
| Task 5 | 群聊后端 | WS 群管理事件处理器 | Task 3 | 📋 |
|
||||||
|
| Task 6 | 群聊后端 | IM Service 扩展(群消息 + @提醒 + 管理员撤回) | Task 2 | 📋 |
|
||||||
|
| Task 7 | 已读回执 | 已读回执后端(ReadDAO + Service + API + WS 推送) | Task 1 | 📋 |
|
||||||
|
| Task 8 | 已读回执 | 前端已读回执 UI(单聊标记 + 群聊计数 + 详情页) | Task 7 | 📋 |
|
||||||
|
| Task 9 | 前端 | 群聊 Store + API 封装 + WS 事件监听 | Task 4, 5 | 📋 |
|
||||||
|
| Task 10 | 前端 | 群聊核心页面(Tab 改造 + 群对话页 + 创建群页) | Task 9 | 📋 |
|
||||||
|
| Task 11 | 前端 | 群聊管理页面(群设置 + 成员 + 邀请 + @选择器) | Task 10 | 📋 |
|
||||||
|
| Task 12 | 前端 | 群聊辅助功能(审批 + 搜索 + 免打扰 + 公告 UI) | Task 11 | 📋 |
|
||||||
|
| Task 13 | 管理端 | 管理端群聊管理 + 全量文档更新 + 代码审查 | Task 12 | 📋 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 0: MinIO Docker + SDK + 通用上传 API
|
||||||
|
|
||||||
|
**目标:** 引入 MinIO 文件存储服务,封装通用上传能力
|
||||||
|
|
||||||
|
### 交付物
|
||||||
|
|
||||||
|
1. **Docker Compose**
|
||||||
|
- `deploy/docker/docker-compose.dev.yml` 添加 minio 服务
|
||||||
|
- volumes 持久化 `minio_data`
|
||||||
|
- 端口:9000(API)+ 9001(Console)
|
||||||
|
|
||||||
|
2. **Go 后端配置**
|
||||||
|
- `config/config.yaml` 添加 minio 配置节
|
||||||
|
- `config/config.go` 添加 MinioConfig 结构体
|
||||||
|
- `pkg/storage/minio.go` — MinIO 客户端初始化(NewMinioClient)
|
||||||
|
|
||||||
|
3. **文件模块**
|
||||||
|
- `app/file/service/file_service.go` — Upload(ctx, file) → URL
|
||||||
|
- `app/file/controller/file_controller.go` — POST /api/v1/upload
|
||||||
|
- `app/file/router.go` — 路由注册
|
||||||
|
- `app/file/provider.go` — Wire ProviderSet
|
||||||
|
|
||||||
|
4. **集成**
|
||||||
|
- `app/provider/wire.go` 添加 FileSet
|
||||||
|
- `router/router.go` 注册 file 路由
|
||||||
|
|
||||||
|
### 验收标准
|
||||||
|
|
||||||
|
- `docker compose up -d minio` 正常启动
|
||||||
|
- `curl -F "file=@test.png" http://localhost:8085/api/v1/upload` 返回 MinIO URL
|
||||||
|
- MinIO Console (localhost:9001) 可看到上传的文件
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 1: 数据库迁移 + Model + 常量定义
|
||||||
|
|
||||||
|
**目标:** 建立 Phase 2c 所需的数据库表和 Go 模型
|
||||||
|
|
||||||
|
### 交付物
|
||||||
|
|
||||||
|
1. **新增表 SQL(init.sql 追加)**
|
||||||
|
- `im_groups` 表(含所有注释和索引)
|
||||||
|
- `im_group_join_requests` 表
|
||||||
|
- `im_message_reads` 表
|
||||||
|
|
||||||
|
2. **ALTER 现有表**
|
||||||
|
- `im_conversation_members` 新增 5 字段:role, nickname, is_muted, is_do_not_disturb, joined_at
|
||||||
|
- `im_messages` 新增 1 字段:at_user_ids (BIGINT[])
|
||||||
|
|
||||||
|
3. **Go Model 文件**
|
||||||
|
- `app/group/model/group.go` — Group 结构体
|
||||||
|
- `app/group/model/join_request.go` — JoinRequest 结构体
|
||||||
|
- `app/im/model/message_read.go` — MessageRead 结构体
|
||||||
|
- `app/im/model/conversation_member.go` — 扩展 ConversationMember 结构体
|
||||||
|
- `app/im/model/message.go` — 扩展 Message 结构体(at_user_ids)
|
||||||
|
|
||||||
|
4. **常量文件**
|
||||||
|
- `app/constants/group.go` — 群角色、群状态、申请状态、系统消息类型
|
||||||
|
|
||||||
|
5. **DTO 文件**
|
||||||
|
- `app/dto/group_dto.go` — 群聊相关 DTO
|
||||||
|
- `app/dto/im_dto.go` — 扩展:已读回执 DTO + ConversationDTO 群聊字段
|
||||||
|
|
||||||
|
6. **GORM AutoMigrate**
|
||||||
|
- `app/provider/wire_gen.go` 中确保新 Model 注册
|
||||||
|
|
||||||
|
### 验收标准
|
||||||
|
|
||||||
|
- 数据库迁移成功,`\d+ im_groups` 等表存在
|
||||||
|
- `go build` 编译通过
|
||||||
|
- 常量和 DTO 定义完整
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 2: Group DAO 层
|
||||||
|
|
||||||
|
**目标:** 实现群聊数据访问层
|
||||||
|
|
||||||
|
### 交付物
|
||||||
|
|
||||||
|
`app/group/dao/group_dao.go`
|
||||||
|
|
||||||
|
| 方法 | 功能 |
|
||||||
|
|------|------|
|
||||||
|
| CreateGroup | 创建 im_groups 记录 |
|
||||||
|
| GetByID | 根据 ID 查群信息 |
|
||||||
|
| GetByConversationID | 根据会话 ID 查群信息 |
|
||||||
|
| UpdateInfo | 更新群名/头像/公告/可搜索性/全体禁言 |
|
||||||
|
| UpdateOwner | 转让群主 |
|
||||||
|
| Dissolve | 解散群(status → 2) |
|
||||||
|
| GetMembers | 获取群成员列表(含用户信息 JOIN auth_users) |
|
||||||
|
| GetMemberRole | 查询用户在群内的角色 |
|
||||||
|
| IsMember | 检查用户是否为群成员 |
|
||||||
|
| AddMembers | 批量添加成员(im_conversation_members) |
|
||||||
|
| RemoveMember | 移除成员(DELETE im_conversation_members) |
|
||||||
|
| UpdateMemberRole | 更新成员角色 |
|
||||||
|
| UpdateMemberMute | 更新成员禁言状态 |
|
||||||
|
| UpdateMemberNickname | 更新群内昵称 |
|
||||||
|
| GetMemberCount | 获取群成员数 |
|
||||||
|
| SearchGroups | 搜索公开群(is_searchable=true,GIN 全文索引) |
|
||||||
|
| GetUserGroups | 获取用户加入的所有群 |
|
||||||
|
| CreateJoinRequest | 创建入群申请 |
|
||||||
|
| GetPendingJoinRequests | 获取待审批申请列表 |
|
||||||
|
| UpdateJoinRequest | 更新申请状态 |
|
||||||
|
| HasPendingRequest | 检查是否有待处理的申请 |
|
||||||
|
|
||||||
|
### 验收标准
|
||||||
|
|
||||||
|
- 所有方法有完整的日志记录(LogFunctionEntry/Exit)
|
||||||
|
- `go build` 编译通过
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 3: Group Service 业务逻辑
|
||||||
|
|
||||||
|
**目标:** 实现群聊核心业务逻辑
|
||||||
|
|
||||||
|
### 交付物
|
||||||
|
|
||||||
|
`app/group/service/group_service.go`
|
||||||
|
|
||||||
|
| 方法 | 功能 | 关键逻辑 |
|
||||||
|
|------|------|----------|
|
||||||
|
| CreateGroup | 创建群聊 | 创建 conversation(type=2) + groups + members,插入系统消息,推送通知 |
|
||||||
|
| GetGroupInfo | 获取群详情 | 包含成员数 |
|
||||||
|
| UpdateGroupInfo | 更新群信息 | 权限校验(群主/管理员),推送 group.info.update |
|
||||||
|
| UpdateNotice | 更新群公告 | 权限校验,插入系统消息,推送 group.notice.update |
|
||||||
|
| DissolveGroup | 解散群聊 | 仅群主,推送 group.dissolved |
|
||||||
|
| InviteMembers | 邀请入群 | 权限校验,检查上限,批量添加,系统消息,推送 group.member.join |
|
||||||
|
| KickMember | 踢人 | 层级权限(群主>管理员>成员),系统消息,推送 group.member.kicked |
|
||||||
|
| LeaveGroup | 退出群 | 群主不能退出(需先转让),系统消息,推送 group.member.leave |
|
||||||
|
| TransferOwner | 转让群主 | 仅群主,修改双方角色 |
|
||||||
|
| SetAdmin | 设置/取消管理员 | 仅群主 |
|
||||||
|
| MuteMember | 禁言/解除 | 群主/管理员(不能禁言同级或上级) |
|
||||||
|
| SetAllMuted | 全体禁言 | 群主/管理员 |
|
||||||
|
| UpdateNickname | 修改群昵称 | 群成员自行修改 |
|
||||||
|
| SearchGroups | 搜索公开群 | 分页 |
|
||||||
|
| ApplyJoin | 申请入群 | 创建申请,推送 group.join.request 给群主/管理员 |
|
||||||
|
| GetJoinRequests | 获取申请列表 | 权限校验 |
|
||||||
|
| ReviewJoinRequest | 审批申请 | 通过→添加成员+系统消息+推送,拒绝→更新状态 |
|
||||||
|
|
||||||
|
**接口依赖:**
|
||||||
|
- `UserInfoGetter` — 获取用户信息(批量)
|
||||||
|
- `PubSub` — 推送通知
|
||||||
|
|
||||||
|
### 验收标准
|
||||||
|
|
||||||
|
- 所有权限校验逻辑完整(群主 > 管理员 > 成员)
|
||||||
|
- 系统消息正确写入 im_messages (type=10)
|
||||||
|
- PubSub 推送事件正确
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 4: Group Controller + Router + Wire
|
||||||
|
|
||||||
|
**目标:** 暴露群聊 REST API 并集成到依赖注入
|
||||||
|
|
||||||
|
### 交付物
|
||||||
|
|
||||||
|
1. **Controller**
|
||||||
|
- `app/group/controller/group_controller.go` — 16 个 REST API 处理函数
|
||||||
|
- 统一使用 `utils.Response*` 系列响应
|
||||||
|
- `handleError` 覆盖所有已知业务错误
|
||||||
|
|
||||||
|
2. **Router**
|
||||||
|
- `app/group/router.go` — 路由注册
|
||||||
|
- 路径前缀 `/api/v1/groups`
|
||||||
|
- JWT 中间件保护
|
||||||
|
|
||||||
|
3. **Wire 集成**
|
||||||
|
- `app/group/provider.go` — GroupSet
|
||||||
|
- `app/provider/wire.go` — 添加 GroupSet + 新接口绑定
|
||||||
|
- `app/provider/wire_gen.go` — 重新生成
|
||||||
|
- `router/router.go` — 注册 group 路由
|
||||||
|
|
||||||
|
### 验收标准
|
||||||
|
|
||||||
|
- `go build` 编译通过
|
||||||
|
- 所有 16 个 API 端点可访问(需 JWT Token)
|
||||||
|
- API 响应格式统一
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 5: WS 群管理事件处理器
|
||||||
|
|
||||||
|
**目标:** 实现群管理相关的 WebSocket 事件推送
|
||||||
|
|
||||||
|
### 交付物
|
||||||
|
|
||||||
|
`app/group/handler/group_handler.go`
|
||||||
|
|
||||||
|
| WS 事件 | 触发时机 | 推送目标 |
|
||||||
|
|---------|----------|----------|
|
||||||
|
| group.member.join | 成员加入 | 群所有成员 |
|
||||||
|
| group.member.leave | 成员退出 | 群所有成员 |
|
||||||
|
| group.member.kicked | 成员被踢 | 群所有成员 + 被踢者 |
|
||||||
|
| group.info.update | 群信息变更 | 群所有成员 |
|
||||||
|
| group.notice.update | 群公告变更 | 群所有成员 |
|
||||||
|
| group.dissolved | 群解散 | 群所有成员 |
|
||||||
|
| group.mute.update | 禁言变更 | 群所有成员 |
|
||||||
|
| group.join.request | 新入群申请 | 群主 + 管理员 |
|
||||||
|
| group.join.approved | 申请通过 | 申请人 |
|
||||||
|
|
||||||
|
**注册方式:** 通过 Hub.RegisterEvent 注册到事件路由表(如有 C→S 事件),S→C 推送通过 PubSub.PublishToUser/PublishToUsers。
|
||||||
|
|
||||||
|
### 验收标准
|
||||||
|
|
||||||
|
- 群管理操作后相关成员能收到实时通知
|
||||||
|
- 系统消息在群聊中正确显示
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 6: IM Service 扩展(群消息 + @提醒 + 管理员撤回)
|
||||||
|
|
||||||
|
**目标:** 扩展现有 IMService 以支持群聊消息场景
|
||||||
|
|
||||||
|
### 交付物
|
||||||
|
|
||||||
|
1. **IMService 方法扩展**
|
||||||
|
|
||||||
|
| 方法 | 变更内容 |
|
||||||
|
|------|----------|
|
||||||
|
| SendMessage | 增加群聊分支:成员校验、禁言检查、批量未读递增、免打扰跳过 Redis |
|
||||||
|
| RecallMessage | 增加群聊分支:管理员可撤回他人消息无时限,撤回展示区分操作者 |
|
||||||
|
| GetConversationList | 增加群聊会话:填充群名/群头像/成员数/免打扰/被@计数 |
|
||||||
|
| GetHistoryMessages | 群聊适配:返回发送者群昵称(优先于全局昵称) |
|
||||||
|
|
||||||
|
2. **新增接口定义**(`app/im/service/im_service.go`)
|
||||||
|
|
||||||
|
```go
|
||||||
|
type GroupMemberChecker interface {
|
||||||
|
IsMember(ctx context.Context, conversationID, userID int64) (bool, error)
|
||||||
|
GetMemberRole(ctx context.Context, conversationID, userID int64) (int, error)
|
||||||
|
IsMuted(ctx context.Context, conversationID, userID int64) (bool, error)
|
||||||
|
IsAllMuted(ctx context.Context, conversationID int64) (bool, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type GroupInfoGetter interface {
|
||||||
|
GetByConversationID(ctx context.Context, conversationID int64) (*GroupBasicInfo, error)
|
||||||
|
GetMemberCount(ctx context.Context, groupID int64) (int, error)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **SendMessage 扩展**
|
||||||
|
- `app/dto/im_dto.go` — SendMessageRequest 新增 at_user_ids 字段
|
||||||
|
- `app/im/handler/event_handler.go` — 适配群消息推送(推给所有群成员)
|
||||||
|
- im.message.new 推送增加 conv_type、at_user_ids 字段
|
||||||
|
|
||||||
|
4. **免打扰逻辑**
|
||||||
|
- 免打扰成员:递增会话 unread_count,不递增 Redis 全局未读
|
||||||
|
- 会话列表中免打扰会话显示灰色未读数
|
||||||
|
|
||||||
|
### 验收标准
|
||||||
|
|
||||||
|
- 群消息发送/撤回功能正常
|
||||||
|
- 禁言用户发消息被拒
|
||||||
|
- @提醒字段正确存储和推送
|
||||||
|
- 免打扰用户不增加全局未读数
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 7: 已读回执后端
|
||||||
|
|
||||||
|
**目标:** 实现已读回执完整后端逻辑
|
||||||
|
|
||||||
|
### 交付物
|
||||||
|
|
||||||
|
1. **ReadDAO**
|
||||||
|
- `app/im/dao/read_dao.go`
|
||||||
|
- BatchCreate(ctx, messageIDs[], userID) — 批量写入已读记录
|
||||||
|
- GetMessageReadUsers(ctx, messageID, page, limit) — 查询已读用户列表
|
||||||
|
- GetMessageReadCount(ctx, messageID) — 查询已读计数
|
||||||
|
- GetBatchReadCounts(ctx, messageIDs[]) — 批量查询已读计数
|
||||||
|
|
||||||
|
2. **IMService 扩展**
|
||||||
|
- MarkRead — 重构:单聊走 last_read_msg_id,群聊写 im_message_reads
|
||||||
|
- GetMessageReadDetail — 已读详情列表(含用户信息)
|
||||||
|
- GetMessageReadCount — 已读/未读计数
|
||||||
|
|
||||||
|
3. **REST API**
|
||||||
|
- GET /api/v1/im/messages/:id/reads — 已读详情
|
||||||
|
- GET /api/v1/im/messages/:id/read-count — 已读计数
|
||||||
|
- Controller + Router 更新
|
||||||
|
|
||||||
|
4. **WS 事件**
|
||||||
|
- im.message.read — 重构:单聊推 read.ack,群聊推 read.count
|
||||||
|
- im.message.read.ack — 单聊实时推送
|
||||||
|
- im.message.read.count — 群聊计数推送
|
||||||
|
|
||||||
|
### 验收标准
|
||||||
|
|
||||||
|
- 单聊:打开会话后对方看到 "已读"
|
||||||
|
- 群聊:打开会话后发送者看到 "X人已读"
|
||||||
|
- 点击 "X人已读" 可查看已读/未读人员列表
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 8: 前端已读回执 UI
|
||||||
|
|
||||||
|
**目标:** 前端实现已读回执展示(使用 ui-ux-pro-max 设计)
|
||||||
|
|
||||||
|
### 交付物
|
||||||
|
|
||||||
|
1. **chat Store 扩展**(`store/chat.js`)
|
||||||
|
- 新增 readStatus 状态管理
|
||||||
|
- WS 监听 im.message.read.ack / im.message.read.count
|
||||||
|
- 打开会话时发送 im.message.read
|
||||||
|
|
||||||
|
2. **单聊已读标记**(修改 `pages/chat/conversation.vue`)
|
||||||
|
- 自己发的消息下方显示 "已读" / "未读"
|
||||||
|
- 基于 last_read_msg_id 判断
|
||||||
|
|
||||||
|
3. **群聊已读计数**(后续 Task 10 的 group/conversation.vue 中实现基础展示)
|
||||||
|
- 消息下方显示 "X人已读"
|
||||||
|
- 点击跳转已读详情页
|
||||||
|
|
||||||
|
4. **已读详情页**(新增 `pages/chat/read-detail.vue`)
|
||||||
|
- Tab 切换:已读 / 未读
|
||||||
|
- 用户列表(头像 + 昵称 + 已读时间)
|
||||||
|
- 调用 GET /api/v1/im/messages/:id/reads
|
||||||
|
|
||||||
|
### 验收标准
|
||||||
|
|
||||||
|
- 单聊对话页正确显示 "已读"/"未读"
|
||||||
|
- 已读详情页正确展示已读/未读人员
|
||||||
|
- 使用 ui-ux-pro-max 设计规范
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 9: 前端群聊 Store + API 封装
|
||||||
|
|
||||||
|
**目标:** 建立前端群聊数据管理层
|
||||||
|
|
||||||
|
### 交付物
|
||||||
|
|
||||||
|
1. **API 封装**
|
||||||
|
- `api/group.js` — 16 个群聊 REST API 封装
|
||||||
|
- `api/file.js` — 文件上传 API 封装
|
||||||
|
|
||||||
|
2. **群聊 Store**(`store/group.js`)
|
||||||
|
- state: groupConversations, currentGroup, groupMessages, groupMembers
|
||||||
|
- actions: loadGroupConversations, sendGroupMessage, loadGroupHistory, ...
|
||||||
|
- WS 监听: im.message.new(conv_type=2), group.* 系列事件
|
||||||
|
- 群消息缓存策略(同 chat.js 模式)
|
||||||
|
|
||||||
|
3. **WS 事件注册**
|
||||||
|
- App.vue `_initGlobalWS` 中初始化 groupStore.initWsListeners()
|
||||||
|
- 处理 group.member.join/leave/kicked/info.update/notice.update/dissolved 等
|
||||||
|
|
||||||
|
### 验收标准
|
||||||
|
|
||||||
|
- API 封装完整,方法命名清晰
|
||||||
|
- Store 能正确管理群聊状态
|
||||||
|
- WS 群管理事件正确触发 Store 更新
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 10: 群聊核心页面(ui-ux-pro-max)
|
||||||
|
|
||||||
|
**目标:** 实现群聊核心交互页面
|
||||||
|
|
||||||
|
### 交付物
|
||||||
|
|
||||||
|
1. **会话列表 Tab 改造**(修改 `pages/chat/index.vue`)
|
||||||
|
- 顶部增加 Tab 切换:单聊 / 群聊
|
||||||
|
- 群聊 Tab 展示群会话列表(群名、群头像、最后消息、未读数)
|
||||||
|
- 免打扰群未读数显示为灰色
|
||||||
|
- 被@标记:"[N条] @了我"
|
||||||
|
|
||||||
|
2. **群聊对话页**(新增 `pages/group/conversation.vue`)
|
||||||
|
- 消息列表(显示发送者昵称 + 头像)
|
||||||
|
- @成员选择器(输入 @ 弹出成员列表)
|
||||||
|
- 消息发送(含 at_user_ids)
|
||||||
|
- 消息撤回(管理员额外权限)
|
||||||
|
- 系统消息特殊展示(居中灰色文字)
|
||||||
|
- "X人已读" 显示 + 点击跳转详情
|
||||||
|
|
||||||
|
3. **创建群聊页**(新增 `pages/group/create.vue`)
|
||||||
|
- 好友列表多选
|
||||||
|
- 搜索用户 ID 添加
|
||||||
|
- 填写群名称
|
||||||
|
- 确认创建
|
||||||
|
|
||||||
|
4. **CustomTabBar 适配**
|
||||||
|
- TabBar 新增或适配群聊入口(如果需要)
|
||||||
|
|
||||||
|
### 验收标准
|
||||||
|
|
||||||
|
- Tab 切换流畅,单聊/群聊列表独立
|
||||||
|
- 群聊对话页消息展示正确
|
||||||
|
- @选择器交互流畅(输入 @ 弹出选择列表)
|
||||||
|
- 创建群聊后自动跳转到群聊对话页
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 11: 群聊管理页面(ui-ux-pro-max)
|
||||||
|
|
||||||
|
**目标:** 实现群聊管理相关页面
|
||||||
|
|
||||||
|
### 交付物
|
||||||
|
|
||||||
|
1. **群设置页**(新增 `pages/group/settings.vue`)
|
||||||
|
- 群信息展示(名称/头像/公告/群 ID)
|
||||||
|
- 群信息编辑(群主/管理员可修改名称/头像/公告)
|
||||||
|
- 成员概览(前 N 个头像 + "查看全部")
|
||||||
|
- 免打扰开关
|
||||||
|
- 群昵称设置
|
||||||
|
- 退出群聊 / 解散群聊
|
||||||
|
|
||||||
|
2. **群成员列表页**(新增 `pages/group/members.vue`)
|
||||||
|
- 完整成员列表
|
||||||
|
- 角色标识(群主皇冠/管理员盾牌/成员无标识)
|
||||||
|
- 管理操作入口(踢人/禁言/设管理员)— 根据当前用户角色显示
|
||||||
|
- 搜索成员
|
||||||
|
|
||||||
|
3. **邀请入群页**(新增 `pages/group/invite.vue`)
|
||||||
|
- 好友列表选择(排除已在群内的)
|
||||||
|
- 搜索用户 ID 添加
|
||||||
|
|
||||||
|
### 验收标准
|
||||||
|
|
||||||
|
- 群设置页信息展示完整
|
||||||
|
- 角色权限控制正确(群主能看到所有管理入口,普通成员看不到)
|
||||||
|
- 邀请页排除已有成员
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 12: 群聊辅助功能(ui-ux-pro-max)
|
||||||
|
|
||||||
|
**目标:** 实现群聊辅助功能页面
|
||||||
|
|
||||||
|
### 交付物
|
||||||
|
|
||||||
|
1. **入群申请审批页**(新增 `pages/group/join-requests.vue`)
|
||||||
|
- 待审批申请列表(申请人信息 + 附言 + 时间)
|
||||||
|
- 通过/拒绝操作
|
||||||
|
- 已处理记录
|
||||||
|
|
||||||
|
2. **搜索群聊页**(新增 `pages/group/search.vue`)
|
||||||
|
- 关键词搜索公开群
|
||||||
|
- 搜索结果:群名、头像、成员数、简介
|
||||||
|
- 申请加入(填写申请附言)
|
||||||
|
- 已加入的群直接进入
|
||||||
|
|
||||||
|
3. **免打扰 UI**
|
||||||
|
- 群设置页免打扰开关
|
||||||
|
- 会话列表免打扰标识(灰色未读数)
|
||||||
|
|
||||||
|
4. **群公告 UI**
|
||||||
|
- 群设置页公告展示 + 编辑
|
||||||
|
- 群公告系统消息展示
|
||||||
|
|
||||||
|
5. **全局消息搜索扩展**(修改 `pages/chat/search.vue`)
|
||||||
|
- 搜索结果包含群聊消息
|
||||||
|
- 结果标识会话类型(单聊/群聊图标)
|
||||||
|
|
||||||
|
### 验收标准
|
||||||
|
|
||||||
|
- 入群审批流程完整(申请→通知→审批→入群)
|
||||||
|
- 群搜索结果准确
|
||||||
|
- 免打扰功能正常
|
||||||
|
- 全局搜索包含群聊消息
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 13: 管理端 + 文档更新 + 代码审查
|
||||||
|
|
||||||
|
**目标:** 管理端群聊管理 + 全量文档同步 + 代码审查
|
||||||
|
|
||||||
|
### 交付物
|
||||||
|
|
||||||
|
1. **管理端后端**
|
||||||
|
- `app/admin/service/group_manage_service.go` — 群列表/详情/解散/移除
|
||||||
|
- `app/admin/controller/group_manage_controller.go` — 4 个 REST API
|
||||||
|
- `app/admin/router.go` — 路由扩展
|
||||||
|
|
||||||
|
2. **管理端前端**
|
||||||
|
- `admin/src/views/group/list.vue` — 群列表页(搜索/分页/状态筛选)
|
||||||
|
- `admin/src/views/group/detail.vue` — 群详情页(成员管理/解散)
|
||||||
|
- `admin/src/api/group.js` — API 封装
|
||||||
|
- 侧边栏菜单添加群聊管理入口
|
||||||
|
|
||||||
|
3. **文档更新**
|
||||||
|
- `docs/progress/CURRENT_STATUS.md` — 进度更新
|
||||||
|
- `.cursor/rules/project-context.mdc` — 记忆更新
|
||||||
|
- `docs/architecture/system-architecture.md` — 架构更新
|
||||||
|
- `docs/plans/2026-02-27-echochat-system-design.md` — 总体设计更新
|
||||||
|
- `docs/api/frontend/im.md` — IM API 文档更新
|
||||||
|
- `docs/api/frontend/group.md` — 新增群聊 API 文档
|
||||||
|
- `docs/api/websocket.md` — WS 事件文档更新
|
||||||
|
- `docs/api/admin/group.md` — 新增管理端群聊 API 文档
|
||||||
|
- `docs/api/README.md` — 导航更新
|
||||||
|
|
||||||
|
4. **代码审查**
|
||||||
|
- 使用 code-reviewer 子代理进行结构化审查
|
||||||
|
- 修复审查发现的问题
|
||||||
|
|
||||||
|
### 验收标准
|
||||||
|
|
||||||
|
- 管理端群列表/详情页功能正常
|
||||||
|
- 管理员可解散群/移除成员
|
||||||
|
- 所有文档与代码保持一致
|
||||||
|
- 代码审查通过
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 实施依赖关系图
|
||||||
|
|
||||||
|
```
|
||||||
|
Task 0 (MinIO) ──────────────────────────────────────────────┐
|
||||||
|
Task 1 (DB迁移) ──┬── Task 2 (Group DAO) ──┬── Task 3 (Group Service) ──┬── Task 4 (Controller+Wire)
|
||||||
|
│ │ └── Task 5 (WS Handler)
|
||||||
|
│ └── Task 6 (IM扩展)
|
||||||
|
└── Task 7 (已读回执后端) ── Task 8 (已读回执前端)
|
||||||
|
│
|
||||||
|
Task 4 + Task 5 ── Task 9 (Store+API) ── Task 10 (核心页面) ── Task 11 (管理页面) ── Task 12 (辅助功能)
|
||||||
|
│
|
||||||
|
Task 0 + Task 12 ── Task 13 (管理端+文档+审查)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 开发注意事项
|
||||||
|
|
||||||
|
1. **代码风格一致性**:严格遵循 Phase 2b 的代码风格(日志记录、错误处理、常量命名、DTO 设计)
|
||||||
|
2. **接口注入模式**:新模块间通信必须走 interface injection,禁止直接 import
|
||||||
|
3. **批量查询优化**:群成员信息获取使用批量查询 + Map 映射,避免 N+1
|
||||||
|
4. **前端设计规范**:所有前端页面使用 ui-ux-pro-max 技能包设计
|
||||||
|
5. **系统消息**:群管理操作产生的系统消息统一使用 type=10(MessageTypeSystem),内容格式化
|
||||||
|
6. **权限层级**:群主(2) > 管理员(1) > 成员(0),操作时必须校验层级
|
||||||
|
7. **Wire 依赖**:Phase 2b 中 Wire 有过手动 patch 历史,注意检查 wire_gen.go 一致性
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
# EchoChat 项目开发进度
|
# EchoChat 项目开发进度
|
||||||
|
|
||||||
> **最后更新**:2026-03-03(Phase 2b 全部完成,含代码审查修复 + 用户测试修复)
|
> **最后更新**:2026-03-04(Phase 2c 设计完成,待实施)
|
||||||
> **当前阶段**:Phase 2b 全部完成,准备进入 Phase 2c
|
> **当前阶段**:Phase 2c 设计完成,准备开始实施
|
||||||
> **当前分支**:`feature/phase2b-instant-messaging`
|
> **当前分支**:`feature/phase2b-instant-messaging`(Phase 2c 分支待创建)
|
||||||
> **实施计划**:`docs/plans/2026-03-03-phase2b-implementation.plan.md`
|
> **实施计划**:`docs/plans/2026-03-04-phase2c-implementation.plan.md`
|
||||||
> **设计文档**:`docs/plans/2026-03-03-phase2b-design.md`
|
> **设计文档**:`docs/plans/2026-03-04-phase2c-design.md`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -237,11 +237,44 @@ cd frontend && npm run dev:h5
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 八、下一阶段规划
|
## 八、下一阶段:Phase 2c — 群聊与已读回执
|
||||||
|
|
||||||
|
> **状态:** 设计完成,待实施
|
||||||
|
> **设计文档:** `docs/plans/2026-03-04-phase2c-design.md`
|
||||||
|
> **实施计划:** `docs/plans/2026-03-04-phase2c-implementation.plan.md`
|
||||||
|
> **分支:** `feature/phase2c-group-read-receipt`(待创建,从 phase2b 拉出)
|
||||||
|
|
||||||
|
### 功能范围
|
||||||
|
|
||||||
|
| 模块 | 内容 |
|
||||||
|
|------|------|
|
||||||
|
| 群聊管理 | 建群/加入/退出/解散/搜索/三级角色/禁言/全体禁言/群公告/群昵称/免打扰 |
|
||||||
|
| 群消息 | 复用 im.message.* 事件 + @某人/@所有人 + 管理员撤回(无时限)+ 系统消息 |
|
||||||
|
| 已读回执 | 单聊会话级(last_read_msg_id)+ 群聊消息级(im_message_reads 表)+ 实时推送 |
|
||||||
|
| MinIO | Docker 容器 + Go SDK + 通用上传 API(群头像) |
|
||||||
|
| 管理端 | 群列表/群详情/解散群/移除成员 |
|
||||||
|
| 前端 | 9 个新页面 + 群聊 Store + 会话列表 Tab 改造 |
|
||||||
|
|
||||||
|
### Task 概览(14 个)
|
||||||
|
|
||||||
|
| Task | 描述 | 状态 |
|
||||||
|
|------|------|------|
|
||||||
|
| Task 0 | MinIO Docker + SDK + 通用上传 API | 📋 |
|
||||||
|
| Task 1 | 数据库迁移 + Model + 常量 | 📋 |
|
||||||
|
| Task 2 | Group DAO 层 | 📋 |
|
||||||
|
| Task 3 | Group Service 业务逻辑 | 📋 |
|
||||||
|
| Task 4 | Group Controller + Router + Wire | 📋 |
|
||||||
|
| Task 5 | WS 群管理事件处理器 | 📋 |
|
||||||
|
| Task 6 | IM Service 扩展(群消息/@提醒/管理员撤回) | 📋 |
|
||||||
|
| Task 7 | 已读回执后端 | 📋 |
|
||||||
|
| Task 8 | 前端已读回执 UI | 📋 |
|
||||||
|
| Task 9 | 前端群聊 Store + API + WS 监听 | 📋 |
|
||||||
|
| Task 10 | 群聊核心页面(Tab + 对话 + 创建) | 📋 |
|
||||||
|
| Task 11 | 群聊管理页面(设置 + 成员 + 邀请 + @选择器) | 📋 |
|
||||||
|
| Task 12 | 群聊辅助功能(审批 + 搜索 + 免打扰 + 公告) | 📋 |
|
||||||
|
| Task 13 | 管理端 + 文档更新 + 代码审查 | 📋 |
|
||||||
|
|
||||||
|
### 留待后续阶段
|
||||||
|
|
||||||
### Phase 2c - 群聊与增强(待规划)
|
|
||||||
- 群聊会话(建群/加入/退出/管理)
|
|
||||||
- 群消息收发
|
|
||||||
- 已读回执(单聊 + 群聊)
|
|
||||||
- 消息类型扩展(图片/语音/文件)
|
- 消息类型扩展(图片/语音/文件)
|
||||||
- 管理端消息管理功能
|
- 管理端消息管理功能
|
||||||
|
|||||||
Reference in New Issue
Block a user