diff --git a/src/main/java/com/yunhai/userhome/controller/api/MenuBarController.java b/src/main/java/com/yunhai/userhome/controller/api/MenuBarController.java new file mode 100644 index 0000000..4b1d6b9 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/controller/api/MenuBarController.java @@ -0,0 +1,92 @@ +package com.yunhai.userhome.controller.api; + +import com.yunhai.platform.utils.model.BoaUser; +import com.yunhai.userhome.config.Config; +import com.yunhai.userhome.entity.MenuBar; +import com.yunhai.userhome.entity.UserCurrentRole; +import com.yunhai.userhome.service.IMenuBarService; +import com.yunhai.userhome.service.IUserCurrentRoleService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.*; + +/** + * 菜单栏控制器(对齐旧 UserHome contorller.api.MenuBarController)。 + */ +@RestController +@RequestMapping(Config.API_PATH) +public class MenuBarController { + + @Autowired + private IMenuBarService menuBarService; + + @Autowired + private IUserCurrentRoleService userCurrentRoleService; + + @GetMapping("getMenuBarSchList") + public List getMenuBarSchList(BoaUser authUserWithDept) { + UserCurrentRole userCurrentRole = userCurrentRoleService.findById(authUserWithDept.getId()) + .orElseThrow(() -> new com.yunhai.platform.apistd.BizException(com.yunhai.platform.utils.exception.ErrorCode.INTERNAL_SERVER_ERROR)); + return menuBarService.getMenuBarList(userCurrentRole.getSchId()); + } + + @GetMapping("getMenuBarList") + public List getMenuBarList(BoaUser authUserWithDept) { + List result = new ArrayList<>(); + UserCurrentRole userCurrentRole = userCurrentRoleService.findById(authUserWithDept.getId()) + .orElseThrow(() -> new com.yunhai.platform.apistd.BizException(com.yunhai.platform.utils.exception.ErrorCode.INTERNAL_SERVER_ERROR)); + Integer roleId = userCurrentRole.getRoleId(); + if (roleId == 7 || roleId == 2) roleId = 2; + Boolean isSuperAdmin = authUserWithDept.getType() == 1; + List list = menuBarService.findMenuBarById(authUserWithDept.getId()); + for (MenuBar model : list) { + Map map = new HashMap(); + if (!isSuperAdmin && !model.getRoleIds().contains(roleId)) continue; + map.put("id", model.getId()); + map.put("name", model.getName()); + map.put("url", model.getUrl()); + map.put("icon", model.getIcon()); + map.put("isNative", model.getIsNative()); + map.put("isHeader", model.getIsHeader()); + map.put("isBottom", model.getIsBottom()); + map.put("orderNum", model.getOrderNum()); + map.put("openType", model.getLinkOpenType()); + result.add(map); + } + return result; + } + + @PostMapping(value = "saveMenuBar", produces = "application/json") + public void saveMenuBar(BoaUser authUserWithDept, @RequestBody MenuBar menuBar) { + UserCurrentRole userCurrentRole = userCurrentRoleService.findById(authUserWithDept.getId()) + .orElseThrow(() -> new com.yunhai.platform.apistd.BizException(com.yunhai.platform.utils.exception.ErrorCode.INTERNAL_SERVER_ERROR)); + menuBar.setCId(authUserWithDept.getId()); + menuBar.setSchId(userCurrentRole.getSchId()); + if (menuBar.getId() == null) menuBar.setCDate(new Date()); + menuBarService.saveMenuBar(menuBar); + } + + @PostMapping(value = "toggleMenuBarShow", produces = "application/json") + public void toggleMenuBarShow(BoaUser authUserWithDept, Integer id) { + UserCurrentRole userCurrentRole = userCurrentRoleService.findById(authUserWithDept.getId()) + .orElseThrow(() -> new com.yunhai.platform.apistd.BizException(com.yunhai.platform.utils.exception.ErrorCode.INTERNAL_SERVER_ERROR)); + menuBarService.toggleMenuBarShow(id, userCurrentRole.getSchId()); + } + + @PostMapping(value = "saveMenuBarOrderNum", produces = "application/json") + public void saveMenuBarOrderNum(BoaUser authUserWithDept, @RequestBody Map params) { + Integer id = params.get("id"), + orderNum = params.get("orderNum"); + menuBarService.saveMenuBarOrderNum(id, orderNum); + } + + @PostMapping(value = "deleteMenuBar", produces = "application/json") + public void deleteMenuBar(BoaUser authUserWithDept, Integer id) { + menuBarService.deleteMenuBar(id); + } +} diff --git a/src/main/java/com/yunhai/userhome/controller/api/MessageController.java b/src/main/java/com/yunhai/userhome/controller/api/MessageController.java new file mode 100644 index 0000000..05bd3dc --- /dev/null +++ b/src/main/java/com/yunhai/userhome/controller/api/MessageController.java @@ -0,0 +1,111 @@ +package com.yunhai.userhome.controller.api; + +import com.yunhai.platform.utils.model.BoaApp; +import com.yunhai.platform.utils.model.BoaAppType; +import com.yunhai.platform.utils.model.BoaUser; +import com.yunhai.userhome.config.Config; +import com.yunhai.userhome.entity.UserMessage; +import com.yunhai.userhome.service.AppRemoteService; +import com.yunhai.userhome.service.IUserMessageService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * 消息中心接口(CAS 登录态,路径 {@code /{platform}/}),对齐旧 UserHome MessageController 契约。 + *

响应字段与旧版 {@code getMessageByUserId} 完全一致:{id,msg,date,name,avatar,appPath,msgType}。

