master
15004070936 1 week ago
parent 98d710435a
commit dc0bd6288e

@ -15,14 +15,7 @@
web服务入口
</description>
<dependencies>
<!-- spring-boot-devtools -->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-devtools</artifactId>-->
<!-- <optional>true</optional> &lt;!&ndash; 表示依赖不会传递 &ndash;&gt;-->
<!-- </dependency>-->
<dependencies>
<!-- 核心模块-->
<dependency>
@ -30,6 +23,32 @@
<artifactId>ruoyi-framework</artifactId>
</dependency>
<!-- Spring Boot Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- JUnit 5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<!-- Mockito -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<!--极光推送-->
<!-- <dependency>-->

@ -4,10 +4,7 @@
<facet type="web" name="Web">
<configuration>
<webroots />
<sourceRoots>
<root url="file://$MODULE_DIR$/src/main/java" />
<root url="file://$MODULE_DIR$/src/main/resources" />
</sourceRoots>
<sourceRoots />
</configuration>
</facet>
<facet type="Spring" name="Spring">
@ -18,8 +15,8 @@
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<content url="file://$MODULE_DIR$">
@ -31,18 +28,6 @@
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="ruoyi-framework" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-web:2.5.14" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter:2.5.14" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot:2.5.14" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-logging:2.5.14" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-classic:1.2.11" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.2.11" level="project" />
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-to-slf4j:2.17.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-api:2.17.2" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:jul-to-slf4j:1.7.36" level="project" />
<orderEntry type="library" name="Maven: jakarta.annotation:jakarta.annotation-api:1.3.5" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-core:5.3.20" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.3.20" level="project" />
<orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.28" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-json:2.5.14" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.12.6.1" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.12.6" level="project" />
@ -175,7 +160,6 @@
<orderEntry type="library" name="Maven: io.springfox:springfox-spi:3.0.0" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-schema:3.0.0" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-core:3.0.0" level="project" />
<orderEntry type="library" name="Maven: net.bytebuddy:byte-buddy:1.10.22" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-spring-web:3.0.0" level="project" />
<orderEntry type="library" name="Maven: io.github.classgraph:classgraph:4.8.83" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-spring-webmvc:3.0.0" level="project" />
@ -223,7 +207,46 @@
<orderEntry type="library" scope="RUNTIME" name="Maven: org.apache.httpcomponents:httpmime:4.5.13" level="project" />
<orderEntry type="library" name="Maven: junit:junit:4.13.2" level="project" />
<orderEntry type="library" name="Maven: org.hamcrest:hamcrest-core:2.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-starter-test:2.5.14" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter:2.5.14" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot:2.5.14" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-logging:2.5.14" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-classic:1.2.11" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.2.11" level="project" />
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-to-slf4j:2.17.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-api:2.17.2" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:jul-to-slf4j:1.7.36" level="project" />
<orderEntry type="library" name="Maven: jakarta.annotation:jakarta.annotation-api:1.3.5" level="project" />
<orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.28" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test:2.5.14" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test-autoconfigure:2.5.14" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: com.jayway.jsonpath:json-path:2.5.0" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: net.minidev:json-smart:2.4.8" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: net.minidev:accessors-smart:2.4.8" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.ow2.asm:asm:9.1" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: jakarta.xml.bind:jakarta.xml.bind-api:2.3.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: jakarta.activation:jakarta.activation-api:1.2.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.assertj:assertj-core:3.19.0" level="project" />
<orderEntry type="library" name="Maven: org.hamcrest:hamcrest:2.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.skyscreamer:jsonassert:1.5.0" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: com.vaadin.external.google:android-json:0.0.20131108.vaadin1" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-core:5.3.20" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.3.20" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework:spring-test:5.3.20" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.xmlunit:xmlunit-core:2.8.4" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter:5.7.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-api:5.7.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.apiguardian:apiguardian-api:1.1.0" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.opentest4j:opentest4j:1.2.0" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.junit.platform:junit-platform-commons:1.7.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-params:5.7.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-engine:5.7.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.junit.platform:junit-platform-engine:1.7.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-core:3.9.0" level="project" />
<orderEntry type="library" name="Maven: net.bytebuddy:byte-buddy:1.10.22" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: net.bytebuddy:byte-buddy-agent:1.10.22" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.objenesis:objenesis:3.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-junit-jupiter:3.9.0" level="project" />
<orderEntry type="library" name="Maven: com.jcraft:jsch:0.1.55" level="project" />
</component>
</module>

@ -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 height1
* @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;
}
}

@ -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;
/**
* <p>
*
* </p>
*
* @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<SysDictData> dictDataList = sysDictDataService.dictTypeDataList(dictType);
return RestResponse.success().setData(dictDataList);
}
}

@ -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();
}
}

@ -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<String,Long> map){
Long courseTimeId=map.get("courseTimeId");
return scClaTimeService.courseTimeDetail(courseTimeId);
}

@ -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<QuestionSurvey> surveys = surveyMapper.selectList(
new LambdaQueryWrapper<QuestionSurvey>()
.eq(QuestionSurvey::getStatus, 1) // 只返回已发布的
.orderByDesc(QuestionSurvey::getCreateTime)
);
List<QuestionSurveyBriefVO> 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 HttpIP
* @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;
}
}

@ -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;
/** 用户账号 */

@ -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<String,Long> map){
Long courseTimeId=map.get("courseTimeId");
return scClaTimeService.getCourseDetail(courseTimeId);
}
/**
*
* @param searchClaTime

@ -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<FriendVO> 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));
}

@ -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);

@ -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<AnswerSubmitDTO.AnswerItem> 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));
}
}

@ -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;

@ -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<HttpMessageConverter<?>> converters) {
converters.add(getMappingJackson2HttpMessageConverter());
}
/**
* jsLongBigIntegerstring
*
* @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;
}
}

@ -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()

@ -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;
/**
* jsonweb 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;
}
}

@ -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'

@ -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;
/**
* <p>
*
* </p>
*
* @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;
}

@ -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<AnswerItem> answers;
@Data
public static class AnswerItem {
@NotNull
private Long questionId;
@NotNull
private Long optionId;
}
}

@ -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;
}

@ -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<ConstitutionScoreDTO> constitutionScores; // 各体质得分
}

@ -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<QuestionVO> questions; // 该体质下的题目列表
}

@ -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;
}

@ -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<OptionVO> options; // 选项列表
}

@ -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<ConstitutionVO> 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<QuestionVO> questions;
}
@Data
public static class QuestionVO implements Serializable{
private Long questionId;
private Integer serialNumber;
private String content;
private Integer fullScore;
private List<OptionVO> options;
}
@Data
public static class OptionVO implements Serializable{
private Long optionId;
private String optionText;
private Integer score;
private Integer sortOrder;
}
}

@ -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;
}

@ -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;
}

@ -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;
}

@ -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;
}

@ -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;
}

@ -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;
}

@ -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;
}

@ -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;
}

@ -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<QuestionAnswerDetail> {
void insertBatch(@Param("list") List<QuestionAnswerDetail> list);
List<QuestionAnswerDetail> getBySheetId(@Param("sheetId") Long sheetId);
}

@ -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<QuestionAnswerSheet> {
// 可扩展自定义查询
}

@ -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<QuestionConstitutionScore> {
void insertBatch(@Param("list") List<QuestionConstitutionScore> list);
}

@ -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<QuestionConstitutionType> {
}

@ -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<QuestionOption> {
}

@ -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<QuestionQuestion> {
}

@ -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<QuestionRule> {
/**
* ID
* @param surveyId ID
* @return
*/
List<QuestionRule> selectEnabledBySurveyId(@Param("surveyId") Long surveyId);
}

