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

@@ -3,16 +3,16 @@
<mapper namespace="com.cxx.home.dao.PasswordDao"> <mapper namespace="com.cxx.home.dao.PasswordDao">
<select id="query" resultType="com.cxx.home.dto.password.PasswordDto"> <select id="query" resultType="com.cxx.home.dto.password.PasswordDto">
SELECT SELECT
id AS id, id AS id,
title AS title, title AS title,
website AS website, website AS website,
username AS username, username AS username,
password AS password, password AS password,
category AS category, category AS category,
owner AS owner, owner AS owner,
remark AS remark remark AS remark
FROM FROM
password password
<where> <where>
<if test="query.category != null and query.category != ''"> <if test="query.category != null and query.category != ''">
category = #{query.category} category = #{query.category}

View File

@@ -1,36 +1,21 @@
<?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,
name AS name, name AS name,
purchase_date AS purchaseDate, purchase_date AS purchaseDate,
expiry_date AS expiryDate, expiry_date AS expiryDate,
@totalDay := (DATEDIFF(CURDATE(), purchase_date) + 1) AS totalDay, @totalDay := (DATEDIFF(CURDATE(), purchase_date) + 1) AS totalDay,
price AS price, price AS price,
ROUND(price / @totalDay, 2) AS averagePrice, ROUND(price / @totalDay, 2) AS averagePrice,
category AS category, category AS category,
purchaser AS purchaser, purchaser AS purchaser,
channel AS channel, channel AS channel,
image_url AS imageUrl image_url AS imageUrl
FROM FROM
product product
<where> <where>
<if test="query.category != null and query.category != ''"> <if test="query.category != null and query.category != ''">
category = #{query.category} category = #{query.category}
@@ -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>