This commit is contained in:
2026-06-01 15:31:49 +08:00
parent 434e874777
commit 55443dac9e
2 changed files with 85 additions and 8 deletions

View File

@@ -2,19 +2,25 @@ package com.ruoyi.oa.im;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.oa.im.mapper.ImBindMapper;
import com.ruoyi.system.mapper.SysUserMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
* 当前用户的 IM 凭据(供 Web SDK 登录)
* 当前用户的 IM 凭据
* 没有绑定时自动给当前 OA 用户注册一个 IM 账号imUserId = "oa_{userId}"),手机号不再是必须。
*/
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/system/user/im")
@@ -23,17 +29,30 @@ public class ImCredentialsController extends BaseController {
private final ImBindMapper bindMapper;
private final OpenImClient openImClient;
private final OpenImProperties props;
private final SysUserMapper userMapper;
/** 当前用户 IM 登录所需信息imUserId + token + apiUrl + wsUrl */
/**
* 获取当前用户 IM 登录所需信息。
* @param platformId 1=iOS 2=Android 3=Windows 4=OSX 5=Web默认 5
*/
@GetMapping("/credentials")
public R<Map<String, Object>> credentials() {
public R<Map<String, Object>> credentials(
@RequestParam(value = "platformId", required = false, defaultValue = "5") int platformId) {
Long userId = LoginHelper.getUserId();
ImBind bind = bindMapper.selectById(userId);
if (bind == null || bind.getImUserId() == null) {
return R.fail("当前账号未绑定 IM");
if (userId == null) {
return R.fail("未登录");
}
// platformId=5: Web
String token = openImClient.issueUserToken(bind.getImUserId(), 5);
ImBind bind = bindMapper.selectById(userId);
if (bind == null || bind.getImUserId() == null || bind.getImUserId().isEmpty()) {
// 自动注册:不再要求手机号
bind = ensureBind(userId);
if (bind == null) {
return R.fail("IM 账号注册失败");
}
}
String token = openImClient.issueUserToken(bind.getImUserId(), platformId);
if (token == null) {
return R.fail("获取 IM token 失败");
}
@@ -44,4 +63,29 @@ public class ImCredentialsController extends BaseController {
data.put("wsUrl", props.getWsUrl());
return R.ok(data);
}
/** 给指定 OA userId 在 OpenIM 主 API 直接注册一个账号并落 bind 表 */
private ImBind ensureBind(Long oaUserId) {
SysUser u = userMapper.selectById(oaUserId);
if (u == null) return null;
String nickname = u.getNickName() != null && !u.getNickName().isEmpty()
? u.getNickName()
: (u.getUserName() != null ? u.getUserName() : ("user" + oaUserId));
String imUserId = "oa_" + oaUserId;
boolean ok = openImClient.registerImUserDirect(imUserId, nickname);
if (!ok) {
log.warn("[IM] registerImUserDirect failed for OA user {}", oaUserId);
return null;
}
ImBind bind = new ImBind();
bind.setUserId(oaUserId);
bind.setPhone(u.getPhonenumber());
bind.setImUserId(imUserId);
bind.setBindStatus(1);
bindMapper.insert(bind);
log.info("[IM] auto-bound OA {} -> IM {}", oaUserId, imUserId);
return bind;
}
}

View File

@@ -205,6 +205,39 @@ public class OpenImClient {
return null;
}
/**
* 直接在 OpenIM 主 API 注册账号(无需手机号、无需 chat 层)。
* 用于给 OA 内部账号(如 admin / 后台账号)建立 IM 账号。
*
* @param imUserId 业务侧自定义的 IM userID建议格式 "oa_{oaUserId}"
* @param nickname 昵称
* @return true 注册成功或已存在false 失败
*/
public boolean registerImUserDirect(String imUserId, String nickname) {
if (!props.isEnabled()) { return false; }
Map<String, Object> user = new HashMap<>();
user.put("userID", imUserId);
user.put("nickname", nickname == null || nickname.isEmpty() ? imUserId : nickname);
user.put("faceURL", "");
Map<String, Object> body = new HashMap<>();
body.put("secret", props.getSecret());
body.put("users", java.util.Collections.singletonList(user));
JSONObject resp = postJson(props.getApiUrl() + "/user/user_register", body, getAdminToken());
Integer errCode = resp.getInteger("errCode");
if (errCode != null && errCode == 0) {
return true;
}
// 已存在通常 errCode 1102 或 20004视为成功
if (errCode != null && (errCode == 1102 || errCode == 20004)) {
log.debug("[OpenIM] imUser {} already exists, ok", imUserId);
return true;
}
log.warn("[OpenIM] registerImUserDirect failed for {}: {}", imUserId, resp);
return false;
}
private static String md5(String text) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");