@ -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<QuestionSurvey> {
}

@ -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<YjStore> {
List<YjStore> getStoreList();
List<YjStore> getChilds(Long id);
List<SysAppIndex> getAppIndex();
}

@ -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<QuestionRule> {
/**
*
* @param surveyId ID
* @return
*/
List<QuestionRule> getEnabledRulesBySurveyId(Long surveyId);
}

@ -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 HttpIP
* @return
*/
AnswerResultVO submitAnswers(AnswerSubmitDTO dto, HttpServletRequest request);
/**
* ID
* @return
*/
AnswerResultVO getResultBySheetId();
}

@ -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<YjStore> {
List<YjStore> getStoreListByTenantId(String tenantId);
YjStore getOne(Long id);
RestResponse getIndex();
}

@ -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<SysDictData> dictTypeDataList(String dictType) {
return sysDictDataService.dictTypeDataList(dictType);
}
}

@ -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<QuestionRuleMapper, QuestionRule> implements QuestionRuleService {
private final QuestionRuleMapper ruleMapper;
@Override
public List<QuestionRule> getEnabledRulesBySurveyId(Long surveyId) {
return ruleMapper.selectEnabledBySurveyId(surveyId);
}
}

@ -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<QuestionAnswerSheetMapper, QuestionAnswerSheet>
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<QuestionAnswerDetail> 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<QuestionConstitutionScore> scores = computeConstitutionScores(sheetId);
if (CollUtil.isNotEmpty(scores)) {
constitutionScoreMapper.insertBatch(scores);
} else {
scores = Collections.emptyList();
}
// 5. 获取所有模块信息用于构建上下文和VO
// 获取所有模块信息
List<QuestionConstitutionType> constitutions = constitutionTypeMapper.selectList(null);
Map<Long, QuestionConstitutionType> constitutionMap = constitutions.stream()
.collect(Collectors.toMap(QuestionConstitutionType::getId, c -> c));
// 构建得分映射体质ID -> 总分)
Map<Long, Integer> 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<QuestionSurvey>()
.eq("status", 1)
.orderByDesc("create_time")
.last("LIMIT 1")
);
if (survey == null) {
return null;
}
Long surveyId=survey.getId();
// 2. 查询该问卷下的所有体质类型按sort_order排序
List<QuestionConstitutionType> constitutions = constitutionTypeMapper.selectList(
new LambdaQueryWrapper<QuestionConstitutionType>()
.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<Long> constitutionIds = constitutions.stream()
.map(QuestionConstitutionType::getId)
.collect(Collectors.toList());
List<QuestionQuestion> allQuestions = questionMapper.selectList(
new LambdaQueryWrapper<QuestionQuestion>()
.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<Long> questionIds = allQuestions.stream()
.map(QuestionQuestion::getId)
.collect(Collectors.toList());
List<QuestionOption> allOptions = optionMapper.selectList(
new LambdaQueryWrapper<QuestionOption>()
.in(QuestionOption::getQuestionId, questionIds)
.orderByAsc(QuestionOption::getQuestionId, QuestionOption::getSortOrder)
);
// 5. 构建 Map 结构便于组装
Map<Long, List<QuestionQuestion>> questionsByConstitutionId = allQuestions.stream()
.collect(Collectors.groupingBy(QuestionQuestion::getConstitutionId));
Map<Long, List<QuestionOption>> optionsByQuestionId = allOptions.stream()
.collect(Collectors.groupingBy(QuestionOption::getQuestionId));
// 6. 组装 VO
List<QuestionnaireVO.ConstitutionVO> 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<QuestionQuestion> questions = questionsByConstitutionId.getOrDefault(ct.getId(), Collections.emptyList());
List<QuestionnaireVO.QuestionVO> 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<QuestionOption> options = optionsByQuestionId.getOrDefault(q.getId(),Collections.emptyList());
List<QuestionnaireVO.OptionVO> 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<QuestionAnswerSheet>()
.eq("app_user_id",SecurityUtils.getAppLoginUser().getAppUserId() )
.orderByDesc("submit_time")
.last("LIMIT 1")
);
if (sheet == null) {
throw new RuntimeException("答卷不存在");
}
Long sheetId=sheet.getId();
List<QuestionConstitutionScore> scores = constitutionScoreMapper.selectList(
new LambdaQueryWrapper<QuestionConstitutionScore>().eq(QuestionConstitutionScore::getSheetId, sheetId));
List<QuestionConstitutionType> constitutions = constitutionTypeMapper.selectList(null);
Map<Long, QuestionConstitutionType> constitutionMap = constitutions.stream()
.collect(Collectors.toMap(QuestionConstitutionType::getId, c -> c));
AnswerResultVO vo = new AnswerResultVO();
vo.setResultType(sheet.getResultType());
vo.setResultText(sheet.getResultText());
List<ConstitutionScoreDTO> 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<QuestionConstitutionScore> computeConstitutionScores(Long sheetId) {
// 查询该答卷的所有答案
List<QuestionAnswerDetail> details =answerDetailMapper.getBySheetId(sheetId);
if (CollUtil.isEmpty(details)) {
return Collections.emptyList();
}
// 构建题目->选项分值的映射
Map<Long, Integer> optionScoreMap = details.stream()
.collect(Collectors.toMap(QuestionAnswerDetail::getQuestionId,
d -> d.getScore()));
// 按体质分组计算总分
Map<Long, Integer> 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<QuestionConstitutionScore> scores, Long sheetId) {
// 获取所有体质信息(含 alias, name, isBalanced
List<QuestionConstitutionType> constitutions = constitutionTypeMapper.selectList(null);
Map<Long, QuestionConstitutionType> constitutionMap = constitutions.stream()
.collect(Collectors.toMap(QuestionConstitutionType::getId, c -> c));
// 构建体质别名 -> 总分
Map<String, Integer> 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<String, Integer> 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<String> 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<String> 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<Long, Integer> scoreById,
Map<Long, QuestionConstitutionType> constitutionMap,
Long surveyId) {
List<QuestionRule> 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<Long, Integer> 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<Long, Integer> 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<ConstitutionScoreDTO> 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<Long, Integer> scoreById,
Map<Long, QuestionConstitutionType> constitutionMap) {
// 兜底结果
List<ConstitutionScoreDTO> 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<QuestionConstitutionScore> scores,
Map<Long, QuestionConstitutionType> constitutionMap) {
AnswerResultVO vo = new AnswerResultVO();
vo.setResultType(resultType);
vo.setResultText(resultText);
List<ConstitutionScoreDTO> 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<QuestionnaireVO.ConstitutionVO> buildConstitutionVOs(
List<QuestionConstitutionType> constitutions,
List<QuestionQuestion> allQuestions,
List<QuestionOption> allOptions) {
if (CollUtil.isEmpty(constitutions)) {
return Collections.emptyList();
}
// 按体质ID分组题目
Map<Long, List<QuestionQuestion>> questionsByConstitutionId = allQuestions.stream()
.collect(Collectors.groupingBy(QuestionQuestion::getConstitutionId));
// 按题目ID分组选项
Map<Long, List<QuestionOption>> 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<QuestionQuestion> questions = questionsByConstitutionId.getOrDefault(ct.getId(), Collections.emptyList());
List<QuestionnaireVO.QuestionVO> 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<QuestionOption> options = optionsByQuestionId.getOrDefault(q.getId(), Collections.emptyList());
List<QuestionnaireVO.OptionVO> 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());
}
}

