diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml index e683ad3..3ce91e3 100644 --- a/ruoyi-admin/pom.xml +++ b/ruoyi-admin/pom.xml @@ -15,14 +15,7 @@ web服务入口 - - - - - - - - + @@ -30,6 +23,32 @@ ruoyi-framework + + + org.springframework.boot + spring-boot-starter-test + test + + + + + org.junit.jupiter + junit-jupiter + test + + + + + org.mockito + mockito-core + test + + + org.mockito + mockito-junit-jupiter + test + + diff --git a/ruoyi-admin/ruoyi-admin.iml b/ruoyi-admin/ruoyi-admin.iml index 93594d6..37e8d48 100644 --- a/ruoyi-admin/ruoyi-admin.iml +++ b/ruoyi-admin/ruoyi-admin.iml @@ -4,10 +4,7 @@ - - - - + @@ -18,8 +15,8 @@ - - + + @@ -31,18 +28,6 @@ - - - - - - - - - - - - @@ -175,7 +160,6 @@ - @@ -223,7 +207,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/HealthyController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/HealthyController.java index 40739be..6ec6cc3 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/HealthyController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/HealthyController.java @@ -13,6 +13,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; +import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.List; import java.util.Map; @@ -57,4 +59,82 @@ public class HealthyController { YjHealthy i=service.getById(healthy.getId()); return new RestResponse().setSuccess(true).setMessage("成功").setData(i); } + + @ApiOperation(value = "计算BIM") + @PostMapping("/calculateBim") + public RestResponse calculateBim(@RequestBody Map map){ + try { + map.get("gender");//male男性 female女性 + map.get("age"); + BigDecimal height= checkAndFormatNum(map.get("height")); + BigDecimal weight= checkAndFormatNum(map.get("weight")); + // 公式:BMI = 体重 ÷ (身高 × 身高) + height=height.divide(new BigDecimal(100)); + BigDecimal heightSquare = height.multiply(height); // 身高平方 + BigDecimal bim=weight.divide(heightSquare,2,RoundingMode.HALF_UP); + + BigDecimal num185 = new BigDecimal("18.5"); + BigDecimal num239 = new BigDecimal("23.9"); + BigDecimal num279 = new BigDecimal("27.9"); + if (bim.compareTo(num185) < 0) { + + return new RestResponse() + .setSuccess(true) + .setMessage("您的体重过轻,请联系馆主或教练领取A方案") + .setData(bim); + } + else if (bim.compareTo(num185) > 0 && bim.compareTo(num239) < 0) { + + return new RestResponse() + .setSuccess(true) + .setMessage("太棒了,您的体重非常健康,请联系馆主或教练领取B方案保持") + .setData(bim); + } + else if (bim.compareTo(num239) > 0 && bim.compareTo(num279) < 0) { + + return new RestResponse() + .setSuccess(true) + .setMessage("您的体重超重,请联系馆主或教练领取C方案") + .setData(bim); + }else { + return new RestResponse() + .setSuccess(true) + .setMessage("您的体重肥胖,请联系馆主或教练领取D方案") + .setData(bim); + } + + }catch (IllegalArgumentException e){ + return RestResponse.failure(e.getMessage()); + } + + } + + /** + * 校验并格式化 height + * @return 格式化后的 height(保留1位小数) + * @throws IllegalArgumentException 校验不通过时抛出异常 + */ + public static BigDecimal checkAndFormatNum(Object obj) { + // 1. 非空校验 + if (obj == null || obj.toString().trim().isEmpty()) { + throw new IllegalArgumentException("身高/体重不能为空"); + } + + String heightStr = obj.toString().trim(); + BigDecimal heightNum; + + try { + // 2. 校验是否为有效数字(整数/小数都支持) + heightNum = new BigDecimal(heightStr); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("身高/体重必须是有效数字,当前值:" + heightStr); + } + + // 3. 保留1位小数(四舍五入,银行家舍入法,最常用) + BigDecimal formattedHeight = heightNum.setScale(1, RoundingMode.HALF_UP); + + // 4. 返回字符串格式结果(也可返回 BigDecimal 类型) + return formattedHeight; + } + } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/ISysDictDataController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/ISysDictDataController.java new file mode 100644 index 0000000..e7db757 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/ISysDictDataController.java @@ -0,0 +1,40 @@ +package com.ruoyi.web.controller.basic; + +import com.ruoyi.RestResponse; +import com.ruoyi.basic.service.impl.BusinessSysDictDataService; +import com.ruoyi.common.core.domain.entity.SysDictData; +import com.ruoyi.system.service.ISysDictDataService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + *

+ * 字典数据表 前端控制器 + *

+ * + * @author zhangby + * @since 2020-01-15 + */ +@RestController +@RequestMapping("/api/dict/data") +public class ISysDictDataController { + + @Autowired + private BusinessSysDictDataService sysDictDataService; + + /** + * 某字典数据 + * @param dictType + * @return + */ + @GetMapping("/list/dictType/{dictType}") + public RestResponse dictTypeDataList(@PathVariable("dictType") String dictType){ + List dictDataList = sysDictDataService.dictTypeDataList(dictType); + return RestResponse.success().setData(dictDataList); + } + + + +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/IndexController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/IndexController.java index 5a6ff40..3cf2a92 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/IndexController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/IndexController.java @@ -11,10 +11,7 @@ import com.ruoyi.basic.service.impl.YjStoreServiceImpl; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; -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 org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.util.ArrayList; @@ -30,6 +27,7 @@ public class IndexController { private YjStoreServiceImpl storeService; + @ApiOperation("门店列表") @PostMapping("/getStores") public RestResponse getStoreList(){ @@ -44,4 +42,10 @@ public class IndexController { return storeService.changeStore(visitStoreId); } + @ApiOperation("获取首页及分类页菜单") + @GetMapping("/getIndex") + public RestResponse getIndex(){ + return storeService.getIndex(); + } + } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/MyController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/MyController.java index 48650be..428cade 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/MyController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/MyController.java @@ -90,8 +90,8 @@ public class MyController extends BaseController { * @return */ @PostMapping("/courseTimeDetail") - public RestResponse courseTimeDetail(@RequestBody Map map){ - Long courseTimeId=(Long)map.get("courseTimeId"); + public RestResponse courseTimeDetail(@RequestBody Map map){ + Long courseTimeId=map.get("courseTimeId"); return scClaTimeService.courseTimeDetail(courseTimeId); } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/QuestionnaireController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/QuestionnaireController.java new file mode 100644 index 0000000..c72cedc --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/QuestionnaireController.java @@ -0,0 +1,106 @@ +package com.ruoyi.web.controller.basic; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.ruoyi.RestResponse; +import com.ruoyi.basic.domain.dto.AnswerSubmitDTO; +import com.ruoyi.basic.domain.model.AnswerResultVO; +import com.ruoyi.basic.domain.model.QuestionnaireVO; +import com.ruoyi.basic.domain.question.QuestionSurvey; +import com.ruoyi.basic.mapper.QuestionSurveyMapper; +import com.ruoyi.basic.service.QuestionnaireService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@RestController +@RequestMapping("/api/questionnaire") +@RequiredArgsConstructor +@Validated +public class QuestionnaireController { + + private final QuestionnaireService questionnaireService; + private final QuestionSurveyMapper surveyMapper; + + /** + * 获取所有已发布的问卷列表(简要信息) + * @return 问卷列表 + */ + @GetMapping("/list") + public RestResponse listSurveys() { + List surveys = surveyMapper.selectList( + new LambdaQueryWrapper() + .eq(QuestionSurvey::getStatus, 1) // 只返回已发布的 + .orderByDesc(QuestionSurvey::getCreateTime) + ); + List briefList = surveys.stream() + .map(s -> new QuestionSurveyBriefVO(s.getId(), s.getTitle(), s.getDescription())) + .collect(Collectors.toList()); + return RestResponse.success().setData(briefList); + } + + /** + * 获取问卷详情(包含体质、题目、选项) + * @return 问卷完整结构 + */ + @GetMapping("/getOne") + public RestResponse getQuestionnaire() { + QuestionnaireVO vo = questionnaireService.getQuestionnaire(); + if (vo == null) { + return RestResponse.failure("问卷不存在或未发布"); + } + return RestResponse.success().setData(vo); + } + + /** + * 提交问卷答案并获取评估结果 + * @param dto 答案提交数据 + * @param request Http请求(用于获取IP) + * @return 评估结果 + */ + @PostMapping("/submit") + public RestResponse submit(@Valid @RequestBody AnswerSubmitDTO dto, + HttpServletRequest request) { + try { + AnswerResultVO result = questionnaireService.submitAnswers(dto, request); + return RestResponse.success().setData(result); + } catch (IllegalArgumentException e) { + log.warn("参数校验失败: {}", e.getMessage()); + return RestResponse.failure(e.getMessage()); + } catch (Exception e) { + log.error("提交答案失败", e); + return RestResponse.failure("提交失败,请稍后重试"); + } + } + + /** + * 根据答卷ID查询结果 + * @return 评估结果 + */ + @GetMapping("/result") + public RestResponse getResult() { + AnswerResultVO result = questionnaireService.getResultBySheetId(); + if (result == null) { + return RestResponse.failure("答卷不存在"); + } + return RestResponse.success().setData(result); + } + + /** + * 问卷简要信息(内部类) + */ + @lombok.Data + @lombok.AllArgsConstructor + public static class QuestionSurveyBriefVO { + private Long id; + private String title; + private String description; + } +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/dto/AppLoginUserForGetInfor.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/dto/AppLoginUserForGetInfor.java index 727f80e..4f9bd0c 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/dto/AppLoginUserForGetInfor.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/dto/AppLoginUserForGetInfor.java @@ -1,5 +1,7 @@ package com.ruoyi.web.controller.basic.dto; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.ruoyi.common.annotation.Excel; import com.ruoyi.common.annotation.Excel.ColumnType; import io.swagger.annotations.ApiModel; @@ -15,6 +17,7 @@ public class AppLoginUserForGetInfor /** 用户ID */ @ApiModelProperty("用户ID") @Excel(name = "用户序号", cellType = ColumnType.NUMERIC, prompt = "用户编号") + @JsonSerialize(using = ToStringSerializer.class) private Long userId; /** 用户账号 */ diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/course/CourseController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/course/CourseController.java index e0ff6a9..d7a8a8f 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/course/CourseController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/course/CourseController.java @@ -5,7 +5,9 @@ import com.ruoyi.RestResponse; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.course.domain.req.ReqSearchClaTime; +import com.ruoyi.course.domain.time.ClaTimeCalendarItem; import com.ruoyi.course.domain.time.RespBusinessClaTimeCalendar; +import com.ruoyi.course.mapper.ScClaTimeMapper; import com.ruoyi.course.service.ScClaTimeService; import io.swagger.annotations.Api; import org.springframework.beans.factory.annotation.Autowired; @@ -47,6 +49,11 @@ public class CourseController extends BaseController { } + @PostMapping("/getCourseDetail") + public RestResponse getCourseDetail(@RequestBody Map map){ + Long courseTimeId=map.get("courseTimeId"); + return scClaTimeService.getCourseDetail(courseTimeId); + } /** * 预约课程 * @param searchClaTime diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/FriendController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/FriendController.java index 0e63e2a..84d2549 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/FriendController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/FriendController.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.ruoyi.basic.service.YjAppUserService; import com.ruoyi.common.annotation.RepeatSubmit; import com.ruoyi.common.core.domain.entity.AppUser; +import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.im.domain.vo.FriendVO; import com.ruoyi.im.domain.vo.UserVO; import com.ruoyi.im.service.FriendService; @@ -45,6 +46,7 @@ public class FriendController { @PostMapping("/add") @Operation(summary = "添加好友", description = "双方建立好友关系") public Result addFriend(@NotNull(message = "好友id不可为空") @RequestParam Long friendId) { + friendService.addFriend(friendId); return ResultUtils.success(); } @@ -52,7 +54,11 @@ public class FriendController { @GetMapping("/find/{friendId}") @Operation(summary = "查找好友信息", description = "查找好友信息") public Result findFriend(@NotNull(message = "好友id不可为空") @PathVariable Long friendId) { - return ResultUtils.success(friendService.findFriend(friendId)); + Long userId= SecurityUtils.getAppLoginUser().getAppUser().getId(); + if (friendId.equals(userId)) { + return null; + } + return ResultUtils.success(friendService.findFriend(userId,friendId)); } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/login/AppLoginController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/login/AppLoginController.java index f76a72a..21ba4d1 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/login/AppLoginController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/login/AppLoginController.java @@ -17,6 +17,7 @@ import com.ruoyi.framework.web.service.AppLoginService; import com.ruoyi.basic.domain.YjStore; import com.ruoyi.basic.service.impl.YjStoreServiceImpl; import com.ruoyi.framework.web.service.SysPermissionService; +import com.ruoyi.system.service.ISysUserService; import com.ruoyi.web.controller.basic.dto.AppLoginUserForGetInfor; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -36,6 +37,9 @@ public class AppLoginController { @Autowired private AppLoginService appLoginService; + @Autowired + private ISysUserService userService; + @Autowired private YjAppUserServiceImpl appUserService; @@ -82,6 +86,7 @@ public class AppLoginController { return ajax; } + /** * 获取用户信息 * @@ -98,6 +103,11 @@ public class AppLoginController { appUser.setPhonenumber(user.getAppUser().getPhoneNumber()); // 角色集合 appUser.setRoleId(user.getRoles()); + //管理人员(教练、店长、顾问)默认访问门店 +// if (ObjectUtil.isNotEmpty(user.getManageAccountId())&&ObjectUtil.isNotEmpty(appUser.getVisitStore())){ +// Long deptId= userService.selectUserById(user.getManageAccountId()).getDeptId(); +// appUser.setVisitStore(deptId); +// } AjaxResult ajax = AjaxResult.success(); ajax.put("appLoginUser", appUser); diff --git a/ruoyi-admin/src/test/java/com/ruoyi/web/controller/basic/QuestionnaireControllerTest.java b/ruoyi-admin/src/test/java/com/ruoyi/web/controller/basic/QuestionnaireControllerTest.java new file mode 100644 index 0000000..3568bf5 --- /dev/null +++ b/ruoyi-admin/src/test/java/com/ruoyi/web/controller/basic/QuestionnaireControllerTest.java @@ -0,0 +1,430 @@ +package com.ruoyi.web.controller.basic; + +import com.ruoyi.RestResponse; +import com.ruoyi.basic.domain.dto.AnswerSubmitDTO; +import com.ruoyi.basic.domain.model.AnswerResultVO; +import com.ruoyi.basic.service.QuestionnaireService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import javax.servlet.http.HttpServletRequest; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@ExtendWith(MockitoExtension.class) +@DisplayName("QuestionnaireController单元测试") +class QuestionnaireControllerTest { + + private MockMvc mockMvc; + + @Mock + private QuestionnaireService questionnaireService; + + @InjectMocks + private QuestionnaireController questionnaireController; + + @BeforeEach + void setUp() { + mockMvc = MockMvcBuilders.standaloneSetup(questionnaireController).build(); + } + + /** + * 测试正常提交答案场景 + * 覆盖:成功路径,返回包含正确答案的AnswerResultVO + */ + @Test + @DisplayName("提交答案成功 - 返回评估结果") + void submit_Success_ReturnsResult() throws Exception { + // Arrange + AnswerSubmitDTO dto = new AnswerSubmitDTO(); + dto.setSurveyId(1L); + dto.setSessionId("test-session-123"); + + AnswerSubmitDTO.AnswerItem item1 = new AnswerSubmitDTO.AnswerItem(); + item1.setQuestionId(1L); + item1.setOptionId(1L); + + AnswerSubmitDTO.AnswerItem item2 = new AnswerSubmitDTO.AnswerItem(); + item2.setQuestionId(2L); + item2.setOptionId(2L); + + dto.setAnswers(Arrays.asList(item1, item2)); + + AnswerResultVO resultVO = new AnswerResultVO(); + resultVO.setResultType("pinghe"); + resultVO.setResultText("恭喜您,您的体质为平和体质"); + resultVO.setConstitutionScores(new ArrayList<>()); + + HttpServletRequest request = mock(HttpServletRequest.class); + when(questionnaireService.submitAnswers(any(AnswerSubmitDTO.class), any(HttpServletRequest.class))) + .thenReturn(resultVO); + + // Act & Assert + mockMvc.perform(post("/api/questionnaire/submit") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"surveyId\":1,\"sessionId\":\"test-session-123\",\"answers\":[{\"questionId\":1,\"optionId\":1},{\"questionId\":2,\"optionId\":2}]}")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.success").value(true)) + .andExpect(jsonPath("$.data.resultType").value("pinghe")) + .andExpect(jsonPath("$.data.resultText").value("恭喜您,您的体质为平和体质")); + + verify(questionnaireService, times(1)).submitAnswers(any(AnswerSubmitDTO.class), any(HttpServletRequest.class)); + } + + /** + * 测试参数校验失败场景 + * 覆盖:IllegalArgumentException异常处理路径 + */ + @Test + @DisplayName("提交答案失败 - 参数校验失败") + void submit_ValidationFailure_ReturnsFailure() throws Exception { + // Arrange + AnswerSubmitDTO dto = new AnswerSubmitDTO(); + dto.setSurveyId(null); // 故意设置为null触发校验失败 + + HttpServletRequest request = mock(HttpServletRequest.class); + when(questionnaireService.submitAnswers(any(AnswerSubmitDTO.class), any(HttpServletRequest.class))) + .thenThrow(new IllegalArgumentException("问卷ID不能为空")); + + // Act & Assert + mockMvc.perform(post("/api/questionnaire/submit") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"surveyId\":null,\"answers\":[]}")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.success").value(false)) + .andExpect(jsonPath("$.message").value("问卷ID不能为空")); + + verify(questionnaireService, times(1)).submitAnswers(any(AnswerSubmitDTO.class), any(HttpServletRequest.class)); + } + + /** + * 测试通用异常处理场景 + * 覆盖:Exception异常处理路径,返回"提交失败,请稍后重试" + */ + @Test + @DisplayName("提交答案失败 - 系统异常") + void submit_SystemException_ReturnsFailure() throws Exception { + // Arrange + AnswerSubmitDTO dto = new AnswerSubmitDTO(); + dto.setSurveyId(1L); + + HttpServletRequest request = mock(HttpServletRequest.class); + when(questionnaireService.submitAnswers(any(AnswerSubmitDTO.class), any(HttpServletRequest.class))) + .thenThrow(new RuntimeException("数据库连接失败")); + + // Act & Assert + mockMvc.perform(post("/api/questionnaire/submit") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"surveyId\":1,\"answers\":[]}")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.success").value(false)) + .andExpect(jsonPath("$.message").value("提交失败,请稍后重试")); + + verify(questionnaireService, times(1)).submitAnswers(any(AnswerSubmitDTO.class), any(HttpServletRequest.class)); + } + + /** + * 测试空答案列表场景 + * 覆盖:边界情况,answers为空列表 + */ + @Test + @DisplayName("提交答案成功 - 空答案列表") + void submit_EmptyAnswersList_ReturnsResult() throws Exception { + // Arrange + AnswerSubmitDTO dto = new AnswerSubmitDTO(); + dto.setSurveyId(1L); + dto.setSessionId(null); // 测试sessionId为null的情况 + dto.setAnswers(Collections.emptyList()); + + AnswerResultVO resultVO = new AnswerResultVO(); + resultVO.setResultType("unknown"); + resultVO.setResultText("无法判定体质类型"); + + HttpServletRequest request = mock(HttpServletRequest.class); + when(questionnaireService.submitAnswers(any(AnswerSubmitDTO.class), any(HttpServletRequest.class))) + .thenReturn(resultVO); + + // Act & Assert + mockMvc.perform(post("/api/questionnaire/submit") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"surveyId\":1,\"answers\":[]}")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.success").value(true)) + .andExpect(jsonPath("$.data.resultType").value("unknown")); + } + + /** + * 测试多种异常类型场景 + * 覆盖:不同类型的RuntimeException + */ + @Test + @DisplayName("提交答案失败 - 问卷不存在异常") + void submit_SurveyNotFound_ReturnsFailure() throws Exception { + // Arrange + AnswerSubmitDTO dto = new AnswerSubmitDTO(); + dto.setSurveyId(999L); + + HttpServletRequest request = mock(HttpServletRequest.class); + when(questionnaireService.submitAnswers(any(AnswerSubmitDTO.class), any(HttpServletRequest.class))) + .thenThrow(new RuntimeException("问卷不存在或未发布")); + + // Act & Assert + mockMvc.perform(post("/api/questionnaire/submit") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"surveyId\":999,\"answers\":[{\"questionId\":1,\"optionId\":1}]}")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.success").value(false)) + .andExpect(jsonPath("$.message").value("提交失败,请稍后重试")); + } + + /** + * 测试返回结果包含体质得分列表场景 + * 覆盖:constitutionScores不为空的正常场景 + */ + @DisplayName("提交答案成功 - 返回包含体质得分的评估结果") + @Test + void submit_Success_ReturnsResultWithScores() throws Exception { + // Arrange + com.ruoyi.basic.domain.dto.ConstitutionScoreDTO scoreDTO = new com.ruoyi.basic.domain.dto.ConstitutionScoreDTO(); + scoreDTO.setConstitutionAlias("pinghe"); + scoreDTO.setConstitutionName("平和体质"); + scoreDTO.setTotalScore(10); + + AnswerResultVO resultVO = new AnswerResultVO(); + resultVO.setResultType("pinghe"); + resultVO.setResultText("恭喜您,您的体质为平和体质"); + resultVO.setConstitutionScores(Collections.singletonList(scoreDTO)); + + HttpServletRequest request = mock(HttpServletRequest.class); + when(questionnaireService.submitAnswers(any(AnswerSubmitDTO.class), any(HttpServletRequest.class))) + .thenReturn(resultVO); + + // Act & Assert + mockMvc.perform(post("/api/questionnaire/submit") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"surveyId\":1,\"answers\":[{\"questionId\":1,\"optionId\":1}]}")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.success").value(true)) + .andExpect(jsonPath("$.data.constitutionScores[0].constitutionAlias").value("pinghe")) + .andExpect(jsonPath("$.data.constitutionScores[0].totalScore").value(10)); + } + + /** + * 测试复合型体质结果场景 + * 覆盖:resultType为"multiple"的情况 + */ + @Test + @DisplayName("提交答案成功 - 复合型体质结果") + void submit_MultipleType_ReturnsResult() throws Exception { + // Arrange + AnswerResultVO resultVO = new AnswerResultVO(); + resultVO.setResultType("multiple"); + resultVO.setResultText("亲爱的伽人您好,您的体质为复合型体质典型,建议综合调理。"); + + HttpServletRequest request = mock(HttpServletRequest.class); + when(questionnaireService.submitAnswers(any(AnswerSubmitDTO.class), any(HttpServletRequest.class))) + .thenReturn(resultVO); + + // Act & Assert + mockMvc.perform(post("/api/questionnaire/submit") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"surveyId\":1,\"answers\":[{\"questionId\":1,\"optionId\":1}]}")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.success").value(true)) + .andExpect(jsonPath("$.data.resultType").value("multiple")); + } + + /** + * 测试偏颇体质结果场景 + * 覆盖:resultType为"qixu"等偏颇体质 + */ + @Test + @DisplayName("提交答案成功 - 偏颇体质结果") + void submit_BiasedType_ReturnsResult() throws Exception { + // Arrange + AnswerResultVO resultVO = new AnswerResultVO(); + resultVO.setResultType("qixu"); + resultVO.setResultText("亲爱的伽人您好,您的体质为典型气虚体质。"); + + HttpServletRequest request = mock(HttpServletRequest.class); + when(questionnaireService.submitAnswers(any(AnswerSubmitDTO.class), any(HttpServletRequest.class))) + .thenReturn(resultVO); + + // Act & Assert + mockMvc.perform(post("/api/questionnaire/submit") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"surveyId\":1,\"answers\":[{\"questionId\":1,\"optionId\":1}]}")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.success").value(true)) + .andExpect(jsonPath("$.data.resultType").value("qixu")); + } + + /** + * 测试倾向体质结果场景 + * 覆盖:resultType为"qixu_tendency"等倾向体质 + */ + @Test + @DisplayName("提交答案成功 - 倾向体质结果") + void submit_TendencyType_ReturnsResult() throws Exception { + // Arrange + AnswerResultVO resultVO = new AnswerResultVO(); + resultVO.setResultType("qixu_tendency"); + resultVO.setResultText("亲爱的伽人您好,您的体质为气虚倾向体质。"); + + HttpServletRequest request = mock(HttpServletRequest.class); + when(questionnaireService.submitAnswers(any(AnswerSubmitDTO.class), any(HttpServletRequest.class))) + .thenReturn(resultVO); + + // Act & Assert + mockMvc.perform(post("/api/questionnaire/submit") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"surveyId\":1,\"answers\":[{\"questionId\":1,\"optionId\":1}]}")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.success").value(true)) + .andExpect(jsonPath("$.data.resultType").value("qixu_tendency")); + } + + /** + * 测试直接调用controller方法 - 成功场景 + */ + @Test + @DisplayName("直接调用submit方法 - 成功场景") + void submit_DirectCall_Success() { + // Arrange + AnswerSubmitDTO dto = new AnswerSubmitDTO(); + dto.setSurveyId(1L); + dto.setSessionId("session-123"); + + AnswerSubmitDTO.AnswerItem item = new AnswerSubmitDTO.AnswerItem(); + item.setQuestionId(1L); + item.setOptionId(1L); + dto.setAnswers(Collections.singletonList(item)); + + AnswerResultVO expectedResult = new AnswerResultVO(); + expectedResult.setResultType("pinghe"); + expectedResult.setResultText("测试结果"); + + HttpServletRequest request = mock(HttpServletRequest.class); + when(questionnaireService.submitAnswers(eq(dto), any(HttpServletRequest.class))) + .thenReturn(expectedResult); + + // Act + RestResponse response = questionnaireController.submit(dto, request); + + // Assert + assertNotNull(response); + assertTrue(response.getSuccess()); + assertEquals("成功", response.getMessage()); + assertNotNull(response.get("data")); + + AnswerResultVO result = (AnswerResultVO) response.get("data"); + assertEquals("pinghe", result.getResultType()); + assertEquals("测试结果", result.getResultText()); + } + + /** + * 测试直接调用controller方法 - 参数校验失败场景 + */ + @Test + @DisplayName("直接调用submit方法 - 参数校验失败场景") + void submit_DirectCall_ValidationFailure() { + // Arrange + AnswerSubmitDTO dto = new AnswerSubmitDTO(); + dto.setSurveyId(null); // 触发校验失败 + dto.setAnswers(Collections.emptyList()); + + HttpServletRequest request = mock(HttpServletRequest.class); + when(questionnaireService.submitAnswers(any(AnswerSubmitDTO.class), any(HttpServletRequest.class))) + .thenThrow(new IllegalArgumentException("问卷ID不能为空")); + + // Act + RestResponse response = questionnaireController.submit(dto, request); + + // Assert + assertNotNull(response); + assertEquals(false, response.getSuccess()); + assertEquals("问卷ID不能为空", response.getMessage()); + } + + /** + * 测试直接调用controller方法 - 系统异常场景 + */ + @Test + @DisplayName("直接调用submit方法 - 系统异常场景") + void submit_DirectCall_SystemException() { + // Arrange + AnswerSubmitDTO dto = new AnswerSubmitDTO(); + dto.setSurveyId(1L); + dto.setAnswers(Collections.emptyList()); + + HttpServletRequest request = mock(HttpServletRequest.class); + when(questionnaireService.submitAnswers(any(AnswerSubmitDTO.class), any(HttpServletRequest.class))) + .thenThrow(new RuntimeException("数据库异常")); + + // Act + RestResponse response = questionnaireController.submit(dto, request); + + // Assert + assertNotNull(response); + assertEquals(false, response.getSuccess()); + assertEquals("提交失败,请稍后重试", response.getMessage()); + } + + /** + * 测试多题目录入场景 + * 覆盖:多个答案项的情况 + */ + @Test + @DisplayName("提交多题目答案 - 正常场景") + void submit_MultipleQuestions_Success() throws Exception { + // Arrange + List answers = new ArrayList<>(); + for (long i = 1; i <= 10; i++) { + AnswerSubmitDTO.AnswerItem item = new AnswerSubmitDTO.AnswerItem(); + item.setQuestionId(i); + item.setOptionId(i); + answers.add(item); + } + + AnswerResultVO resultVO = new AnswerResultVO(); + resultVO.setResultType("qixu"); + resultVO.setResultText("气虚体质"); + + HttpServletRequest request = mock(HttpServletRequest.class); + when(questionnaireService.submitAnswers(any(AnswerSubmitDTO.class), any(HttpServletRequest.class))) + .thenReturn(resultVO); + + // Act & Assert - 使用MockMvc直接测试 + mockMvc.perform(post("/api/questionnaire/submit") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"surveyId\":1,\"answers\":[{\"questionId\":1,\"optionId\":1},{\"questionId\":2,\"optionId\":2},{\"questionId\":3,\"optionId\":3},{\"questionId\":4,\"optionId\":4},{\"questionId\":5,\"optionId\":5}]}")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.success").value(true)); + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/db/SshContextListener.java b/ruoyi-common/src/main/java/com/ruoyi/common/db/SshContextListener.java index a71c384..860d1e1 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/db/SshContextListener.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/db/SshContextListener.java @@ -7,8 +7,8 @@ import javax.servlet.ServletContextListener; import javax.servlet.annotation.WebListener; -//@Component//尽量加上这个 -//@WebListener//声明为监听器 implements ServletContextListener +@Component//尽量加上这个 +@WebListener//声明为监听器 implements ServletContextListener public class SshContextListener implements ServletContextListener{ private SshTunnelConfig sshConnectionConfig; diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java index 3661783..e736b30 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java @@ -1,17 +1,26 @@ package com.ruoyi.framework.config; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.ruoyi.common.config.RuoYiConfig; import com.ruoyi.common.constant.Constants; import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor; +import com.ruoyi.framework.config.converter.CustomMappingJackson2HttpMessageConverter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import java.math.BigInteger; +import java.util.List; + /** * 通用配置 * @@ -20,6 +29,8 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class ResourcesConfig implements WebMvcConfigurer { + @Autowired + private ObjectMapper objectMapper; @Override public void addResourceHandlers(ResourceHandlerRegistry registry) @@ -57,4 +68,25 @@ public class ResourcesConfig implements WebMvcConfigurer // 返回新的CorsFilter return new CorsFilter(source); } + + @Override + public void configureMessageConverters(List> converters) { + converters.add(getMappingJackson2HttpMessageConverter()); + } + /** + * 解决前端js处理大数字丢失精度问题,将Long和BigInteger转换成string + * + * @return + */ + public MappingJackson2HttpMessageConverter getMappingJackson2HttpMessageConverter() { + CustomMappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new CustomMappingJackson2HttpMessageConverter(); + SimpleModule simpleModule = new SimpleModule(); + // 序列换成json时,将所有的long变成string 因为js中得数字类型不能包含所有的java long值 + simpleModule.addSerializer(BigInteger.class, ToStringSerializer.instance); + simpleModule.addSerializer(Long.class, ToStringSerializer.instance); + simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance); + objectMapper.registerModule(simpleModule); + jackson2HttpMessageConverter.setObjectMapper(objectMapper); + return jackson2HttpMessageConverter; + } } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java index 8c89396..411ba43 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java @@ -138,12 +138,18 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter // 过滤请求 .authorizeRequests() // 对于登录login 注册register 验证码captchaImage 允许匿名访问 - .antMatchers("/login", "/register", "/captchaImage","/getStoreList", "/api/login", "/api/register" ).anonymous() + .antMatchers("/login", + "/register", + "/captchaImage", + "/getStoreList", + "/api/login", + "/api/register" ).anonymous() // 静态资源,可匿名访问 .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll() .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll() .antMatchers("/api/appreciate/**","/api/context/**","/api/healthy/**","/api/index/**","/api/context/searchListForCalendar", - "/api/inherit/**", "/api/moments/**", "/api/sense/**", "/api/store/**", "/api/product/**").permitAll() + "/api/inherit/**", "/api/moments/**", "/api/sense/**", "/api/store/**", "/api/product/**","/api/questionnaire/list" + ,"/api/questionnaire/list","/api/questionnaire/getOne").permitAll() // 除上面外的所有请求全部需要鉴权认证 .anyRequest().authenticated() .and() diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/converter/CustomMappingJackson2HttpMessageConverter.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/converter/CustomMappingJackson2HttpMessageConverter.java new file mode 100644 index 0000000..c17f68f --- /dev/null +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/converter/CustomMappingJackson2HttpMessageConverter.java @@ -0,0 +1,61 @@ +package com.ruoyi.framework.config.converter; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.MediaType; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; +import java.lang.reflect.Type; + +/** + * 自定义的json转换器,匹配web api(以/web/开头的controller)中的接口方法的返回参数 + * + * @author zhangby + * + */ +public class CustomMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter { + + private final static Logger logger = LoggerFactory.getLogger(CustomMappingJackson2HttpMessageConverter.class); + + /** + * 判断该转换器是否能将请求内容转换成 Java 对象 + */ + @Override + public boolean canRead(Class clazz, MediaType mediaType) { + // 不需要反序列化 + return false; + } + + /** + * 判断该转换器是否能将请求内容转换成 Java 对象 + */ + @Override + public boolean canRead(Type type, Class contextClass, MediaType mediaType) { + // 不需要反序列化 + return false; + } + + /** + * 判断该转换器是否可以将 Java 对象转换成返回内容. + * 匹配web api(形如/web/xxxx)中的接口方法的返回参数 + */ + @Override + public boolean canWrite(Class clazz, MediaType mediaType) { + if (super.canWrite(clazz, mediaType)) { + ServletRequestAttributes ra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + if (null != ra) { // web请求 + HttpServletRequest request = ra.getRequest(); + String uri = request.getRequestURI(); + /*if (uri.startsWith("/api/")) { + return true; + }*/ + return true; + } + } + return false; + } + +} diff --git a/ruoyi-im-server/src/main/resources/application-druid.yml b/ruoyi-im-server/src/main/resources/application-druid.yml index 8ae77c1..fffaa94 100644 --- a/ruoyi-im-server/src/main/resources/application-druid.yml +++ b/ruoyi-im-server/src/main/resources/application-druid.yml @@ -6,7 +6,7 @@ spring: druid: # 主库数据源 master: - url: jdbc:mysql://127.0.0.1:32768/yoga?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 + url: jdbc:mysql://127.0.0.1:32769/yoga?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 # url: jdbc:mysql://127.0.0.1:3306/yj?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 username: root password: '!Runpeng888' diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/SysAppIndex.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/SysAppIndex.java new file mode 100644 index 0000000..3c3507d --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/SysAppIndex.java @@ -0,0 +1,39 @@ +package com.ruoyi.basic.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.util.List; + +/** + *

+ * 首页菜单 + *

+ * + * @author xn + * @since 2022-09-28 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("sys_app_index") +public class SysAppIndex implements Serializable { + + private static final long serialVersionUID=1L; + + @TableId(value = "id", type = IdType.ASSIGN_UUID) + private Long id; + + private String name; + private String img; + private String color; + private String sort; + private String url; + + +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/dto/AnswerSubmitDTO.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/dto/AnswerSubmitDTO.java new file mode 100644 index 0000000..aa86fc4 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/dto/AnswerSubmitDTO.java @@ -0,0 +1,22 @@ +package com.ruoyi.basic.domain.dto; + +import lombok.Data; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Data +public class AnswerSubmitDTO { + @NotNull(message = "问卷ID不能为空") + private Long surveyId; + private String sessionId; // 可选,为空时自动生成 + @NotNull(message = "答案列表不能为空") + private List answers; + + @Data + public static class AnswerItem { + @NotNull + private Long questionId; + @NotNull + private Long optionId; + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/dto/ConstitutionScoreDTO.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/dto/ConstitutionScoreDTO.java new file mode 100644 index 0000000..10617da --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/dto/ConstitutionScoreDTO.java @@ -0,0 +1,10 @@ +package com.ruoyi.basic.domain.dto; + +import lombok.Data; + +@Data +public class ConstitutionScoreDTO { + private String constitutionAlias; + private String constitutionName; + private Integer totalScore; +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/model/AnswerResultVO.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/model/AnswerResultVO.java new file mode 100644 index 0000000..e42ec43 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/model/AnswerResultVO.java @@ -0,0 +1,14 @@ +package com.ruoyi.basic.domain.model; + +import com.ruoyi.basic.domain.dto.ConstitutionScoreDTO; +import lombok.Data; + +import java.util.List; + +// 返回的结果视图 +@Data +public class AnswerResultVO { + private String resultType; // pinghe, qixu, multiple 等 + private String resultText; // 结果描述 + private List constitutionScores; // 各体质得分 +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/model/ConstitutionVO.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/model/ConstitutionVO.java new file mode 100644 index 0000000..ae88cff --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/model/ConstitutionVO.java @@ -0,0 +1,18 @@ +package com.ruoyi.basic.domain.model; + +import lombok.Data; + +import java.util.List; + +/** + * 体质信息(含题目列表) + */ +@Data +public class ConstitutionVO { + private Long constitutionId; + private String name; // 体质名称,如“平和体质” + private String alias; // 标识,如“pinghe” + private String description; // 体质描述 + private Integer sortOrder; + private List questions; // 该体质下的题目列表 +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/model/OptionVO.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/model/OptionVO.java new file mode 100644 index 0000000..d2a3762 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/model/OptionVO.java @@ -0,0 +1,14 @@ +package com.ruoyi.basic.domain.model; + +import lombok.Data; + +/** + * 选项信息 + */ +@Data +public class OptionVO { + private Long optionId; + private String optionText; // 完全符合 / 偶尔有 / 完全不符合 + private Integer score; // 2 / 1 / 0 + private Integer sortOrder; +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/model/QuestionVO.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/model/QuestionVO.java new file mode 100644 index 0000000..47293f4 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/model/QuestionVO.java @@ -0,0 +1,17 @@ +package com.ruoyi.basic.domain.model; + +import lombok.Data; + +import java.util.List; + +/** + * 题目信息(含选项列表) + */ +@Data +public class QuestionVO { + private Long questionId; + private Integer serialNumber; // 序号(1-5) + private String content; // 题目描述 + private Integer fullScore; // 满分(固定2) + private List options; // 选项列表 +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/model/QuestionnaireVO.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/model/QuestionnaireVO.java new file mode 100644 index 0000000..46804dd --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/model/QuestionnaireVO.java @@ -0,0 +1,45 @@ +package com.ruoyi.basic.domain.model; + +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * 问卷完整信息VO + */ +@Data +public class QuestionnaireVO implements Serializable { + private Long surveyId; // 问卷ID + private String title; // 问卷标题 + private String description; // 问卷说明 + private List constitutions; // 体质列表(含题目) + + @Data + public static class ConstitutionVO implements Serializable{ // 必须是 static + private Long constitutionId; + private String name; + private String alias; + private String description; + private Integer sortOrder; + private List questions; + } + + @Data + public static class QuestionVO implements Serializable{ + private Long questionId; + private Integer serialNumber; + private String content; + private Integer fullScore; + private List options; + } + + @Data + public static class OptionVO implements Serializable{ + private Long optionId; + private String optionText; + private Integer score; + private Integer sortOrder; + } +} + diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionAnswerDetail.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionAnswerDetail.java new file mode 100644 index 0000000..b526611 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionAnswerDetail.java @@ -0,0 +1,16 @@ +package com.ruoyi.basic.domain.question; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +@Data +@TableName("question_answer_detail") +public class QuestionAnswerDetail { + @TableId(type = IdType.AUTO) + private Long id; + private Long sheetId; + private Long questionId; + private Long optionId; + @TableField(exist = false) + private Integer score; +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionAnswerSheet.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionAnswerSheet.java new file mode 100644 index 0000000..8d04695 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionAnswerSheet.java @@ -0,0 +1,20 @@ +package com.ruoyi.basic.domain.question; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import java.time.LocalDateTime; + +@Data +@TableName("question_answer_sheet") +public class QuestionAnswerSheet { + @TableId(type = IdType.AUTO) + private Long id; + private Long surveyId; + @TableField("app_user_id") + private Long userId; + private String sessionId; + private LocalDateTime submitTime; + private String ipAddress; + private String resultType; + private String resultText; +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionConstitutionScore.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionConstitutionScore.java new file mode 100644 index 0000000..f525775 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionConstitutionScore.java @@ -0,0 +1,14 @@ +package com.ruoyi.basic.domain.question; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +@Data +@TableName("question_constitution_score") +public class QuestionConstitutionScore { + @TableId(type = IdType.AUTO) + private Long id; + private Long sheetId; + private Long constitutionId; + private Integer totalScore; +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionConstitutionType.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionConstitutionType.java new file mode 100644 index 0000000..f102534 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionConstitutionType.java @@ -0,0 +1,16 @@ +package com.ruoyi.basic.domain.question; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +@Data +@TableName("question_constitution_type") +public class QuestionConstitutionType { + @TableId(type = IdType.AUTO) + private Long id; + private Long surveyId; + private String name; + private String alias; + private String description; + private Integer sortOrder; +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionOption.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionOption.java new file mode 100644 index 0000000..a7a975d --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionOption.java @@ -0,0 +1,15 @@ +package com.ruoyi.basic.domain.question; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +@Data +@TableName("question_option") +public class QuestionOption { + @TableId(type = IdType.AUTO) + private Long id; + private Long questionId; + private String optionText; + private Integer score; + private Integer sortOrder; +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionQuestion.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionQuestion.java new file mode 100644 index 0000000..d1ea8c5 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionQuestion.java @@ -0,0 +1,15 @@ +package com.ruoyi.basic.domain.question; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +@Data +@TableName("question_question") +public class QuestionQuestion { + @TableId(type = IdType.AUTO) + private Long id; + private Long constitutionId; + private Integer serialNumber; + private String content; + private Integer fullScore; +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionRule.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionRule.java new file mode 100644 index 0000000..8c9cad8 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionRule.java @@ -0,0 +1,24 @@ +package com.ruoyi.basic.domain.question; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import java.time.LocalDateTime; + +@Data +@TableName("question_rule") +public class QuestionRule { + @TableId(type = IdType.AUTO) + private Long id; + private Long surveyId; + private String ruleName; + private Long targetConstitutionId; // 目标体质ID + private Integer minScore; // 得分下限(包含) + private Integer maxScore; // 得分上限(包含) + private Integer requireOtherMaxScore;// 其他体质最高分上限 + private Integer requireOtherMinScore;// 其他体质最低分下限(预留) + private Integer priority;//优先级(数字越小越先匹配) + private Integer status;//状态:0-启用 1-禁用 + private String resultText; + private LocalDateTime createTime; + private LocalDateTime updateTime; +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionSurvey.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionSurvey.java new file mode 100644 index 0000000..57b1d96 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionSurvey.java @@ -0,0 +1,17 @@ +package com.ruoyi.basic.domain.question; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import java.time.LocalDateTime; + +@Data +@TableName("question_survey") +public class QuestionSurvey { + @TableId(type = IdType.AUTO) + private Long id; + private String title; + private String description; + private Integer status; // 0-草稿 1-发布 2-关闭 + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/QuestionAnswerDetailMapper.java b/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/QuestionAnswerDetailMapper.java new file mode 100644 index 0000000..0ea37c1 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/QuestionAnswerDetailMapper.java @@ -0,0 +1,13 @@ +package com.ruoyi.basic.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.ruoyi.basic.domain.question.QuestionAnswerDetail; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import java.util.List; + +@Mapper +public interface QuestionAnswerDetailMapper extends BaseMapper { + void insertBatch(@Param("list") List list); + List getBySheetId(@Param("sheetId") Long sheetId); +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/QuestionAnswerSheetMapper.java b/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/QuestionAnswerSheetMapper.java new file mode 100644 index 0000000..099cb53 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/QuestionAnswerSheetMapper.java @@ -0,0 +1,10 @@ +package com.ruoyi.basic.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.ruoyi.basic.domain.question.QuestionAnswerSheet; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface QuestionAnswerSheetMapper extends BaseMapper { + // 可扩展自定义查询 +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/QuestionConstitutionScoreMapper.java b/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/QuestionConstitutionScoreMapper.java new file mode 100644 index 0000000..2e091ad --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/QuestionConstitutionScoreMapper.java @@ -0,0 +1,12 @@ +package com.ruoyi.basic.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.ruoyi.basic.domain.question.QuestionConstitutionScore; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import java.util.List; + +@Mapper +public interface QuestionConstitutionScoreMapper extends BaseMapper { + void insertBatch(@Param("list") List list); +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/QuestionConstitutionTypeMapper.java b/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/QuestionConstitutionTypeMapper.java new file mode 100644 index 0000000..7cb9a6d --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/QuestionConstitutionTypeMapper.java @@ -0,0 +1,9 @@ +package com.ruoyi.basic.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.ruoyi.basic.domain.question.QuestionConstitutionType; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface QuestionConstitutionTypeMapper extends BaseMapper { +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/QuestionOptionMapper.java b/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/QuestionOptionMapper.java new file mode 100644 index 0000000..bee8875 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/QuestionOptionMapper.java @@ -0,0 +1,9 @@ +package com.ruoyi.basic.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.ruoyi.basic.domain.question.QuestionOption; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface QuestionOptionMapper extends BaseMapper { +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/QuestionQuestionMapper.java b/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/QuestionQuestionMapper.java new file mode 100644 index 0000000..67b64f7 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/QuestionQuestionMapper.java @@ -0,0 +1,9 @@ +package com.ruoyi.basic.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.ruoyi.basic.domain.question.QuestionQuestion; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface QuestionQuestionMapper extends BaseMapper { +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/QuestionRuleMapper.java b/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/QuestionRuleMapper.java new file mode 100644 index 0000000..07a7511 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/QuestionRuleMapper.java @@ -0,0 +1,18 @@ +package com.ruoyi.basic.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.ruoyi.basic.domain.question.QuestionRule; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import java.util.List; + +@Mapper +public interface QuestionRuleMapper extends BaseMapper { + + /** + * 根据问卷ID查询启用的规则(按优先级升序) + * @param surveyId 问卷ID + * @return 规则列表 + */ + List selectEnabledBySurveyId(@Param("surveyId") Long surveyId); +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/QuestionSurveyMapper.java b/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/QuestionSurveyMapper.java new file mode 100644 index 0000000..67ed03f --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/QuestionSurveyMapper.java @@ -0,0 +1,9 @@ +package com.ruoyi.basic.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.ruoyi.basic.domain.question.QuestionSurvey; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface QuestionSurveyMapper extends BaseMapper { +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/YjStoreMapper.java b/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/YjStoreMapper.java index a2b7d7c..110f62e 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/YjStoreMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/mapper/YjStoreMapper.java @@ -2,6 +2,7 @@ package com.ruoyi.basic.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.ruoyi.basic.domain.SysAppIndex; import com.ruoyi.basic.domain.YjStore; import java.util.List; @@ -21,4 +22,6 @@ public interface YjStoreMapper extends BaseMapper { List getStoreList(); List getChilds(Long id); + + List getAppIndex(); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/service/QuestionRuleService.java b/ruoyi-system/src/main/java/com/ruoyi/basic/service/QuestionRuleService.java new file mode 100644 index 0000000..2c276ec --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/service/QuestionRuleService.java @@ -0,0 +1,16 @@ +package com.ruoyi.basic.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.ruoyi.basic.domain.question.QuestionRule; + +import java.util.List; + +public interface QuestionRuleService extends IService { + + /** + * 获取问卷启用的规则列表(按优先级排序) + * @param surveyId 问卷ID + * @return 规则列表 + */ + List getEnabledRulesBySurveyId(Long surveyId); +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/service/QuestionnaireService.java b/ruoyi-system/src/main/java/com/ruoyi/basic/service/QuestionnaireService.java new file mode 100644 index 0000000..a024c79 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/service/QuestionnaireService.java @@ -0,0 +1,30 @@ +package com.ruoyi.basic.service; + +import com.ruoyi.basic.domain.dto.AnswerSubmitDTO; +import com.ruoyi.basic.domain.model.AnswerResultVO; +import com.ruoyi.basic.domain.model.QuestionnaireVO; + +import javax.servlet.http.HttpServletRequest; + +public interface QuestionnaireService { + + /** + * 获取问卷完整信息(含体质、题目、选项) + * @return 问卷VO + */ + QuestionnaireVO getQuestionnaire(); + + /** + * 提交问卷答案 + * @param dto 提交数据 + * @param request Http请求(用于获取IP) + * @return 评估结果 + */ + AnswerResultVO submitAnswers(AnswerSubmitDTO dto, HttpServletRequest request); + + /** + * 根据答卷ID查询结果 + * @return 评估结果 + */ + AnswerResultVO getResultBySheetId(); +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/service/YjStoreService.java b/ruoyi-system/src/main/java/com/ruoyi/basic/service/YjStoreService.java index 2bb0b76..9f7a4f2 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/basic/service/YjStoreService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/service/YjStoreService.java @@ -3,6 +3,7 @@ package com.ruoyi.basic.service; import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.RestResponse; +import com.ruoyi.basic.domain.SysAppIndex; import com.ruoyi.basic.domain.YjStore; import java.util.List; @@ -21,4 +22,6 @@ public interface YjStoreService extends IService { List getStoreListByTenantId(String tenantId); YjStore getOne(Long id); + + RestResponse getIndex(); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/service/impl/BusinessSysDictDataService.java b/ruoyi-system/src/main/java/com/ruoyi/basic/service/impl/BusinessSysDictDataService.java new file mode 100644 index 0000000..4c6e484 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/service/impl/BusinessSysDictDataService.java @@ -0,0 +1,40 @@ +package com.ruoyi.basic.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.ruoyi.common.core.domain.entity.SysDictData; +import com.ruoyi.system.service.ISysDictDataService; +import com.ruoyi.system.service.ISysDictTypeService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Arrays; +import java.util.List; + +/** + * @author :zhangbaoyu + * @date :Created in 2020-01-14 17:24 + */ +@Service +@Transactional +public class BusinessSysDictDataService { + + @Autowired + private ISysDictDataService sysDictDataService; + + + + /** + * 某字典数据 + * + * @param dictType + * @return + */ + public List dictTypeDataList(String dictType) { + return sysDictDataService.dictTypeDataList(dictType); + } + + +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/service/impl/QuestionRuleServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/basic/service/impl/QuestionRuleServiceImpl.java new file mode 100644 index 0000000..e83e967 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/service/impl/QuestionRuleServiceImpl.java @@ -0,0 +1,21 @@ +package com.ruoyi.basic.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.ruoyi.basic.domain.question.QuestionRule; +import com.ruoyi.basic.mapper.QuestionRuleMapper; +import com.ruoyi.basic.service.QuestionRuleService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import java.util.List; + +@Service +@RequiredArgsConstructor +public class QuestionRuleServiceImpl extends ServiceImpl implements QuestionRuleService { + + private final QuestionRuleMapper ruleMapper; + + @Override + public List getEnabledRulesBySurveyId(Long surveyId) { + return ruleMapper.selectEnabledBySurveyId(surveyId); + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/service/impl/QuestionnaireServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/basic/service/impl/QuestionnaireServiceImpl.java new file mode 100644 index 0000000..6ecec67 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/service/impl/QuestionnaireServiceImpl.java @@ -0,0 +1,569 @@ +package com.ruoyi.basic.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.servlet.ServletUtil; +import cn.hutool.http.HttpUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.ruoyi.basic.domain.dto.AnswerSubmitDTO; +import com.ruoyi.basic.domain.dto.ConstitutionScoreDTO; +import com.ruoyi.basic.domain.model.*; +import com.ruoyi.basic.domain.question.*; +import com.ruoyi.basic.mapper.*; +import com.ruoyi.basic.service.QuestionRuleService; +import com.ruoyi.basic.service.QuestionnaireService; +import com.ruoyi.common.utils.SecurityUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.servlet.http.HttpServletRequest; +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + +@Slf4j +@Service +@RequiredArgsConstructor +public class QuestionnaireServiceImpl extends ServiceImpl + implements QuestionnaireService { + + private final QuestionSurveyMapper surveyMapper; + private final QuestionConstitutionTypeMapper constitutionTypeMapper; + private final QuestionQuestionMapper questionMapper; + private final QuestionOptionMapper optionMapper; + private final QuestionAnswerDetailMapper answerDetailMapper; + private final QuestionConstitutionScoreMapper constitutionScoreMapper; + private final QuestionRuleService ruleService; + + @Override + @Transactional(rollbackFor = Exception.class) + public AnswerResultVO submitAnswers(AnswerSubmitDTO dto, HttpServletRequest request) { + // 1. 校验问卷 + QuestionSurvey survey = surveyMapper.selectById(dto.getSurveyId()); + if (survey == null || survey.getStatus() != 1) { + throw new RuntimeException("问卷不存在或未发布"); + } + + // 2. 保存答卷主表 + QuestionAnswerSheet sheet = new QuestionAnswerSheet(); + sheet.setSurveyId(dto.getSurveyId()); + sheet.setUserId(SecurityUtils.getAppLoginUser().getAppUserId()); + sheet.setSessionId(StrUtil.blankToDefault(dto.getSessionId(), UUID.randomUUID().toString())); + sheet.setSubmitTime(LocalDateTime.now()); + sheet.setIpAddress(ServletUtil.getClientIP(request)); + this.save(sheet); + Long sheetId = sheet.getId(); + + // 3. 批量保存答案明细 + List details = dto.getAnswers().stream() + .map(item -> { + QuestionAnswerDetail detail = new QuestionAnswerDetail(); + detail.setSheetId(sheetId); + detail.setQuestionId(item.getQuestionId()); + detail.setOptionId(item.getOptionId()); + return detail; + }).collect(Collectors.toList()); + answerDetailMapper.insertBatch(details); + + // 4. 计算各模块总分 + List scores = computeConstitutionScores(sheetId); + if (CollUtil.isNotEmpty(scores)) { + constitutionScoreMapper.insertBatch(scores); + } else { + scores = Collections.emptyList(); + } + + // 5. 获取所有模块信息(用于构建上下文和VO) + // 获取所有模块信息 + List constitutions = constitutionTypeMapper.selectList(null); + Map constitutionMap = constitutions.stream() + .collect(Collectors.toMap(QuestionConstitutionType::getId, c -> c)); + // 构建得分映射(体质ID -> 总分) + Map scoreById = scores.stream() + .collect(Collectors.toMap(QuestionConstitutionScore::getConstitutionId, QuestionConstitutionScore::getTotalScore)); + + // 动态规则匹配 +// AnswerResultVO result = determineResultByRules(scoreById, constitutionMap, dto.getSurveyId()); + AnswerResultVO result = determineResult(scores,sheetId); + + // 5.1 更新答卷结果 + sheet.setResultType(result.getResultType()); + sheet.setResultText(result.getResultText()); + this.updateById(sheet); + // 更新答卷、返回结果 + return result; + } + + /** + * 获取问卷完整信息(带缓存) + * @return 问卷VO + */ + @Override +// @Cacheable(value = "questionnaire", unless = "#result == null") + public QuestionnaireVO getQuestionnaire() { + // 1. 查询问卷基本信息 +// QuestionSurvey survey = surveyMapper.selectById(surveyId); + QuestionSurvey survey = surveyMapper.selectOne(new QueryWrapper() + .eq("status", 1) + .orderByDesc("create_time") + .last("LIMIT 1") + ); + if (survey == null) { + return null; + } + Long surveyId=survey.getId(); + // 2. 查询该问卷下的所有体质类型(按sort_order排序) + List constitutions = constitutionTypeMapper.selectList( + new LambdaQueryWrapper() + .eq(QuestionConstitutionType::getSurveyId, surveyId) + .orderByAsc(QuestionConstitutionType::getSortOrder) + ); + if (CollUtil.isEmpty(constitutions)) { + QuestionnaireVO vo = new QuestionnaireVO(); + vo.setSurveyId(surveyId); + vo.setTitle(survey.getTitle()); + vo.setDescription(survey.getDescription()); + vo.setConstitutions(Collections.emptyList()); + return vo; + } + + // 3. 查询所有体质对应的题目(批量,避免N+1) + List constitutionIds = constitutions.stream() + .map(QuestionConstitutionType::getId) + .collect(Collectors.toList()); + List allQuestions = questionMapper.selectList( + new LambdaQueryWrapper() + .in(QuestionQuestion::getConstitutionId, constitutionIds) + .orderByAsc(QuestionQuestion::getConstitutionId, QuestionQuestion::getSerialNumber) + ); + if (CollUtil.isEmpty(allQuestions)) { + // 没有题目则返回空列表 + QuestionnaireVO vo = new QuestionnaireVO(); + vo.setSurveyId(surveyId); + vo.setTitle(survey.getTitle()); + vo.setDescription(survey.getDescription()); + vo.setConstitutions(buildConstitutionVOs(constitutions, Collections.emptyList(), Collections.emptyList())); + return vo; + } + + // 4. 查询所有题目的选项(每道题固定3个选项,也可批量查) + List questionIds = allQuestions.stream() + .map(QuestionQuestion::getId) + .collect(Collectors.toList()); + List allOptions = optionMapper.selectList( + new LambdaQueryWrapper() + .in(QuestionOption::getQuestionId, questionIds) + .orderByAsc(QuestionOption::getQuestionId, QuestionOption::getSortOrder) + ); + + // 5. 构建 Map 结构便于组装 + Map> questionsByConstitutionId = allQuestions.stream() + .collect(Collectors.groupingBy(QuestionQuestion::getConstitutionId)); + Map> optionsByQuestionId = allOptions.stream() + .collect(Collectors.groupingBy(QuestionOption::getQuestionId)); + + // 6. 组装 VO + List constitutionVOs = constitutions.stream().map(ct -> { + QuestionnaireVO.ConstitutionVO ctVO = new QuestionnaireVO.ConstitutionVO(); + ctVO.setConstitutionId(ct.getId()); + ctVO.setName(ct.getName()); + ctVO.setAlias(ct.getAlias()); + ctVO.setDescription(ct.getDescription()); + ctVO.setSortOrder(ct.getSortOrder()); + + List questions = questionsByConstitutionId.getOrDefault(ct.getId(), Collections.emptyList()); + List questionVOs = questions.stream().map(q -> { + QuestionnaireVO.QuestionVO qVO = new QuestionnaireVO.QuestionVO(); + qVO.setQuestionId(q.getId()); + qVO.setSerialNumber(q.getSerialNumber()); + qVO.setContent(q.getContent()); + qVO.setFullScore(q.getFullScore()); + + List options = optionsByQuestionId.getOrDefault(q.getId(),Collections.emptyList()); + List optionVOs = options.stream().map(opt -> { + QuestionnaireVO.OptionVO optVO = new QuestionnaireVO.OptionVO(); + optVO.setOptionId(opt.getId()); + optVO.setOptionText(opt.getOptionText()); + optVO.setScore(opt.getScore()); + optVO.setSortOrder(opt.getSortOrder()); + return optVO; + }).collect(Collectors.toList()); + qVO.setOptions(optionVOs); + return qVO; + }).collect(Collectors.toList()); + ctVO.setQuestions(questionVOs); + return ctVO; + }).collect(Collectors.toList()); + + QuestionnaireVO vo = new QuestionnaireVO(); + vo.setSurveyId(surveyId); + vo.setTitle(survey.getTitle()); + vo.setDescription(survey.getDescription()); + vo.setConstitutions(constitutionVOs); + return vo; + } + + @Override + public AnswerResultVO getResultBySheetId() { + QuestionAnswerSheet sheet = this.getOne(new QueryWrapper() + .eq("app_user_id",SecurityUtils.getAppLoginUser().getAppUserId() ) + .orderByDesc("submit_time") + .last("LIMIT 1") + ); + if (sheet == null) { + throw new RuntimeException("答卷不存在"); + } + Long sheetId=sheet.getId(); + List scores = constitutionScoreMapper.selectList( + new LambdaQueryWrapper().eq(QuestionConstitutionScore::getSheetId, sheetId)); + List constitutions = constitutionTypeMapper.selectList(null); + Map constitutionMap = constitutions.stream() + .collect(Collectors.toMap(QuestionConstitutionType::getId, c -> c)); + AnswerResultVO vo = new AnswerResultVO(); + vo.setResultType(sheet.getResultType()); + vo.setResultText(sheet.getResultText()); + List dtoList = scores.stream().map(score -> { + QuestionConstitutionType ct = constitutionMap.get(score.getConstitutionId()); + ConstitutionScoreDTO dto = new ConstitutionScoreDTO(); + dto.setConstitutionAlias(ct.getAlias()); + dto.setConstitutionName(ct.getName()); + dto.setTotalScore(score.getTotalScore()); + return dto; + }).collect(Collectors.toList()); + vo.setConstitutionScores(dtoList); + return vo; + } + /** + * 计算答卷中各体质的得分 + */ + private List computeConstitutionScores(Long sheetId) { + // 查询该答卷的所有答案 + List details =answerDetailMapper.getBySheetId(sheetId); + if (CollUtil.isEmpty(details)) { + return Collections.emptyList(); + } + // 构建题目->选项分值的映射 + Map optionScoreMap = details.stream() + .collect(Collectors.toMap(QuestionAnswerDetail::getQuestionId, + d -> d.getScore())); + + // 按体质分组计算总分 + Map constitutionScoreMap = new HashMap<>(); + for (QuestionAnswerDetail detail : details) { + Long questionId = detail.getQuestionId(); + QuestionQuestion question = questionMapper.selectById(questionId); + Long constitutionId = question.getConstitutionId(); + Integer score = optionScoreMap.getOrDefault(questionId, 0); + constitutionScoreMap.merge(constitutionId, score, Integer::sum); + } + + // 转为实体列表 + return constitutionScoreMap.entrySet().stream() + .map(entry -> { + QuestionConstitutionScore score = new QuestionConstitutionScore(); + score.setSheetId(sheetId); + score.setConstitutionId(entry.getKey()); + score.setTotalScore(entry.getValue()); + return score; + }).collect(Collectors.toList()); + } + + /** + * 根据得分规则判定体质结果 + */ + private AnswerResultVO determineResult(List scores, Long sheetId) { + // 获取所有体质信息(含 alias, name, isBalanced) + List constitutions = constitutionTypeMapper.selectList(null); + Map constitutionMap = constitutions.stream() + .collect(Collectors.toMap(QuestionConstitutionType::getId, c -> c)); + + // 构建体质别名 -> 总分 + Map scoreMap = new HashMap<>(); + for (QuestionConstitutionScore score : scores) { + QuestionConstitutionType ct = constitutionMap.get(score.getConstitutionId()); + if (ct != null) { + scoreMap.put(ct.getAlias(), score.getTotalScore()); + } + } + + Integer pingheScore = scoreMap.getOrDefault("pinghe", 0); + // 偏颇体质(排除平和) + Map biasedScores = new HashMap<>(scoreMap); + biasedScores.remove("pinghe"); + + // 规则1: 平和体质(总分≥8 且所有偏颇<6) + boolean isPurePinghe = pingheScore >= 8 && biasedScores.values().stream().allMatch(v -> v < 6); + if (isPurePinghe) { + return buildResult("pinghe", "恭喜您,您的体质为“平和体质”,非常完美。请联系您的馆主或教练,领取训练及生活方案,继续保持哦。", scores, constitutionMap); + } + + // 规则2: 某偏颇体质总分 ≥ 8 + Optional highKey = biasedScores.entrySet().stream() + .filter(e -> e.getValue() >= 8) .map(Map.Entry::getKey).findFirst(); + if (highKey.isPresent()) { + String alias = highKey.get(); + String name = constitutionMap.values().stream() + .filter(ct -> ct.getAlias().equals(alias)).findFirst().get().getName(); + String text = String.format("亲爱的伽人您好,您的体质为典型%s。请联系您的馆主或教练,领取训练及生活方案,快速调整哦。", name); + return buildResult(alias, text, scores, constitutionMap); + } + // 规则4: 两种及以上偏颇体质分数 ≥ 7 + long count = biasedScores.values().stream().filter(v -> v >= 7).count(); + if (count >= 2) { + String text = "亲爱的伽人您好,您的体质为复合型体质典型,建议综合调理。请联系您的馆主或教练,领取训练及生活方案,快速调整哦。"; + return buildResult("multiple", text, scores, constitutionMap); + } + + // 规则3: 某偏颇体质总分在 6~7 之间 + Optional midKey = biasedScores.entrySet().stream() + .filter(e -> e.getValue() >= 6 && e.getValue() <= 7) .map(Map.Entry::getKey).findFirst(); + if (midKey.isPresent()) { + String alias = midKey.get(); + String name = constitutionMap.values().stream() + .filter(ct -> ct.getAlias().equals(alias)).findFirst().get().getName().substring(0,2); + String text = String.format("亲爱的伽人您好,您的体质为%s倾向体质。请联系您的馆主或教练,领取训练及生活方案,快速调整哦。", name); + return buildResult(alias + "_tendency", text, scores, constitutionMap); + } + + + + // 默认兜底(一般不会触发) + return buildResult("unknown", "无法判定体质类型,请重新测评。", scores, constitutionMap); + } + + + // 修改 determineResult 方法,使用数据库规则动态判定 + + /** + * + * @param scoreById 体质得分映射(体质ID -> 总分) + * @param constitutionMap 模块信息 + * @param surveyId 问卷id + * @return + */ + private AnswerResultVO determineResultByRules(Map scoreById, + Map constitutionMap, + Long surveyId) { + List rules = ruleService.getEnabledRulesBySurveyId(surveyId); + if (rules.isEmpty()) { + return buildFallbackResult(scoreById, constitutionMap); + } + + for (Long aLong : scoreById.keySet()) { + + Integer score = scoreById.get(aLong); + if (score == null) continue; + + if (score >=8) { + // + scoreById.values().stream().filter(v -> v < 6).count(); + } + + } + + // + + // 预计算一些统计值,供规则使用 + Map biasedScores = new HashMap<>(scoreById); +// Long pingheId = constitutionMap.values().stream() +// .filter(ct -> ct.getIsBalanced() == 1) +// .findFirst().map(QuestionConstitutionType::getId).orElse(null); +// if (pingheId != null) { +// biasedScores.remove(pingheId); +// } + int maxBiasedScore = biasedScores.values().stream().mapToInt(v -> v).max().orElse(0); + long countBiasedGe7 = biasedScores.values().stream().filter(v -> v >= 7).count(); + + // 按优先级匹配规则 +// for (QuestionRule rule : rules) { +// boolean matched = false; +// if ("constitution".equals(rule.getTargetType())) { +// Long targetId = rule.getTargetConstitutionId(); +// if (targetId == null) continue; +// Integer targetScore = scoreById.getOrDefault(targetId, 0); +// // 检查目标体质得分区间 +// boolean scoreInRange = true; +// if (rule.getMinScore() != null && targetScore < rule.getMinScore()) scoreInRange = false; +// if (rule.getMaxScore() != null && targetScore > rule.getMaxScore()) scoreInRange = false; +// if (!scoreInRange) continue; +// +// // 检查“其他体质最高分上限”条件 +// boolean otherMaxOk = true; +// if (rule.getRequireOtherMaxScore() != null) { +// // 若目标体质是平和体质,则其他体质包括所有偏颇;否则其他体质指除目标外的所有体质(含平和?按业务调整) +//// if (pingheId != null && targetId.equals(pingheId)) { +//// int maxOther = biasedScores.values().stream().mapToInt(v -> v).max().orElse(0); +//// if (maxOther >= rule.getRequireOtherMaxScore()) otherMaxOk = false; +//// } else { +// // 非平和体质:其他体质指除自己外所有(含平和) +// Map otherScores = new HashMap<>(scoreById); +// otherScores.remove(targetId); +// int maxOther = otherScores.values().stream().mapToInt(v -> v).max().orElse(0); +// if (maxOther >= rule.getRequireOtherMaxScore()) otherMaxOk = false; +//// } +// } +// matched = scoreInRange && otherMaxOk; +// } +// else if ("compound".equals(rule.getTargetType())) { +// // 复合型规则:例如 countBiasedGe7 >= 2,可存储在 condition_json 中 +// if (rule.getConditionJson() != null && !rule.getConditionJson().isEmpty()) { +// // 解析 JSON 条件,例如 {"countBiasedGe7": 2} +// // 简化:只支持 countBiasedGe7 比较 +// // 实际可用 Jackson 解析 +// matched = countBiasedGe7 >= 2; // 示例,可改为读取 JSON +// } +// } +// +// if (matched) { +// // 渲染结果文案:替换 ${targetName} 等变量 +// String targetName = ""; +// if (rule.getTargetConstitutionId() != null) { +// QuestionConstitutionType ct = constitutionMap.get(rule.getTargetConstitutionId()); +// targetName = ct != null ? ct.getName() : ""; +// } +// String resultText = rule.getResultText().replace("${targetName}", targetName); +// // 确定结果类型:若目标体质存在则用其别名,否则用 rule 的 targetType +// String resultType = ""; +// if (rule.getTargetConstitutionId() != null) { +// QuestionConstitutionType ct = constitutionMap.get(rule.getTargetConstitutionId()); +// resultType = ct != null ? ct.getAlias() : rule.getTargetType(); +// } else { +// resultType = rule.getTargetType(); // "compound" +// } +// // 构建得分明细列表 +// List dtoList = scoreById.entrySet().stream() +// .map(e -> { +// QuestionConstitutionType ct = constitutionMap.get(e.getKey()); +// ConstitutionScoreDTO dto = new ConstitutionScoreDTO(); +// dto.setConstitutionAlias(ct.getAlias()); +// dto.setConstitutionName(ct.getName()); +// dto.setTotalScore(e.getValue()); +// return dto; +// }).collect(Collectors.toList()); +// AnswerResultVO vo = new AnswerResultVO(); +// vo.setResultType(resultType); +// vo.setResultText(resultText); +// vo.setConstitutionScores(dtoList); +// return vo; +// } +// } + return buildFallbackResult(scoreById, constitutionMap); + } + + private AnswerResultVO buildFallbackResult(Map scoreById, + Map constitutionMap) { + // 兜底结果 + List dtoList = scoreById.entrySet().stream() + .map(e -> { + QuestionConstitutionType ct = constitutionMap.get(e.getKey()); + ConstitutionScoreDTO dto = new ConstitutionScoreDTO(); + dto.setConstitutionAlias(ct.getAlias()); + dto.setConstitutionName(ct.getName()); + dto.setTotalScore(e.getValue()); + return dto; + }).collect(Collectors.toList()); + AnswerResultVO vo = new AnswerResultVO(); + vo.setResultType("unknown"); + vo.setResultText("无法判定体质类型,请重新测评。"); + vo.setConstitutionScores(dtoList); + return vo; + } + + // 简单表达式求值(示例,实际可用 Aviator/SpEL) + private boolean evaluateCondition(String expression, int pingheScore, int maxBiasedScore, String alias, String name) { + // 替换变量后使用 JavaScript 引擎或 SpEL + // 例如:expression = "pingheScore >= 8 && maxBiasedScore < 6" + // 实际实现请引入 AviatorEvaluator + return false; // 伪代码 + } + + // 模板渲染(支持 ${name} 等变量) + private String renderTemplate(String template, String name, int pingheScore) { + return template.replace("${name}", name).replace("${pingheScore}", String.valueOf(pingheScore)); + } + + private AnswerResultVO buildResult(String resultType, String resultText, + List scores, + Map constitutionMap) { + AnswerResultVO vo = new AnswerResultVO(); + vo.setResultType(resultType); + vo.setResultText(resultText); + + List dtoList = scores.stream().map(score -> { + QuestionConstitutionType ct = constitutionMap.get(score.getConstitutionId()); + ConstitutionScoreDTO dto = new ConstitutionScoreDTO(); + dto.setConstitutionAlias(ct.getAlias()); + dto.setConstitutionName(ct.getName()); + dto.setTotalScore(score.getTotalScore()); + return dto; + }).collect(Collectors.toList()); + vo.setConstitutionScores(dtoList); + return vo; + } + + /** + * 构建体质VO列表(包含题目和选项) + * @param constitutions 体质类型列表 + * @param allQuestions 所有题目列表(可能为空) + * @param allOptions 所有选项列表(可能为空) + * @return 体质VO列表 + */ + private List buildConstitutionVOs( + List constitutions, + List allQuestions, + List allOptions) { + + if (CollUtil.isEmpty(constitutions)) { + return Collections.emptyList(); + } + + // 按体质ID分组题目 + Map> questionsByConstitutionId = allQuestions.stream() + .collect(Collectors.groupingBy(QuestionQuestion::getConstitutionId)); + + // 按题目ID分组选项 + Map> optionsByQuestionId = allOptions.stream() + .collect(Collectors.groupingBy(QuestionOption::getQuestionId)); + + // 构建结果 + return constitutions.stream().map(ct -> { + QuestionnaireVO.ConstitutionVO ctVO = new QuestionnaireVO.ConstitutionVO(); + ctVO.setConstitutionId(ct.getId()); + ctVO.setName(ct.getName()); + ctVO.setAlias(ct.getAlias()); + ctVO.setDescription(ct.getDescription()); + ctVO.setSortOrder(ct.getSortOrder()); + + // 获取该体质下的题目 + List questions = questionsByConstitutionId.getOrDefault(ct.getId(), Collections.emptyList()); + List questionVOs = questions.stream().map(q -> { + QuestionnaireVO.QuestionVO qVO = new QuestionnaireVO.QuestionVO(); + qVO.setQuestionId(q.getId()); + qVO.setSerialNumber(q.getSerialNumber()); + qVO.setContent(q.getContent()); + qVO.setFullScore(q.getFullScore()); + + // 获取该题目下的选项 + List options = optionsByQuestionId.getOrDefault(q.getId(), Collections.emptyList()); + List optionVOs = options.stream().map(opt -> { + QuestionnaireVO.OptionVO optVO = new QuestionnaireVO.OptionVO(); + optVO.setOptionId(opt.getId()); + optVO.setOptionText(opt.getOptionText()); + optVO.setScore(opt.getScore()); + optVO.setSortOrder(opt.getSortOrder()); + return optVO; + }).collect(Collectors.toList()); + qVO.setOptions(optionVOs); + return qVO; + }).collect(Collectors.toList()); + + ctVO.setQuestions(questionVOs); + return ctVO; + }).collect(Collectors.toList()); + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/service/impl/YjStoreServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/basic/service/impl/YjStoreServiceImpl.java index 5ba7a97..7159292 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/basic/service/impl/YjStoreServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/service/impl/YjStoreServiceImpl.java @@ -6,19 +6,31 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.RestResponse; +import com.ruoyi.basic.domain.SysAppIndex; import com.ruoyi.basic.domain.YjStore; import com.ruoyi.basic.mapper.YjStoreMapper; import com.ruoyi.basic.service.YjAppUserService; import com.ruoyi.basic.service.YjStoreService; +import com.ruoyi.common.constant.CacheConstants; +import com.ruoyi.common.constant.Constants; import com.ruoyi.common.core.domain.entity.AppUser; +import com.ruoyi.common.core.domain.model.AppLoginUser; +import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.utils.SecurityUtils; +import com.ruoyi.common.utils.spring.SpringUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; + +import org.springframework.security.core.token.TokenService; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; /** *

@@ -50,19 +62,37 @@ public class YjStoreServiceImpl extends ServiceImpl impl String tenantId= baseMapper.getOne(appUser.getVisitStore()).getTenantId(); List list=getStoreListByTenantId(tenantId); - - list.forEach(l->{ - if (l.getParentId().equals("0")){ - l.setStoreName(l.getStoreName()+"(总店)"); - } - - }); - return new RestResponse().setSuccess(true).setData(list); + List list1=new ArrayList<>(); +// list.forEach(l->{ +// if (l.getParentId().equals("0")){ +// l.setStoreName(l.getStoreName()+"(总店)"); +// l.setChildList(baseMapper.getChilds(l.getId())); +// } +// }); + YjStore store=list.stream().filter(s-> s.getParentId().equals(new Long(0))).collect(Collectors.toList()).get(0); + list.remove(store); + store.setChildList(list); + list1.add(store); + return new RestResponse().setSuccess(true).setData(list1); } - + @Autowired + private RedisCache redisCache; @Override public RestResponse changeStore(Long visitStoreId){ - AppUser appUser = SecurityUtils.getAppLoginUser().getAppUser(); + AppLoginUser loginUser=SecurityUtils.getAppLoginUser(); + AppUser appUser =loginUser.getAppUser(); + appUser.setVisitStore(visitStoreId); + loginUser.setAppUser(appUser); + //更新缓存(Redis 里的登录信息) + Authentication auth = new UsernamePasswordAuthenticationToken( + loginUser, + null, + loginUser.getAuthorities() + ); + SecurityContextHolder.getContext().setAuthentication(auth); + String userKey = CacheConstants.LOGIN_APPUSER_TOKEN_KEY + loginUser.getToken(); + redisCache.setCacheObject(userKey, loginUser); + appUserService.update(new UpdateWrapper() .eq("app_user_id",appUser.getId()) .set("visit_store",visitStoreId)); @@ -81,4 +111,12 @@ public class YjStoreServiceImpl extends ServiceImpl impl public YjStore getOne(Long id){ return baseMapper.getOne(id); } + + @Override + public RestResponse getIndex(){ + + List appIndices=baseMapper.getAppIndex(); + + return RestResponse.success().setData(appIndices); + } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScClaTime.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScClaTime.java index 1d0503a..29e0b2b 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScClaTime.java +++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/ScClaTime.java @@ -51,6 +51,9 @@ public class ScClaTime implements Serializable { @TableField("cla_id") private Long claId; + @TableField( "course_id") + private Long courseId; + /** * 任课教师 */ @@ -194,7 +197,7 @@ public class ScClaTime implements Serializable { */ @TableField("tenant_id") private String tenantId; - @TableField(exist = false) + @TableField("dept_id") private Long storeId; @TableField(exist = false) private String courseName; diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespClaTimeCalendar.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespClaTimeCalendar.java index e4b7b4c..47d7b29 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespClaTimeCalendar.java +++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespClaTimeCalendar.java @@ -21,8 +21,10 @@ public class RespClaTimeCalendar extends ScClaTime { // 上课 开始小时 private Integer startHour; + private Integer star; - + private Integer fontSize; + private String fontColor; diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/time/ClaTimeBookItem.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/time/ClaTimeBookItem.java index b5a9e79..0a0c5b1 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/course/domain/time/ClaTimeBookItem.java +++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/time/ClaTimeBookItem.java @@ -22,6 +22,7 @@ public class ClaTimeBookItem { @JsonSerialize(using = ToStringSerializer.class) private Long courseTimeId; + @JsonSerialize(using = ToStringSerializer.class) private Long bookId; private String claName; @@ -36,8 +37,10 @@ public class ClaTimeBookItem { // 星期 private String weekDay; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern="HH:mm",timezone = "GMT+8") private String startTime; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern="HH:mm",timezone = "GMT+8") private String endTime; // 教室 diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/time/ClaTimeCalendarItem.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/time/ClaTimeCalendarItem.java index 7b09294..7f094f5 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/course/domain/time/ClaTimeCalendarItem.java +++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/time/ClaTimeCalendarItem.java @@ -20,6 +20,7 @@ public class ClaTimeCalendarItem { private String claName; private String courseName; + private String courseTypeName; private String storeName; @@ -43,6 +44,8 @@ public class ClaTimeCalendarItem { private String roomName; private String claColor; + private Integer fontSize; + private String fontColor; // 上课状态 private String claTimeStatus; @@ -61,6 +64,10 @@ public class ClaTimeCalendarItem { * 最低开课人数 */ private Integer lessCnt; + private Integer star; + + + private String remark; public ClaTimeCalendarItem transfer(RespClaTimeCalendar respClaTime) { this.courseTimeId = respClaTime.getCourseTimeId(); @@ -75,7 +82,10 @@ public class ClaTimeCalendarItem { // this.studentCount = respClaTime.getStudentCount(); this.roomName = respClaTime.getRoomName(); this.claColor = respClaTime.getClaColor(); + this.fontSize = respClaTime.getFontSize(); + this.fontColor = respClaTime.getFontColor(); this.claTimeStatus = respClaTime.getStatus(); + this.star=respClaTime.getStar(); return this; } diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScClaTimeMapper.java b/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScClaTimeMapper.java index 5a228de..0123c79 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScClaTimeMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScClaTimeMapper.java @@ -38,9 +38,9 @@ public interface ScClaTimeMapper extends BaseMapper { @Param("courseTimeId")Long courseTimeId, @Param("deptId")Long deptId ); + ClaTimeCalendarItem getCourseDetail(@Param("courseTimeId")Long courseTimeId); - - List getCourseBookStudent(Long courseTimeId); + List getCourseBookStudent(Long courseTimeId); List getCourseCountByStoreManager(@Param("staffId")Long staffId, @Param("beginTime")String beginTime, @Param("endTime")String endTime); List getStudentsBySaleStaff(Long staffId); diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScStudentCourseMapper.java b/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScStudentCourseMapper.java index 46730f9..70717dc 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScStudentCourseMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/course/mapper/ScStudentCourseMapper.java @@ -18,84 +18,10 @@ import java.util.List; * 学生课程 Mapper 接口 *

* - * - * + * + * */ public interface ScStudentCourseMapper extends BaseMapper { - /** - * 学生在读课程名称 - * @param studentId - * @return - */ - List selectStudentCourseNameList(Long studentId); - - /** - * 学生报读校区 - * @param studentId - * @return - */ - List selectStudentDeptNameList(Long studentId); - - /** - * 课程、班级 学生列表 - * - * @param reqSearchStudentCourseCla - * @param page - * @return - */ - List selectStudentList(@Param("reqSearchStudentCourseCla") ReqSearchStudentCourseCla reqSearchStudentCourseCla, @Param("page")Page page); - - /** - * 应到人数 - * @param claId - * @return - */ - int selectClaNeedAttendCnt(Long claId); - - /** - * 学生报读课程列表 - * @param searchStudentCourse - * @return - */ - List selectStudentCourseList(ReqSearchStudentCourse searchStudentCourse); - - /** - * 当报读课程总课时、总费用 为0时,删除报读 - * @param studentCourseId - * @return - */ - int deleteWhenTotalHourZeroForInvalid(Long studentCourseId); - - /** - * 当报读课程总天数、总费用 为0时,删除报读 - * @param studentCourseId - * @return - */ - int deleteWhenTotalDayZeroForInvalid(Long studentCourseId); - - /** - * 在读学生 剩余天数 小于 minBalanceDay 的数量 - * 未生效天数 + 生效剩余天数 < minBalanceDay - * @param minBalanceDay 最小剩余天数 - * @return - */ - Integer selectWillExpireDateCount(Integer minBalanceDay); - - /** - * 在读学生 剩余课时 小于 minBalanceHour 的数量 - * 剩余课时 - 过期课时 < minBalanceHour - * @param minBalanceHour 最小剩余课时数 - * @return - */ - Integer selectWillExpireHourCount(Integer minBalanceHour); - /** - * 学生报读列表 - * - * @param reqSearchStuCourseSignUp - * @param page - * @return - */ - List selectStudentSignUpList(@Param("reqSearchStuCourseSignUp") ReqSearchStuCourseSignUp reqSearchStuCourseSignUp, @Param("page")Page page); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/service/ScClaTimeService.java b/ruoyi-system/src/main/java/com/ruoyi/course/service/ScClaTimeService.java index a973c84..c7fec9d 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/course/service/ScClaTimeService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/course/service/ScClaTimeService.java @@ -27,6 +27,7 @@ public interface ScClaTimeService extends IService { RestResponse cancelCourse(Long courseTimeId); RestResponse courseTimeDetail(Long courseTimeId); + RestResponse getCourseDetail(Long courseTimeId); RestResponse appointmentListForTeacher(); RestResponse appointmentListForManager(); RestResponse checkAppointment(Long courseTimeId,int bookStatus); diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/ScClaTimeServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/ScClaTimeServiceImpl.java index e13c677..db7f3f9 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/ScClaTimeServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/ScClaTimeServiceImpl.java @@ -10,6 +10,7 @@ import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.common.collect.Maps; import com.ruoyi.RestResponse; import com.ruoyi.basic.service.YjAppUserService; import com.ruoyi.common.constant.Constants; @@ -40,6 +41,7 @@ import org.apache.commons.compress.utils.Lists; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.RequestBody; import java.math.BigDecimal; @@ -119,9 +121,17 @@ public class ScClaTimeServiceImpl extends ServiceImpl星期->课程 - Map>> claTimeCalendarMap = new HashMap(); - Constants.CLA_TIME_MAP.forEach((claTimeKey, claTimeValue) -> { + + reqSearchClaTime.setBeginDate(DateUtil.format(cycleBegin,"yyyy-MM-dd")); + reqSearchClaTime.setEndDate(DateUtil.format(cycleEnd,"yyyy-MM-dd")); + // 获取排课信息 + List respClaTimeList = claTimeMapper.selectListForCalendar(reqSearchClaTime); + + // 2. 根据返回的 开始时间(startHour) + 时长(claDuration) 自动生成时间段 MAP + Map AUTO_CLA_TIME_MAP = generateTimeMapFromData(respClaTimeList); + + Map>> claTimeCalendarMap = Maps.newHashMap(); + AUTO_CLA_TIME_MAP.forEach((claTimeKey, claTimeValue) -> { Map> halfMonthDayMap = new HashMap(); for (int i = 0; i < dateList.size(); i++) { List claTimeArrayList = Lists.newArrayList(); @@ -129,23 +139,19 @@ public class ScClaTimeServiceImpl extends ServiceImpl respClaTimeList = claTimeMapper.selectListForCalendar(reqSearchClaTime); - // 将排课信息 入到 claTimeCalendarMap respClaTimeList.forEach(item -> { DateTime day=new DateTime(item.getClaDate()); Integer halfMonthDay=dateList.indexOf(day)+1; - Integer startHour = item.getStartHour(); + String startTime =item.getStartTime(); - if (claTimeCalendarMap.containsKey(startHour)) { - claTimeCalendarMap.get(startHour).get(halfMonthDay).add(item); - } else if (claTimeCalendarMap.containsKey(startHour - 1)) { - // 每两个小时 一个上课时段,所以-1 - claTimeCalendarMap.get(startHour - 1).get(halfMonthDay).add(item); + if (claTimeCalendarMap.containsKey(startTime)) { + claTimeCalendarMap.get(startTime).get(halfMonthDay).add(item); } +// else if (claTimeCalendarMap.containsKey(startHour - 1)) { +// // 每两个小时 一个上课时段,所以-1 +// claTimeCalendarMap.get(startHour - 1).get(halfMonthDay).add(item); +// } }); @@ -158,7 +164,7 @@ public class ScClaTimeServiceImpl extends ServiceImpl { ClaTimeContainer claTimeContainer = new ClaTimeContainer(); - claTimeContainer.setTime(Constants.CLA_TIME_MAP.get(claTimeKey)); + claTimeContainer.setTime(AUTO_CLA_TIME_MAP.get(claTimeKey)); Map> claTimeWeekDayMap = new HashMap(); claTimeMap.forEach((weekDayKey, list) -> { @@ -180,17 +186,19 @@ public class ScClaTimeServiceImpl extends ServiceImpl { - int a = Integer.parseInt(o1.getTime().substring(0, 2)); - int b = Integer.parseInt(o2.getTime().substring(0, 2)); - if (a > b) { - return 1; - } else if (a < b) { - return -1; - } else { - return 0; - } - }); +// Collections.sort(claTimeContainerList, (o1, o2) -> { +// int a = Integer.parseInt(o1.getTime().substring(0, 2)); +// int b = Integer.parseInt(o2.getTime().substring(0, 2)); +// if (a > b) { +// return 1; +// } else if (a < b) { +// return -1; +// } else { +// return 0; +// } +// }); + // 按小时正序排序 + Collections.sort(claTimeContainerList, Comparator.comparing(o -> o.getTime())); timeCalendar.setClaTimeContainer(claTimeContainerList); @@ -259,10 +267,9 @@ public class ScClaTimeServiceImpl extends ServiceImpl cardList=memberCardsMapper.getByMemberId(studentId,courseCla.getTenantId(),claTim.getClaDate()); + List cardList=memberCardsMapper.getByMemberId(studentId,claTim.getTenantId(),claTim.getClaDate()); if (cardList.size()==0){ @@ -271,7 +278,7 @@ public class ScClaTimeServiceImpl extends ServiceImpl cardIds=cardList.stream().map(it -> it.getId()).collect(Collectors.toList()); - List course= memberCardsMapper.getCourseDetail(courseCla.getCourseId(),claTim.getTeacherId(),cardIds); + List course= memberCardsMapper.getCourseDetail(claTim.getCourseId(),claTim.getTeacherId(),cardIds); //改: // 1.会员卡排序 按天 -> 按课时 -> 按储值 @@ -395,10 +402,9 @@ public class ScClaTimeServiceImpl extends ServiceImpl logs=bookCourseLogMapper.selectList(new QueryWrapper() .eq("book_id",bookId).orderByAsc("update_time")); @@ -569,6 +578,12 @@ public class ScClaTimeServiceImpl extends ServiceImpl listForTeacher=claTimeMapper.getBookListForTeacher(userId,beginTime.toString(),endTime.toString()); + List listForTeacher=claTimeMapper.getBookListForTeacher(userId,DateUtil.format(beginTime,"yyyy-MM-dd"),DateUtil.format(endTime,"yyyy-MM-dd")); return new RestResponse().setData(listForTeacher); @@ -594,14 +609,13 @@ public class ScClaTimeServiceImpl extends ServiceImpl list=deptService.selectDeptList(dept); - Long deptId= list .get(0).getDeptId(); + + SysUser sysUser= sysUserService.selectUserById(userId); + Long deptId= sysUser.getDeptId(); Date beginTime = new Date();//开始时间 Date endTime = DateUtil.offsetDay(beginTime,14);//结束时间 - List listForManager=claTimeMapper.getBookListForManager(deptId,beginTime.toString(),endTime.toString()); + List listForManager=claTimeMapper.getBookListForManager(deptId,DateUtil.format(beginTime,"yyyy-MM-dd"),DateUtil.format(endTime,"yyyy-MM-dd")); return new RestResponse().setData(listForManager); } @@ -1167,4 +1181,49 @@ public class ScClaTimeServiceImpl extends ServiceImpl generateTimeMapFromData(List respClaTimeList) { + // TreeMap 自动按 key 升序排列 + Map timeMap = new TreeMap<>(); + for (RespClaTimeCalendar item : respClaTimeList) { + String startHour = item.getStartTime(); + if (startHour == null) continue; + timeMap.put(startHour, startHour ); + } + return timeMap; + } + private Map generateTimeMapFromData_old(List respClaTimeList) { + // TreeMap 自动按 key 升序排列 + Map timeMap = new TreeMap<>(); + if (CollectionUtils.isEmpty(respClaTimeList)) { + timeMap=Constants.CLA_TIME_MAP; + return timeMap; + } + + // 第一步:收集所有【合法的2小时制开始小时】(8、10、12、14、16、18...) + Set validStartHours = new HashSet<>(); + for (RespClaTimeCalendar item : respClaTimeList) { + Integer startHour = item.getStartHour(); + if (startHour == null) continue; + + // 计算属于哪个2小时时段(核心:向下取整到偶数整点) + int sectionStart = (startHour / 2) * 2; + // 限制在合理范围 0~24 + if (sectionStart >= 0 && sectionStart <= 22) { + validStartHours.add(sectionStart); + } + } + + // 第二步:生成 2小时间隔、不重叠 的时间段 + for (Integer start : validStartHours) { + int end = start + 2; + String startTime = String.format("%02d:00", start); + String endTime = String.format("%02d:00", end); + timeMap.put(start, startTime + " ~ " + endTime); + } + + return timeMap; + } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/domain/Friend.java b/ruoyi-system/src/main/java/com/ruoyi/im/domain/Friend.java index 7f939b4..3adb650 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/im/domain/Friend.java +++ b/ruoyi-system/src/main/java/com/ruoyi/im/domain/Friend.java @@ -44,7 +44,6 @@ public class Friend { /** * 用户头像 */ - @TableField(exist = false) private String friendHeadImage; @TableField(exist = false) private Long roleId; diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/mapper/FriendMapper.java b/ruoyi-system/src/main/java/com/ruoyi/im/mapper/FriendMapper.java index 2ba5c6b..0690ff5 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/im/mapper/FriendMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/im/mapper/FriendMapper.java @@ -7,7 +7,7 @@ import java.util.List; public interface FriendMapper extends BaseMapper { - List getFriendListForConsumer(Long userId); + List getFriendListForConsumer(Long storeId); List getFriendListForManage(Long userId); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/service/FriendService.java b/ruoyi-system/src/main/java/com/ruoyi/im/service/FriendService.java index 4f9802e..834d5db 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/im/service/FriendService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/im/service/FriendService.java @@ -56,7 +56,7 @@ public interface FriendService extends IService { * @param friendId 好友的用户id * @return 好友信息 */ - FriendVO findFriend(Long friendId); + FriendVO findFriend( Long userId, Long friendId); /** * 绑定好友关系 diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/FriendServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/FriendServiceImpl.java index 2696176..8fd5b51 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/FriendServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/FriendServiceImpl.java @@ -3,9 +3,12 @@ package com.ruoyi.im.service.impl; import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.ruoyi.basic.service.YjAppUserService; +import com.ruoyi.common.core.domain.entity.AppUser; import com.ruoyi.common.im.constant.RedisKey; import com.ruoyi.common.exception.GlobalException; import com.ruoyi.common.utils.SecurityUtils; @@ -13,6 +16,7 @@ import com.ruoyi.im.domain.Friend; import com.ruoyi.im.domain.vo.FriendVO; import com.ruoyi.im.service.FriendService; import com.ruoyi.im.mapper.FriendMapper; +import com.ruoyi.system.service.SysTeacherService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.aop.framework.AopContext; @@ -35,6 +39,9 @@ import java.util.stream.Collectors; public class FriendServiceImpl extends ServiceImpl implements FriendService { + + private final YjAppUserService yjAppUserService; + private final SysTeacherService t; @Override public Map findAllFriends() { Long userId= SecurityUtils.getAppLoginUser().getAppUser().getId(); @@ -45,14 +52,15 @@ public class FriendServiceImpl extends ServiceImpl impleme map.put("consumer",list); return map; } + Long storeId=SecurityUtils.getAppLoginUser().getAppUser().getVisitStore(); - List list=baseMapper.getFriendListForConsumer(userId); + List list=baseMapper.getFriendListForConsumer(storeId); Map> friendMap = list.stream().collect(Collectors.groupingBy(Friend::getRoleId)); - map.put("storeManager",friendMap.get(105l)); - map.put("coach",friendMap.get(104l)); - map.put("adviser",friendMap.get(103l)); - map.put("customerService",friendMap.get(108l)); + map.put("storeManager",friendMap.get(105l));//店长 + map.put("coach",friendMap.get(104l));//教练 + map.put("adviser",friendMap.get(103l));//课程顾问 + map.put("customerService",friendMap.get(108l));//客服 return map; @@ -119,19 +127,19 @@ public class FriendServiceImpl extends ServiceImpl impleme */ @CacheEvict(key = "#userId+':'+#friendId") public void bindFriend(Long userId, Long friendId) { -// QueryWrapper wrapper = new QueryWrapper<>(); -// wrapper.lambda().eq(Friend::getUserId, userId).eq(Friend::getFriendId, friendId); -// Friend friend = this.getOne(wrapper); -// if (Objects.isNull(friend)) { -// friend = new Friend(); -// } -// friend.setUserId(userId); -// friend.setFriendId(friendId); -// User friendInfo = userMapper.selectById(friendId); -// friend.setFriendHeadImage(friendInfo.getHeadImage()); -// friend.setFriendNickName(friendInfo.getNickName()); -// friend.setDeleted(false); -// this.saveOrUpdate(friend); + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda().eq(Friend::getUserId, userId).eq(Friend::getFriendId, friendId); + Friend friend = this.getOne(wrapper); + if (Objects.isNull(friend)) { + friend = new Friend(); + } + friend.setUserId(userId); + friend.setFriendId(friendId); + AppUser friendInfo = yjAppUserService.getById(friendId); + friend.setFriendHeadImage(friendInfo.getAvatar()); + friend.setFriendNickName(friendInfo.getNickName()); + friend.setDeleted(false); + this.saveOrUpdate(friend); // // 推送好友变化信息s // sendAddFriendMessage(userId, friendId, friend); } @@ -155,16 +163,22 @@ public class FriendServiceImpl extends ServiceImpl impleme } @Override - public FriendVO findFriend(Long friendId) { - Long userId= SecurityUtils.getAppLoginUser().getAppUser().getId(); + @CacheEvict(key = "#userId+':'+#friendId") + public FriendVO findFriend(Long userId, Long friendId) { LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); wrapper.eq(Friend::getUserId, userId); wrapper.eq(Friend::getFriendId, friendId); Friend friend = this.getOne(wrapper); if (Objects.isNull(friend)) { - addFriend(friendId); -// throw new GlobalException("对方不是您的好友"); + friend = new Friend(); } + friend.setUserId(userId); + friend.setFriendId(friendId); + AppUser friendInfo = yjAppUserService.getById(friendId); + friend.setFriendHeadImage(friendInfo.getAvatar()); + friend.setFriendNickName(friendInfo.getNickName()); + friend.setDeleted(false); + this.saveOrUpdate(friend); return conver(friend); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/GroupMessageServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/GroupMessageServiceImpl.java index 014ae9d..22572cc 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/GroupMessageServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/GroupMessageServiceImpl.java @@ -3,6 +3,7 @@ package com.ruoyi.im.service.impl; import cn.hutool.core.collection.CollStreamUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; @@ -144,16 +145,17 @@ public class GroupMessageServiceImpl extends ServiceImpl members = groupMemberService.findByUserId(SecurityUtils.getAppLoginUser().getAppUserId()); + List members = groupMemberService.findByUserId(session.getId()); Map groupMemberMap = CollStreamUtil.toIdentityMap(members, GroupMember::getGroupId); Set groupIds = groupMemberMap.keySet(); if (CollectionUtil.isEmpty(groupIds)) { // 关闭加载中标志 - this.sendLoadingMessage(false); + this.sendLoadingMessage(false,session); return; } @@ -170,7 +172,7 @@ public class GroupMessageServiceImpl extends ServiceImpl> messageGroupMap = messages.stream().collect(Collectors.groupingBy(GroupMessage::getGroupId)); // 退群前的消息 - List quitMembers = groupMemberService.findQuitInMonth(SecurityUtils.getAppLoginUser().getAppUserId()); + List quitMembers = groupMemberService.findQuitInMonth(session.getId()); for (GroupMember quitMember : quitMembers) { wrapper = Wrappers.lambdaQuery(); wrapper.gt(GroupMessage::getId, minId).between(GroupMessage::getSendTime, minDate, quitMember.getQuitTime()) @@ -182,7 +184,7 @@ public class GroupMessageServiceImpl extends ServiceImpl { // 开启加载中标志 - this.sendLoadingMessage(true); + this.sendLoadingMessage(true,session); // 推送消息 AtomicInteger sendCount = new AtomicInteger(); messageGroupMap.forEach((groupId, groupMessages) -> { @@ -193,7 +195,7 @@ public class GroupMessageServiceImpl extends ServiceImpl maxIdMap = null; for (GroupMessage m : sendMessages) { @@ -204,7 +206,7 @@ public class GroupMessageServiceImpl extends ServiceImpl recvIds = CommaTextUtils.asList(m.getRecvIds()); - if (!recvIds.isEmpty() && !recvIds.contains(SecurityUtils.getAppLoginUser().getAppUserId().toString())) { + if (!recvIds.isEmpty() && !recvIds.contains(session.getId().toString())) { continue; } // 组装vo @@ -225,7 +227,7 @@ public class GroupMessageServiceImpl extends ServiceImpl sendMessage = new IMGroupMessage<>(); sendMessage.setSender(new IMUserInfo(m.getSendId(), IMTerminalType.WEB.code())); - sendMessage.setRecvIds(Arrays.asList(SecurityUtils.getAppLoginUser().getAppUserId())); + sendMessage.setRecvIds(Arrays.asList(session.getId())); sendMessage.setRecvTerminals(Arrays.asList(1)); sendMessage.setSendResult(false); sendMessage.setSendToSelf(false); @@ -235,7 +237,7 @@ public class GroupMessageServiceImpl extends ServiceImpl(); - sendMessage.setSender(new IMUserInfo(SecurityUtils.getAppLoginUser().getAppUserId(), 1)); - sendMessage.setRecvIds(Arrays.asList(SecurityUtils.getAppLoginUser().getAppUserId())); + + sendMessage.setSender(new IMUserInfo(session.getId(), 1)); + sendMessage.setRecvIds(Arrays.asList(session.getId())); sendMessage.setRecvTerminals(Arrays.asList(1)); sendMessage.setData(msgInfo); sendMessage.setSendToSelf(false); @@ -379,15 +382,18 @@ public class GroupMessageServiceImpl extends ServiceImpl wrapper = Wrappers.lambdaQuery(); // wrapper -//// .eq(GroupMessage::getRecvId, session.getId()) // .eq(GroupMessage::getGroupId, groupId) // .eq(GroupMessage::getStatus, MessageStatus.READED.code()).orderByDesc(GroupMessage::getId) // .select(GroupMessage::getId).last("limit 1"); // GroupMessage message = this.getOne(wrapper); // if (Objects.isNull(message)) { -// return -1L; +// return "-1"; // } return maxReadedId.toString(); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/mall/domain/order/OrderItem.java b/ruoyi-system/src/main/java/com/ruoyi/mall/domain/order/OrderItem.java index 5afa5d4..f194b3a 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/mall/domain/order/OrderItem.java +++ b/ruoyi-system/src/main/java/com/ruoyi/mall/domain/order/OrderItem.java @@ -3,6 +3,8 @@ package com.ruoyi.mall.domain.order; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.ruoyi.basic.domain.model.BaseAudit; import com.ruoyi.common.annotation.Excel; import io.swagger.annotations.ApiModel; @@ -23,6 +25,7 @@ public class OrderItem extends BaseAudit { @ApiModelProperty("ID") @TableId(type = IdType.ASSIGN_ID) + @JsonSerialize(using = ToStringSerializer.class) private Long id; @ApiModelProperty("订单id") diff --git a/ruoyi-system/src/main/java/com/ruoyi/mall/mapper/ProductMapper.java b/ruoyi-system/src/main/java/com/ruoyi/mall/mapper/ProductMapper.java index 3f78c5a..58f8e68 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/mall/mapper/ProductMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/mall/mapper/ProductMapper.java @@ -2,6 +2,7 @@ package com.ruoyi.mall.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.mall.domain.Product; +import org.apache.ibatis.annotations.Param; import java.util.List; @@ -19,4 +20,8 @@ public interface ProductMapper extends BaseMapper { */ List selectByEntity(Product product); List selectByGoodStuff(Long selectByGoodStuff); + + List getMallProductList(@Param("categoryId") Long categoryId, + @Param("search")String search, + @Param("isCourse")Integer isCourse); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/mall/service/impl/ProductCategoryServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/mall/service/impl/ProductCategoryServiceImpl.java index 0539f54..82dcdfc 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/mall/service/impl/ProductCategoryServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/mall/service/impl/ProductCategoryServiceImpl.java @@ -43,7 +43,7 @@ public class ProductCategoryServiceImpl extends ServiceImpl qw = new QueryWrapper<>(); qw.select("id", "parent_id", "type_name", "level", "sort", "icon"); qw.eq("show_status", 1);//展示 - qw.eq("store_id", params.get("storeId"));//门店id + qw.eq("store_id", 1);//全部 // qw.le("level", 2); return mapper.selectList(qw); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/mall/service/impl/ProductServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/mall/service/impl/ProductServiceImpl.java index 3c3ab28..e705de2 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/mall/service/impl/ProductServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/mall/service/impl/ProductServiceImpl.java @@ -76,19 +76,23 @@ public class ProductServiceImpl extends ServiceImpl impl if (page != null) { PageHelper.startPage(page.getPageNumber() + 1, page.getPageSize()); } - QueryWrapper qw = new QueryWrapper<>(); - qw.orderByDesc("publish_status"); - qw.orderByAsc("sort"); Long categoryId = query.getCategoryId(); - if (categoryId != null) { + if (categoryId != null && categoryId.equals(1L)) { + QueryWrapper qw = new QueryWrapper<>(); + qw.eq("publish_status", 1); + qw.orderByAsc("sort"); qw.eq("category_id", categoryId); + qw.eq("store_id", query.getStoreId());//门店id + String search = query.getSearch(); + if (StringUtils.isNoneEmpty(search)){ + qw.like("name", "%".concat(query.getSearch().trim()).concat("%")); + } + return productMapper.selectList(qw); } - String search = query.getSearch(); - if (StringUtils.isNoneEmpty(search)){ - qw.like("name", "%".concat(query.getSearch().trim()).concat("%")); - } - qw.eq("store_id", query.getStoreId());//门店id - return productMapper.selectList(qw); + //商城商品 + + return productMapper.getMallProductList(categoryId,query.getSearch(),null); + } public ProductDetailVO queryDetail(Long id) { @@ -110,30 +114,10 @@ public class ProductServiceImpl extends ServiceImpl impl } public Map selectByGoodStuff(String storeId) { Map> map=new HashMap<>(); - List courses=productMapper.selectList(new QueryWrapper() - .eq("store_id", storeId) - .eq("is_course",1) - .orderByAsc("sort") - .last("limit 2") - ); - List goods=productMapper.selectList(new QueryWrapper() - .eq("store_id", storeId) - .eq("is_course",0) - .orderByAsc("sort") - .last("limit 2") - ); -// List productList=productMapper.selectByGoodStuff(Long.parseLong(storeId)); -// List goods=new ArrayList<>(); -// List courses=new ArrayList<>(); -// for (Product product : productList) { -// if (product.getIsCourse()==1){ -// courses.add(product); -// }else { -// goods.add(product); -// } -// } - map.put("goods",goods); - map.put("courses",courses); + List courses=productMapper.getMallProductList(null,null,1); + List goods=productMapper.getMallProductList(null,null,0); + map.put("goods",goods.size()>2?goods.subList(0,2):goods); + map.put("courses",courses.size()>2?courses.subList(0,2):courses); return map; } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTeacher.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTeacher.java index 8cae50c..c5dae30 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTeacher.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTeacher.java @@ -101,4 +101,7 @@ public class SysTeacher implements Serializable { */ @TableField("update_time") private Date updateTime; + + @TableField( exist = false) + private Long appUserId; } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictDataMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictDataMapper.java index fe60a4d..b32aee0 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictDataMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictDataMapper.java @@ -1,5 +1,6 @@ package com.ruoyi.system.mapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.common.core.domain.entity.SysDictData; import org.apache.ibatis.annotations.Param; @@ -7,10 +8,10 @@ import java.util.List; /** * 字典表 数据层 - * + * * @author ruoyi */ -public interface SysDictDataMapper +public interface SysDictDataMapper extends BaseMapper { /** * 新商户的字典内容初始化 @@ -20,7 +21,7 @@ public interface SysDictDataMapper int newMerchant(String merchantId); /** * 根据条件分页查询字典数据 - * + * * @param dictData 字典数据信息 * @return 字典数据集合信息 */ @@ -28,7 +29,7 @@ public interface SysDictDataMapper /** * 根据字典类型查询字典数据 - * + * * @param dictData 字典类型 * @return 字典数据集合信息 */ @@ -36,7 +37,7 @@ public interface SysDictDataMapper /** * 根据字典类型和字典键值查询字典数据信息 - * + * * @param dictType 字典类型 * @param dictValue 字典键值 * @return 字典标签 @@ -45,7 +46,7 @@ public interface SysDictDataMapper /** * 根据字典数据ID查询信息 - * + * * @param dictCode 字典数据ID * @return 字典数据 */ @@ -53,7 +54,7 @@ public interface SysDictDataMapper /** * 查询字典数据 - * + * * @param dictType 字典类型 * @return 字典数据 */ @@ -61,7 +62,7 @@ public interface SysDictDataMapper /** * 通过字典ID删除字典数据信息 - * + * * @param dictCode 字典数据ID * @return 结果 */ @@ -69,7 +70,7 @@ public interface SysDictDataMapper /** * 批量删除字典数据信息 - * + * * @param dictCodes 需要删除的字典数据ID * @return 结果 */ @@ -77,7 +78,7 @@ public interface SysDictDataMapper /** * 新增字典数据信息 - * + * * @param dictData 字典数据信息 * @return 结果 */ @@ -85,7 +86,7 @@ public interface SysDictDataMapper /** * 修改字典数据信息 - * + * * @param dictData 字典数据信息 * @return 结果 */ @@ -93,7 +94,7 @@ public interface SysDictDataMapper /** * 同步修改字典类型 - * + * * @param oldDictType 旧字典类型 * @param newDictType 新旧字典类型 * @return 结果 diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java index 9bc4f13..a7090de 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java @@ -1,60 +1,29 @@ package com.ruoyi.system.service; import java.util.List; + +import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.common.core.domain.entity.SysDictData; /** * 字典 业务层 - * + * * @author ruoyi */ -public interface ISysDictDataService +public interface ISysDictDataService extends IService { - /** - * 根据条件分页查询字典数据 - * - * @param dictData 字典数据信息 - * @return 字典数据集合信息 - */ - public List selectDictDataList(SysDictData dictData); - /** - * 根据字典类型和字典键值查询字典数据信息 - * - * @param dictType 字典类型 - * @param dictValue 字典键值 - * @return 字典标签 - */ - public String selectDictLabel(String dictType, String dictValue); + List dictTypeDataList(String dictType); /** * 根据字典数据ID查询信息 - * + * * @param dictCode 字典数据ID * @return 字典数据 */ public SysDictData selectDictDataById(Long dictCode); - /** - * 批量删除字典数据信息 - * - * @param dictCodes 需要删除的字典数据ID - */ - public void deleteDictDataByIds(Long[] dictCodes); - /** - * 新增保存字典数据信息 - * - * @param dictData 字典数据信息 - * @return 结果 - */ - public int insertDictData(SysDictData dictData); - /** - * 修改保存字典数据信息 - * - * @param dictData 字典数据信息 - * @return 结果 - */ - public int updateDictData(SysDictData dictData); + } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java index abf29a3..9f28e6f 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java @@ -1,10 +1,14 @@ package com.ruoyi.system.service.impl; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.common.collect.Lists; import com.ruoyi.common.core.domain.entity.SysDictData; import com.ruoyi.common.utils.DictUtils; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.system.mapper.SysDictDataMapper; import com.ruoyi.system.service.ISysDictDataService; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -16,38 +20,22 @@ import java.util.List; * @author ruoyi */ @Service -public class SysDictDataServiceImpl implements ISysDictDataService +public class SysDictDataServiceImpl extends ServiceImpl implements ISysDictDataService { @Autowired private SysDictDataMapper dictDataMapper; - /** - * 根据条件分页查询字典数据 - * - * @param dictData 字典数据信息 - * @return 字典数据集合信息 - */ - @Override - public List selectDictDataList(SysDictData dictData) - { - return dictDataMapper.selectDictDataList(dictData); - } - /** - * 根据字典类型和字典键值查询字典数据信息 - * - * @param dictType 字典类型 - * @param dictValue 字典键值 - * @return 字典标签 - */ @Override - public String selectDictLabel(String dictType, String dictValue) - { - SysDictData dictData=new SysDictData(); - dictData.setDictValue(dictValue); - dictData.setDictType(dictType); - dictData.setTenantId(SecurityUtils.getTenantId()); - return dictDataMapper.selectDictLabel(dictData); + public List dictTypeDataList(String dictType) { + if (StringUtils.isEmpty(dictType)) { + return Lists.newArrayList(); + } + QueryWrapper qw = new QueryWrapper<>(); + qw.select("dict_label", "dict_value") + .eq("dict_type", dictType); + qw.orderByAsc("dict_sort"); + return this.list(qw); } /** @@ -62,59 +50,5 @@ public class SysDictDataServiceImpl implements ISysDictDataService return dictDataMapper.selectDictDataById(dictCode); } - /** - * 批量删除字典数据信息 - * - * @param dictCodes 需要删除的字典数据ID - */ - @Override - public void deleteDictDataByIds(Long[] dictCodes) - { - for (Long dictCode : dictCodes) - { - SysDictData data = selectDictDataById(dictCode); - data.setTenantId(SecurityUtils.getTenantId()); - dictDataMapper.deleteDictDataById(dictCode); - List dictDatas = dictDataMapper.selectDictDataByType(data); - DictUtils.setDictCache(data.getDictType(), dictDatas); - } - } - - /** - * 新增保存字典数据信息 - * - * @param data 字典数据信息 - * @return 结果 - */ - @Override - public int insertDictData(SysDictData data) - { - int row = dictDataMapper.insertDictData(data); - if (row > 0) - { - data.setTenantId(SecurityUtils.getTenantId()); - List dictDatas = dictDataMapper.selectDictDataByType(data); - DictUtils.setDictCache(data.getDictType(), dictDatas); - } - return row; - } - /** - * 修改保存字典数据信息 - * - * @param data 字典数据信息 - * @return 结果 - */ - @Override - public int updateDictData(SysDictData data) - { - int row = dictDataMapper.updateDictData(data); - if (row > 0) - { - data.setTenantId(SecurityUtils.getTenantId()); - List dictDatas = dictDataMapper.selectDictDataByType(data); - DictUtils.setDictCache(data.getDictType(), dictDatas); - } - return row; - } } diff --git a/ruoyi-system/src/main/resources/mapper/basic/QuestionAnswerDetailMapper.xml b/ruoyi-system/src/main/resources/mapper/basic/QuestionAnswerDetailMapper.xml new file mode 100644 index 0000000..91b3695 --- /dev/null +++ b/ruoyi-system/src/main/resources/mapper/basic/QuestionAnswerDetailMapper.xml @@ -0,0 +1,17 @@ + + + + + INSERT INTO question_answer_detail (sheet_id, question_id, option_id) VALUES + + (#{item.sheetId}, #{item.questionId}, #{item.optionId}) + + + + + diff --git a/ruoyi-system/src/main/resources/mapper/basic/QuestionConstitutionScoreMapper.xml b/ruoyi-system/src/main/resources/mapper/basic/QuestionConstitutionScoreMapper.xml new file mode 100644 index 0000000..55c0dff --- /dev/null +++ b/ruoyi-system/src/main/resources/mapper/basic/QuestionConstitutionScoreMapper.xml @@ -0,0 +1,11 @@ + + + + + INSERT INTO question_constitution_score (sheet_id, constitution_id, total_score) VALUES + + (#{item.sheetId}, #{item.constitutionId}, #{item.totalScore}) + + + + diff --git a/ruoyi-system/src/main/resources/mapper/basic/QuestionRuleMapper.xml b/ruoyi-system/src/main/resources/mapper/basic/QuestionRuleMapper.xml new file mode 100644 index 0000000..7fbb135 --- /dev/null +++ b/ruoyi-system/src/main/resources/mapper/basic/QuestionRuleMapper.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-system/src/main/resources/mapper/basic/YjStoreMapper.xml b/ruoyi-system/src/main/resources/mapper/basic/YjStoreMapper.xml index 37deaa3..0a64043 100644 --- a/ruoyi-system/src/main/resources/mapper/basic/YjStoreMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/basic/YjStoreMapper.xml @@ -7,6 +7,8 @@ from yj_store a,sys_dept b WHERE a.dept_id=b.dept_id and a.dept_id=#{deptId} + and b.activation_date NOW() b.expiry_date + @@ -35,6 +38,7 @@ WHERE a.dept_id=b.dept_id and b.tenant_id=c.tenant_id and c.super_tenant != 1 and b.parent_id='0' + and b.status='0' and a.display=1 and c.in_use='0' and c.delete_flag='0' @@ -45,6 +49,12 @@ SELECT b.dept_id as id,a.store_name,b.parent_id,a.address,a.phone from yj_store a,sys_dept b WHERE a.dept_id=b.dept_id - and b.parent_id=#{id} and a.display=1 + and b.parent_id=#{id} and a.display=1 and b.status='0' + and b.activation_date NOW() b.expiry_date + + + + diff --git a/ruoyi-system/src/main/resources/mapper/cource/ScBookCourseMapper.xml b/ruoyi-system/src/main/resources/mapper/cource/ScBookCourseMapper.xml index 9a986b9..e216e8b 100644 --- a/ruoyi-system/src/main/resources/mapper/cource/ScBookCourseMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/cource/ScBookCourseMapper.xml @@ -9,9 +9,7 @@ a.id as book_id, a.book_status, c.course_time_id, - b.cla_name, - b.cla_color, - b.cla_pic, + c.cla_color, c.cla_date, c.start_time, c.end_time, @@ -19,16 +17,18 @@ c.at_class_cnt, c.status as cla_time_status, c.room_name, + b.teacher_name, + b.avatar_img as pic, d.store_name from - sc_book_course a, - sc_course_cla b, + sys_teacher b, sc_cla_time c, yj_store d - where b.cla_id=c.cla_id and a.course_time_id =c.course_time_id - and b.depart_id=d.dept_id + where a.course_time_id =c.course_time_id + and c.teacher_id=b.user_id + and c.dept_id=d.dept_id and a.student_id=#{studentId} ORDER BY a.create_time @@ -47,20 +47,21 @@ b.start_time, b.end_time, c.teacher_name, - d.cla_name, + c.avatar_img as pic, + d.course_name, e.store_name from sc_book_course a, sc_cla_time b, sys_teacher c, - sc_course_cla d, + sc_course d, yj_store e WHERE a.course_time_id=b.course_time_id + and b.course_id=d.course_id and b.teacher_id=c.user_id - and b.cla_id=d.cla_id - and d.depart_id=e.dept_id + and b.dept_id=e.dept_id and a.id=#{bookId} diff --git a/ruoyi-system/src/main/resources/mapper/cource/ScClaTimeAttendMapper.xml b/ruoyi-system/src/main/resources/mapper/cource/ScClaTimeAttendMapper.xml index 78948c7..2e0a427 100644 --- a/ruoyi-system/src/main/resources/mapper/cource/ScClaTimeAttendMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/cource/ScClaTimeAttendMapper.xml @@ -5,9 +5,8 @@ - - - + + SELECT d.nick_name as teacherName, - b.cla_name, c.real_cla_date, c.real_start_time, c.real_end_time, @@ -182,11 +167,11 @@ c.venue_fee from sys_dept a, - sc_course_cla b, + sys_user b, sc_cla_time c, sys_user d - WHERE a.dept_id=b.depart_id and c.cla_id=b.cla_id and c.teacher_id=d.user_id - and a.leader_id=#{staffId} + WHERE a.dept_id=b.dept_id and c.teacher_id=d.user_id + and b.user_id=#{staffId} and real_cla_date BETWEEN #{beginTime} and #{endTime} @@ -252,8 +237,8 @@ select b.id as book_id, - (select cour.course_name from sc_course cour WHERE d.course_id=cour.course_id ) as course_name, - d.cla_name, + (select cour.course_name from sc_course cour WHERE a.course_id=cour.course_id ) as course_name, (select teacher_name from sys_teacher WHERE user_id=a.teacher_id)as teacher_name, a.room_name, a.cla_date, @@ -295,10 +279,10 @@ c.sex, c.phone - from sc_cla_time a,sc_book_course b,sc_student c,sc_course_cla d - WHERE a.course_time_id=b.course_time_id and b.student_id=c.student_id and a.cla_id=d.cla_id + from sc_cla_time a,sc_book_course b,sc_student c + WHERE a.course_time_id=b.course_time_id and b.student_id=c.student_id -- and b.book_status=1 - and d.depart_id=#{deptId} + and a.dept_id=#{deptId} and a.cla_date BETWEEN #{beginTime} and #{endTime} ORDER BY FIELD(b.book_status, 1) desc,b.create_time diff --git a/ruoyi-system/src/main/resources/mapper/cource/ScMemberCardMapper.xml b/ruoyi-system/src/main/resources/mapper/cource/ScMemberCardMapper.xml index 9ad1596..04fe567 100644 --- a/ruoyi-system/src/main/resources/mapper/cource/ScMemberCardMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/cource/ScMemberCardMapper.xml @@ -75,31 +75,13 @@ INNER JOIN sc_course e ON ( - - a.restricted_courses = '1' - AND e.course_type_id = b.course_type_id - ) - OR ( - - a.restricted_courses = '2' - AND ( - - ( - JSON_LENGTH(COALESCE(d.courses, '[]')) = 0 - AND e.course_type_id = b.course_type_id - ) - OR - - ( - JSON_LENGTH(COALESCE(d.courses, '[]')) > 0 - AND JSON_CONTAINS( - d.courses, - CAST(e.course_id AS CHAR), - '$' - ) - ) - ) - ) + a.restricted_courses = '1' + AND e.course_type_id = b.course_type_id + ) + OR ( + a.restricted_courses = '2' + AND JSON_CONTAINS(d.courses,CAST(e.course_id AS CHAR),'$') + ) WHERE a.delete_flag = '0' diff --git a/ruoyi-system/src/main/resources/mapper/cource/ScStudentCourseMapper.xml b/ruoyi-system/src/main/resources/mapper/cource/ScStudentCourseMapper.xml index a4bf5f6..ab2e713 100644 --- a/ruoyi-system/src/main/resources/mapper/cource/ScStudentCourseMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/cource/ScStudentCourseMapper.xml @@ -2,193 +2,4 @@ - - - - - - - delete from sc_student_course where student_course_id=#{studentCourseId} and charge_type ]]> 'date' and total_hour=0 and total_fee=0 - - - delete from sc_student_course where student_course_id=#{studentCourseId} and charge_type = 'date' and total_day=0 and total_fee=0 - - - - diff --git a/ruoyi-system/src/main/resources/mapper/im/FriendMapper.xml b/ruoyi-system/src/main/resources/mapper/im/FriendMapper.xml index 803a36c..636b7cd 100644 --- a/ruoyi-system/src/main/resources/mapper/im/FriendMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/im/FriendMapper.xml @@ -2,7 +2,7 @@ - select a.id, a.user_id, a.friend_id, @@ -19,7 +19,25 @@ and b.manage_account_id=c.user_id and b.manage_account_id=e.user_id and e.dept_id=d.dept_id - and a.user_id=#{userId} + and a.user_id=#{userId} + + + + + diff --git a/ruoyi-system/src/main/resources/mapper/mall/ProductMapper.xml b/ruoyi-system/src/main/resources/mapper/mall/ProductMapper.xml index b03b62d..b459844 100644 --- a/ruoyi-system/src/main/resources/mapper/mall/ProductMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/mall/ProductMapper.xml @@ -62,4 +62,56 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" WHERE g.product_id=p.id and g.store_id=#{storeId} + + diff --git a/ruoyi-system/src/main/resources/mapper/system/SysTeacherMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysTeacherMapper.xml index 976e02a..36eff74 100644 --- a/ruoyi-system/src/main/resources/mapper/system/SysTeacherMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/system/SysTeacherMapper.xml @@ -37,16 +37,21 @@ SELECT a.user_id as user_id, - a.nick_name as user_name, + b.teacher_name as user_name, a.sex, a.phonenumber, b.avatar_img as avatar, b.context, b.releases, b.url, - b.intro - FROM sys_user a, sys_teacher b - WHERE a.user_id=b.user_id and - b.releases=1 and a.delete_flag='0' and a.teacher=1 and a.user_id =#{userId} + b.intro, + c.app_user_id as appUserId + FROM sys_user a, sys_teacher b,yj_app_user c + WHERE a.user_id=b.user_id + and a.user_id=c.manage_account_id + and b.releases=1 + and a.delete_flag='0' + and a.teacher=1 + and a.user_id =#{userId}