diff --git a/im-platform/src/main/java/com/bx/implatform/controller/UserController.java b/im-platform/src/main/java/com/bx/implatform/controller/UserController.java index 4731a53..03bafef 100644 --- a/im-platform/src/main/java/com/bx/implatform/controller/UserController.java +++ b/im-platform/src/main/java/com/bx/implatform/controller/UserController.java @@ -18,6 +18,11 @@ import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; +import com.bx.implatform.vo.LoginVO; +import com.bx.implatform.enums.ResultCode; +import com.alibaba.fastjson.JSON; +import com.bx.imcommon.util.JwtUtil; +import com.bx.implatform.config.props.JwtProperties; import java.util.HashMap; import java.util.List; @@ -32,6 +37,7 @@ import static com.bx.implatform.enums.ResultCode.XSS_PARAM_ERROR; public class UserController { private final UserService userService; + private final JwtProperties jwtProperties; @GetMapping("/terminal/online") @Operation(summary = "判断用户哪个终端在线", description = "返回在线的用户id的终端集合") @@ -115,5 +121,49 @@ public class UserController { return ResultUtils.success(); } + + + @PostMapping("/switchAccount") + @Operation(summary = "切换账号", description = "管理员或客服免密切换到其他账号") + public Result switchAccount(@RequestBody JSONObject jsonObject) { + Long targetUserId = jsonObject.getLong("targetUserId"); + Integer terminal = jsonObject.getInt("terminal"); + + // 获取当前登录用户 + UserSession currentSession = SessionContext.getSession(); + User currentUser = userService.getById(currentSession.getUserId()); + + // 权限校验:只有客服才能切换账号 + if (currentUser.getIsCustomer() != 2) { + return ResultUtils.error(XSS_PARAM_ERROR, "无权限切换账号"); + } + + // 获取目标用户信息 + User targetUser = userService.getById(targetUserId); + if (ObjectUtil.isNull(targetUser)) { + return ResultUtils.error(ResultCode.XSS_PARAM_ERROR, "目标用户不存在"); + } + + // 生成新的token + UserSession newSession = BeanUtils.copyProperties(targetUser, UserSession.class); + newSession.setUserId(targetUser.getId()); + newSession.setTerminal(terminal); + String strJson = JSON.toJSONString(newSession); + String accessToken = JwtUtil.sign(targetUser.getId(), strJson, + jwtProperties.getAccessTokenExpireIn(), jwtProperties.getAccessTokenSecret()); + String refreshToken = JwtUtil.sign(targetUser.getId(), strJson, + jwtProperties.getRefreshTokenExpireIn(), jwtProperties.getRefreshTokenSecret()); + + LoginVO vo = new LoginVO(); + vo.setAccessToken(accessToken); + vo.setAccessTokenExpiresIn(jwtProperties.getAccessTokenExpireIn()); + vo.setRefreshToken(refreshToken); + vo.setRefreshTokenExpiresIn(jwtProperties.getRefreshTokenExpireIn()); + vo.setUser(targetUser); + +// log.info("账号切换:从用户 {} 切换到用户 {}", currentSession.getUserId(), targetUserId); + + return ResultUtils.success(vo); + } } diff --git a/im-platform/src/main/java/com/bx/implatform/service/UserService.java b/im-platform/src/main/java/com/bx/implatform/service/UserService.java index 1d8c6db..565c9e0 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/UserService.java +++ b/im-platform/src/main/java/com/bx/implatform/service/UserService.java @@ -115,4 +115,6 @@ public interface UserService extends IService { * @return 客服列表 */ List getEnableChangeCustomerList(Long userId); + + } diff --git a/im-web/src/components/setting/Setting.vue b/im-web/src/components/setting/Setting.vue index ad06382..57a5729 100644 --- a/im-web/src/components/setting/Setting.vue +++ b/im-web/src/components/setting/Setting.vue @@ -1,36 +1,84 @@ \ No newline at end of file diff --git a/im-web/src/main.js b/im-web/src/main.js index 9a95449..7573a82 100644 --- a/im-web/src/main.js +++ b/im-web/src/main.js @@ -36,6 +36,7 @@ Vue.prototype.$str = str; // 字符串相关 Vue.prototype.$elm = element; // 元素操作 Vue.prototype.$enums = enums; // 枚举 Vue.prototype.$eventBus = new Vue(); // 全局事件 + Vue.config.productionTip = false; new Vue({ diff --git a/im-web/src/store/userStore.js b/im-web/src/store/userStore.js index 45a5452..50e7a02 100644 --- a/im-web/src/store/userStore.js +++ b/im-web/src/store/userStore.js @@ -5,17 +5,22 @@ import { RTC_STATE } from "../api/enums.js" export default defineStore('userStore', { state: () => { return { - userInfo: {}, + // 初始化永远从本地存储取 + userInfo: localStorage.getItem('userInfo') + ? JSON.parse(localStorage.getItem('userInfo')) + : {}, rtcInfo: { - friend: {}, // 好友信息 - mode: "video", // 模式 video:视频 voice:语音 - state: RTC_STATE.FREE // FREE:空闲 WAIT_CALL:呼叫方等待 WAIT_ACCEPT: 被呼叫方等待接听 CHATING:聊天中 + friend: {}, + mode: "video", + state: RTC_STATE.FREE } } }, actions: { setUserInfo(userInfo) { - this.userInfo = userInfo + this.userInfo = userInfo; + // 同步本地存储 + localStorage.setItem('userInfo', JSON.stringify(userInfo)); }, setRtcInfo(rtcInfo) { this.rtcInfo = rtcInfo; @@ -25,14 +30,30 @@ export default defineStore('userStore', { }, clear() { this.userInfo = {}; + localStorage.removeItem('userInfo'); + localStorage.removeItem('accessToken'); + localStorage.removeItem('refreshToken'); this.rtcInfo = { friend: {}, mode: "video", state: RTC_STATE.FREE }; }, + + // ============================================== + // 【关键修复】:如果本地已有用户信息,不再重复拉取覆盖! + // ============================================== loadUser() { return new Promise((resolve, reject) => { + // 如果本地已经有账号 → 直接用本地的,不请求接口! + const localUser = localStorage.getItem('userInfo'); + if (localUser && localUser !== '{}') { + this.userInfo = JSON.parse(localUser); + resolve(); + return; + } + + // 只有本地没有时,才去后端获取 http({ url: '/user/self', method: 'GET'