@ -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;
/**
* <p>
@ -50,19 +62,37 @@ public class YjStoreServiceImpl extends ServiceImpl<YjStoreMapper, YjStore> impl
String tenantId= baseMapper.getOne(appUser.getVisitStore()).getTenantId();
List<YjStore> list=getStoreListByTenantId(tenantId);
list.forEach(l->{
if (l.getParentId().equals("0")){
l.setStoreName(l.getStoreName()+"(总店)");
}
});
return new RestResponse().setSuccess(true).setData(list);
List<YjStore> 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<AppUser>()
.eq("app_user_id",appUser.getId())
.set("visit_store",visitStoreId));
@ -81,4 +111,12 @@ public class YjStoreServiceImpl extends ServiceImpl<YjStoreMapper, YjStore> impl
public YjStore getOne(Long id){
return baseMapper.getOne(id);
}
@Override
public RestResponse getIndex(){
List<SysAppIndex> appIndices=baseMapper.getAppIndex();
return RestResponse.success().setData(appIndices);
}
}

@ -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;

@ -21,8 +21,10 @@ public class RespClaTimeCalendar extends ScClaTime {
// 上课 开始小时
private Integer startHour;
private Integer star;
private Integer fontSize;
private String fontColor;

@ -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;
// 教室

@ -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;
}

@ -38,9 +38,9 @@ public interface ScClaTimeMapper extends BaseMapper<ScClaTime> {
@Param("courseTimeId")Long courseTimeId,
@Param("deptId")Long deptId
);
ClaTimeCalendarItem getCourseDetail(@Param("courseTimeId")Long courseTimeId);
List<RespStuBook> getCourseBookStudent(Long courseTimeId);
List<RespStuBook> getCourseBookStudent(Long courseTimeId);
List<ClaTimeItem> getCourseCountByStoreManager(@Param("staffId")Long staffId, @Param("beginTime")String beginTime, @Param("endTime")String endTime);
List<StudentOrderItem> getStudentsBySaleStaff(Long staffId);

@ -18,84 +18,10 @@ import java.util.List;
* Mapper
* </p>
*
*
*
*
*
*/
public interface ScStudentCourseMapper extends BaseMapper<ScStudentCourse> {
/**
*
* @param studentId
* @return
*/
List<String> selectStudentCourseNameList(Long studentId);
/**
*
* @param studentId
* @return
*/
List<String> selectStudentDeptNameList(Long studentId);
/**
*
*
* @param reqSearchStudentCourseCla
* @param page
* @return
*/
List<RespCourseClaStudent> selectStudentList(@Param("reqSearchStudentCourseCla") ReqSearchStudentCourseCla reqSearchStudentCourseCla, @Param("page")Page page);
/**
*
* @param claId
* @return
*/
int selectClaNeedAttendCnt(Long claId);
/**
*
* @param searchStudentCourse
* @return
*/
List<RespStudentCourse> 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<RespStuCourseSignUpStudent> selectStudentSignUpList(@Param("reqSearchStuCourseSignUp") ReqSearchStuCourseSignUp reqSearchStuCourseSignUp, @Param("page")Page page);
}

@ -27,6 +27,7 @@ public interface ScClaTimeService extends IService<ScClaTime> {
RestResponse cancelCourse(Long courseTimeId);
RestResponse courseTimeDetail(Long courseTimeId);
RestResponse getCourseDetail(Long courseTimeId);
RestResponse appointmentListForTeacher();
RestResponse appointmentListForManager();
RestResponse checkAppointment(Long courseTimeId,int bookStatus);

@ -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<ScClaTimeMapper, ScClaTime
, cycleEnd
, DateField.DAY_OF_YEAR);
// // 日历数据 格式为:时间->星期->课程
Map<Integer, Map<Integer, List<RespClaTimeCalendar>>> 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<RespClaTimeCalendar> respClaTimeList = claTimeMapper.selectListForCalendar(reqSearchClaTime);
// 2. 根据返回的 开始时间(startHour) + 时长(claDuration) 自动生成时间段 MAP
Map<String, String> AUTO_CLA_TIME_MAP = generateTimeMapFromData(respClaTimeList);
Map<String, Map<Integer, List<RespClaTimeCalendar>>> claTimeCalendarMap = Maps.newHashMap();
AUTO_CLA_TIME_MAP.forEach((claTimeKey, claTimeValue) -> {
Map<Integer, List<RespClaTimeCalendar>> halfMonthDayMap = new HashMap();
for (int i = 0; i < dateList.size(); i++) {
List<RespClaTimeCalendar> claTimeArrayList = Lists.newArrayList();
@ -129,23 +139,19 @@ public class ScClaTimeServiceImpl extends ServiceImpl<ScClaTimeMapper, ScClaTime
}
claTimeCalendarMap.put(claTimeKey, halfMonthDayMap);
});
reqSearchClaTime.setBeginDate(DateUtil.format(cycleBegin,"yyyy-MM-dd"));
reqSearchClaTime.setEndDate(DateUtil.format(cycleEnd,"yyyy-MM-dd"));
// 获取排课信息
List<RespClaTimeCalendar> 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<ScClaTimeMapper, ScClaTime
// 每行数据
claTimeCalendarMap.forEach((claTimeKey, claTimeMap) -> {
ClaTimeContainer claTimeContainer = new ClaTimeContainer();
claTimeContainer.setTime(Constants.CLA_TIME_MAP.get(claTimeKey));
claTimeContainer.setTime(AUTO_CLA_TIME_MAP.get(claTimeKey));
Map<Integer, List<ClaTimeCalendarItem>> claTimeWeekDayMap = new HashMap();
claTimeMap.forEach((weekDayKey, list) -> {
@ -180,17 +186,19 @@ public class ScClaTimeServiceImpl extends ServiceImpl<ScClaTimeMapper, ScClaTime
claTimeContainer.setClaTimeWeekDayMap(claTimeWeekDayMap);
claTimeContainerList.add(claTimeContainer);
});
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, (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<ScClaTimeMapper, ScClaTime
return new RestResponse().setSuccess(false).setMessage("课程已开始上课,无法预约!");
}
ScCourseCla courseCla= claMapper.selectById(claTim.getClaId());
//获取当前用户 在租户所拥有的会员卡
List<ScMemberCard> cardList=memberCardsMapper.getByMemberId(studentId,courseCla.getTenantId(),claTim.getClaDate());
List<ScMemberCard> cardList=memberCardsMapper.getByMemberId(studentId,claTim.getTenantId(),claTim.getClaDate());
if (cardList.size()==0){
@ -271,7 +278,7 @@ public class ScClaTimeServiceImpl extends ServiceImpl<ScClaTimeMapper, ScClaTime
List<Long> cardIds=cardList.stream().map(it -> it.getId()).collect(Collectors.toList());
List<RespMemberTypeCourses> course= memberCardsMapper.getCourseDetail(courseCla.getCourseId(),claTim.getTeacherId(),cardIds);
List<RespMemberTypeCourses> course= memberCardsMapper.getCourseDetail(claTim.getCourseId(),claTim.getTeacherId(),cardIds);
//改:
// 1.会员卡排序 按天 -> 按课时 -> 按储值
@ -395,10 +402,9 @@ public class ScClaTimeServiceImpl extends ServiceImpl<ScClaTimeMapper, ScClaTime
book.setChargeType(selected.getChargeType());
book.setDeductCnt(selected.getDeductCnt());
book.setDeductFee(selected.getDeductFee());
book.setTenantId(courseCla.getTenantId());
book.setCourseId(courseCla.getCourseId());
book.setClaId(courseCla.getClaId());
book.setDepartId(courseCla.getDepartId());
book.setTenantId(claTim.getTenantId());
book.setCourseId(claTim.getCourseId());
book.setDepartId(claTim.getStoreId());
//生成一个code 用于消课
Long code = IDGenerator.generateId();
bookCourseMapper.insert(book);
@ -498,6 +504,9 @@ public class ScClaTimeServiceImpl extends ServiceImpl<ScClaTimeMapper, ScClaTime
@Override
public RestResponse bookCourseDetail(Long bookId){
ClaTimeBookItem bookItem=bookCourseMapper.getDetail(bookId);
if (ObjectUtil.isEmpty(bookItem)){
return new RestResponse().setSuccess(false).setMessage("预约详情不存在");
}
List<ScBookCourseLog> logs=bookCourseLogMapper.selectList(new QueryWrapper<ScBookCourseLog>()
.eq("book_id",bookId).orderByAsc("update_time"));
@ -569,6 +578,12 @@ public class ScClaTimeServiceImpl extends ServiceImpl<ScClaTimeMapper, ScClaTime
return new RestResponse().setSuccess(true).setData(map);
}
@Override
public RestResponse getCourseDetail(Long courseTimeId){
ClaTimeCalendarItem claTimeCalendarItem=claTimeMapper.getCourseDetail(courseTimeId);
return new RestResponse().setSuccess(true).setData(claTimeCalendarItem);
}
@Override
public RestResponse appointmentListForTeacher(){
Long[] roleId=SecurityUtils.getAppLoginUser().getRoles();
@ -580,7 +595,7 @@ public class ScClaTimeServiceImpl extends ServiceImpl<ScClaTimeMapper, ScClaTime
Date beginTime = new Date();//开始时间
Date endTime = DateUtil.offsetDay(beginTime,14);//结束时间
//按教师id 查 近15日课程 sc_cla_time 预约sc_book_course
List<RespBook> listForTeacher=claTimeMapper.getBookListForTeacher(userId,beginTime.toString(),endTime.toString());
List<RespBook> 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<ScClaTimeMapper, ScClaTime
}
Long userId= SecurityUtils.getAppLoginUser().getManageAccountId();
SysDept dept=new SysDept();
dept.setLeaderId(userId);
List<SysDept> 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<RespBook> listForManager=claTimeMapper.getBookListForManager(deptId,beginTime.toString(),endTime.toString());
List<RespBook> 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<ScClaTimeMapper, ScClaTime
throw new RuntimeException("请选择查询时间范围");
}
}
/**
* 3.
*/
private Map<String, String> generateTimeMapFromData(List<RespClaTimeCalendar> respClaTimeList) {
// TreeMap 自动按 key 升序排列
Map<String, String> timeMap = new TreeMap<>();
for (RespClaTimeCalendar item : respClaTimeList) {
String startHour = item.getStartTime();
if (startHour == null) continue;
timeMap.put(startHour, startHour );
}
return timeMap;
}
private Map<Integer, String> generateTimeMapFromData_old(List<RespClaTimeCalendar> respClaTimeList) {
// TreeMap 自动按 key 升序排列
Map<Integer, String> timeMap = new TreeMap<>();
if (CollectionUtils.isEmpty(respClaTimeList)) {
timeMap=Constants.CLA_TIME_MAP;
return timeMap;
}
// 第一步收集所有【合法的2小时制开始小时】8、10、12、14、16、18...
Set<Integer> 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;
}
}

