群管理员加入申请改造 (2026-02-25)

数据结构

  • 表:group_admin_join_requests
  • 字段:idgroup_iduser_idrolestatus、时间戳
  • roleuser | artist(记录“申请当时”该用户在群内的 group_user_pivot.role
  • statuspending | canceled | accepted

影响接口

  • POST /api/groups/request_admin_join
  • POST /api/groups/cancel_request_admin_join
  • POST /api/groups/list
  • POST /api/groups/new_groups
  • POST /api/groups/info
  • POST /api/groups/open
  • POST /api/admin_center/work_task/list
  • POST /api/admin_center/profile/job_count
  • POST /api/admin_center/group/join
  • Echo 事件:GroupUpdated / GroupCreated / GroupMessageCreated

变更点

  • request_admin_join 从布尔标记升级为申请记录数组(默认只返回 pending)。
  • 支持多人申请,同一群可有多个申请人。
  • 同一用户同一群仅允许 1 条 pending 申请。
  • 申请时会记录 roleuser/artist)。
  • 返回申请关联数据时,user 补充 artist 关联,便于前端按 role 决定展示 user.name/cnameuser.artist.name/cname
  • 用户执行申请/取消申请后,会更新该用户在 group_user_pivot 中对应群的 order_at_ts
  • 用户执行申请/取消申请后,会触发 GroupUpdated 给该群所有成员(不仅是申请人),用于刷新聊天页 group list。
  • POST /api/groups/info 现已复用与 list/new_groups 相同的组装逻辑(getGroupsByIds + transformGroups),返回结构保持一致。
  • POST /api/groups/info 查询不到可见群时返回 data: null
  • 群相关实时事件消息中的 group 也会返回 request_admin_join(pending 申请数组),与接口数据结构保持一致。
  • 管理员执行 POST /api/admin_center/group/join 后,该群 pending 申请统一改为 accepted

接口示例(详细)

1) 用户发起申请

POST /api/groups/request_admin_join

请求:

{
  "group_id": 123
}

返回:

{
  "ok": true,
  "data": {
    "id": 456,
    "group_id": 123,
    "user_id": 10001,
    "role": "artist",
    "status": "pending",
    "created_at": "2026-02-26T02:10:00.000000Z",
    "updated_at": "2026-02-26T02:10:00.000000Z",
    "user": {
      "id": 10001,
      "name": "user_name",
      "cname": "用户名",
      "avatar_id": 999,
      "language_id": 1,
      "artist": {
        "id": 20001,
        "user_id": 10001,
        "name": "artist_name",
        "cname": "艺术家名",
        "avatar_id": 888
      }
    }
  }
}

2) 用户取消申请(按申请 id)

POST /api/groups/cancel_request_admin_join

请求:

{
  "id": 456
}

效果:

  • 当前用户在该群的 order_at_ts 会更新为当前时间戳(毫秒)。
  • 该群所有成员都会收到 GroupUpdated 事件,前端可直接刷新 group list 排序。

返回:

{
  "ok": true,
  "data": {
    "id": 456,
    "group_id": 123,
    "user_id": 10001,
    "role": "artist",
    "status": "canceled",
    "user": {
      "id": 10001,
      "name": "user_name",
      "cname": "用户名",
      "artist": {
        "id": 20001,
        "name": "artist_name",
        "cname": "艺术家名"
      }
    }
  }
}

3) 群信息类接口返回(list/new_groups/info/open)

  • POST /api/groups/list
  • POST /api/groups/new_groups
  • POST /api/groups/info
  • POST /api/groups/open

返回中的群对象片段:

{
  "id": 123,
  "name": "group_name",
  "request_admin_join": [
    {
      "id": 456,
      "group_id": 123,
      "user_id": 10001,
      "role": "artist",
      "status": "pending",
      "user": {
        "id": 10001,
        "name": "user_name",
        "cname": "用户名",
        "artist": {
          "id": 20001,
          "name": "artist_name",
          "cname": "艺术家名"
        }
      }
    },
    {
      "id": 457,
      "group_id": 123,
      "user_id": 10002,
      "role": "user",
      "status": "pending",
      "user": {
        "id": 10002,
        "name": "normal_user",
        "cname": "普通用户",
        "artist": null
      }
    }
  ]
}

说明:

  • 由于申请/取消会更新 order_at_ts 并触发 GroupUpdated,该群会在 list 中上浮到最前(同 open group 行为)。

3.1) info 返回结构对齐 list

POST /api/groups/info

请求(按 id 查询):

{
  "id": 123
}

请求(按 work_task_id 查询):

{
  "work_task_id": 9001
}