+ */ +@RestController +@RequestMapping(value = Config.API_PATH) +public class MessageController { + + @Autowired + private IUserMessageService userMessageService; + + @Autowired + private AppRemoteService appRemoteService; + + /** schId=0 时推断:主学校 → 主归属组(bureau)→ 0(对齐旧版 school.id→bureau.id→0)。 */ + private Integer resolveSchId(BoaUser user) { + if (user.getSchool() != null) { + return user.getSchool().getId(); + } + if (user.getBureau() != null) { + return user.getBureau().getId(); + } + return 0; + } + + private List flattenApps(BoaUser user) { + List types = appRemoteService.getUserApps(user); + if (types == null) { + return new ArrayList<>(); + } + List apps = new ArrayList<>(); + for (BoaAppType t : types) { + if (t.getApps() != null) { + apps.addAll(t.getApps()); + } + } + return apps; + } + + // 获取个人最近消息(对齐旧 getMessageByUserId,响应 List,字段逐字核对) + @GetMapping("getMessageByUserId") + public List> getMessageByUserId(BoaUser authUserWithDept, Integer page, Integer count) { + Integer userId = authUserWithDept.getId(); + Integer schId = resolveSchId(authUserWithDept); + + List msgList = userMessageService.findUserMessageByUserId(userId); + Collections.reverse(msgList); + + List appList = flattenApps(authUserWithDept); + + List> list = new ArrayList<>(); + for (UserMessage msg : msgList) { + Optional boaApp = appList.stream().filter(x -> x.getId() != null && x.getId().equals(msg.getAppId())).findFirst(); + if (!boaApp.isPresent()) { + continue; + } + BoaApp model = boaApp.get(); + Map map = new HashMap<>(); + map.put("id", msg.getId()); + map.put("msg", msg.getContent()); + map.put("date", msg.getCDate()); + map.put("name", model.getName()); + map.put("avatar", model.getIcon()); + map.put("appPath", model.getWebAddr()); + map.put("msgType", model.getType()); + list.add(map); + } + return list; + } + + // 已读消息(对齐旧 readMessage,POST,参数 id,返回 void) + @PostMapping("readMessage") + public void readMessage(BoaUser authUserWithDept, Integer id) { + userMessageService.updateUserRead(id, authUserWithDept.getId()); + } + + // 全部已读消息(对齐旧 readMessageAll,POST 无参,返回 void) + @PostMapping("readMessageAll") + public void readMessageAll(BoaUser authUserWithDept) { + userMessageService.updateReadAll(authUserWithDept.getId()); + } + + // 是否有新消息(对齐旧 findUserMessageUnRead,GET,返回 Boolean) + @GetMapping("findUserMessageUnRead") + public Boolean findUserMessageUnRead(BoaUser authUserWithDept) { + return userMessageService.findUserMessageUnRead(authUserWithDept.getId()); + } +} diff --git a/src/main/java/com/yunhai/userhome/controller/api/MiscController.java b/src/main/java/com/yunhai/userhome/controller/api/MiscController.java new file mode 100644 index 0000000..a1aba21 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/controller/api/MiscController.java @@ -0,0 +1,58 @@ +package com.yunhai.userhome.controller.api; + +import com.yunhai.platform.apistd.BizException; +import com.yunhai.platform.openapi.client.YschBaseOpenApi; +import com.yunhai.platform.utils.exception.ErrorCode; +import com.yunhai.platform.utils.model.BoaUser; +import com.yunhai.userhome.config.Config; +import com.yunhai.userhome.utils.OtherUtil; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.view.RedirectView; + +import java.util.Map; + +/** + * 承载旧后端 UserController 中挂在扁平路径 {@code /{platform}/} 下的端点。 + * + *

新后端 UserController 已改为 {@code /{platform}/user/} 前缀, + * 但以下两个端点的前端调用路径是扁平的(不含 /user/ 段),故单独抽出: + *

    + *
  • {@code POST /api/updateUserPassword} — 前端 BaseApi.updatePassword
  • + *
  • {@code GET /api/RedirectTo/{hexUrl}} — 前端 bschSsoRedirect.replaceOriginUrl
  • + *
+ */ +@RestController +@RequestMapping(value = Config.API_PATH) +public class MiscController { + + /** + * 修改用户密码(对齐旧 UserController.updateUserPassword)。 + * 前端调用:BaseApi.updatePassword → POST /api/updateUserPassword + */ + @PostMapping("updateUserPassword") + public void updateUserPassword(BoaUser authUserWithDept, @RequestBody Map params) { + String password = params.get("password"); + String oldPassword = params.get("oldPassword"); + if (password == null || password.trim().isEmpty() || oldPassword == null || oldPassword.trim().isEmpty()) { + throw new BizException(ErrorCode.PARAM_ERROR, "密码参数不能为空"); + } + if (password.equals(oldPassword)) { + throw new BizException(ErrorCode.CUSTOM, "新密码不得与旧密码相同!"); + } + try { + YschBaseOpenApi.updateUserPassword(authUserWithDept.getId(), oldPassword, password); + } catch (Exception e) { + throw new BizException(ErrorCode.CUSTOM, e.getMessage()); + } + } + + /** + * 十六进制 URL 重定向(对齐旧 UserController.RedirectTo)。 + * 前端调用:bschSsoRedirect.replaceOriginUrl → GET /api/RedirectTo/{hexUrl} + */ + @GetMapping("RedirectTo/{id}") + public RedirectView redirectTo(@PathVariable(name = "id") String id) { + String url = OtherUtil.hexToString(id); + return new RedirectView(url, true); + } +} diff --git a/src/main/java/com/yunhai/userhome/controller/api/SchSettingsController.java b/src/main/java/com/yunhai/userhome/controller/api/SchSettingsController.java new file mode 100644 index 0000000..4724a88 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/controller/api/SchSettingsController.java @@ -0,0 +1,84 @@ +package com.yunhai.userhome.controller.api; + +import com.yunhai.platform.utils.model.BoaUser; +import com.yunhai.userhome.config.Config; +import com.yunhai.userhome.entity.SchSettings; +import com.yunhai.userhome.service.ISchSettingsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Date; +import java.util.Optional; + +/** + * 学校设置接口(CAS 登录态,路径 {@code /{platform}/}),对齐旧 UserHome SchSettingsController。 + *

getSchSettings 实际跨仓调用 schConfig(见 SchSettingsServiceImpl); + * saveSchTheme/saveSchLogo(P1)本期写入本地 sch_settings 表(跨仓回写可后续对接)。

+ */ +@RestController +@RequestMapping(value = Config.API_PATH) +public class SchSettingsController { + + @Autowired + private ISchSettingsService schSettingsService; + + private Integer resolveSchId(BoaUser user) { + if (user.getSchool() != null) { + return user.getSchool().getId(); + } + if (user.getBureau() != null) { + return user.getBureau().getId(); + } + return 0; + } + + @PostMapping("saveSchTheme") + public void saveSchTheme(BoaUser authUserWithDept, String themeName, @RequestParam(name = "schId", defaultValue = "0") Integer schId) { + if (schId == null || schId == 0) { + schId = resolveSchId(authUserWithDept); + } + SchSettings schSettings = new SchSettings(); + Optional model = schSettingsService.findBySchId(schId); + if (model.isPresent()) { + schSettings = model.get(); + } + schSettings.setCDate(new Date()); + schSettings.setSchId(schId); + schSettings.setCId(authUserWithDept.getId()); + schSettings.setThemeName(themeName); + schSettingsService.save(schSettings); + } + + @PostMapping("saveSchLogo") + public void saveSchLogo(BoaUser authUserWithDept, String logoUrl, @RequestParam(name = "schId", defaultValue = "0") Integer schId) { + if (schId == null || schId == 0) { + schId = resolveSchId(authUserWithDept); + } + SchSettings schSettings = newSchSettingsOrLoad(schId, authUserWithDept); + schSettings.setLogoUrl(logoUrl); + schSettingsService.save(schSettings); + } + + /** getSchSettings:schId=0 时按 主学校→主归属组→0 推断(对齐旧 SchSettingsController)。 */ + @GetMapping("getSchSettings") + public Optional getSchSettings(BoaUser authUserWithDept, + @RequestParam(name = "schId", defaultValue = "0") Integer schId) { + if (schId == null || schId == 0) { + schId = resolveSchId(authUserWithDept); + } + return schSettingsService.findBySchId(schId); + } + + private SchSettings newSchSettingsOrLoad(Integer schId, BoaUser user) { + Optional model = schSettingsService.findBySchId(schId); + SchSettings schSettings = model.orElseGet(SchSettings::new); + schSettings.setCDate(new Date()); + schSettings.setSchId(schId); + schSettings.setCId(user.getId()); + return schSettings; + } +} diff --git a/src/main/java/com/yunhai/userhome/controller/api/SocketController.java b/src/main/java/com/yunhai/userhome/controller/api/SocketController.java new file mode 100644 index 0000000..7c8c8aa --- /dev/null +++ b/src/main/java/com/yunhai/userhome/controller/api/SocketController.java @@ -0,0 +1,33 @@ +package com.yunhai.userhome.controller.api; + +import com.yunhai.platform.utils.model.BoaUser; +import com.yunhai.userhome.config.Config; +import com.yunhai.userhome.utils.MapCacheUtil; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.UUID; + +/** + * WebSocket 鉴权地址端点(CAS 登录态,路径 {@code /{platform}/})。 + *

对齐旧 UserHome SocketController.getMsgAddress:生成 uuid → 缓存(uuid→userId, 20s) → + * 返回 {@code {WEBSOCKET_URL}/{uuid}},供前端握手阶段鉴权。WS 推送服务端本期可后置, + * 前端改轮询 {@code getMessageByUserId} 兜底刷新。

+ */ +@RestController +@RequestMapping(value = Config.API_PATH) +public class SocketController { + + @Value("${WEBSOCKET_URL:ws://localhost:8091/ws}") + private String websocketUrl; + + @GetMapping("getMsgAddress") + public String getMsgAddress(BoaUser authUserWithDept) { + Integer uid = authUserWithDept.getId(); + UUID uuid = UUID.randomUUID(); + MapCacheUtil.getInstance().add(uuid.toString(), uid.toString(), 20 * 1000L); + return this.websocketUrl + "/" + uuid.toString(); + } +} diff --git a/src/main/java/com/yunhai/userhome/controller/api/StatsBarController.java b/src/main/java/com/yunhai/userhome/controller/api/StatsBarController.java new file mode 100644 index 0000000..3660957 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/controller/api/StatsBarController.java @@ -0,0 +1,88 @@ +package com.yunhai.userhome.controller.api; + +import com.yunhai.platform.utils.model.BoaUser; +import com.yunhai.userhome.config.Config; +import com.yunhai.userhome.entity.StatsBar; +import com.yunhai.userhome.entity.UserCurrentRole; +import com.yunhai.userhome.service.IStatsBarService; +import com.yunhai.userhome.service.IUserCurrentRoleService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.*; + +/** + * 统计栏目控制器(对齐旧 UserHome contorller.api.StatsBarController)。 + */ +@RestController +@RequestMapping(Config.API_PATH) +public class StatsBarController { + + @Autowired + private IStatsBarService statsBarService; + + @Autowired + private IUserCurrentRoleService userCurrentRoleService; + + @GetMapping("getStatsBarSchList") + public List getStatsBarSchList(BoaUser authUserWithDept) { + UserCurrentRole userCurrentRole = userCurrentRoleService.findById(authUserWithDept.getId()) + .orElseThrow(() -> new com.yunhai.platform.apistd.BizException(com.yunhai.platform.utils.exception.ErrorCode.INTERNAL_SERVER_ERROR)); + return statsBarService.getStatsBarList(userCurrentRole.getSchId()); + } + + @GetMapping("getStatsBarList") + public List getStatsBarList(BoaUser authUserWithDept) { + List result = new ArrayList<>(); + UserCurrentRole userCurrentRole = userCurrentRoleService.findById(authUserWithDept.getId()) + .orElseThrow(() -> new com.yunhai.platform.apistd.BizException(com.yunhai.platform.utils.exception.ErrorCode.INTERNAL_SERVER_ERROR)); + Integer roleId = userCurrentRole.getRoleId(); + if (roleId == 7 || roleId == 2) roleId = 2; + Boolean isSuperAdmin = authUserWithDept.getType() == 1; + List list = statsBarService.findStatsBarById(authUserWithDept.getId()); + for (StatsBar model : list) { + Map map = new HashMap(); + if (!isSuperAdmin && !model.getRoleIds().contains(roleId)) continue; + map.put("id", model.getId()); + map.put("name", model.getName()); + map.put("url", model.getUrl()); + map.put("icon", model.getIcon()); + map.put("openType", model.getLinkOpenType()); + result.add(map); + } + return result; + } + + @PostMapping(value = "saveStatsBar", produces = "application/json") + public void saveStatsBar(BoaUser authUserWithDept, @RequestBody StatsBar statsBar) { + UserCurrentRole userCurrentRole = userCurrentRoleService.findById(authUserWithDept.getId()) + .orElseThrow(() -> new com.yunhai.platform.apistd.BizException(com.yunhai.platform.utils.exception.ErrorCode.INTERNAL_SERVER_ERROR)); + statsBar.setCId(authUserWithDept.getId()); + statsBar.setSchId(userCurrentRole.getSchId()); + if (statsBar.getId() == null) statsBar.setCDate(new Date()); + statsBarService.saveStatsBar(statsBar); + } + + @PostMapping(value = "toggleStatsBarShow", produces = "application/json") + public void toggleStatsBarShow(BoaUser authUserWithDept, Integer id) { + UserCurrentRole userCurrentRole = userCurrentRoleService.findById(authUserWithDept.getId()) + .orElseThrow(() -> new com.yunhai.platform.apistd.BizException(com.yunhai.platform.utils.exception.ErrorCode.INTERNAL_SERVER_ERROR)); + statsBarService.toggleStatsBarShow(id, userCurrentRole.getSchId()); + } + + @PostMapping(value = "saveStatsBarOrderNum", produces = "application/json") + public void saveStatsBarOrderNum(BoaUser authUserWithDept, @RequestBody Map params) { + Integer id = params.get("id"), + orderNum = params.get("orderNum"); + statsBarService.saveStatsBarOrderNum(id, orderNum); + } + + @PostMapping(value = "deleteStatsBar", produces = "application/json") + public void deleteStatsBar(BoaUser authUserWithDept, Integer id) { + statsBarService.deleteStatsBar(id); + } +} diff --git a/src/main/java/com/yunhai/userhome/controller/api/TeacherCopilotController.java b/src/main/java/com/yunhai/userhome/controller/api/TeacherCopilotController.java new file mode 100644 index 0000000..c6813f3 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/controller/api/TeacherCopilotController.java @@ -0,0 +1,89 @@ +package com.yunhai.userhome.controller.api; + +import com.yunhai.platform.utils.model.BoaUser; +import com.yunhai.userhome.config.Config; +import com.yunhai.userhome.entity.TeacherCopilot; +import com.yunhai.userhome.entity.UserCurrentRole; +import com.yunhai.userhome.service.ITeacherCopilotService; +import com.yunhai.userhome.service.IUserCurrentRoleService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.*; + +/** + * 教师助手控制器(对齐旧 UserHome contorller.api.TeacherCopilotController)。 + */ +@RestController +@RequestMapping(Config.API_PATH) +public class TeacherCopilotController { + + @Autowired + private ITeacherCopilotService teacherCopilotService; + + @Autowired + private IUserCurrentRoleService userCurrentRoleService; + + @GetMapping("TeacherCopilot/getSchList") + public List getList(BoaUser authUserWithDept) { + UserCurrentRole userCurrentRole = userCurrentRoleService.findById(authUserWithDept.getId()) + .orElseThrow(() -> new com.yunhai.platform.apistd.BizException(com.yunhai.platform.utils.exception.ErrorCode.INTERNAL_SERVER_ERROR)); + return teacherCopilotService.getList(userCurrentRole.getSchId()); + } + + @GetMapping("TeacherCopilot/getUserList") + public List getUserList(BoaUser authUserWithDept) { + List result = new ArrayList<>(); + UserCurrentRole userCurrentRole = userCurrentRoleService.findById(authUserWithDept.getId()) + .orElseThrow(() -> new com.yunhai.platform.apistd.BizException(com.yunhai.platform.utils.exception.ErrorCode.INTERNAL_SERVER_ERROR)); + Integer roleId = userCurrentRole.getRoleId(); + if (roleId == 7 || roleId == 2) roleId = 2; + Boolean isSuperAdmin = authUserWithDept.getType() == 1; + List list = teacherCopilotService.findById(authUserWithDept.getId()); + for (TeacherCopilot model : list) { + TeacherCopilot.Dto dto = new TeacherCopilot.Dto(); + if (!isSuperAdmin && !model.getRoleIds().contains(roleId)) continue; + dto.setId(model.getId()); + dto.setName(model.getName()); + dto.setUrl(model.getUrl()); + dto.setIcon(model.getIcon()); + dto.setOpenType(model.getLinkOpenType()); + dto.setType(model.getType()); + result.add(dto); + } + return result; + } + + @PostMapping(value = "TeacherCopilot/save", produces = "application/json") + public void save(BoaUser authUserWithDept, @RequestBody TeacherCopilot teacherCopilot) { + UserCurrentRole userCurrentRole = userCurrentRoleService.findById(authUserWithDept.getId()) + .orElseThrow(() -> new com.yunhai.platform.apistd.BizException(com.yunhai.platform.utils.exception.ErrorCode.INTERNAL_SERVER_ERROR)); + teacherCopilot.setCId(authUserWithDept.getId()); + teacherCopilot.setSchId(userCurrentRole.getSchId()); + if (teacherCopilot.getId() == null) teacherCopilot.setCDate(new Date()); + teacherCopilotService.save(teacherCopilot); + } + + @PostMapping(value = "TeacherCopilot/toggleShow", produces = "application/json") + public void toggleShow(BoaUser authUserWithDept, Integer id) { + UserCurrentRole userCurrentRole = userCurrentRoleService.findById(authUserWithDept.getId()) + .orElseThrow(() -> new com.yunhai.platform.apistd.BizException(com.yunhai.platform.utils.exception.ErrorCode.INTERNAL_SERVER_ERROR)); + teacherCopilotService.toggleShow(id, userCurrentRole.getSchId()); + } + + @PostMapping(value = "TeacherCopilot/saveOrderNum", produces = "application/json") + public void saveOrderNum(BoaUser authUserWithDept, @RequestBody Map params) { + Integer id = params.get("id"), + orderNum = params.get("orderNum"); + teacherCopilotService.saveOrderNum(id, orderNum); + } + + @PostMapping(value = "TeacherCopilot/delete", produces = "application/json") + public void delete(BoaUser authUserWithDept, Integer id) { + teacherCopilotService.delete(id); + } +} diff --git a/src/main/java/com/yunhai/userhome/controller/api/UserSettingsController.java b/src/main/java/com/yunhai/userhome/controller/api/UserSettingsController.java new file mode 100644 index 0000000..238cb08 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/controller/api/UserSettingsController.java @@ -0,0 +1,428 @@ +package com.yunhai.userhome.controller.api; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.yunhai.platform.apistd.BizException; +import com.yunhai.platform.openapi.client.YschBaseOpenApi; +import com.yunhai.platform.utils.enums.ClientEnum; +import com.yunhai.platform.utils.exception.ErrorCode; +import com.yunhai.platform.utils.model.BoaApp; +import com.yunhai.platform.utils.model.BoaAppType; +import com.yunhai.platform.utils.model.BoaUser; +import com.yunhai.userhome.config.Config; +import com.yunhai.userhome.entity.*; +import com.yunhai.userhome.enums.DesktopAppType; +import com.yunhai.userhome.enums.LightAppGroup; +import com.yunhai.userhome.enums.LinkOpenType; +import com.yunhai.userhome.service.IUserCurrentRoleService; +import com.yunhai.userhome.service.IUserSettingsService; +import com.yunhai.userhome.service.UsedAppService; +import com.yunhai.userhome.utils.EnumUtil; +import com.yunhai.userhome.utils.FileUtil; +import com.yunhai.userhome.utils.OtherUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 用户设置控制器(对齐旧 UserHome contorller.api.UserSettingsController)。 + * + *

待确认接口(已写入待确认清单): + *

    + *
  • getUserSettings 中 bschBaseOpenApi.getPcGrzxPage —— 新框架 YschBaseOpenApi 是否有此方法待确认
  • + *
  • GetSchSettingsWallpaper 依赖 SCH_CONF_URL —— 需确认环境地址
  • + *
+ */ +@RestController +@RequestMapping(Config.API_PATH) +public class UserSettingsController { + + @Value("${FILE_PATH:./upload/}") + private String FILE_PATH; + + @Value("${FILE_WEB_PATH:}") + private String FILE_WEB_PATH; + + @Value("${SCH_CONF_URL:}") + private String SCH_CONF_URL; + + @Autowired + private IUserSettingsService userSettingsService; + + @Autowired + private IUserCurrentRoleService userCurrentRoleService; + + @Autowired + private UsedAppService usedAppService; + + private final RestTemplate restTemplate = new RestTemplate(); + private final ObjectMapper objectMapper = new ObjectMapper(); + + // ==================== 壁纸 ==================== + + @PostMapping(value = "wallpaperUpload", produces = "application/json") + public void wallpaperUpload(BoaUser authUserWithDept, @RequestParam("file") MultipartFile file) { + String uploadUrl = this.upload(file, "wallpaper"); + UserCurrentRole currentRole = userCurrentRoleService.findById(authUserWithDept.getId()) + .orElseThrow(() -> new BizException(ErrorCode.INTERNAL_SERVER_ERROR)); + Integer type = authUserWithDept.getType() == 1 ? 0 : OtherUtil.isAdminById(currentRole.getRoleId()) ? 1 : 2; + Wallpaper wallpaper = new Wallpaper(); + wallpaper.setSchId(currentRole.getSchId()); + wallpaper.setWallpaperUrl(uploadUrl); + wallpaper.setUserId(authUserWithDept.getId()); + wallpaper.setType(type); + userSettingsService.saveWallpaper(wallpaper); + } + + @PostMapping(value = "iconUpload", produces = "application/json") + public String iconUpload(BoaUser authUserWithDept, @RequestParam("file") MultipartFile file) { + return this.upload(file, "icon"); + } + + @PostMapping(value = "deleteWallById", produces = "application/json") + public void deleteWallById(BoaUser authUserWithDept, Integer id) { + userSettingsService.deleteWallById(id); + } + + @PostMapping(value = "checkWallpaper", produces = "application/json") + public void checkWallpaper(BoaUser authUserWithDept, @RequestBody Map res) { + String wallpaperUrl = res.get("wallpaperUrl").toString(); + userSettingsService.checkWallpaper(authUserWithDept.getId(), wallpaperUrl); + } + + @GetMapping(value = "getUserWallpaperList") + public List getUserWallpaperList(BoaUser authUserWithDept, Integer schId) { + List result = new ArrayList<>(); + List list = userSettingsService.findWallList(authUserWithDept.getId()); + list = list.stream().sorted(Comparator.comparing(Wallpaper::getId).reversed()).collect(Collectors.toList()); + list.forEach(model -> { + Map map = new HashMap(); + map.put("id", model.getId()); + map.put("url", FILE_WEB_PATH + model.getWallpaperUrl().replace("/upload", "")); + map.put("type", model.getType()); + map.put("isEdit", model.getIsEdit()); + result.add(map); + }); + if (authUserWithDept.getType() != 1 && !list.stream().anyMatch(x -> x.getType() == 1)) { + List schList = getSchSettingsWallpaper(schId); + for (String schWall : schList) { + Map map = new HashMap(); + map.put("id", null); + map.put("type", 1); + map.put("url", schWall); + map.put("isEdit", false); + result.add(map); + } + } + return result; + } + + // ==================== 用户设置 ==================== + + @GetMapping(value = "getUserSettings") + public UserSettings getUserSettings(BoaUser authUserWithDept) { + UserCurrentRole currentRole = userCurrentRoleService.findById(authUserWithDept.getId()) + .orElseThrow(() -> new BizException(ErrorCode.INTERNAL_SERVER_ERROR)); + Integer schId = currentRole.getSchId(); + UserSettings model = new UserSettings(); + Optional optional = userSettingsService.findUserSettings(authUserWithDept.getId()); + // TODO 待确认:bschBaseOpenApi.getPcGrzxPage —— 新框架 YschBaseOpenApi 是否有此方法待确认 + // List appPageList = bschBaseOpenApi.getPcGrzxPage(authUserWithDept.getId(), schId); + List appPageList = Collections.emptyList(); + if (optional.isPresent()) model = optional.get(); + if (model.getWallpaperUrl() == null || model.getWallpaperUrl().isEmpty()) { + List schList = getSchSettingsWallpaper(schId); + if (schList.size() > 0) model.setWallpaperUrl(schList.get(0)); + } + List mapList = appPageList.stream().map(boaApp -> { + Map map = new HashMap<>(); + map.put("id", boaApp.getId()); + map.put("appId", boaApp.getId()); + map.put("name", boaApp.getName()); + map.put("url", boaApp.getWebAddr()); + return map; + }).collect(Collectors.toList()); + + model.setWidgetAppList(mapList); + return model; + } + + @GetMapping(value = "getUserDesktopAppList") + public List getUserDesktopAppList(BoaUser authUserWithDept) { + UserCurrentRole currentRole = userCurrentRoleService.findById(authUserWithDept.getId()) + .orElseThrow(() -> new BizException(ErrorCode.INTERNAL_SERVER_ERROR)); + Optional optional = userSettingsService.findUserSettings(authUserWithDept.getId()); + Integer schId = currentRole.getSchId(), userId = currentRole.getUserId(); + UserSettings model = new UserSettings(); + List desktopAppList = new ArrayList<>(); + List result = new ArrayList<>(); + if (optional.isPresent()) model = optional.get(); + // 初始化设置为常用应用 + if (model.getDesktopApps().isEmpty()) desktopAppList = getUserUsedByUserId(authUserWithDept.getId()); + else desktopAppList = model.getDesktopApps(); + + List bschAllList = new ArrayList<>(); + List lightAllList = new ArrayList<>(); + List bschAppIds = desktopAppList.stream() + .filter(x -> x.getAppType() == DesktopAppType.Bsch) + .map(UserSettingsDesktopApp::getAppId) + .collect(Collectors.toList()); + List lightAppIds = desktopAppList.stream() + .filter(x -> x.getAppType() == DesktopAppType.Light) + .map(UserSettingsDesktopApp::getAppId) + .collect(Collectors.toList()); + if (bschAppIds.size() > 0) { + List appTypeList = YschBaseOpenApi.getUserApp(authUserWithDept.getId(), ClientEnum.PC_BROWSER); + for (BoaAppType mode : appTypeList) bschAllList.addAll(mode.getApps()); + } + if (lightAppIds.size() > 0) { + lightAllList = userSettingsService.findLightAppList(schId, userId); + } + desktopAppList = desktopAppList.stream() + .sorted(Comparator.comparing(UserSettingsDesktopApp::getOrderNum, Comparator.nullsLast(Integer::compareTo))) + .collect(Collectors.toList()); + for (UserSettingsDesktopApp desktopApp : desktopAppList) { + Map map = new HashMap(); + map.put("id", desktopApp.getId()); + map.put("appId", desktopApp.getAppId()); + if (desktopApp.getAppType() == DesktopAppType.Bsch) { + Optional optionalBoaApp = bschAllList.stream() + .filter(boa -> desktopApp.getAppId().equals(boa.getId())).findFirst(); + if (!optionalBoaApp.isPresent()) continue; + map.put("name", optionalBoaApp.get().getName()); + map.put("icon", optionalBoaApp.get().getIcon()); + map.put("url", optionalBoaApp.get().getWebAddr()); + map.put("type", DesktopAppType.Bsch.getKey()); + map.put("linkType", LinkOpenType.Open.getKey()); + map.put("layout", null); + } else if (desktopApp.getAppType() == DesktopAppType.Light) { + Optional optionalLightApp = lightAllList.stream() + .filter(app -> desktopApp.getAppId().equals(app.getId())).findFirst(); + if (!optionalLightApp.isPresent()) continue; + map.put("name", optionalLightApp.get().getName()); + map.put("icon", optionalLightApp.get().getIcon()); + map.put("url", optionalLightApp.get().getUrl()); + map.put("type", DesktopAppType.Light.getKey()); + map.put("linkType", optionalLightApp.get().getLinkOpenType()); + map.put("layout", optionalLightApp.get().getLayout()); + } + result.add(map); + } + return result; + } + + @PostMapping(value = "saveUserWidget", produces = "application/json") + public void saveUserWidget(BoaUser authUserWithDept, @RequestBody UserSettings userSettings) { + userSettings.setUserId(authUserWithDept.getId()); + userSettingsService.saveUserWidget(userSettings); + } + + @PostMapping(value = "toggleWidgetShow", produces = "application/json") + public void toggleWidgetShow(BoaUser authUserWithDept, @RequestBody Map params) { + Integer id = params.get("id"); + userSettingsService.toggleWidgetShow(id, authUserWithDept.getId()); + } + + @PostMapping(value = "saveUserAppIds", produces = "application/json") + public void saveUserAppIds(BoaUser authUserWithDept, @RequestBody Map params) { + Integer id = null; + if (params.get("id") != null) id = Integer.parseInt(params.get("id")); + String appIds = params.get("appIds"); + userSettingsService.saveUserAppIds(id, authUserWithDept.getId(), appIds); + } + + // ==================== 轻应用 ==================== + + @GetMapping(value = "getLightAppGroup") + public Object getLightAppGroup(BoaUser authUserWithDept) { + return EnumUtil.toMapList(LightAppGroup.class); + } + + @GetMapping(value = "getLightAppList", produces = "application/json") + public List getLightAppList(BoaUser authUserWithDept) { + UserCurrentRole currentRole = userCurrentRoleService.findById(authUserWithDept.getId()) + .orElseThrow(() -> new BizException(ErrorCode.INTERNAL_SERVER_ERROR)); + Integer schId, userId = null; + if (authUserWithDept.getType() == 1) { + schId = 0; + } else if (currentRole.getRoleId() == 7 || currentRole.getRoleId() == 2) { + schId = currentRole.getSchId(); + } else { + schId = currentRole.getSchId(); + userId = currentRole.getUserId(); + } + return userSettingsService.findLightAppList(schId, userId); + } + + @PostMapping(value = "saveLightApp", produces = "application/json") + public void saveLightApp(BoaUser authUserWithDept, @RequestBody LightApp lightApp) { + UserCurrentRole currentRole = userCurrentRoleService.findById(authUserWithDept.getId()) + .orElseThrow(() -> new BizException(ErrorCode.INTERNAL_SERVER_ERROR)); + Integer schId, userId = null; + if (authUserWithDept.getType() == 1) { + schId = 0; + } else if (currentRole.getRoleId() == 7 || currentRole.getRoleId() == 2) { + schId = currentRole.getSchId(); + } else { + schId = currentRole.getSchId(); + userId = currentRole.getUserId(); + } + lightApp.setUserId(userId); + lightApp.setSchId(schId); + lightApp.setCId(authUserWithDept.getId()); + lightApp.setCDate(new Date()); + userSettingsService.saveLightApp(lightApp); + } + + @PostMapping(value = "deleteLightAppById", produces = "application/json") + public void deleteLightAppById(BoaUser authUserWithDept, Integer id) { + userSettingsService.deleteLightAppById(id); + } + + // ==================== 桌面应用 ==================== + + @PostMapping(value = "saveUserDesktopAppById", produces = "application/json") + public void saveUserDesktopAppById(BoaUser authUserWithDept, @RequestBody Map params) { + Integer id = params.get("id"); + Integer type = params.get("type"); + DesktopAppType desktopAppType = DesktopAppType.valueOf(type); + Optional optional = userSettingsService.findUserSettings(authUserWithDept.getId()); + if (!optional.isPresent() || optional.get().getDesktopApps().isEmpty()) { + initUserSettingsDesktopApp(authUserWithDept.getId()); + optional = userSettingsService.findUserSettings(authUserWithDept.getId()); + } + UserSettings userSettings = optional.get(); + if (userSettings.getDesktopApps().stream().anyMatch(x -> x.getAppId().equals(id))) + throw new BizException(ErrorCode.CUSTOM, "该应用已存在于桌面,请勿重复添加!"); + + UserSettingsDesktopApp desktopApp = new UserSettingsDesktopApp(); + desktopApp.setAppType(desktopAppType); + desktopApp.setAppId(id); + desktopApp.setUserSettingsId(userSettings.getId()); + userSettingsService.saveDesktopApp(desktopApp); + } + + @PostMapping(value = "deleteDesktopAppById", produces = "application/json") + public void deleteDesktopAppById(BoaUser authUserWithDept, @RequestBody Map params) { + Integer id = params.get("id"); + Integer appId = params.get("appId"); + if (id != null) { + userSettingsService.deleteDesktopAppById(id); + } else { + Integer userId = authUserWithDept.getId(); + Optional optional = userSettingsService.findUserSettings(userId); + List desktopList = getUserUsedByUserId(userId); + desktopList = desktopList.stream().filter(x -> !x.getAppId().equals(appId)).collect(Collectors.toList()); + UserSettings model; + if (!optional.isPresent()) model = userSettingsService.initUserSettings(userId); + else model = optional.get(); + desktopList.forEach(x -> x.setUserSettingsId(model.getId())); + userSettingsService.saveDesktopAppList(desktopList); + } + } + + @PostMapping(value = "sortUserDesktopApp", produces = "application/json") + public void sortUserDesktopApp(BoaUser authUserWithDept, @RequestBody Map params) { + String idsStr = params.get("ids"); + List ids = Arrays.stream(idsStr.split(",")).map(s -> Integer.parseInt(s.trim())).collect(Collectors.toList()); + Optional optional = userSettingsService.findUserSettings(authUserWithDept.getId()); + List desktopApps = new ArrayList<>(); + if (!optional.isPresent() || optional.get().getDesktopApps().isEmpty()) { + desktopApps = initUserSettingsDesktopApp(authUserWithDept.getId()); + desktopApps.forEach(x -> { + Integer i = ids.indexOf(x.getAppId()); + x.setOrderNum(i); + }); + } else { + desktopApps = optional.get().getDesktopApps(); + desktopApps.forEach(x -> { + Integer i = ids.indexOf(x.getId()); + x.setOrderNum(i); + }); + } + userSettingsService.saveDesktopAppList(desktopApps); + } + + // ==================== 私有方法 ==================== + + private String upload(@RequestParam("file") MultipartFile file, String pathName) { + File fl = new File(FILE_PATH + "/" + pathName + "/"); + if (!fl.exists()) fl.mkdirs(); + String fileName = FileUtil.uploadImg(file, FILE_PATH + "/" + pathName + "/"); + return "/upload/" + pathName + "/" + fileName; + } + + /** + * 获取学校设置的壁纸集合(对齐旧 UserHome GetSchSettingsWallpaper,fastjson → Jackson)。 + */ + private List getSchSettingsWallpaper(Integer schId) { + if (SCH_CONF_URL == null || SCH_CONF_URL.isEmpty()) return Collections.emptyList(); + String apiPath = SCH_CONF_URL + "/oapi/getSchSetting?schId=" + schId; + List result = new ArrayList<>(); + try { + String resultStr = restTemplate.getForObject(apiPath, String.class); + if (resultStr == null || resultStr.isEmpty()) return result; + JsonNode root = objectMapper.readTree(resultStr); + JsonNode dataNode = root.get("data"); + if (root.has("code") && "0".equals(root.get("code").asText()) && dataNode != null && !dataNode.isNull()) { + JsonNode appBgUrlNode = dataNode.get("appBackgroundUrl"); + if (appBgUrlNode == null) appBgUrlNode = dataNode.get("appBgUrl"); + String appBgUrlStr = appBgUrlNode != null ? appBgUrlNode.asText("") : ""; + if (appBgUrlStr.isEmpty()) return result; + String[] imgUrls = appBgUrlStr.split(","); + for (String imgUrl : imgUrls) { + if (!imgUrl.contains(SCH_CONF_URL)) + result.add(SCH_CONF_URL + imgUrl); + else + result.add(imgUrl); + } + } + } catch (Exception e) { + // 跨仓调用失败时返回空列表 + } + return result; + } + + /** + * 将某个人常用应用转化为桌面应用 + */ + private List initUserSettingsDesktopApp(Integer userId) { + Optional optional = userSettingsService.findUserSettings(userId); + List desktopList = getUserUsedByUserId(userId); + UserSettings model; + if (!optional.isPresent()) model = userSettingsService.initUserSettings(userId); + else model = optional.get(); + desktopList.forEach(x -> x.setUserSettingsId(model.getId())); + return userSettingsService.saveDesktopAppList(desktopList); + } + + /** + * 获取常用应用转化为桌面应用类型 + */ + private List getUserUsedByUserId(Integer userId) { + UserCurrentRole currentRole = userCurrentRoleService.findById(userId) + .orElseThrow(() -> new BizException(ErrorCode.INTERNAL_SERVER_ERROR)); + Optional optionalUsedApp = usedAppService.findById(currentRole.getSchId(), currentRole.getUserId(), currentRole.getRoleId()); + List desktopAppList = new ArrayList<>(); + if (optionalUsedApp.isPresent() && optionalUsedApp.get().getAppIds() != null && !optionalUsedApp.get().getAppIds().isEmpty()) { + List appIds = Arrays.asList(optionalUsedApp.get().getAppIds().split(",")); + List bschAppIds = appIds.stream().mapToInt(Integer::parseInt).boxed().collect(Collectors.toList()); + Integer i = 0; + for (Integer appId : bschAppIds) { + UserSettingsDesktopApp desktopApp = new UserSettingsDesktopApp(); + desktopApp.setAppId(appId); + desktopApp.setAppType(DesktopAppType.Bsch); + desktopApp.setOrderNum(i); + desktopAppList.add(desktopApp); + i++; + } + } + return desktopAppList; + } +} diff --git a/src/main/java/com/yunhai/userhome/entity/LightApp.java b/src/main/java/com/yunhai/userhome/entity/LightApp.java new file mode 100644 index 0000000..e43b401 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/entity/LightApp.java @@ -0,0 +1,63 @@ +package com.yunhai.userhome.entity; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Transient; +import javax.validation.constraints.NotNull; +import java.util.Date; + +/** + * 轻应用数据实体(对齐旧 UserHome model.LightApp)。 + */ +@AllArgsConstructor +@NoArgsConstructor +@Data +@Entity +@Table(name = "light_app") +public class LightApp { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @NotNull(groups = UsedApp.Update.class) + private Integer id; + + private String name; + + private Integer groupId; + + private String icon; + + private String url; + + @Column(name = "desc_txt") + private String desc; + + @JsonIgnore + private Boolean isPublic = false; + + @Transient + private Boolean isEdit = false; + + private Integer linkOpenType; + + private String layout; + + @Column(name = "sch_id") + private Integer schId; + + private Integer userId; + + @Column(name = "c_id") + private Integer cId; + + @Column(name = "c_date") + private Date cDate; +} diff --git a/src/main/java/com/yunhai/userhome/entity/MenuBar.java b/src/main/java/com/yunhai/userhome/entity/MenuBar.java new file mode 100644 index 0000000..6c1bb6c --- /dev/null +++ b/src/main/java/com/yunhai/userhome/entity/MenuBar.java @@ -0,0 +1,78 @@ +package com.yunhai.userhome.entity; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.CollectionTable; +import javax.persistence.Column; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Transient; +import javax.validation.constraints.NotNull; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * 菜单栏实体类(对齐旧 UserHome model.MenuBar)。 + */ +@AllArgsConstructor +@NoArgsConstructor +@Data +@Entity +@Table(name = "menu_bar") +public class MenuBar { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @NotNull(groups = Update.class) + private Integer id; + + private String name; + + private String url; + + private String icon; + + private Integer linkOpenType; + + private Boolean isNative = false; + + private Boolean isHeader = false; + + private Boolean isBottom = false; + + private Integer orderNum; + + private Integer schId; + + @ElementCollection + @CollectionTable(name = "menu_bar_role") + @Column(name = "role_ids") + private List roleIds = new ArrayList<>(); + + @JsonIgnore + @ElementCollection + @CollectionTable(name = "menu_bar_hide_sch") + @Column(name = "sch_ids") + private List hideSchIds = new ArrayList<>(); + + @Column(name = "c_id") + private Integer cId; + + @Column(name = "c_date") + private Date cDate; + + @Transient + private Boolean isShow = true; + + @Transient + private Boolean isEdit = false; + + public @interface Update {} +} diff --git a/src/main/java/com/yunhai/userhome/entity/SchSettings.java b/src/main/java/com/yunhai/userhome/entity/SchSettings.java new file mode 100644 index 0000000..c8e3dad --- /dev/null +++ b/src/main/java/com/yunhai/userhome/entity/SchSettings.java @@ -0,0 +1,57 @@ +package com.yunhai.userhome.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +/** + * 学校设置(sch_settings 表,字段名/表名对齐旧 UserHome model.SchSettings)。 + *

注意:旧版 {@code SchSettingsService.getSchSettings} 并不查本地表,而是跨仓调用 + * {@code SCH_CONF_URL/oapi/getSchSetting},返回结构经 fastjson 映射为此实体。本工程保持同一行为。

+ */ +@AllArgsConstructor +@NoArgsConstructor +@Data +@Entity +@Table(name = "sch_settings") +public class SchSettings { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + @Column(name = "theme_name") + private String themeName; + + @Column(name = "logo_url") + private String logoUrl; + + @Column(name = "home_img_url") + private String homeImgUrl; + + @Column(name = "app_background_url") + private String appBgUrl; + + @Column(name = "sch_id") + private Integer schId; + + // 是否开启桌面 + private Boolean isEnableDesktop = false; + + // 是否默认跳转桌面 + private Boolean isLinkDesktop = false; + + // 操作人id + @Column(name = "c_id") + private Integer cId; + + @Column(name = "c_date") + private java.util.Date cDate; +} diff --git a/src/main/java/com/yunhai/userhome/entity/StatsBar.java b/src/main/java/com/yunhai/userhome/entity/StatsBar.java new file mode 100644 index 0000000..5969b23 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/entity/StatsBar.java @@ -0,0 +1,72 @@ +package com.yunhai.userhome.entity; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.CollectionTable; +import javax.persistence.Column; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Transient; +import javax.validation.constraints.NotNull; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * 统计栏目实体(对齐旧 UserHome model.StatsBar)。 + */ +@AllArgsConstructor +@NoArgsConstructor +@Data +@Entity +@Table(name = "stats_bar") +public class StatsBar { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @NotNull(groups = MenuBar.Update.class) + private Integer id; + + private String name; + + private String url; + + private String icon; + + private Integer linkOpenType; + + private Integer orderNum; + + private Integer schId; + + @ElementCollection + @CollectionTable(name = "stats_bar_role") + @Column(name = "role_ids") + private List roleIds = new ArrayList<>(); + + @JsonIgnore + @ElementCollection + @CollectionTable(name = "stats_bar_show_sch") + @Column(name = "sch_ids") + private List showSchIds = new ArrayList<>(); + + @Column(name = "c_id") + private Integer cId; + + @Column(name = "c_date") + private Date cDate; + + @Transient + private Boolean isShow = true; + + @Transient + private Boolean isEdit = false; + + public @interface Update {} +} diff --git a/src/main/java/com/yunhai/userhome/entity/TeacherCopilot.java b/src/main/java/com/yunhai/userhome/entity/TeacherCopilot.java new file mode 100644 index 0000000..105e05a --- /dev/null +++ b/src/main/java/com/yunhai/userhome/entity/TeacherCopilot.java @@ -0,0 +1,85 @@ +package com.yunhai.userhome.entity; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.CollectionTable; +import javax.persistence.Column; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Transient; +import javax.validation.constraints.NotNull; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * 教师助手实体(对齐旧 UserHome model.TeacherCopilot)。 + */ +@AllArgsConstructor +@NoArgsConstructor +@Data +@Entity +@Table(name = "teacher_copilot") +public class TeacherCopilot { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @NotNull(groups = MenuBar.Update.class) + private Integer id; + + private String name; + + private String url; + + private String icon; + + private Integer linkOpenType; + + private Integer orderNum; + + /** 数据类别 1课前 2课堂 3课后 */ + private Integer type; + + private Integer schId; + + @ElementCollection + @CollectionTable(name = "teacher_copilot_role") + @Column(name = "role_ids") + private List roleIds = new ArrayList<>(); + + @JsonIgnore + @ElementCollection + @CollectionTable(name = "teacher_copilot_show_sch") + @Column(name = "sch_ids") + private List showSchIds = new ArrayList<>(); + + @Column(name = "c_id") + private Integer cId; + + @Column(name = "c_date") + private Date cDate; + + @Transient + private Boolean isShow = true; + + @Transient + private Boolean isEdit = false; + + public @interface Update {} + + @Data + public static class Dto { + private Integer id; + private String name; + private String url; + private String icon; + private Integer openType; + private Integer type; + } +} diff --git a/src/main/java/com/yunhai/userhome/entity/UsedApp.java b/src/main/java/com/yunhai/userhome/entity/UsedApp.java index 8da229a..714c36c 100644 --- a/src/main/java/com/yunhai/userhome/entity/UsedApp.java +++ b/src/main/java/com/yunhai/userhome/entity/UsedApp.java @@ -61,4 +61,7 @@ public class UsedApp extends BaseEntity { /** 操作时间。 */ @Column(name = "c_date") private Date cDate; + + /** 验证分组:更新操作时 id 必须非空(对齐旧 UserHome UsedApp.Update)。 */ + public @interface Update {} } diff --git a/src/main/java/com/yunhai/userhome/entity/UserMessage.java b/src/main/java/com/yunhai/userhome/entity/UserMessage.java new file mode 100644 index 0000000..5923096 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/entity/UserMessage.java @@ -0,0 +1,56 @@ +package com.yunhai.userhome.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import java.util.Date; + +/** + * 用户消息表(user_message,字段名/表名对齐旧 UserHome model.UserMessage)。 + */ +@AllArgsConstructor +@NoArgsConstructor +@Data +@Entity +@Table(name = "user_message") +public class UserMessage { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + @Column(name = "app_id") + private Integer appId; + + @Column(name = "c_date") + private Date cDate; + + @Column(name = "imgs") + private String imgs; + + private String urls; + + @Column(name = "btn_texts") + private String btnTexts; + + private String content; + + @Column(name = "user_id") + private Integer userId; + + @Column(name = "sch_id") + private Integer schId; + + /** 消息类型(0文字/1图文/2审批,对齐旧 MsgType)。 */ + private Integer type; + + @Column(name = "is_read") + private Boolean isRead = false; +} diff --git a/src/main/java/com/yunhai/userhome/entity/UserSettings.java b/src/main/java/com/yunhai/userhome/entity/UserSettings.java new file mode 100644 index 0000000..3f2a731 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/entity/UserSettings.java @@ -0,0 +1,75 @@ +package com.yunhai.userhome.entity; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Index; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.persistence.Transient; +import javax.validation.constraints.NotNull; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 用户个性化配置(对齐旧 UserHome model.UserSettings)。 + */ +@AllArgsConstructor +@NoArgsConstructor +@Data +@Entity +@Table(name = "user_settings", indexes = {@Index(columnList = "user_id,sch_id,role_id", name = "index_setting_user_sch_role")}) +public class UserSettings { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @NotNull(groups = Update.class) + private Integer id; + + @Column(name = "widget_app_ids") + private String widgetAppIds; + + @Column(name = "is_widget_show") + private Boolean isWidgetShow = true; + + @Column(name = "width") + private Integer width; + + @Column(name = "height") + private Integer height; + + @Column(name = "x_axis") + private Integer xAxis; + + @Column(name = "y_axis") + private Integer yAxis; + + @Column(name = "wallpaper_url") + private String wallpaperUrl; + + @Column(name = "sch_id") + private Integer schId; + + @Column(name = "user_id") + private Integer userId; + + @Column(name = "role_id") + private Integer roleId; + + @JsonIgnore + @OneToMany(mappedBy = "userSettings", cascade = CascadeType.ALL, orphanRemoval = true) + private List desktopApps = new ArrayList<>(); + + @Transient + private List widgetAppList; + + public @interface Update {} +} diff --git a/src/main/java/com/yunhai/userhome/entity/UserSettingsDesktopApp.java b/src/main/java/com/yunhai/userhome/entity/UserSettingsDesktopApp.java new file mode 100644 index 0000000..06290bb --- /dev/null +++ b/src/main/java/com/yunhai/userhome/entity/UserSettingsDesktopApp.java @@ -0,0 +1,48 @@ +package com.yunhai.userhome.entity; + +import com.yunhai.userhome.enums.DesktopAppType; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import javax.validation.constraints.NotNull; + +/** + * 用户设置桌面应用(对齐旧 UserHome model.UserSettingsDesktopApp)。 + */ +@AllArgsConstructor +@NoArgsConstructor +@Data +@Entity +@Table(name = "user_settings_desktop_app") +public class UserSettingsDesktopApp { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @NotNull(groups = UserSettings.Update.class) + private Integer id; + + private Integer appId; + + @Enumerated(EnumType.ORDINAL) + private DesktopAppType appType; + + private Integer orderNum; + + @Column(name = "user_settings_id") + private Integer userSettingsId; + + @ManyToOne(cascade = {javax.persistence.CascadeType.PERSIST}, optional = false) + @JoinColumn(name = "user_settings_id", insertable = false, updatable = false) + private UserSettings userSettings; +} diff --git a/src/main/java/com/yunhai/userhome/entity/Wallpaper.java b/src/main/java/com/yunhai/userhome/entity/Wallpaper.java new file mode 100644 index 0000000..deef6b2 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/entity/Wallpaper.java @@ -0,0 +1,46 @@ +package com.yunhai.userhome.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Transient; +import javax.validation.constraints.NotNull; + +/** + * 壁纸实体(对齐旧 UserHome model.Wallpaper)。 + */ +@AllArgsConstructor +@NoArgsConstructor +@Data +@Entity +@Table(name = "wallpaper") +public class Wallpaper { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @NotNull(groups = Update.class) + private Integer id; + + /** 0:随机壁纸 | 1:个人上传壁纸 */ + private Integer type; + + @Column(name = "sch_id") + private Integer schId; + + private Integer userId; + + @Column(name = "wallpaper_url") + private String wallpaperUrl; + + @Transient + private Boolean isEdit = false; + + public @interface Update {} +} diff --git a/src/main/java/com/yunhai/userhome/enums/DesktopAppType.java b/src/main/java/com/yunhai/userhome/enums/DesktopAppType.java new file mode 100644 index 0000000..b9f0e9f --- /dev/null +++ b/src/main/java/com/yunhai/userhome/enums/DesktopAppType.java @@ -0,0 +1,31 @@ +package com.yunhai.userhome.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +/** + * 桌面应用类型(对齐旧 UserHome enums.DesktopAppType)。 + */ +@Getter +@NoArgsConstructor +@AllArgsConstructor +public enum DesktopAppType { + Bsch(1, "应用中心应用"), + Light(2, "轻应用"), + ; + + private Integer key; + private String value; + + public static DesktopAppType valueOf(Integer value) { + switch (value) { + case 1: + return Bsch; + case 2: + return Light; + default: + return null; + } + } +} diff --git a/src/main/java/com/yunhai/userhome/enums/LightAppGroup.java b/src/main/java/com/yunhai/userhome/enums/LightAppGroup.java new file mode 100644 index 0000000..55059c1 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/enums/LightAppGroup.java @@ -0,0 +1,25 @@ +package com.yunhai.userhome.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +/** + * 轻应用分组类型(对齐旧 UserHome enums.LightAppGroup)。 + */ +@Getter +@NoArgsConstructor +@AllArgsConstructor +public enum LightAppGroup { + + AI(1, "AI助手"), + VR(2, "虚拟现实"), + Program(3, "编程体验"), + Tools(4, "在线工具"), + Resource(5, "资源推荐"), + Others(6, "其他"), + ; + + private Integer key; + private String value; +} diff --git a/src/main/java/com/yunhai/userhome/enums/LinkOpenType.java b/src/main/java/com/yunhai/userhome/enums/LinkOpenType.java new file mode 100644 index 0000000..a3013f3 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/enums/LinkOpenType.java @@ -0,0 +1,22 @@ +package com.yunhai.userhome.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +/** + * 链接打开方式(对齐旧 UserHome enums.LinkOpenType)。 + */ +@Getter +@NoArgsConstructor +@AllArgsConstructor +public enum LinkOpenType { + + Open(1, "新窗口"), + Href(2, "当前页"), + IFrame(3, "嵌入页面"), + ; + + private Integer key; + private String value; +} diff --git a/src/main/java/com/yunhai/userhome/enums/StatsDateType.java b/src/main/java/com/yunhai/userhome/enums/StatsDateType.java new file mode 100644 index 0000000..43676ad --- /dev/null +++ b/src/main/java/com/yunhai/userhome/enums/StatsDateType.java @@ -0,0 +1,43 @@ +package com.yunhai.userhome.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +/** + * 统计日期类型(对齐旧 UserHome enums.StatsDateType)。 + */ +@Getter +@NoArgsConstructor +@AllArgsConstructor +public enum StatsDateType { + Day(1, "今日"), + Week(2, "本周"), + Mont(3, "本月"), + Academic(4, "本学期"), + Total(5, "累计"), + Custom(6, "自定义"), + ; + + private Integer key; + private String value; + + public static StatsDateType valueOf(Integer value) { + switch (value) { + case 1: + return Day; + case 2: + return Week; + case 3: + return Mont; + case 4: + return Academic; + case 5: + return Total; + case 6: + return Custom; + default: + return null; + } + } +} diff --git a/src/main/java/com/yunhai/userhome/repository/LightAppRepository.java b/src/main/java/com/yunhai/userhome/repository/LightAppRepository.java new file mode 100644 index 0000000..806bfbd --- /dev/null +++ b/src/main/java/com/yunhai/userhome/repository/LightAppRepository.java @@ -0,0 +1,8 @@ +package com.yunhai.userhome.repository; + +import com.yunhai.userhome.entity.LightApp; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +public interface LightAppRepository extends JpaRepository, JpaSpecificationExecutor { +} diff --git a/src/main/java/com/yunhai/userhome/repository/MenuBarRepository.java b/src/main/java/com/yunhai/userhome/repository/MenuBarRepository.java new file mode 100644 index 0000000..8144361 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/repository/MenuBarRepository.java @@ -0,0 +1,14 @@ +package com.yunhai.userhome.repository; + +import com.yunhai.userhome.entity.MenuBar; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; + +public interface MenuBarRepository extends JpaRepository, JpaSpecificationExecutor { + + List findBySchId(Integer schId); + + List findBySchIdIn(List schIds); +} diff --git a/src/main/java/com/yunhai/userhome/repository/SchSettingsRepository.java b/src/main/java/com/yunhai/userhome/repository/SchSettingsRepository.java new file mode 100644 index 0000000..481f81a --- /dev/null +++ b/src/main/java/com/yunhai/userhome/repository/SchSettingsRepository.java @@ -0,0 +1,19 @@ +package com.yunhai.userhome.repository; + +import com.yunhai.userhome.entity.SchSettings; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface SchSettingsRepository extends JpaRepository, JpaSpecificationExecutor { + + Optional findFirstBySchId(Integer schId); + + @Query(nativeQuery = true, value = "SELECT * FROM `sch_settings` where sch_id in ?1 ") + List getSchSettingList(List schIds); +} diff --git a/src/main/java/com/yunhai/userhome/repository/StatsBarRepository.java b/src/main/java/com/yunhai/userhome/repository/StatsBarRepository.java new file mode 100644 index 0000000..7993306 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/repository/StatsBarRepository.java @@ -0,0 +1,14 @@ +package com.yunhai.userhome.repository; + +import com.yunhai.userhome.entity.StatsBar; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; + +public interface StatsBarRepository extends JpaRepository, JpaSpecificationExecutor { + + List findBySchId(Integer schId); + + List findBySchIdIn(List schIds); +} diff --git a/src/main/java/com/yunhai/userhome/repository/TeacherCopilotRepository.java b/src/main/java/com/yunhai/userhome/repository/TeacherCopilotRepository.java new file mode 100644 index 0000000..056b0ff --- /dev/null +++ b/src/main/java/com/yunhai/userhome/repository/TeacherCopilotRepository.java @@ -0,0 +1,14 @@ +package com.yunhai.userhome.repository; + +import com.yunhai.userhome.entity.TeacherCopilot; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; + +public interface TeacherCopilotRepository extends JpaRepository, JpaSpecificationExecutor { + + List findBySchId(Integer schId); + + List findBySchIdIn(List schIds); +} diff --git a/src/main/java/com/yunhai/userhome/repository/UserMessageRepository.java b/src/main/java/com/yunhai/userhome/repository/UserMessageRepository.java new file mode 100644 index 0000000..af17418 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/repository/UserMessageRepository.java @@ -0,0 +1,34 @@ +package com.yunhai.userhome.repository; + +import com.yunhai.userhome.entity.UserMessage; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +public interface UserMessageRepository extends JpaRepository, JpaSpecificationExecutor { + + List findUserMessageByUserIdAndAppId(Integer userId, Integer appId); + + /** 按用户分组取「每应用最新一条消息」(对齐旧 getUserMessageAppList 原生 SQL)。 */ + @Query(nativeQuery = true, value = "select * from (SELECT * FROM `user_message` where user_id=?1 group by app_id,c_date desc) as Base group by app_id order by c_date desc") + List getUserMessageAppList(Integer userId, Integer schId); + + @Transactional + @Modifying + @Query(nativeQuery = true, value = "update user_message set is_read =1 where user_id=?1 and app_id=?2 and is_read = 0") + void updateRead(Integer userId, Integer appId); + + @Transactional + @Modifying + @Query(nativeQuery = true, value = "update user_message set is_read =1 where user_id=?1 and is_read = 0") + void updateReadAll(Integer userId); + + @Transactional + @Modifying + @Query(nativeQuery = true, value = "update user_message set is_read =1 where id=:msgId ") + void updateReadById(Integer msgId); +} diff --git a/src/main/java/com/yunhai/userhome/repository/UserSettingsDesktopAppRepository.java b/src/main/java/com/yunhai/userhome/repository/UserSettingsDesktopAppRepository.java new file mode 100644 index 0000000..749db51 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/repository/UserSettingsDesktopAppRepository.java @@ -0,0 +1,8 @@ +package com.yunhai.userhome.repository; + +import com.yunhai.userhome.entity.UserSettingsDesktopApp; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +public interface UserSettingsDesktopAppRepository extends JpaRepository, JpaSpecificationExecutor { +} diff --git a/src/main/java/com/yunhai/userhome/repository/UserSettingsRepository.java b/src/main/java/com/yunhai/userhome/repository/UserSettingsRepository.java new file mode 100644 index 0000000..bf2cc16 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/repository/UserSettingsRepository.java @@ -0,0 +1,12 @@ +package com.yunhai.userhome.repository; + +import com.yunhai.userhome.entity.UserSettings; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.Optional; + +public interface UserSettingsRepository extends JpaRepository, JpaSpecificationExecutor { + + Optional findByUserIdAndSchIdAndRoleId(Integer userId, Integer schId, Integer roleId); +} diff --git a/src/main/java/com/yunhai/userhome/repository/WallpaperRepository.java b/src/main/java/com/yunhai/userhome/repository/WallpaperRepository.java new file mode 100644 index 0000000..c9fd8f2 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/repository/WallpaperRepository.java @@ -0,0 +1,14 @@ +package com.yunhai.userhome.repository; + +import com.yunhai.userhome.entity.Wallpaper; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; + +public interface WallpaperRepository extends JpaRepository, JpaSpecificationExecutor { + + List findByUserIdAndType(Integer userId, Integer type); + + List findBySchIdAndType(Integer schId, Integer type); +} diff --git a/src/main/java/com/yunhai/userhome/service/IMenuBarService.java b/src/main/java/com/yunhai/userhome/service/IMenuBarService.java new file mode 100644 index 0000000..0e3f745 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/service/IMenuBarService.java @@ -0,0 +1,20 @@ +package com.yunhai.userhome.service; + +import com.yunhai.userhome.entity.MenuBar; + +import java.util.List; + +public interface IMenuBarService { + + List getMenuBarList(Integer schId); + + List findMenuBarById(Integer userId); + + void saveMenuBar(MenuBar menuBar); + + void toggleMenuBarShow(Integer id, Integer schId); + + void saveMenuBarOrderNum(Integer id, Integer orderNum); + + void deleteMenuBar(Integer id); +} diff --git a/src/main/java/com/yunhai/userhome/service/ISchSettingsService.java b/src/main/java/com/yunhai/userhome/service/ISchSettingsService.java new file mode 100644 index 0000000..f318d36 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/service/ISchSettingsService.java @@ -0,0 +1,16 @@ +package com.yunhai.userhome.service; + +import com.yunhai.userhome.entity.SchSettings; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public interface ISchSettingsService { + + void save(SchSettings schSettings); + + Optional findBySchId(Integer schId); + + List findBySchIds(List schIds); +} diff --git a/src/main/java/com/yunhai/userhome/service/IStatsBarService.java b/src/main/java/com/yunhai/userhome/service/IStatsBarService.java new file mode 100644 index 0000000..2f5cdc2 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/service/IStatsBarService.java @@ -0,0 +1,20 @@ +package com.yunhai.userhome.service; + +import com.yunhai.userhome.entity.StatsBar; + +import java.util.List; + +public interface IStatsBarService { + + List getStatsBarList(Integer schId); + + List findStatsBarById(Integer userId); + + void saveStatsBar(StatsBar statsBar); + + void toggleStatsBarShow(Integer id, Integer schId); + + void saveStatsBarOrderNum(Integer id, Integer orderNum); + + void deleteStatsBar(Integer id); +} diff --git a/src/main/java/com/yunhai/userhome/service/ITeacherCopilotService.java b/src/main/java/com/yunhai/userhome/service/ITeacherCopilotService.java new file mode 100644 index 0000000..0d60ba5 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/service/ITeacherCopilotService.java @@ -0,0 +1,20 @@ +package com.yunhai.userhome.service; + +import com.yunhai.userhome.entity.TeacherCopilot; + +import java.util.List; + +public interface ITeacherCopilotService { + + List getList(Integer schId); + + List findById(Integer userId); + + void save(TeacherCopilot teacherCopilot); + + void toggleShow(Integer id, Integer schId); + + void saveOrderNum(Integer id, Integer orderNum); + + void delete(Integer id); +} diff --git a/src/main/java/com/yunhai/userhome/service/IUserMessageService.java b/src/main/java/com/yunhai/userhome/service/IUserMessageService.java new file mode 100644 index 0000000..0a6c342 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/service/IUserMessageService.java @@ -0,0 +1,32 @@ +package com.yunhai.userhome.service; + +import com.yunhai.userhome.entity.UserMessage; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +import java.util.List; + +public interface IUserMessageService { + + List getUserMessageAppIds(Integer userId, Integer schId); + + Page findUserMessageByAppId(UserMessage userMessage, Pageable pageable); + + Page findUserMessageByUserId(Integer userId, Pageable pageable); + + List findUserMessageByUserId(Integer userId); + + Boolean findUserMessageUnRead(Integer userId); + + void updateRead(Integer userId, Integer appId); + + void updateUserRead(Integer id, Integer userId); + + void updateReadAll(Integer userId); + + Page findUserMessageById(Integer userId, Integer page, Integer count); + + void readMsgById(Integer msgId); + + void readMsgAll(Integer userId); +} diff --git a/src/main/java/com/yunhai/userhome/service/IUserSettingsService.java b/src/main/java/com/yunhai/userhome/service/IUserSettingsService.java new file mode 100644 index 0000000..d05c514 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/service/IUserSettingsService.java @@ -0,0 +1,44 @@ +package com.yunhai.userhome.service; + +import com.yunhai.userhome.entity.LightApp; +import com.yunhai.userhome.entity.UserSettings; +import com.yunhai.userhome.entity.UserSettingsDesktopApp; +import com.yunhai.userhome.entity.Wallpaper; + +import java.util.List; +import java.util.Optional; + +public interface IUserSettingsService { + + List findWallList(Integer userId); + + void deleteWallById(Integer id); + + void saveWallpaper(Wallpaper wallpaper); + + void checkWallpaper(Integer userId, String wallpaperUrl); + + Optional findUserSettings(Integer userId); + + void saveUserSettings(UserSettings userSettings); + + void saveUserWidget(UserSettings userSettings); + + void saveUserAppIds(Integer id, Integer userId, String appIds); + + void toggleWidgetShow(Integer id, Integer userId); + + List findLightAppList(Integer schId, Integer userId); + + void saveLightApp(LightApp lightApp); + + void deleteLightAppById(Integer id); + + void deleteDesktopAppById(Integer id); + + void saveDesktopApp(UserSettingsDesktopApp model); + + List saveDesktopAppList(List list); + + UserSettings initUserSettings(Integer userId); +} diff --git a/src/main/java/com/yunhai/userhome/service/impl/MenuBarServiceImpl.java b/src/main/java/com/yunhai/userhome/service/impl/MenuBarServiceImpl.java new file mode 100644 index 0000000..f2ead44 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/service/impl/MenuBarServiceImpl.java @@ -0,0 +1,98 @@ +package com.yunhai.userhome.service.impl; + +import com.yunhai.platform.apistd.BizException; +import com.yunhai.platform.utils.exception.ErrorCode; +import com.yunhai.userhome.entity.MenuBar; +import com.yunhai.userhome.entity.UserCurrentRole; +import com.yunhai.userhome.repository.MenuBarRepository; +import com.yunhai.userhome.service.IMenuBarService; +import com.yunhai.userhome.service.IUserCurrentRoleService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 菜单栏服务(对齐旧 UserHome service.impl.MenuBarService)。 + */ +@Service +public class MenuBarServiceImpl implements IMenuBarService { + + @Autowired + private IUserCurrentRoleService userCurrentRoleService; + + @Autowired + private MenuBarRepository menuBarRepository; + + @Override + public List getMenuBarList(Integer schId) { + List list; + if (schId == 0) + list = menuBarRepository.findBySchId(0); + else + list = menuBarRepository.findBySchIdIn(Arrays.asList(0, schId)); + list.forEach(x -> { + Boolean isHide = x.getHideSchIds().contains(schId); + x.setIsShow(!isHide); + x.setIsEdit(x.getSchId().equals(schId)); + }); + list = list.stream().sorted(Comparator.comparing(MenuBar::getOrderNum, Comparator.nullsLast(Integer::compareTo))).collect(Collectors.toList()); + return list; + } + + @Override + public List findMenuBarById(Integer userId) { + UserCurrentRole userCurrentRole = userCurrentRoleService.findById(userId) + .orElseThrow(() -> new BizException(ErrorCode.INTERNAL_SERVER_ERROR)); + List list = getMenuBarList(userCurrentRole.getSchId()); + List result = list.stream().filter(MenuBar::getIsShow).collect(Collectors.toList()); + result = result.stream().sorted(Comparator.comparing(MenuBar::getOrderNum, Comparator.nullsLast(Integer::compareTo))).collect(Collectors.toList()); + return result; + } + + @Override + public void saveMenuBar(MenuBar menuBar) { + if (menuBar.getId() != null) { + Optional optional = menuBarRepository.findById(menuBar.getId()); + if (optional.isPresent()) { + menuBar.setHideSchIds(optional.get().getHideSchIds()); + } + } + menuBarRepository.save(menuBar); + } + + @Override + public void saveMenuBarOrderNum(Integer id, Integer orderNum) { + Optional optionalMenuBar = menuBarRepository.findById(id); + if (!optionalMenuBar.isPresent()) + throw new BizException(ErrorCode.INTERNAL_SERVER_ERROR); + MenuBar menuBar = optionalMenuBar.get(); + menuBar.setOrderNum(orderNum); + menuBarRepository.save(menuBar); + } + + @Override + public void toggleMenuBarShow(Integer id, Integer schId) { + Optional optionalMenuBar = menuBarRepository.findById(id); + if (!optionalMenuBar.isPresent()) + throw new BizException(ErrorCode.INTERNAL_SERVER_ERROR); + MenuBar menuBar = optionalMenuBar.get(); + Integer index = menuBar.getHideSchIds().indexOf(schId); + List schIds = menuBar.getHideSchIds(); + if (index.equals(-1)) + schIds.add(schId); + else + schIds.remove(Integer.valueOf(schId)); + menuBar.setHideSchIds(schIds); + menuBarRepository.save(menuBar); + } + + @Override + public void deleteMenuBar(Integer id) { + Optional optionalMenuBar = menuBarRepository.findById(id); + if (!optionalMenuBar.isPresent()) + throw new BizException(ErrorCode.INTERNAL_SERVER_ERROR); + menuBarRepository.delete(optionalMenuBar.get()); + } +} diff --git a/src/main/java/com/yunhai/userhome/service/impl/SchSettingsServiceImpl.java b/src/main/java/com/yunhai/userhome/service/impl/SchSettingsServiceImpl.java new file mode 100644 index 0000000..fe3e853 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/service/impl/SchSettingsServiceImpl.java @@ -0,0 +1,81 @@ +package com.yunhai.userhome.service.impl; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.yunhai.userhome.entity.SchSettings; +import com.yunhai.userhome.repository.SchSettingsRepository; +import com.yunhai.userhome.service.ISchSettingsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import java.util.Optional; + +/** + * 学校设置服务:行为对齐旧 UserHome SchSettingsService。 + *

关键:{@code findBySchId} 不查本地表,而是跨仓调用 {@code SCH_CONF_URL/oapi/getSchSetting}, + * 旧版如此(schConfig 服务为 homeImgUrl/isEnableDesktop/isLinkDesktop 等字段的权威来源), + * 因此本地 sch_settings 表变更类能力(saveSchTheme/saveSchLogo)本期仅保留 P1 占位写入本地表。

+ */ +@Service +public class SchSettingsServiceImpl implements ISchSettingsService { + + @Autowired + private SchSettingsRepository schSettingsRepository; + + @Value("${SCH_CONF_URL:}") + private String schConfUrl; + + private final RestTemplate restTemplate = new RestTemplate(); + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Override + public void save(SchSettings schSettings) { + schSettingsRepository.save(schSettings); + } + + @Override + public Optional findBySchId(Integer schId) { + SchSettings model = new SchSettings(); + try { + if (schConfUrl == null || schConfUrl.isEmpty()) { + return Optional.of(localFallbackBySchId(schId)); + } + String apiPath = schConfUrl + "/oapi/getSchSetting?schId=" + schId; + String resultStr = restTemplate.getForObject(apiPath, String.class); + if (resultStr == null || resultStr.isEmpty()) { + return Optional.of(localFallbackBySchId(schId)); + } + JsonNode root = objectMapper.readTree(resultStr); + JsonNode dataNode = root.get("data"); + if (root.has("code") && "0".equals(root.get("code").asText()) && dataNode != null && !dataNode.isNull()) { + model = objectMapper.convertValue(dataNode, SchSettings.class); + } else { + return Optional.of(localFallbackBySchId(schId)); + } + } catch (Exception e) { + return Optional.of(localFallbackBySchId(schId)); + } + return Optional.of(model); + } + + /** 跨仓不通时先查本地表,再兜底默认主题(对齐旧版异常分支)。 */ + private SchSettings localFallbackBySchId(Integer schId) { + Optional local = schSettingsRepository.findFirstBySchId(schId); + if (local.isPresent()) { + return local.get(); + } + SchSettings def = new SchSettings(); + def.setSchId(schId); + def.setThemeName("default-theme"); + def.setAppBgUrl(""); + def.setLogoUrl(""); + return def; + } + + @Override + public java.util.List findBySchIds(java.util.List schId) { + return schSettingsRepository.getSchSettingList(schId); + } +} diff --git a/src/main/java/com/yunhai/userhome/service/impl/StatsBarServiceImpl.java b/src/main/java/com/yunhai/userhome/service/impl/StatsBarServiceImpl.java new file mode 100644 index 0000000..4dd6a31 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/service/impl/StatsBarServiceImpl.java @@ -0,0 +1,97 @@ +package com.yunhai.userhome.service.impl; + +import com.yunhai.platform.apistd.BizException; +import com.yunhai.platform.utils.exception.ErrorCode; +import com.yunhai.userhome.entity.StatsBar; +import com.yunhai.userhome.entity.UserCurrentRole; +import com.yunhai.userhome.repository.StatsBarRepository; +import com.yunhai.userhome.service.IStatsBarService; +import com.yunhai.userhome.service.IUserCurrentRoleService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 统计栏目服务(对齐旧 UserHome service.impl.StatsBarService)。 + */ +@Service +public class StatsBarServiceImpl implements IStatsBarService { + + @Autowired + private IUserCurrentRoleService userCurrentRoleService; + + @Autowired + private StatsBarRepository statsBarRepository; + + @Override + public List getStatsBarList(Integer schId) { + List list; + if (schId == 0) + list = statsBarRepository.findBySchId(0); + else + list = statsBarRepository.findBySchIdIn(Arrays.asList(0, schId)); + list.forEach(x -> { + x.setIsShow(x.getShowSchIds().contains(schId)); + x.setIsEdit(x.getSchId().equals(schId)); + }); + list = list.stream().sorted(Comparator.comparing(StatsBar::getOrderNum, Comparator.nullsLast(Integer::compareTo))).collect(Collectors.toList()); + return list; + } + + @Override + public List findStatsBarById(Integer userId) { + UserCurrentRole userCurrentRole = userCurrentRoleService.findById(userId) + .orElseThrow(() -> new BizException(ErrorCode.INTERNAL_SERVER_ERROR)); + List list = getStatsBarList(userCurrentRole.getSchId()); + List result = list.stream().filter(StatsBar::getIsShow).collect(Collectors.toList()); + result = result.stream().sorted(Comparator.comparing(StatsBar::getOrderNum, Comparator.nullsLast(Integer::compareTo))).collect(Collectors.toList()); + return result; + } + + @Override + public void saveStatsBar(StatsBar statsBar) { + if (statsBar.getId() != null) { + Optional optional = statsBarRepository.findById(statsBar.getId()); + if (optional.isPresent()) { + statsBar.setShowSchIds(optional.get().getShowSchIds()); + } + } + statsBarRepository.save(statsBar); + } + + @Override + public void saveStatsBarOrderNum(Integer id, Integer orderNum) { + Optional optionalStatsBar = statsBarRepository.findById(id); + if (!optionalStatsBar.isPresent()) + throw new BizException(ErrorCode.INTERNAL_SERVER_ERROR); + StatsBar statsBar = optionalStatsBar.get(); + statsBar.setOrderNum(orderNum); + statsBarRepository.save(statsBar); + } + + @Override + public void toggleStatsBarShow(Integer id, Integer schId) { + Optional optionalStatsBar = statsBarRepository.findById(id); + if (!optionalStatsBar.isPresent()) + throw new BizException(ErrorCode.INTERNAL_SERVER_ERROR); + StatsBar statsBar = optionalStatsBar.get(); + Integer index = statsBar.getShowSchIds().indexOf(schId); + List schIds = statsBar.getShowSchIds(); + if (index.equals(-1)) + schIds.add(schId); + else + schIds.remove(Integer.valueOf(schId)); + statsBar.setShowSchIds(schIds); + statsBarRepository.save(statsBar); + } + + @Override + public void deleteStatsBar(Integer id) { + Optional optionalStatsBar = statsBarRepository.findById(id); + if (!optionalStatsBar.isPresent()) + throw new BizException(ErrorCode.INTERNAL_SERVER_ERROR); + statsBarRepository.delete(optionalStatsBar.get()); + } +} diff --git a/src/main/java/com/yunhai/userhome/service/impl/TeacherCopilotServiceImpl.java b/src/main/java/com/yunhai/userhome/service/impl/TeacherCopilotServiceImpl.java new file mode 100644 index 0000000..1bff689 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/service/impl/TeacherCopilotServiceImpl.java @@ -0,0 +1,97 @@ +package com.yunhai.userhome.service.impl; + +import com.yunhai.platform.apistd.BizException; +import com.yunhai.platform.utils.exception.ErrorCode; +import com.yunhai.userhome.entity.TeacherCopilot; +import com.yunhai.userhome.entity.UserCurrentRole; +import com.yunhai.userhome.repository.TeacherCopilotRepository; +import com.yunhai.userhome.service.ITeacherCopilotService; +import com.yunhai.userhome.service.IUserCurrentRoleService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 教师助手服务(对齐旧 UserHome service.impl.TeacherCopilotService)。 + */ +@Service +public class TeacherCopilotServiceImpl implements ITeacherCopilotService { + + @Autowired + private IUserCurrentRoleService userCurrentRoleService; + + @Autowired + private TeacherCopilotRepository teacherCopilotRepository; + + @Override + public List getList(Integer schId) { + List list; + if (schId == 0) + list = teacherCopilotRepository.findBySchId(0); + else + list = teacherCopilotRepository.findBySchIdIn(Arrays.asList(0, schId)); + list.forEach(x -> { + x.setIsShow(x.getShowSchIds().contains(schId)); + x.setIsEdit(x.getSchId().equals(schId)); + }); + list = list.stream().sorted(Comparator.comparing(TeacherCopilot::getOrderNum, Comparator.nullsLast(Integer::compareTo))).collect(Collectors.toList()); + return list; + } + + @Override + public List findById(Integer userId) { + UserCurrentRole userCurrentRole = userCurrentRoleService.findById(userId) + .orElseThrow(() -> new BizException(ErrorCode.INTERNAL_SERVER_ERROR)); + List list = getList(userCurrentRole.getSchId()); + List result = list.stream().filter(TeacherCopilot::getIsShow).collect(Collectors.toList()); + result = result.stream().sorted(Comparator.comparing(TeacherCopilot::getOrderNum, Comparator.nullsLast(Integer::compareTo))).collect(Collectors.toList()); + return result; + } + + @Override + public void save(TeacherCopilot teacherCopilot) { + if (teacherCopilot.getId() != null) { + Optional optional = teacherCopilotRepository.findById(teacherCopilot.getId()); + if (optional.isPresent()) { + teacherCopilot.setShowSchIds(optional.get().getShowSchIds()); + } + } + teacherCopilotRepository.save(teacherCopilot); + } + + @Override + public void saveOrderNum(Integer id, Integer orderNum) { + Optional optional = teacherCopilotRepository.findById(id); + if (!optional.isPresent()) + throw new BizException(ErrorCode.INTERNAL_SERVER_ERROR); + TeacherCopilot teacherCopilot = optional.get(); + teacherCopilot.setOrderNum(orderNum); + teacherCopilotRepository.save(teacherCopilot); + } + + @Override + public void toggleShow(Integer id, Integer schId) { + Optional optional = teacherCopilotRepository.findById(id); + if (!optional.isPresent()) + throw new BizException(ErrorCode.INTERNAL_SERVER_ERROR); + TeacherCopilot teacherCopilot = optional.get(); + Integer index = teacherCopilot.getShowSchIds().indexOf(schId); + List schIds = teacherCopilot.getShowSchIds(); + if (index.equals(-1)) + schIds.add(schId); + else + schIds.remove(Integer.valueOf(schId)); + teacherCopilot.setShowSchIds(schIds); + teacherCopilotRepository.save(teacherCopilot); + } + + @Override + public void delete(Integer id) { + Optional optional = teacherCopilotRepository.findById(id); + if (!optional.isPresent()) + throw new BizException(ErrorCode.INTERNAL_SERVER_ERROR); + teacherCopilotRepository.delete(optional.get()); + } +} diff --git a/src/main/java/com/yunhai/userhome/service/impl/UserMessageServiceImpl.java b/src/main/java/com/yunhai/userhome/service/impl/UserMessageServiceImpl.java new file mode 100644 index 0000000..65e86a7 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/service/impl/UserMessageServiceImpl.java @@ -0,0 +1,118 @@ +package com.yunhai.userhome.service.impl; + +import com.yunhai.userhome.entity.UserMessage; +import com.yunhai.userhome.repository.UserMessageRepository; +import com.yunhai.userhome.service.IUserMessageService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.stereotype.Service; + +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +/** + * 用户消息服务:行为对齐旧 UserHome UserMessageService(本地 user_message 表)。 + * WS 推送态由前端轮询兜底,本服务不消费 Redis 缓存(旧工程依赖 Redis,新工程未引入)。 + */ +@Service +public class UserMessageServiceImpl implements IUserMessageService { + + @Autowired + private UserMessageRepository userMessageRepository; + + @Override + public List getUserMessageAppIds(Integer userId, Integer schId) { + return userMessageRepository.getUserMessageAppList(userId, schId); + } + + @Override + public Page findUserMessageByAppId(UserMessage userMessage, Pageable pageable) { + return userMessageRepository.findAll(select(userMessage), pageable); + } + + @Override + public Page findUserMessageByUserId(Integer userId, Pageable pageable) { + return userMessageRepository.findAll(select(userId, null), pageable); + } + + @Override + public List findUserMessageByUserId(Integer userId) { + // 旧版优先读 Redis 缓存,缓存缺失再查库;新工程无 Redis,直接查库(行为等价:返回该用户全部消息) + return userMessageRepository.findAll(select(userId, null), PageRequest.of(0, Integer.MAX_VALUE, Sort.by(Sort.Direction.DESC, "cDate"))).getContent(); + } + + @Override + public Boolean findUserMessageUnRead(Integer userId) { + return userMessageRepository.count(select(userId, false)) > 0; + } + + @Override + public void updateRead(Integer userId, Integer appId) { + userMessageRepository.updateRead(userId, appId); + } + + @Override + public void updateUserRead(Integer id, Integer userId) { + // 单条已读:前端按 id 移除本地列表后再调;服务端标记该条已读 + userMessageRepository.updateReadById(id); + } + + @Override + public void updateReadAll(Integer userId) { + userMessageRepository.updateReadAll(userId); + } + + @Override + public Page findUserMessageById(Integer userId, Integer page, Integer count) { + Sort sort = Sort.by(Sort.Direction.DESC, "id"); + Pageable pageable = PageRequest.of(page - 1, count, sort); + return userMessageRepository.findAll(select(userId, null), pageable); + } + + @Override + public void readMsgById(Integer msgId) { + userMessageRepository.updateReadById(msgId); + } + + @Override + public void readMsgAll(Integer userId) { + userMessageRepository.updateReadAll(userId); + } + + private Specification select(UserMessage userMessage) { + return (Root root, CriteriaQuery query, CriteriaBuilder cb) -> { + List predicates = new ArrayList<>(); + if (userMessage != null) { + if (userMessage.getUserId() != null) { + predicates.add(cb.equal(root.get("userId"), userMessage.getUserId())); + } + if (userMessage.getAppId() != null) { + predicates.add(cb.equal(root.get("appId"), userMessage.getAppId())); + } + } + return query.where(predicates.toArray(new Predicate[0])).getRestriction(); + }; + } + + private Specification select(Integer userId, Boolean isRead) { + return (Root root, CriteriaQuery query, CriteriaBuilder cb) -> { + List predicates = new ArrayList<>(); + if (userId != null) { + predicates.add(cb.equal(root.get("userId"), userId)); + } + if (isRead != null) { + predicates.add(cb.equal(root.get("isRead"), isRead)); + } + return query.where(predicates.toArray(new Predicate[0])).getRestriction(); + }; + } +} diff --git a/src/main/java/com/yunhai/userhome/service/impl/UserSettingsServiceImpl.java b/src/main/java/com/yunhai/userhome/service/impl/UserSettingsServiceImpl.java new file mode 100644 index 0000000..9b8b405 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/service/impl/UserSettingsServiceImpl.java @@ -0,0 +1,203 @@ +package com.yunhai.userhome.service.impl; + +import com.yunhai.platform.apistd.BizException; +import com.yunhai.platform.utils.exception.ErrorCode; +import com.yunhai.userhome.entity.*; +import com.yunhai.userhome.repository.LightAppRepository; +import com.yunhai.userhome.repository.UserSettingsDesktopAppRepository; +import com.yunhai.userhome.repository.UserSettingsRepository; +import com.yunhai.userhome.repository.WallpaperRepository; +import com.yunhai.userhome.service.IUserCurrentRoleService; +import com.yunhai.userhome.service.IUserSettingsService; +import com.yunhai.userhome.utils.OtherUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.stereotype.Service; + +import javax.persistence.criteria.Predicate; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * 用户设置服务(对齐旧 UserHome service.impl.UserSettingsService)。 + */ +@Service +public class UserSettingsServiceImpl implements IUserSettingsService { + + @Autowired + private WallpaperRepository wallpaperRepository; + + @Autowired + private UserSettingsRepository userSettingsRepository; + + @Autowired + private IUserCurrentRoleService userCurrentRoleService; + + @Autowired + private LightAppRepository lightAppRepository; + + @Autowired + private UserSettingsDesktopAppRepository userSettingsDesktopAppRepository; + + @Override + public List findWallList(Integer userId) { + UserCurrentRole currentRole = userCurrentRoleService.findById(userId) + .orElseThrow(() -> new BizException(ErrorCode.INTERNAL_SERVER_ERROR)); + List resultList = new ArrayList<>(); + List baseList = wallpaperRepository.findBySchIdAndType(0, 0); + List schList = wallpaperRepository.findBySchIdAndType(currentRole.getSchId(), 1); + List userList = wallpaperRepository.findByUserIdAndType(userId, 2); + if (currentRole.getSchId() == 0) baseList.forEach(x -> x.setIsEdit(true)); + if (OtherUtil.isAdminById(currentRole.getRoleId())) schList.forEach(x -> x.setIsEdit(true)); + userList.forEach(x -> x.setIsEdit(true)); + resultList.addAll(baseList); + resultList.addAll(schList); + resultList.addAll(userList); + return resultList; + } + + @Override + public void deleteWallById(Integer id) { + if (!wallpaperRepository.existsById(id)) + throw new BizException(ErrorCode.INTERNAL_SERVER_ERROR); + wallpaperRepository.deleteById(id); + } + + @Override + public void saveWallpaper(Wallpaper wallpaper) { + wallpaperRepository.save(wallpaper); + } + + @Override + public void checkWallpaper(Integer userId, String wallpaperUrl) { + UserSettings model = getUserSettings(null, userId); + model.setWallpaperUrl(wallpaperUrl); + userSettingsRepository.save(model); + } + + @Override + public Optional findUserSettings(Integer userId) { + UserCurrentRole currentRole = userCurrentRoleService.findById(userId) + .orElseThrow(() -> new BizException(ErrorCode.INTERNAL_SERVER_ERROR)); + return userSettingsRepository.findByUserIdAndSchIdAndRoleId(currentRole.getUserId(), currentRole.getSchId(), currentRole.getRoleId()); + } + + @Override + public void saveUserSettings(UserSettings userSettings) { + userSettingsRepository.save(userSettings); + } + + @Override + public void saveUserWidget(UserSettings userSettings) { + UserSettings model = getUserSettings(userSettings.getId(), userSettings.getUserId()); + model.setXAxis(userSettings.getXAxis()); + model.setYAxis(userSettings.getYAxis()); + model.setWidth(userSettings.getWidth()); + model.setHeight(userSettings.getHeight()); + model.setIsWidgetShow(true); + userSettingsRepository.save(model); + } + + @Override + public void saveUserAppIds(Integer id, Integer userId, String appIds) { + UserSettings model = getUserSettings(id, userId); + model.setWidgetAppIds(appIds); + userSettingsRepository.save(model); + } + + @Override + public void toggleWidgetShow(Integer id, Integer userId) { + UserSettings model = getUserSettings(id, userId); + if (model.getIsWidgetShow() == null) model.setIsWidgetShow(true); + model.setIsWidgetShow(!model.getIsWidgetShow()); + userSettingsRepository.save(model); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + @Override + public List findLightAppList(Integer schId, Integer userId) { + Specification specification = (Specification) (root, criteriaQuery, criteriaBuilder) -> { + List predicates = new ArrayList<>(); + Predicate basePre = criteriaBuilder.and( + criteriaBuilder.equal(root.get("schId"), 0), + criteriaBuilder.equal(root.get("isPublic"), true)); + Predicate schPre = criteriaBuilder.and( + criteriaBuilder.equal(root.get("schId"), schId), + criteriaBuilder.equal(root.get("isPublic"), true)); + Predicate userPre = criteriaBuilder.and( + criteriaBuilder.equal(root.get("schId"), schId), + criteriaBuilder.equal(root.get("userId"), userId)); + if (schId == 0) + predicates.add(basePre); + else if (userId == null) + predicates.add(criteriaBuilder.or(basePre, schPre)); + else + predicates.add(criteriaBuilder.or(basePre, schPre, userPre)); + return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()])); + }; + Sort sort = Sort.by(Sort.Direction.DESC, "id"); + List result = lightAppRepository.findAll(specification, sort); + + if (schId == 0) result.forEach(x -> x.setIsEdit(true)); + else if (userId == null) + result.stream().filter(x -> x.getSchId() != null && x.getSchId().equals(schId) && x.getUserId() == null) + .forEach(x -> x.setIsEdit(true)); + else + result.stream().filter(x -> x.getSchId() != null && x.getUserId() != null && x.getSchId().equals(schId) && x.getUserId().equals(userId)) + .forEach(x -> x.setIsEdit(true)); + return result; + } + + @Override + public void saveLightApp(LightApp lightApp) { + if (lightApp.getSchId() == 0) lightApp.setUserId(null); + if (lightApp.getUserId() == null) lightApp.setIsPublic(true); + lightAppRepository.save(lightApp); + } + + @Override + public void deleteLightAppById(Integer id) { + lightAppRepository.deleteById(id); + } + + @Override + public void deleteDesktopAppById(Integer id) { + userSettingsDesktopAppRepository.deleteById(id); + } + + @Override + public void saveDesktopApp(UserSettingsDesktopApp model) { + userSettingsDesktopAppRepository.save(model); + } + + @Override + public List saveDesktopAppList(List list) { + return userSettingsDesktopAppRepository.saveAll(list); + } + + @Override + public UserSettings initUserSettings(Integer userId) { + UserCurrentRole currentRole = userCurrentRoleService.findById(userId) + .orElseThrow(() -> new BizException(ErrorCode.INTERNAL_SERVER_ERROR)); + UserSettings model = new UserSettings(); + model.setSchId(currentRole.getSchId()); + model.setRoleId(currentRole.getRoleId()); + model.setUserId(currentRole.getUserId()); + return userSettingsRepository.save(model); + } + + private UserSettings getUserSettings(Integer id, Integer userId) { + Optional optional; + if (id != null) + optional = userSettingsRepository.findById(id); + else + optional = findUserSettings(userId); + if (optional.isPresent()) return optional.get(); + else { + return initUserSettings(userId); + } + } +} diff --git a/src/main/java/com/yunhai/userhome/utils/EnumUtil.java b/src/main/java/com/yunhai/userhome/utils/EnumUtil.java new file mode 100644 index 0000000..1bb16f1 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/utils/EnumUtil.java @@ -0,0 +1,108 @@ +package com.yunhai.userhome.utils; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 枚举工具类(对齐旧 UserHome utils.EnumUtil,commons-lang → hutool)。 + */ +public final class EnumUtil { + + /** + * 枚举转 List<Map> 格式(每个枚举项 → {key, value, enum})。 + */ + @SuppressWarnings("rawtypes") + public static List> toMapList(Class targetEnumClazz) { + Method[] methods = targetEnumClazz.getMethods(); + Field[] fields = targetEnumClazz.getDeclaredFields(); + List fieldList = new ArrayList<>(); + for (Method method : methods) { + for (Field field : fields) { + String capitalized = Character.toUpperCase(field.getName().charAt(0)) + field.getName().substring(1); + if (method.getName().endsWith(capitalized)) { + fieldList.add(field); + } + } + } + List> resultList = new ArrayList<>(); + Enum[] enums = (Enum[]) targetEnumClazz.getEnumConstants(); + Object value = null; + try { + for (Enum e : enums) { + Map eMap = new HashMap<>(); + for (Field field : fieldList) { + field.setAccessible(true); + value = field.get(e); + eMap.put(field.getName(), value); + } + eMap.put("enum", e); + resultList.add(eMap); + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + return resultList; + } + + @SuppressWarnings("rawtypes") + public static String getValue(Class targetEnumClazz, String key) { + List> list = toMapList(targetEnumClazz); + for (Map map : list) { + if (map.get("key").toString().equals(key)) { + return map.get("value").toString(); + } + } + return ""; + } + + @SuppressWarnings("rawtypes") + public static String getKey(Class targetEnumClazz, String value) { + List> list = toMapList(targetEnumClazz); + for (Map map : list) { + if (map.get("value").toString().equals(value)) { + return map.get("key").toString(); + } + } + return ""; + } + + @SuppressWarnings("rawtypes") + public static boolean isExistKey(Class targetEnumClazz, String key) { + List> list = toMapList(targetEnumClazz); + return list.stream().filter(x -> x.get("key").equals(key)).count() > 0; + } + + @SuppressWarnings("rawtypes") + public static boolean isExistValue(Class targetEnumClazz, String value) { + List> list = toMapList(targetEnumClazz); + return list.stream().filter(x -> x.get("value").equals(value)).count() > 0; + } + + @SuppressWarnings("rawtypes") + public static Object getEnumByKey(Class targetEnumClazz, String key) { + List> list = toMapList(targetEnumClazz); + for (Map map : list) { + if (map.get("key").toString().equals(key)) { + return map.get("enum"); + } + } + return null; + } + + @SuppressWarnings("rawtypes") + public static List> toMapList(Class targetEnumClazz, String keyName, String valueName) { + List> list = toMapList(targetEnumClazz); + List result = new ArrayList(); + for (Map map : list) { + Map newMap = new HashMap(); + newMap.put(keyName, map.get("key")); + newMap.put(valueName, map.get("value")); + result.add(newMap); + } + return result; + } +} diff --git a/src/main/java/com/yunhai/userhome/utils/FileUtil.java b/src/main/java/com/yunhai/userhome/utils/FileUtil.java new file mode 100644 index 0000000..5e1ffaa --- /dev/null +++ b/src/main/java/com/yunhai/userhome/utils/FileUtil.java @@ -0,0 +1,70 @@ +package com.yunhai.userhome.utils; + +import cn.hutool.core.util.IdUtil; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.UUID; + +/** + * File工具类(对齐旧 UserHome utils.FileUtil,仅保留 uploadImg 方法——本期迁移实际使用的唯一方法)。 + */ +public class FileUtil { + + /** + * 上传图片(byte[] 版),返回生成的文件名。 + */ + public static String uploadImg(byte[] imgData, String pathName) { + String imgName = null; + String path = null; + File floorFile = null; + try { + for (int i = 0; i < 100; i++) { + imgName = UUID.randomUUID().toString().substring(0, 8) + ".png"; + path = pathName + imgName; + floorFile = new File(path); + if (floorFile.exists()) continue; + else break; + } + FileOutputStream fos = new FileOutputStream(floorFile); + fos.write(imgData); + fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return imgName; + } + + /** + * 上传图片(MultipartFile 版),保留原始扩展名,返回生成的文件名。 + */ + public static String uploadImg(MultipartFile file, String pathName) { + String imgName = null; + String path = null; + File floorFile = null; + try { + byte[] imgData = file.getBytes(); + String fileName = file.getOriginalFilename(); + int index = fileName.lastIndexOf("."); + String ext = ""; + if (index > 0) { + ext = fileName.substring(index); + } + for (int i = 0; i < 100; i++) { + imgName = UUID.randomUUID().toString().substring(0, 8) + ext; + path = pathName + imgName; + floorFile = new File(path); + if (floorFile.exists()) continue; + else break; + } + FileOutputStream fos = new FileOutputStream(floorFile); + fos.write(imgData); + fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return imgName; + } +} diff --git a/src/main/java/com/yunhai/userhome/utils/MapCacheUtil.java b/src/main/java/com/yunhai/userhome/utils/MapCacheUtil.java new file mode 100644 index 0000000..7b101b1 --- /dev/null +++ b/src/main/java/com/yunhai/userhome/utils/MapCacheUtil.java @@ -0,0 +1,89 @@ +package com.yunhai.userhome.utils; + +import org.springframework.stereotype.Component; + +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 轻量内存缓存(替换旧工程 bsch MapCacheUtil)。 + * 用于 getMsgAddress 的 uuid→userId 鉴权握手缓存,20s 有效。 + * 单例 + 守护线程周期清扫过期项,线程安全(ConcurrentHashMap)。 + */ +@Component +public class MapCacheUtil { + + private static final int CLEAN_UP_PERIOD_IN_SEC = 5; + + private final ConcurrentHashMap cache = new ConcurrentHashMap<>(); + + private static MapCacheUtil instance; + + public static synchronized MapCacheUtil getInstance() { + if (instance == null) { + instance = new MapCacheUtil(); + } + return instance; + } + + private MapCacheUtil() { + Thread cleanerThread = new Thread(() -> { + while (!Thread.currentThread().isInterrupted()) { + try { + Thread.sleep(CLEAN_UP_PERIOD_IN_SEC * 1000L); + cache.entrySet().removeIf(entry -> + Optional.ofNullable(entry.getValue()).map(CacheObject::isExpired).orElse(false)); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + }); + cleanerThread.setDaemon(true); + cleanerThread.start(); + } + + public void add(String key, Object value, long periodInMillis) { + if (key == null) { + return; + } + if (value == null) { + cache.remove(key); + } else { + long expiryTime = System.currentTimeMillis() + periodInMillis; + cache.put(key, new CacheObject(value, expiryTime)); + } + } + + public void remove(String key) { + cache.remove(key); + } + + public Object get(String key) { + return Optional.ofNullable(cache.get(key)) + .filter(c -> !c.isExpired()) + .map(CacheObject::getValue) + .orElse(null); + } + + public void clear() { + cache.clear(); + } + + private static class CacheObject { + private final Object value; + private final long expiryTime; + + private CacheObject(Object value, long expiryTime) { + this.value = value; + this.expiryTime = expiryTime; + } + + boolean isExpired() { + return System.currentTimeMillis() > expiryTime; + } + + public Object getValue() { + return value; + } + } +} diff --git a/src/main/java/com/yunhai/userhome/utils/OtherUtil.java b/src/main/java/com/yunhai/userhome/utils/OtherUtil.java new file mode 100644 index 0000000..78e0ded --- /dev/null +++ b/src/main/java/com/yunhai/userhome/utils/OtherUtil.java @@ -0,0 +1,29 @@ +package com.yunhai.userhome.utils; + +import java.util.Arrays; + +/** + * 杂项公用方法集合(对齐旧 UserHome utils.OtherUtil,fastjson 相关方法移除——新框架用 Jackson)。 + */ +public class OtherUtil { + + /** + * 十六进制转字符串 + */ + public final static String hexToString(String hex) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < hex.length(); i += 2) { + String hexSubstring = hex.substring(i, i + 2); + int decimalValue = Integer.parseInt(hexSubstring, 16); + sb.append((char) decimalValue); + } + return sb.toString(); + } + + /** + * 判断是否为校领导 + */ + public final static Boolean isAdminById(Integer roleId) { + return Arrays.asList(2, 5, 7).contains(roleId); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index bd8439c..154349c 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -38,10 +38,16 @@ spring: # ===== 基础平台 yh 配置(遵循 yh-* spring-boot-starter 约定,具体 key 以对应 starter 版本为准)===== yh: auth: + enabled: true + sso: # CAS 单点登录(浏览器 SSO 重定向 / ticket 校验) - cas: - server-url-prefix: https://sso.yunhaixingtong.com/cas - service: http://localhost:8070 + server-url-prefix: https://sso.yunhaixingtong.com/cas/ + # 本地 context-path=/、端口 8070;prod 由 Nacos 的 yh.sso.client-host-url 覆盖 + client-host-url: http://localhost:8070 + allow-headers: all + allow-origins: all + url-pattern: /api/* + mobi-api-pattern: /mobiapi/* app-auth: # 应用间签名鉴权(UserHome 作为调用方访问 UserBase 跨仓接口时使用) enabled: true @@ -60,3 +66,11 @@ yh: logging: level: com.yunhai.userhome: debug + +# ===== 文件上传与学校配置 ===== +# 文件存储根目录(UserSettingsController 壁纸/图标上传使用) +FILE_PATH: ./upload/ +# 文件 Web 访问前缀(prod 由 Nacos 覆盖) +FILE_WEB_PATH: http://localhost:8070/upload/ +# 学校配置接口基址(SchSettingsController 使用,prod 由 Nacos 覆盖) +SCH_CONF_URL: ""