@ -44,7 +44,6 @@ public class Friend {
/**
*
*/
@TableField(exist = false)
private String friendHeadImage;
@TableField(exist = false)
private Long roleId;

@ -7,7 +7,7 @@ import java.util.List;
public interface FriendMapper extends BaseMapper<Friend> {
List<Friend> getFriendListForConsumer(Long userId);
List<Friend> getFriendListForConsumer(Long storeId);
List<Friend> getFriendListForManage(Long userId);
}

@ -56,7 +56,7 @@ public interface FriendService extends IService<Friend> {
* @param friendId id
* @return
*/
FriendVO findFriend(Long friendId);
FriendVO findFriend( Long userId, Long friendId);
/**
*

@ -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<FriendMapper, Friend> 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<FriendMapper, Friend> impleme
map.put("consumer",list);
return map;
}
Long storeId=SecurityUtils.getAppLoginUser().getAppUser().getVisitStore();
List<Friend> list=baseMapper.getFriendListForConsumer(userId);
List<Friend> list=baseMapper.getFriendListForConsumer(storeId);
Map<Long, List<Friend>> 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<FriendMapper, Friend> impleme
*/
@CacheEvict(key = "#userId+':'+#friendId")
public void bindFriend(Long userId, Long friendId) {
// QueryWrapper<Friend> 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<Friend> 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<FriendMapper, Friend> 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<Friend> 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);
}

@ -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<GroupMessageMapper, Gro
@Override
public void pullOfflineMessage(Long minId) {
if (!imClient.isOnline(SecurityUtils.getAppLoginUser().getAppUserId())) {
AppUser session = SecurityUtils.getAppLoginUser().getAppUser();
if (!imClient.isOnline(session.getId())) {
throw new GlobalException("网络连接失败,无法拉取离线消息");
}
// 查询用户加入的群组
List<GroupMember> members = groupMemberService.findByUserId(SecurityUtils.getAppLoginUser().getAppUserId());
List<GroupMember> members = groupMemberService.findByUserId(session.getId());
Map<Long, GroupMember> groupMemberMap = CollStreamUtil.toIdentityMap(members, GroupMember::getGroupId);
Set<Long> groupIds = groupMemberMap.keySet();
if (CollectionUtil.isEmpty(groupIds)) {
// 关闭加载中标志
this.sendLoadingMessage(false);
this.sendLoadingMessage(false,session);
return;
}
@ -170,7 +172,7 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro
Map<Long, List<GroupMessage>> messageGroupMap =
messages.stream().collect(Collectors.groupingBy(GroupMessage::getGroupId));
// 退群前的消息
List<GroupMember> quitMembers = groupMemberService.findQuitInMonth(SecurityUtils.getAppLoginUser().getAppUserId());
List<GroupMember> 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<GroupMessageMapper, Gro
}
EXECUTOR.execute(() -> {
// 开启加载中标志
this.sendLoadingMessage(true);
this.sendLoadingMessage(true,session);
// 推送消息
AtomicInteger sendCount = new AtomicInteger();
messageGroupMap.forEach((groupId, groupMessages) -> {
@ -193,7 +195,7 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro
}
// 填充消息状态
String key = StrUtil.join(":", RedisKey.IM_GROUP_READED_POSITION, groupId);
Object o = redisTemplate.opsForHash().get(key, SecurityUtils.getAppLoginUser().getAppUserId().toString());
Object o = redisTemplate.opsForHash().get(key,session.getId().toString());
long readedMaxId = Objects.isNull(o) ? -1 : Long.parseLong(o.toString());
Map<Object, Object> maxIdMap = null;
for (GroupMessage m : sendMessages) {
@ -204,7 +206,7 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro
}
// 排除不需要接收的消息
List<String> 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<GroupMessageMapper, Gro
// 推送
IMGroupMessage<GroupMessageVO> 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<GroupMessageMapper, Gro
}
});
// 关闭加载中标志
this.sendLoadingMessage(false);
this.sendLoadingMessage(false,session);
log.info("拉取离线群聊消息,用户id:{},数量:{}",SecurityUtils.getAppLoginUser().getAppUserId(), sendCount.get());
});
}
@ -359,13 +361,14 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro
return userIds;
}
private void sendLoadingMessage(Boolean isLoadding) {
private void sendLoadingMessage(Boolean isLoadding, AppUser session) {
GroupMessageVO msgInfo = new GroupMessageVO();
msgInfo.setType(MessageType.LOADING.code());
msgInfo.setContent(isLoadding.toString());
IMGroupMessage sendMessage = new IMGroupMessage<>();
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<GroupMessageMapper, Gro
String key = StrUtil.join(":", RedisKey.IM_GROUP_READED_POSITION, groupId);
// 原来的已读消息位置
Object maxReadedId = redisTemplate.opsForHash().get(key,SecurityUtils.getAppLoginUser().getAppUserId().toString());
if (ObjectUtil.isEmpty(maxReadedId)) {
return "-1";
}
// LambdaQueryWrapper<GroupMessage> 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();
}

@ -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")

@ -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<Product> {
*/
List<Product> selectByEntity(Product product);
List<Product> selectByGoodStuff(Long selectByGoodStuff);
List<Product> getMallProductList(@Param("categoryId") Long categoryId,
@Param("search")String search,
@Param("isCourse")Integer isCourse);
}

@ -43,7 +43,7 @@ public class ProductCategoryServiceImpl extends ServiceImpl<ProductCategoryMappe
QueryWrapper<ProductCategory> 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);
}