返回(结构与 list/new_groups 中单个群对象一致):

{
  "data": {
    "id": 123,
    "has_new_message": true,
    "request_admin_join": [
      {
        "id": 456,
        "role": "artist",
        "status": "pending",
        "user": {
          "id": 10001,
          "name": "user_name",
          "artist": {
            "id": 20001,
            "name": "artist_name"
          }
        }
      }
    ]
  }
}

无可见群(不存在 / 不在群里)时:

{
  "data": null
}

4) 管理端工单列表

POST /api/admin_center/work_task/list

请求(筛选有管理员申请的群):

{
  "page": 1,
  "size": 20,
  "filter_request_admin_join": true
}

返回片段:

{
  "data": [
    {
      "id": 9001,
      "group": {
        "id": 123,
        "request_admin_join": [
          {
            "id": 456,
            "role": "artist",
            "status": "pending",
            "user": {
              "id": 10001,
              "name": "user_name",
              "artist": {
                "id": 20001,
                "name": "artist_name"
              }
            }
          }
        ]
      }
    }
  ],
  "total": 1
}

5) 管理端计数

POST /api/admin_center/profile/job_count

返回片段:

{
  "data": {
    "join_group": 3
  }
}

说明:join_group 表示“存在至少 1 条 pending 申请的群数量”。

6) 管理员加入群后的状态变化

POST /api/admin_center/group/join

行为:

  • 该群所有 pending 申请改为 accepted
  • 之后群对象 request_admin_join 默认不再返回这些申请(因为只返回 pending)。

7) 群相关 Echo 事件返回

适用事件:

  • GroupUpdated
  • GroupCreated
  • GroupMessageCreated(其 group 字段)

事件 group 片段示例:

{
  "group": {
    "id": 123,
    "request_admin_join": [
      {
        "id": 456,
        "group_id": 123,
        "user_id": 10001,
        "role": "artist",
        "status": "pending",
        "user": {
          "id": 10001,
          "name": "user_name",
          "cname": "用户名",
          "artist": {
            "id": 20001,
            "name": "artist_name",
            "cname": "艺术家名"
          }
        }
      }
    ]
  }
}

兼容性说明

  • 前端不应再把 request_admin_join 当布尔值使用,应按数组处理。
  • 前端可基于 request_admin_join[i].role 决定展示名称来源:
    • artist:优先展示 request_admin_join[i].user.artist.name/cname
    • user:展示 request_admin_join[i].user.name/cname

补充更新:Admin 取消通知模板(2026-02-28)

影响接口

  • POST /api/admin_center/service_request/cancel
  • POST /api/admin_center/work_task/cancel
  • POST /api/admin_center/admin_cancel_notify_templates/list

变更点

  • 管理员取消 service_request/work_task 时,新增可选参数:cancel_notify_template_id
  • cancel_notify_template_id 必须是启用状态(is_active=true)的模板。
  • 新增模板列表接口:POST /api/admin_center/admin_cancel_notify_templates/list
  • 列表接口不分页,且仅返回启用中的模板(按 sort asc, id asc)。
  • 旧接口已移除:
    • POST /api/admin_center/cancel_notify_template/list
    • POST /api/admin_center/admin_cancel_notify_templates/update

通知渲染规则

  • 取消通知仍由 notification_templates 统一管理。
  • admin_canceled 场景模板渲染变量:
    • title 使用 {{ $cancel_reason_title }}
    • content 使用 {{ $cancel_reason }}
  • 业务层会向通知 meta 注入:
    • cancel_notify_template_id
    • cancel_reason_title(多语言)
    • cancel_reason(多语言)
  • 未选择模板时,cancel_reason_title/cancel_reason 会注入空多语言值(zh/en/ja 为空字符串),保证模板可稳定渲染。

请求示例

POST /api/admin_center/service_request/cancel

{
  "id": 123,
  "cancel_notify_template_id": 5
}

POST /api/admin_center/work_task/cancel

{
  "id": 456,
  "cancel_notify_template_id": 5
}

POST /api/admin_center/admin_cancel_notify_templates/list

{}

返回片段示例:

{
  "data": [
    {
      "id": 5,
      "template_key": "operation_expired",
      "title": {
        "zh": "操作失效",
        "en": "Operation expired",
        "ja": "操作失効",
        "_lang": "en"
      },
      "content": {
        "zh": "该操作已失效,系统自动终止。",
        "en": "This operation has expired and was automatically terminated by the system.",
        "ja": "この操作は失効しており、システムにより自動終了されました。",
        "_lang": "en"
      },
      "is_active": true,
      "sort": 5
    }
  ]
}