feat:增加月经日期统计

This commit is contained in:
2025-10-30 15:00:00 +08:00
parent 67c72779ad
commit c8d2bd1df0
20 changed files with 213 additions and 104 deletions

View File

@@ -2,6 +2,7 @@ package com.cxx.home.controller;
import com.cxx.common.ReadView; import com.cxx.common.ReadView;
import com.cxx.common.WriteView; import com.cxx.common.WriteView;
import com.cxx.home.dto.period.MenstrualPeriodDto;
import com.cxx.home.dto.period.PeriodDayDto; import com.cxx.home.dto.period.PeriodDayDto;
import com.cxx.home.dto.period.PeriodSettingDto; import com.cxx.home.dto.period.PeriodSettingDto;
import com.cxx.home.service.PeriodService; import com.cxx.home.service.PeriodService;
@@ -39,6 +40,12 @@ public class PeriodController {
return periodService.getMenstruateFirstDate(month); return periodService.getMenstruateFirstDate(month);
} }
@Operation(summary = "获取月经周期天数")
@GetMapping("/menstruate/days")
public List<MenstrualPeriodDto> getMenstrualPeriod() {
return periodService.getMenstrualPeriod();
}
@Operation(summary = "查询月经设置") @Operation(summary = "查询月经设置")
@GetMapping("/setting") @GetMapping("/setting")
public @JsonView(ReadView.class) PeriodSettingDto queryPeriodSetting() { public @JsonView(ReadView.class) PeriodSettingDto queryPeriodSetting() {

View File

@@ -0,0 +1,18 @@
package com.cxx.home.converter;
import com.cxx.home.dto.journal.JournalDto;
import com.cxx.home.entity.Journal;
import org.mapstruct.Mapper;
import java.util.List;
@Mapper(componentModel = "spring")
public interface JournalConverter {
Journal toEntity(JournalDto dto);
List<Journal> toEntities(List<JournalDto> dto);
JournalDto toDto(Journal entities);
List<JournalDto> toDtos(List<Journal> entities);
}

View File

@@ -0,0 +1,18 @@
package com.cxx.home.converter;
import com.cxx.home.dto.kpi.KpiDto;
import com.cxx.home.entity.Kpi;
import org.mapstruct.Mapper;
import java.util.List;
@Mapper(componentModel = "spring")
public interface KpiConverter {
Kpi toEntity(KpiDto dto);
List<Kpi> toEntities(List<KpiDto> dto);
KpiDto toDto(Kpi entities);
List<KpiDto> toDtos(List<Kpi> entities);
}

View File

@@ -0,0 +1,18 @@
package com.cxx.home.converter;
import com.cxx.home.dto.product.ProductDto;
import com.cxx.home.entity.Product;
import org.mapstruct.Mapper;
import java.util.List;
@Mapper(componentModel = "spring")
public interface ProductConverter {
Product toEntity(ProductDto dto);
List<Product> toEntities(List<ProductDto> dto);
ProductDto toDto(Product entities);
List<ProductDto> toDtos(List<Product> entities);
}

View File

@@ -1,13 +0,0 @@
package com.cxx.home.dao;
import com.cxx.home.dto.kpi.KpiDto;
import com.cxx.home.vo.KpiQueryVo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface KpiDao {
List<KpiDto> queryKpi(@Param("query") KpiQueryVo queryVo);
}

View File

@@ -9,9 +9,5 @@ import java.util.List;
@Mapper @Mapper
public interface ProductDao { public interface ProductDao {
ProductDto queryProduct(@Param("id") Long id);
List<ProductDto> queryProductList(@Param("query") ProductQueryVo queryVo); List<ProductDto> queryProductList(@Param("query") ProductQueryVo queryVo);
List<String> queryProductCategory();
} }

View File

@@ -0,0 +1,13 @@
package com.cxx.home.dto.period;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.time.LocalDate;
@Data
@AllArgsConstructor
public class MenstrualPeriodDto {
private LocalDate startDate;
private LocalDate endDate;
}

View File

@@ -8,7 +8,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import java.util.Date; import java.time.LocalDate;
@Getter @Getter
@Setter @Setter
@@ -20,7 +20,7 @@ public class PeriodDayDto {
@Schema(description = "日期") @Schema(description = "日期")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date date; private LocalDate date;
@Schema(description = "是否吃药") @Schema(description = "是否吃药")
private Boolean isDrug; private Boolean isDrug;

View File

@@ -6,14 +6,14 @@ import com.cxx.framework.data.AbstractEntity;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import java.util.Date; import java.time.LocalDate;
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@TableName("period_day") @TableName("period_day")
public class PeriodDay extends AbstractEntity { public class PeriodDay extends AbstractEntity {
@TableField("date") @TableField("date")
private Date date; private LocalDate date;
@TableField("is_drug") @TableField("is_drug")
private Integer isDrug; private Integer isDrug;

View File

@@ -1,5 +1,6 @@
package com.cxx.home.service; package com.cxx.home.service;
import com.cxx.home.dto.period.MenstrualPeriodDto;
import com.cxx.home.dto.period.PeriodDayDto; import com.cxx.home.dto.period.PeriodDayDto;
import com.cxx.home.dto.period.PeriodSettingDto; import com.cxx.home.dto.period.PeriodSettingDto;
@@ -15,4 +16,6 @@ public interface PeriodService {
Boolean updatePeriodSetting(Long id, PeriodSettingDto periodSettingDto); Boolean updatePeriodSetting(Long id, PeriodSettingDto periodSettingDto);
PeriodSettingDto queryPeriodSetting(); PeriodSettingDto queryPeriodSetting();
List<MenstrualPeriodDto> getMenstrualPeriod();
} }

View File

@@ -184,7 +184,7 @@ public class FoodServiceImpl implements FoodService {
@Override @Override
public List<String> queryFoodName() { public List<String> queryFoodName() {
return foodRecipeMapper.selectList(null) return foodRecipeMapper.selectList(Wrappers.emptyWrapper())
.stream().map(FoodRecipe::getName).collect(Collectors.toList()); .stream().map(FoodRecipe::getName).collect(Collectors.toList());
} }

View File

@@ -1,6 +1,8 @@
package com.cxx.home.service.impl; package com.cxx.home.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cxx.framework.web.CustomException; import com.cxx.framework.web.CustomException;
import com.cxx.home.converter.JournalConverter;
import com.cxx.home.dao.JournalDao; import com.cxx.home.dao.JournalDao;
import com.cxx.home.dto.journal.JournalDto; import com.cxx.home.dto.journal.JournalDto;
import com.cxx.home.entity.Journal; import com.cxx.home.entity.Journal;
@@ -11,6 +13,7 @@ import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.util.List; import java.util.List;
@Service @Service
@@ -21,6 +24,9 @@ public class JournalServiceImpl implements JournalService {
@Resource @Resource
private JournalMapper journalMapper; private JournalMapper journalMapper;
@Resource
private JournalConverter journalConverter;
@Override @Override
public Boolean addJournal(JournalDto journalDto) { public Boolean addJournal(JournalDto journalDto) {
Journal journal = new Journal(); Journal journal = new Journal();
@@ -52,6 +58,14 @@ public class JournalServiceImpl implements JournalService {
@Override @Override
public List<JournalDto> queryJournal(JournalQueryVo queryVo) { public List<JournalDto> queryJournal(JournalQueryVo queryVo) {
return journalDao.queryJournal(queryVo); LocalDate startDate = LocalDate.parse(queryVo.getStartDate());
LocalDate endDate = LocalDate.parse(queryVo.getEndDate());
LambdaQueryWrapper<Journal> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.ge(Journal::getDate, startDate)
.le(Journal::getDate, endDate)
.orderByDesc(Journal::getDate);
return journalConverter.toDtos(journalMapper.selectList(queryWrapper));
} }
} }

View File

@@ -1,7 +1,8 @@
package com.cxx.home.service.impl; package com.cxx.home.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cxx.framework.web.CustomException; import com.cxx.framework.web.CustomException;
import com.cxx.home.dao.KpiDao; import com.cxx.home.converter.KpiConverter;
import com.cxx.home.dto.kpi.KpiDto; import com.cxx.home.dto.kpi.KpiDto;
import com.cxx.home.entity.Kpi; import com.cxx.home.entity.Kpi;
import com.cxx.home.mapper.KpiMapper; import com.cxx.home.mapper.KpiMapper;
@@ -11,16 +12,16 @@ import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.util.List; import java.util.List;
@Service @Service
public class KpiServiceImpl implements KpiService { public class KpiServiceImpl implements KpiService {
@Resource
private KpiDao kpiDao;
@Resource @Resource
private KpiMapper kpiMapper; private KpiMapper kpiMapper;
@Resource
private KpiConverter kpiConverter;
@Override @Override
public Boolean addKpi(KpiDto kpiDto) { public Boolean addKpi(KpiDto kpiDto) {
@@ -53,6 +54,14 @@ public class KpiServiceImpl implements KpiService {
@Override @Override
public List<KpiDto> queryKpi(KpiQueryVo queryVo) { public List<KpiDto> queryKpi(KpiQueryVo queryVo) {
return kpiDao.queryKpi(queryVo); LocalDate startDate = LocalDate.parse(queryVo.getStartDate());
LocalDate endDate = LocalDate.parse(queryVo.getEndDate());
LambdaQueryWrapper<Kpi> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.ge(Kpi::getDate, startDate)
.le(Kpi::getDate, endDate)
.orderByDesc(Kpi::getDate);
return kpiConverter.toDtos(kpiMapper.selectList(queryWrapper));
} }
} }

View File

@@ -1,12 +1,13 @@
package com.cxx.home.service.impl; package com.cxx.home.service.impl;
import cn.hutool.crypto.SecureUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cxx.framework.web.CustomException; import com.cxx.framework.web.CustomException;
import com.cxx.home.dao.PasswordDao; import com.cxx.home.dao.PasswordDao;
import com.cxx.home.dto.password.PasswordDto; import com.cxx.home.dto.password.PasswordDto;
import com.cxx.home.entity.Password; import com.cxx.home.entity.Password;
import com.cxx.home.mapper.PasswordMapper; import com.cxx.home.mapper.PasswordMapper;
import com.cxx.home.service.PasswordService; import com.cxx.home.service.PasswordService;
import com.cxx.home.util.CommonUtils;
import com.cxx.home.vo.PasswordQueryVo; import com.cxx.home.vo.PasswordQueryVo;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
@@ -14,6 +15,7 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
@Service @Service
public class PasswordServiceImpl implements PasswordService { public class PasswordServiceImpl implements PasswordService {
@@ -30,7 +32,7 @@ public class PasswordServiceImpl implements PasswordService {
public Boolean add(PasswordDto passwordDto) { public Boolean add(PasswordDto passwordDto) {
Password password = new Password(); Password password = new Password();
BeanUtils.copyProperties(passwordDto, password); BeanUtils.copyProperties(passwordDto, password);
password.setPassword(encryptPassword(passwordDto.getPassword())); password.setPassword(CommonUtils.encryptPassword(secretKey, passwordDto.getPassword()));
return passwordMapper.insert(password) == 1; return passwordMapper.insert(password) == 1;
} }
@@ -44,7 +46,7 @@ public class PasswordServiceImpl implements PasswordService {
Password password = new Password(); Password password = new Password();
BeanUtils.copyProperties(passwordDto, password); BeanUtils.copyProperties(passwordDto, password);
password.setId(id); password.setId(id);
password.setPassword(encryptPassword(passwordDto.getPassword())); password.setPassword(CommonUtils.encryptPassword(secretKey, passwordDto.getPassword()));
return passwordMapper.updateById(password) == 1; return passwordMapper.updateById(password) == 1;
} }
@@ -61,20 +63,15 @@ public class PasswordServiceImpl implements PasswordService {
public List<PasswordDto> query(PasswordQueryVo query) { public List<PasswordDto> query(PasswordQueryVo query) {
List<PasswordDto> passwordList = passwordDao.query(query); List<PasswordDto> passwordList = passwordDao.query(query);
passwordList.forEach(item -> item.setPassword(decryptStr(item.getPassword()))); passwordList.forEach(item -> item.setPassword(CommonUtils.decryptStr(secretKey, item.getPassword())));
return passwordList; return passwordList;
} }
@Override @Override
public List<String> queryCategory() { public List<String> queryCategory() {
return passwordDao.queryCategory(); LambdaQueryWrapper<Password> queryWrapper = new LambdaQueryWrapper<>();
} List<Object> categories = passwordMapper.selectObjs(queryWrapper.select(Password::getCategory));
private String encryptPassword(String password) { return categories.stream().map(Object::toString).distinct().collect(Collectors.toList());
return SecureUtil.aes(secretKey.getBytes()).encryptBase64(password);
}
private String decryptStr(String password) {
return SecureUtil.aes(secretKey.getBytes()).decryptStr(password);
} }
} }

View File

@@ -1,6 +1,8 @@
package com.cxx.home.service.impl; package com.cxx.home.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cxx.home.dao.PeriodDao; import com.cxx.home.dao.PeriodDao;
import com.cxx.home.dto.period.MenstrualPeriodDto;
import com.cxx.home.dto.period.PeriodDayDto; import com.cxx.home.dto.period.PeriodDayDto;
import com.cxx.home.dto.period.PeriodSettingDto; import com.cxx.home.dto.period.PeriodSettingDto;
import com.cxx.home.entity.PeriodDay; import com.cxx.home.entity.PeriodDay;
@@ -13,6 +15,9 @@ import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
@Service @Service
@@ -89,16 +94,55 @@ public class PeriodServiceImpl implements PeriodService {
List<PeriodSetting> periodSettingList = periodSettingMapper.selectList(null); List<PeriodSetting> periodSettingList = periodSettingMapper.selectList(null);
PeriodSettingDto periodSettingDto = new PeriodSettingDto(); PeriodSettingDto periodSettingDto = new PeriodSettingDto();
if (periodSettingList.size() > 0) { if (periodSettingList.isEmpty()) {
BeanUtils.copyProperties(periodSettingList.get(0), periodSettingDto);
periodSettingDto.setIsCalculate(periodSettingList.get(0).getIsCalculate() == 1);
} else {
periodSettingDto.setId(0L); periodSettingDto.setId(0L);
periodSettingDto.setCycleLength(0); periodSettingDto.setCycleLength(0);
periodSettingDto.setDuration(0); periodSettingDto.setDuration(0);
periodSettingDto.setIsCalculate(false); periodSettingDto.setIsCalculate(false);
} else {
BeanUtils.copyProperties(periodSettingList.get(0), periodSettingDto);
periodSettingDto.setIsCalculate(periodSettingList.get(0).getIsCalculate() == 1);
} }
return periodSettingDto; return periodSettingDto;
} }
@Override
public List<MenstrualPeriodDto> getMenstrualPeriod() {
LambdaQueryWrapper<PeriodDay> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(PeriodDay::getIsMenstruate, 1).select(PeriodDay::getDate).orderByAsc(PeriodDay::getDate);
List<LocalDate> dates = periodDayMapper.selectList(queryWrapper)
.stream().map(PeriodDay::getDate).toList();
if (dates.isEmpty()) {
return Collections.emptyList();
}
List<MenstrualPeriodDto> result = new ArrayList<>();
LocalDate start = dates.get(0);
LocalDate end = dates.get(0);
for (int i = 1; i < dates.size(); i++) {
LocalDate current = dates.get(i);
// 如果当前日期与前一天连续,继续当前周期
if (current.equals(end.plusDays(1))) {
end = current;
} else {
// 日期不连续,保存当前周期,开始新周期
result.add(new MenstrualPeriodDto(start, end));
// 重新开始新的周期
start = current;
end = current;
}
}
// 添加最后一个周期
result.add(new MenstrualPeriodDto(start, end));
Collections.reverse(result);
return result;
}
} }

View File

@@ -2,6 +2,7 @@ package com.cxx.home.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cxx.framework.web.CustomException; import com.cxx.framework.web.CustomException;
import com.cxx.home.converter.ProductConverter;
import com.cxx.home.dao.ProductDao; import com.cxx.home.dao.ProductDao;
import com.cxx.home.dto.product.ProductDto; import com.cxx.home.dto.product.ProductDto;
import com.cxx.home.entity.*; import com.cxx.home.entity.*;
@@ -14,6 +15,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
@Service @Service
public class ProductServiceImpl implements ProductService { public class ProductServiceImpl implements ProductService {
@@ -23,6 +25,9 @@ public class ProductServiceImpl implements ProductService {
@Resource @Resource
private ProductMapper productMapper; private ProductMapper productMapper;
@Resource
private ProductConverter productConverter;
@Override @Override
@Transactional @Transactional
public Boolean addProduct(ProductDto productDto) { public Boolean addProduct(ProductDto productDto) {
@@ -61,7 +66,7 @@ public class ProductServiceImpl implements ProductService {
throw new CustomException("该商品不存在"); throw new CustomException("该商品不存在");
} }
return productDao.queryProduct(id); return productConverter.toDto(productMapper.selectById(id));
} }
@Override @Override
@@ -71,6 +76,9 @@ public class ProductServiceImpl implements ProductService {
@Override @Override
public List<String> queryProductCategory() { public List<String> queryProductCategory() {
return productDao.queryProductCategory(); LambdaQueryWrapper<Product> queryWrapper = new LambdaQueryWrapper<>();
List<Object> categories = productMapper.selectObjs(queryWrapper.select(Product::getCategory));
return categories.stream().map(Object::toString).distinct().collect(Collectors.toList());
} }
} }

View File

@@ -0,0 +1,13 @@
package com.cxx.home.util;
import cn.hutool.crypto.SecureUtil;
public class CommonUtils {
public static String encryptPassword(String secretKey, String password) {
return SecureUtil.aes(secretKey.getBytes()).encryptBase64(password);
}
public static String decryptStr(String secretKey, String password) {
return SecureUtil.aes(secretKey.getBytes()).decryptStr(password);
}
}

View File

@@ -1,15 +0,0 @@
<?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.cxx.home.dao.KpiDao">
<select id="queryKpi" resultType="com.cxx.home.dto.kpi.KpiDto">
SELECT id AS id,
date AS date,
patient_name AS patientName,
project AS project,
price AS price
FROM kpi AS a
WHERE a.date <![CDATA[ >=]]> STR_TO_DATE(#{query.startDate}, '%Y-%m-%d')
AND a.date <![CDATA[ <=]]> STR_TO_DATE(#{query.endDate}, '%Y-%m-%d')
ORDER BY a.date DESC
</select>
</mapper>

View File

@@ -1,21 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?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"> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cxx.home.dao.ProductDao"> <mapper namespace="com.cxx.home.dao.ProductDao">
<select id="queryProduct" resultType="com.cxx.home.dto.product.ProductDto">
SELECT id AS id,
name AS name,
purchase_date AS purchaseDate,
expiry_date AS expiryDate,
price AS price,
category AS category,
purchaser AS purchaser,
channel AS channel,
image_url As imageUrl
FROM product
WHERE id = #{id}
ORDER BY purchase_date DESC
</select>
<select id="queryProductList" resultType="com.cxx.home.dto.product.ProductDto"> <select id="queryProductList" resultType="com.cxx.home.dto.product.ProductDto">
SELECT SELECT
id AS id, id AS id,
@@ -46,10 +31,4 @@
ORDER BY averagePrice ORDER BY averagePrice
</if> </if>
</select> </select>
<select id="queryProductCategory" resultType="string">
SELECT DISTINCT category
FROM product
WHERE category IS NOT NULL AND category != '';
</select>
</mapper> </mapper>