@ -76,19 +76,23 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
if (page != null) {
PageHelper.startPage(page.getPageNumber() + 1, page.getPageSize());
}
QueryWrapper<Product> qw = new QueryWrapper<>();
qw.orderByDesc("publish_status");
qw.orderByAsc("sort");
Long categoryId = query.getCategoryId();
if (categoryId != null) {
if (categoryId != null && categoryId.equals(1L)) {
QueryWrapper<Product> 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<ProductMapper, Product> impl
}
public Map selectByGoodStuff(String storeId) {
Map<String,List<Product>> map=new HashMap<>();
List<Product> courses=productMapper.selectList(new QueryWrapper<Product>()
.eq("store_id", storeId)
.eq("is_course",1)
.orderByAsc("sort")
.last("limit 2")
);
List<Product> goods=productMapper.selectList(new QueryWrapper<Product>()
.eq("store_id", storeId)
.eq("is_course",0)
.orderByAsc("sort")
.last("limit 2")
);
// List<Product> productList=productMapper.selectByGoodStuff(Long.parseLong(storeId));
// List<Product> goods=new ArrayList<>();
// List<Product> 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<Product> courses=productMapper.getMallProductList(null,null,1);
List<Product> 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;
}

@ -101,4 +101,7 @@ public class SysTeacher implements Serializable {
*/
@TableField("update_time")
private Date updateTime;
@TableField( exist = false)
private Long appUserId;
}

@ -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<SysDictData>
{
/**
*
@ -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

@ -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<SysDictData>
{
/**
*
*
* @param dictData
* @return
*/
public List<SysDictData> selectDictDataList(SysDictData dictData);
/**
*
*
* @param dictType
* @param dictValue
* @return
*/
public String selectDictLabel(String dictType, String dictValue);
List<SysDictData> 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);
}

@ -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<SysDictDataMapper, SysDictData> implements ISysDictDataService
{
@Autowired
private SysDictDataMapper dictDataMapper;
/**
*
*
* @param dictData
* @return
*/
@Override
public List<SysDictData> 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<SysDictData> dictTypeDataList(String dictType) {
if (StringUtils.isEmpty(dictType)) {
return Lists.newArrayList();
}
QueryWrapper<SysDictData> 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<SysDictData> 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<SysDictData> 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<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(data);
DictUtils.setDictCache(data.getDictType(), dictDatas);
}
return row;
}
}

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.basic.mapper.QuestionAnswerDetailMapper">
<insert id="insertBatch">
INSERT INTO question_answer_detail (sheet_id, question_id, option_id) VALUES
<foreach collection="list" item="item" separator=",">
(#{item.sheetId}, #{item.questionId}, #{item.optionId})
</foreach>
</insert>
<select id="getBySheetId" resultType="com.ruoyi.basic.domain.question.QuestionAnswerDetail">
select
* ,
(select score from question_option where question_id = question_answer_detail.question_id and id = question_answer_detail.option_id) as score
from question_answer_detail where sheet_id = #{sheetId}
</select>
</mapper>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.basic.mapper.QuestionConstitutionScoreMapper">
<insert id="insertBatch">
INSERT INTO question_constitution_score (sheet_id, constitution_id, total_score) VALUES
<foreach collection="list" item="item" separator=",">
(#{item.sheetId}, #{item.constitutionId}, #{item.totalScore})
</foreach>
</insert>
</mapper>

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.basic.mapper.QuestionRuleMapper">
<resultMap id="BaseResultMap" type="com.ruoyi.basic.domain.question.QuestionRule">
<id column="id" property="id"/>
<result column="survey_id" property="surveyId"/>
<result column="rule_name" property="ruleName"/>
<result column="target_type" property="targetType"/>
<result column="target_constitution_id" property="targetConstitutionId"/>
<result column="min_score" property="minScore"/>
<result column="max_score" property="maxScore"/>
<result column="require_other_max_score" property="requireOtherMaxScore"/>
<result column="require_other_min_score" property="requireOtherMinScore"/>
<result column="condition_json" property="conditionJson"/>
<result column="priority" property="priority"/>
<result column="status" property="status"/>
<result column="result_text" property="resultText"/>
<result column="create_time" property="createTime"/>
<result column="update_time" property="updateTime"/>
</resultMap>
<select id="selectEnabledBySurveyId" resultMap="BaseResultMap">
SELECT *
FROM question_rule
WHERE survey_id = #{surveyId}
AND status = 1
ORDER BY priority ASC, id ASC
</select>
</mapper>

@ -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 <![CDATA[ <= ]]> NOW() <![CDATA[ <= ]]> b.expiry_date
</select>
<select id="getStoreListByTenantId" resultType="com.ruoyi.basic.domain.YjStore">
@ -25,6 +27,7 @@
and c.delete_flag='0'
and now() between c.begin_time and c.end_time
and b.tenant_id=#{tenantId}
and b.activation_date <![CDATA[ <= ]]> NOW() <![CDATA[ <= ]]> b.expiry_date
</select>
@ -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 <![CDATA[ <= ]]> NOW() <![CDATA[ <= ]]> b.expiry_date
</select>
<select id="getAppIndex" resultType="SysAppIndex">
select * from sys_app_index order by sort
</select>
</mapper>

@ -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
</select>
@ -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}
</select>
</mapper>

@ -5,9 +5,8 @@
<select id="selectTeacherSumGetHour" resultType="java.math.BigDecimal">
select
ifnull(sum(b.teacher_get_hour),0)
from sc_course_cla a,sc_cla_time_attend b
where a.delete_flag='0' and a.cla_id=b.cla_id
and b.teacher_id=#{teacherId}
from sc_cla_time_attend b
where b.teacher_id=#{teacherId}
and b.charge_type <![CDATA[ <> ]]> 'date'
and exists(
select 1

@ -7,91 +7,42 @@
b.cla_id,
b.cla_date,
WEEKDAY(b.cla_date) + 1 as week_day,
hour(b.start_time) as start_hour,b.start_time,
hour(b.start_time) as start_hour,
DATE_FORMAT(b.start_time, '%H:%i') AS start_time,
b.end_time,
b.source,
b.status,
b.memo,
b.class_theme,
a.cla_name,
a.cla_color,
b.cla_color,
b.font_size,
b.font_color,
course.course_name,
course.star,
s.user_id as teacher_id,
s.teacher_name as staff_name,
(select store.store_name from yj_store store where b.dept_id=store.dept_id )as store_name,
r.room_id,
r.room_name
from sc_course_cla a
left join sc_course course on a.course_id=course.course_id
,sc_cla_time b
left join sys_teacher s on b.teacher_id = s.user_id
left join sc_room r on b.room_id = r.room_id
where a.cla_id=b.cla_id
from sc_cla_time b
left join sc_course course on b.course_id=course.course_id
left join sys_teacher s on b.teacher_id = s.user_id
left join sc_room r on b.room_id = r.room_id
where 1=1
<if test="courseTimeId != null">
and b.course_time_id=#{courseTimeId}
</if>
<if test="beginDate != null and beginDate != '' and endDate != null and endDate != ''">
and b.cla_date between #{beginDate} and #{endDate}
</if>
<if test="claId != null">
and a.cla_id=#{claId}
</if>
<if test="deptId != null">
and a.depart_id=#{deptId}
and b.dept_id=#{deptId}
</if>
<if test="teacherId != null">
and b.teacher_id=#{teacherId}
</if>
<if test="courseId != null">
and a.course_id = #{courseId}
</if>
<if test="attended != null and attended == false">
and b.status = '1'
</if>
<if test="attended != null and attended == true">
and b.status = '2'
</if>
order by b.cla_date,b.status,b.start_time
</select>
<select id="selectListForCalendar_old" resultType="com.ruoyi.course.domain.res.RespClaTimeCalendar">
select b.course_time_id,b.cla_id,b.cla_date,WEEKDAY(b.cla_date) + 1 as week_day,
hour(b.start_time) as start_hour,b.start_time,
b.end_time,b.source,b.status,b.memo,b.status,b.class_theme,
a.cla_name,a.cla_color,course.course_name,
s.user_id as teacher_id,s.teacher_name as staff_name,
r.room_id,r.room_name,
(select count(distinct student_id) from sc_student_course sc where sc.cla_id=a.cla_id and sc.status='1') as student_count,
b.pay_hour
from sc_course_cla a
left join sc_course course on a.course_id=course.course_id
,sc_cla_time b
left join sys_teacher s on b.teacher_id = s.user_id
left join sc_room r on b.room_id = r.room_id
where a.cla_id=b.cla_id
<if test="courseTimeId != null">
and b.course_time_id=#{courseTimeId}
</if>
<if test="beginDate != null and beginDate != '' and endDate != null and endDate != ''">
and b.cla_date between #{beginDate} and #{endDate}
</if>
<if test="claId != null">
and a.cla_id=#{claId}
</if>
<if test="studentId != null">
and exists(select 1 from sc_student_course sc where a.cla_id=sc.cla_id and sc.student_id=#{studentId})
</if>
<if test="deptId != null">
and a.depart_id=#{deptId}
</if>
<!-- <if test="deptId == null and userId != null and userId != ''">-->
<!-- and exists(select 1 from sys_user_dept ud-->
<!-- where ud.user_id=#{userId}-->
<!-- and (ud.dept_id=a.depart_id or ud.dept_id=-1))-->
<!-- </if>-->
<if test="teacherId != null">
and b.teacher_id=#{teacherId}
</if>
<if test="courseId != null">
and a.course_id = #{courseId}
and b.course_id = #{courseId}
</if>
<if test="attended != null and attended == false">
and b.status = '1'
@ -102,17 +53,15 @@
order by b.cla_date,b.status,b.start_time
</select>
<select id="getCourseList" resultType="com.ruoyi.course.domain.time.ClaTimeCalendarItem">
SELECT
c.course_time_id,
a.course_name,
a.star,
c.room_name,
d.teacher_name as staff_Name,
b.cla_name,
b.cla_color,
b.cla_pic,
d.avatar_img as pic,
c.cla_color,
c.cla_date,
c.start_time,
c.end_time,
@ -127,15 +76,13 @@
from
sc_course a,
sc_course_cla b,
sc_cla_time c,
sys_teacher d,
yj_store e
WHERE a.course_id=b.course_id
and b.cla_id=c.cla_id
WHERE a.course_id=c.course_id
and c.teacher_id=d.user_id
and b.depart_id=e.dept_id
and c.dept_id=e.dept_id
<if test="date != null ">
and c.cla_date =#{date}
</if>
@ -145,7 +92,46 @@
<if test="deptId != null ">
and e.dept_id =#{deptId}
</if>
order by c.cla_date,c.start_time
</select>
<select id="getCourseDetail" resultType="com.ruoyi.course.domain.time.ClaTimeCalendarItem">
SELECT
c.course_time_id,
a.course_name,
(select course_type from sc_course_type where course_type_id=a.course_type_id)as course_type_name,
a.star,
c.room_name,
d.teacher_name as staff_Name,
d.avatar_img as pic,
c.cla_color,
c.cla_date,
c.start_time,
c.end_time,
c.book_attend_cnt,
c.at_class_cnt,
c.status as cla_time_status,
c.room_name,
c.book_attend_cnt,
c.at_class_cnt,
c.less_cnt,
e.store_name,
a.remark
from
sc_course a,
sc_cla_time c,
sys_teacher d,
yj_store e
WHERE a.course_id=c.course_id
and c.teacher_id=d.user_id
and c.dept_id=e.dept_id
<if test="courseTimeId != null ">
and c.course_time_id =#{courseTimeId}
</if>
order by c.cla_date,c.start_time
</select>
<select id="getCourseBookStudent" resultType="com.ruoyi.course.domain.res.RespStuBook">
@ -171,7 +157,6 @@
<select id="getCourseCountByStoreManager" resultType="com.ruoyi.course.domain.time.ClaTimeItem">
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}
</select>
@ -252,8 +237,8 @@
<select id="getBookListForTeacher" resultType="com.ruoyi.course.domain.res.RespBook">
SELECT
b.id as book_id,
(select cour.course_name from sc_course_cla cla ,sc_course cour WHERE cla.course_id=cour.course_id and cla.cla_id=a.cla_id) as course_name,
(select cla_name from sc_course_cla WHERE cla_id=a.cla_id) as cla_name,
(select cour.course_name from sc_course cour
WHERE cour.course_id=a.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,
@ -278,8 +263,7 @@
<select id="getBookListForManager" resultType="com.ruoyi.course.domain.res.RespBook">
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
</select>

@ -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'

@ -2,193 +2,4 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.course.mapper.ScStudentCourseMapper">
<select id="selectStudentCourseNameList" resultType="java.lang.String">
select distinct b.course_name
from sc_student_course a
left join sc_course b on a.course_id=b.course_id
where a.student_id = #{studentId} and a.status = '1'
</select>
<select id="selectStudentDeptNameList" resultType="java.lang.String">
select distinct c.dept_name
from sc_student_course a
left join sc_course_cla b on a.cla_id=b.cla_id
left join sys_dept c on b.depart_id=c.dept_id
where a.student_id = #{studentId} and a.status = '1' and a.cla_id is not null
</select>
<select id="selectStudentList" resultType="com.ruoyi.course.domain.res.RespCourseClaStudent">
select a.student_course_id,a.cla_id,a.course_id,
d.dept_name,
a.charge_type,a.total_day,a.total_hour,
a.balance_hour,
case a.charge_type when 'date' then null else (select ifnull(sum(co.balance_hour),0) from sc_student_course_order co where a.student_course_id=co.student_course_id and co.valid=1 and date_format(now(),'%Y-%m-%d') <![CDATA[ > ]]> co.expire_date) end as expire_hour,
case a.charge_type when 'date' then (select ifnull(sum(co.total_day),0) from sc_student_course_order co where a.student_course_id=co.student_course_id and co.valid=1 and date_format(now(),'%Y-%m-%d') <![CDATA[ < ]]> co.begin_date) end as coming_effect_day,
case a.charge_type when 'date' then (select co.end_date from sc_student_course_order co where a.student_course_id=co.student_course_id and co.valid=1 and date_format(now(),'%Y-%m-%d') between co.begin_date and co.end_date limit 1) end as end_date,
a.status,
a.create_time as first_sign_time,
(select co.create_time from sc_student_course_order co where a.student_course_id=co.student_course_id and co.valid=1 order by co.create_time desc limit 1) as last_sign_time,
b.student_id,b.student_name,b.sex,b.phone,
(select group_concat(sc.contact_nick,'(',fcn_dict_name(sc.contact_relation,'contact_relation'),') ',sc.contact_phone separator ';') from sc_student_contact sc where sc.student_id=b.student_id) as contact_info
from sc_student_course a left join sys_dept d on a.dept_id=d.dept_id
,sc_student b
where a.student_id=b.student_id
<if test="reqSearchStudentCourseCla.claId != null">
and a.cla_id=#{reqSearchStudentCourseCla.claId}
</if>
<if test="reqSearchStudentCourseCla.departId != null">
and a.dept_id=#{reqSearchStudentCourseCla.departId}
</if>
<!-- <if test="reqSearchStudentCourseCla.deptId == null and reqSearchStudentCourseCla.userId != null and reqSearchStudentCourseCla.userId != ''">-->
<!-- and exists(select 1 from sys_user_dept ud-->
<!-- where ud.user_id=#{reqSearchStudentCourseCla.userId}-->
<!-- and (ud.dept_id=a.dept_id or ud.dept_id=-1))-->
<!-- </if>-->
<if test="reqSearchStudentCourseCla.courseId != null">
and a.course_id=#{reqSearchStudentCourseCla.courseId}
</if>
<if test="reqSearchStudentCourseCla.unChooseCla != null and reqSearchStudentCourseCla.unChooseCla == true">
and a.cla_id is null
</if>
<if test="reqSearchStudentCourseCla.unChooseCla != null and reqSearchStudentCourseCla.unChooseCla == false">
and a.cla_id is not null
</if>
<if test="reqSearchStudentCourseCla.effect != null and reqSearchStudentCourseCla.effect == true">
and a.status='1'
and (charge_type in ('hour','cycle')
or (charge_type='date' and exists(
select 1 from sc_student_course_order sco
where a.student_course_id=sco.student_course_id
and sco.valid=1
and date_format(now(),'%Y-%m-%d') between sco.begin_date and sco.end_date)))
</if>
order by a.create_time desc
</select>
<select id="selectClaNeedAttendCnt" resultType="int">
select count(1) from sc_student_course sc
where sc.cla_id=#{claId}
and sc.status='1'
and (charge_type in ('hour','cycle')
or (charge_type='date' and exists(
select 1 from sc_student_course_order sco
where sc.student_course_id=sco.student_course_id
and sco.valid=1
and date_format(now(),'%Y-%m-%d') between sco.begin_date and sco.end_date)))
</select>
<select id="selectStudentCourseList" resultType="com.ruoyi.course.domain.res.RespStudentCourse">
select a.student_course_id,a.course_name,a.charge_type,a.total_day,a.total_hour,
a.balance_hour,
case a.charge_type when 'date' then null else (select ifnull(sum(co.balance_hour),0) from sc_student_course_order co where a.student_course_id=co.student_course_id and co.valid=1 and date_format(now(),'%Y-%m-%d') <![CDATA[ > ]]> co.expire_date) end as expire_hour,
a.total_fee,a.status,
b.student_id,b.student_name,c.dept_name,d.cla_name,
(select case a.charge_type
when 'date' then group_concat(sco.total_day, ',', sco.begin_date, '~', sco.end_date separator ';')
else group_concat(sco.total_hour, ',', date_format(sco.create_time, '%Y%m%d') separator ';')
end
from sc_student_course_order sco
where a.student_course_id = sco.student_course_id and sco.valid=1) as order_detail,
case a.charge_type when 'date' then (select ifnull(sum(co.total_day),0) from sc_student_course_order co where a.student_course_id=co.student_course_id and co.valid=1 and date_format(now(),'%Y-%m-%d') <![CDATA[ < ]]> co.begin_date) end as coming_effect_day,
case a.charge_type when 'date' then (select co.end_date from sc_student_course_order co where a.student_course_id=co.student_course_id and co.valid=1 and date_format(now(),'%Y-%m-%d') between co.begin_date and co.end_date limit 1) end as end_date
from sc_student_course a
left join sc_student b on a.student_id=b.student_id
left join sys_dept c on a.dept_id=c.dept_id
left join sc_course_cla d on a.cla_id=d.cla_id
where 1=1
<if test="studentId != null">
and a.student_id=#{studentId}
</if>
<if test="deptId != null">
and a.dept_id=#{deptId}
</if>
<!-- <if test="deptId == null and userId != null and userId != ''">-->
<!-- and exists(select 1 from sys_user_dept ud-->
<!-- where ud.user_id=#{userId}-->
<!-- and (ud.dept_id=a.dept_id or ud.dept_id=-1))-->
<!-- </if>-->
order by a.create_time desc
</select>
<delete id="deleteWhenTotalHourZeroForInvalid">
delete from sc_student_course where student_course_id=#{studentCourseId} and charge_type <![CDATA[ <> ]]> 'date' and total_hour=0 and total_fee=0
</delete>
<delete id="deleteWhenTotalDayZeroForInvalid">
delete from sc_student_course where student_course_id=#{studentCourseId} and charge_type = 'date' and total_day=0 and total_fee=0
</delete>
<select id="selectWillExpireDateCount" resultType="java.lang.Integer">
select count(1) from sc_student_course sc
where sc.charge_type='date' and sc.status='1'
and exists(select 1 from sc_student_course_order sco
where sco.student_course_id=sc.student_course_id
and sco.valid=1
and date_format(now(),'%Y-%m-%d') between sco.begin_date and sco.end_date
and (datediff(sco.end_date,now())+1+((select ifnull(sum(sco.total_day),0) from sc_student_course_order sco_will_effect
where sco_will_effect.student_course_id=sc.student_course_id
and sco_will_effect.valid=1 and date_format(now(),'%Y-%m-%d') <![CDATA[ < ]]> sco_will_effect.begin_date))
) <![CDATA[ <= ]]> #{minBalanceDay})
</select>
<select id="selectWillExpireHourCount" resultType="java.lang.Integer">
select count(1) from sc_student_course sc
where sc.charge_type <![CDATA[ <> ]]> 'date'
and sc.status='1'
and (sc.balance_hour - (select ifnull(sum(sco.balance_hour),0)
from sc_student_course_order sco
where sc.student_course_id=sco.student_course_id
and sco.valid=1 and date_format(now(),'%Y-%m-%d') <![CDATA[ > ]]> sco.expire_date)
) <![CDATA[ <= ]]> #{minBalanceHour}
</select>
<select id="selectStudentSignUpList" resultType="com.ruoyi.course.domain.res.RespStuCourseSignUpStudent">
select a.student_course_id,
a.cla_id,a.cla_name,
a.course_id,a.course_name,
d.dept_name,
a.charge_type,a.total_day,a.total_hour,
a.balance_hour,
(select case a.charge_type
when 'date' then group_concat(sco.total_day, ',', sco.begin_date, '~', sco.end_date separator ';')
else group_concat(sco.total_hour, ',', date_format(sco.create_time, '%Y%m%d') separator ';')
end
from sc_student_course_order sco
where a.student_course_id = sco.student_course_id and sco.valid=1) as order_detail,
(select sum(co.total_fee) from sc_student_course_order co where a.student_course_id=co.student_course_id and co.valid=1) as total_fee,
(select sum(co.balance_hour * co.unit_fee) from sc_student_course_order co where a.student_course_id=co.student_course_id and co.valid=1) as balance_fee,
case a.charge_type when 'date' then null else (select ifnull(sum(co.balance_hour),0) from sc_student_course_order co where a.student_course_id=co.student_course_id and co.valid=1 and date_format(now(),'%Y-%m-%d') <![CDATA[ > ]]> co.expire_date) end as expire_hour,
case a.charge_type when 'date' then null else (select ifnull(sum(co.balance_hour * co.unit_fee),0) from sc_student_course_order co where a.student_course_id=co.student_course_id and co.valid=1 and date_format(now(),'%Y-%m-%d') <![CDATA[ > ]]> co.expire_date) end as expire_fee,
case a.charge_type when 'date' then (select ifnull(sum(co.total_day),0) from sc_student_course_order co where a.student_course_id=co.student_course_id and co.valid=1 and date_format(now(),'%Y-%m-%d') <![CDATA[ < ]]> co.begin_date) end as coming_effect_day,
case a.charge_type when 'date' then (select co.end_date from sc_student_course_order co where a.student_course_id=co.student_course_id and co.valid=1 and date_format(now(),'%Y-%m-%d') between co.begin_date and co.end_date limit 1) end as end_date,
a.status,
a.create_time as first_sign_time,
(select co.create_time from sc_student_course_order co where a.student_course_id=co.student_course_id and co.valid=1 order by co.create_time desc limit 1) as last_sign_time,
b.student_id,b.student_name,b.sex,b.phone,
(select group_concat(sc.contact_nick,'(',fcn_dict_name(sc.contact_relation,'contact_relation'),') ',sc.contact_phone separator ';') from sc_student_contact sc where sc.student_id=b.student_id) as contact_info
from sc_student_course a
left join sys_dept d on a.dept_id=d.dept_id
,sc_student b
where a.student_id=b.student_id
<if test="reqSearchStuCourseSignUp.claId != null">
and a.cla_id=#{reqSearchStuCourseSignUp.claId}
</if>
<if test="reqSearchStuCourseSignUp.departId != null">
and a.dept_id=#{reqSearchStuCourseSignUp.departId}
</if>
<if test="reqSearchStuCourseSignUp.courseId != null">
and a.course_id=#{reqSearchStuCourseSignUp.courseId}
</if>
<if test="reqSearchStuCourseSignUp.minBalanceDay != null">
and a.charge_type='date' and a.status='1'
and exists(select 1 from sc_student_course_order sco
where sco.student_course_id=a.student_course_id
and sco.valid=1
and date_format(now(),'%Y-%m-%d') between sco.begin_date and sco.end_date
and (datediff(sco.end_date,now())+1+((select ifnull(sum(sco.total_day),0) from sc_student_course_order sco_will_effect
where sco_will_effect.student_course_id=a.student_course_id
and sco_will_effect.valid=1 and date_format(now(),'%Y-%m-%d') <![CDATA[ < ]]> sco_will_effect.begin_date))
) <![CDATA[ <= ]]> #{reqSearchStuCourseSignUp.minBalanceDay})
</if>
<if test="reqSearchStuCourseSignUp.minBalanceHour != null">
and a.charge_type <![CDATA[ <> ]]> 'date' and a.status='1'
and (a.balance_hour - (select ifnull(sum(sco.balance_hour),0)
from sc_student_course_order sco
where a.student_course_id=sco.student_course_id
and sco.valid=1 and date_format(now(),'%Y-%m-%d') <![CDATA[ > ]]> sco.expire_date)
) <![CDATA[ <= ]]> #{reqSearchStuCourseSignUp.minBalanceHour}
</if>
order by a.create_time desc
</select>
</mapper>

@ -2,7 +2,7 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.im.mapper.FriendMapper">
<select id="getFriendListForConsumer" resultType="com.ruoyi.im.domain.Friend">
<select id="getFriendListForConsumer_old" resultType="com.ruoyi.im.domain.Friend">
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}
</select>
<select id="getFriendListForConsumer" resultType="com.ruoyi.im.domain.Friend">
select
d.app_user_id as friend_id,
-- CONCAT(d.nick_name,'(',b.store_name,')') as friend_nick_name,
d.nick_name as friend_nick_name,
d.avatar as friend_head_image,
e.role_id,
b.dept_id as store_id
from yj_store b
,sys_user c
,yj_app_user d
,sys_user_role e
WHERE c.dept_id=b.dept_id
and d.manage_account_id=c.user_id
and c.user_id=e.user_id
and b.dept_id=#{storeId}
</select>
<select id="getFriendListForManage" resultType="com.ruoyi.im.domain.Friend">
@ -34,4 +52,14 @@
and a.user_id=#{userId}
</select>
<select id="getUserByDept" resultType="AppUser">
select b.app_user_id ,b.nick_name
from sys_user a,yj_app_user b
WHERE a.user_id=b.manage_account_id
and a.personnel_status='1'
and a.delete_flag='0'
and a.status='0'
and a.dept_id=#{deptId}
</select>
</mapper>

@ -62,4 +62,56 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
WHERE g.product_id=p.id
and g.store_id=#{storeId}
</select>
<select id="getMallProductList" resultMap="ProductResult">
SELECT
a.id,
a.product_snapshot_id,
a.brand_id,
CASE
WHEN b.show_category IS NOT NULL THEN b.show_category
ELSE a.category_id
END AS category_id,
a.out_product_id,
a.name,
a.pic,
a.album_pics,
a.publish_status,
CASE
WHEN b.sort IS NOT NULL THEN b.sort
ELSE a.sort
END AS sort,
a.price,
a.unit,
a.weight,
a.detail_html,
a.detail_mobile_html,
a.brand_name,
a.product_category_name,
a.create_by,
a.create_time,
a.update_by,
a.update_time,
a.product_attr,
a.is_course,
a.store_id,
a.course_id,
a.customer_service,
a.instructor,
a.tenant_id
from mall_product a LEFT JOIN mall_product_show b
on a.id=b.product_id
WHERE
a.publish_status=1 and
(a.store_id=1 <if test="categoryId != null "> and a.category_id = #{categoryId}</if> )
or
(b.show_flag='1'
and b.show_start_time <![CDATA[ <= ]]> NOW() <![CDATA[ <= ]]> b.show_end_time
and b.apply_status='2'
<if test="categoryId != null "> and b.show_category = #{categoryId}</if>
)
<if test="isCourse != null "> and a.is_course = #{isCourse}</if>
<if test="search != null "> and a.name like concat('%', #{search}, '%')</if>
order by b.sort,a.sort
</select>
</mapper>

@ -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}
</select>
</mapper>

Loading…
Cancel
Save