打卡统计

master
382696293@qq.com 2 years ago
parent 07dc468c11
commit b8a8d1962a

@ -0,0 +1,116 @@
package com.flossom.common.core.domain.entity;
import java.math.BigDecimal;
import com.flossom.common.core.annotation.Excel;
import com.flossom.common.core.web.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
/**
* wx_clock_statistics
*
* @author flossom
* @date 2024-01-30
*/
public class WxClockStatistics extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* $column.columnComment
*/
private Long id;
/**
*
*/
@Excel(name = "年")
private Integer year;
/**
*
*/
@Excel(name = "月份")
private Integer month;
/**
*
*/
@Excel(name = "微信用户")
private Long userId;
/**
*
*/
@Excel(name = "打卡天数")
private Integer clockNum;
/**
*
*/
@Excel(name = "超越多少比例用户")
private BigDecimal percentage;
/**
* 0 1
*/
@Excel(name = "状态", readConverterExp = "0=正常,1=停用")
private Long status;
public void setId(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public void setMonth(Integer month) {
this.month = month;
}
public Integer getMonth() {
return month;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public Long getUserId() {
return userId;
}
public void setClockNum(Integer clockNum) {
this.clockNum = clockNum;
}
public Integer getClockNum() {
return clockNum;
}
public void setPercentage(BigDecimal percentage) {
this.percentage = percentage;
}
public BigDecimal getPercentage() {
return percentage;
}
public void setStatus(Long status) {
this.status = status;
}
public Long getStatus() {
return status;
}
public Integer getYear() {
return year;
}
public void setYear(Integer year) {
this.year = year;
}
}

@ -0,0 +1,65 @@
package com.flossom.common.core.mapper;
import com.flossom.common.core.domain.entity.WxClockStatistics;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* Mapper
*
* @author flossom
* @date 2024-01-30
*/
public interface WxClockStatisticsMapper {
/**
*
*
* @param id
* @return
*/
public WxClockStatistics selectWxClockStatisticsById(Long id);
/**
*
*
* @param wxClockStatistics
* @return
*/
public List<WxClockStatistics> selectWxClockStatisticsList(WxClockStatistics wxClockStatistics);
/**
*
*
* @param wxClockStatistics
* @return
*/
public int insertWxClockStatistics(WxClockStatistics wxClockStatistics);
/**
*
*
* @param wxClockStatistics
* @return
*/
public int updateWxClockStatistics(WxClockStatistics wxClockStatistics);
/**
*
*
* @param id
* @return
*/
public int deleteWxClockStatisticsById(Long id);
/**
*
*
* @param ids
* @return
*/
public int deleteWxClockStatisticsByIds(Long[] ids);
List<WxClockStatistics> selectByUserIdAndYearMonth(@Param("userIdList") List<Long> userIdList, @Param("year") int year, @Param("month") int month);
}

@ -89,4 +89,7 @@ public interface WxUserMemberMapper {
List<WxUserMemberRet> selectWxUserMemberRetByIdList(@Param("userIdList") List<Integer> userIdList);
List<WxUserMemberRet> selectWxUserMemberRetListByVm(WxUserMemberVm wxUserMemberVm);
Integer selectWxUserTotal();
}

@ -15,7 +15,7 @@ public class PageUtils extends PageHelper
/**
*
*/
public static void startPage()
public static Integer startPage()
{
PageDomain pageDomain = TableSupport.buildPageRequest();
Integer pageNum = pageDomain.getPageNum();
@ -23,6 +23,7 @@ public class PageUtils extends PageHelper
String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
Boolean reasonable = pageDomain.getReasonable();
PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);
return pageNum;
}
/**

@ -44,9 +44,9 @@ public class BaseController
/**
*
*/
protected void startPage()
protected Integer startPage()
{
PageUtils.startPage();
return PageUtils.startPage();
}
/**

@ -13,6 +13,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="status" column="status" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
</resultMap>
<resultMap type="WxClockLogRet" id="WxClockLogRetResult">
@ -23,10 +25,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="clockContent" column="clock_content" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
</resultMap>
<sql id="selectWxClockLogVo">
select id, user_id, instrument_id, instrument_name, clock_content, status, create_by, create_time from wx_clock_log
select id, user_id, instrument_id, instrument_name, clock_content, status, create_by, create_time, update_by, update_time from wx_clock_log
</sql>
<select id="selectCountByUserId" parameterType="WxClockLog" resultType="Integer">
@ -92,6 +96,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="status != null">status,</if>
<if test="createBy != null">create_by,</if>
<if test="createTime != null">create_time,</if>
<if test="updateBy != null">update_by,</if>
<if test="updateTime != null">update_time,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="userId != null">#{userId},</if>
@ -101,6 +107,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="status != null">#{status},</if>
<if test="createBy != null">#{createBy},</if>
<if test="createTime != null">#{createTime},</if>
<if test="updateBy != null">#{updateBy},</if>
<if test="updateTime != null">#{updateTime},</if>
</trim>
</insert>
@ -114,6 +122,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="status != null">status = #{status},</if>
<if test="createBy != null">create_by = #{createBy},</if>
<if test="createTime != null">create_time = #{createTime},</if>
<if test="updateBy != null">update_by = #{updateBy},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
</trim>
where id = #{id}
</update>

@ -0,0 +1,112 @@
<?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.flossom.common.core.mapper.WxClockStatisticsMapper">
<resultMap type="WxClockStatistics" id="WxClockStatisticsResult">
<result property="id" column="id" />
<result property="year" column="year" />
<result property="month" column="month" />
<result property="userId" column="user_id" />
<result property="clockNum" column="clock_num" />
<result property="percentage" column="percentage" />
<result property="status" column="status" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
</resultMap>
<sql id="selectWxClockStatisticsVo">
select id, `year`, `month`, user_id, clock_num, percentage, status, create_by, create_time, update_by, update_time from wx_clock_statistics
</sql>
<select id="selectWxClockStatisticsList" parameterType="WxClockStatistics" resultMap="WxClockStatisticsResult">
<include refid="selectWxClockStatisticsVo"/>
<where>
<if test="year != null "> and `year` = #{year}</if>
<if test="month != null "> and `month` = #{month}</if>
<if test="userId != null "> and user_id = #{userId}</if>
<if test="clockNum != null "> and clock_num = #{clockNum}</if>
<if test="percentage != null "> and percentage = #{percentage}</if>
<if test="status != null "> and status = #{status}</if>
</where>
</select>
<select id="selectWxClockStatisticsById" parameterType="Long" resultMap="WxClockStatisticsResult">
<include refid="selectWxClockStatisticsVo"/>
where id = #{id}
</select>
<select id="selectByUserIdAndYearMonth" resultMap="WxClockStatisticsResult">
<include refid="selectWxClockStatisticsVo"/>
<where>
`year` = #{year} and `month` = #{month}
<if test="userIdList != null and userIdList.size > 0">
and user_id in
<foreach item="userId" collection="userIdList" open="(" separator="," close=")">
#{userId}
</foreach>
</if>
</where>
</select>
<insert id="insertWxClockStatistics" parameterType="WxClockStatistics" useGeneratedKeys="true" keyProperty="id">
insert into wx_clock_statistics
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="year != null">`year`,</if>
<if test="month != null">`month`,</if>
<if test="userId != null">user_id,</if>
<if test="clockNum != null">clock_num,</if>
<if test="percentage != null">percentage,</if>
<if test="status != null">status,</if>
<if test="createBy != null">create_by,</if>
<if test="createTime != null">create_time,</if>
<if test="updateBy != null">update_by,</if>
<if test="updateTime != null">update_time,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="year != null">#{year},</if>
<if test="month != null">#{month},</if>
<if test="userId != null">#{userId},</if>
<if test="clockNum != null">#{clockNum},</if>
<if test="percentage != null">#{percentage},</if>
<if test="status != null">#{status},</if>
<if test="createBy != null">#{createBy},</if>
<if test="createTime != null">#{createTime},</if>
<if test="updateBy != null">#{updateBy},</if>
<if test="updateTime != null">#{updateTime},</if>
</trim>
</insert>
<update id="updateWxClockStatistics" parameterType="WxClockStatistics">
update wx_clock_statistics
<trim prefix="SET" suffixOverrides=",">
<if test="year != null">`year` = #{year},</if>
<if test="month != null">`month` = #{month},</if>
<if test="userId != null">user_id = #{userId},</if>
<if test="clockNum != null">clock_num = #{clockNum},</if>
<if test="percentage != null">percentage = #{percentage},</if>
<if test="status != null">status = #{status},</if>
<if test="createBy != null">create_by = #{createBy},</if>
<if test="createTime != null">create_time = #{createTime},</if>
<if test="updateBy != null">update_by = #{updateBy},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
</trim>
where id = #{id}
</update>
<delete id="deleteWxClockStatisticsById" parameterType="Long">
delete from wx_clock_statistics where id = #{id}
</delete>
<delete id="deleteWxClockStatisticsByIds" parameterType="String">
delete from wx_clock_statistics where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
</mapper>

@ -341,6 +341,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
SELECT count(1) as count FROM `wx_user_member` WHERE devices_num > 0
</select>
<select id="selectWxUserTotal" resultType="integer">
SELECT count(1) as count FROM `wx_user_member` WHERE status = 0 and user_type = 1
</select>
<select id="selectWxUserMemberIdList" resultType="java.lang.Integer">
SELECT id FROM `wx_user_member`
</select>

@ -3,8 +3,7 @@ package com.flossom.miniProgram.controller;
import com.flossom.common.core.constant.Constants;
import com.flossom.common.core.domain.R;
import com.flossom.common.core.domain.SysFile;
import com.flossom.common.core.domain.entity.WxClockLog;
import com.flossom.common.core.domain.entity.WxNursingLog;
import com.flossom.common.core.domain.entity.WxClockStatistics;
import com.flossom.common.core.domain.req.WxClockLogReq;
import com.flossom.common.core.domain.ret.WxClockLogRet;
import com.flossom.common.core.exception.ServiceException;
@ -126,4 +125,27 @@ public class WxClockLogController extends BaseController {
}
/**
*
*/
@GetMapping("/clockStatistics")
public TableDataInfo clockStatistics(WxClockStatistics wxClockStatistics) {
Integer pageNum = startPage();
List<WxClockStatistics> list = wxClockLogService.clockStatistics(wxClockStatistics, pageNum);
return getDataTable(list);
}
/**
* TODO system
*
* redis
*/
@GetMapping("/clockStatisticsTimedTask")
public void clockStatisticsTimedTask(@RequestParam(value = "userIdList", required = false) List<Long> userIdList,
@RequestParam(value = "year", required = false) Integer year,
@RequestParam(value = "month", required = false) Integer month) {
wxClockLogService.clockStatisticsTimedTask(userIdList, year, month);
}
}

@ -1,6 +1,7 @@
package com.flossom.miniProgram.service;
import com.flossom.common.core.domain.entity.WxClockLog;
import com.flossom.common.core.domain.entity.WxClockStatistics;
import com.flossom.common.core.domain.req.WxClockLogReq;
import com.flossom.common.core.domain.ret.WxClockLogRet;
@ -16,4 +17,7 @@ public interface IWxClockLogService {
List<WxClockLogRet> selectWxClockLogList();
List<WxClockStatistics> clockStatistics(WxClockStatistics wxClockStatistics, Integer pageNum);
void clockStatisticsTimedTask(List<Long> userIdList, Integer year, Integer month);
}

@ -4,27 +4,31 @@ import com.flossom.common.core.domain.entity.*;
import com.flossom.common.core.domain.req.WxClockLogReq;
import com.flossom.common.core.domain.ret.WxClockLogRet;
import com.flossom.common.core.enums.Status;
import com.flossom.common.core.mapper.WxClockImgMapper;
import com.flossom.common.core.mapper.WxClockInstrumentLogMapper;
import com.flossom.common.core.mapper.WxClockLogMapper;
import com.flossom.common.core.mapper.WxInstrumentMapper;
import com.flossom.common.core.mapper.*;
import com.flossom.common.core.utils.DateUtils;
import com.flossom.common.security.utils.SecurityUtils;
import com.flossom.miniProgram.service.IWxClockLogService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Service
@RefreshScope
public class WxClockLogServiceImpl implements IWxClockLogService {
@Autowired
@ -39,6 +43,18 @@ public class WxClockLogServiceImpl implements IWxClockLogService {
@Autowired
private WxInstrumentMapper wxInstrumentMapper;
@Autowired
private WxClockStatisticsMapper wxClockStatisticsMapper;
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private WxUserMemberMapper wxUserMemberMapper;
@Value("${rank.clock.redisKey}")
private String CLOCK_RANK_REDIS_KEY;
@Override
@Transactional
@ -86,10 +102,45 @@ public class WxClockLogServiceImpl implements IWxClockLogService {
.collect(Collectors.joining(","));
wxClockLog.setInstrumentName(instrumentNameList);
}
if (wxClockLog.getId() == null) {
wxClockLogMapper.insertWxClockLog(wxClockLog);
} else {
if (wxClockLog.getId() != null) {
wxClockLog.setUpdateBy(SecurityUtils.getLoginUser().getWxUserMember().getNickname());
wxClockLog.setUpdateTime(DateUtils.getNowDate());
wxClockLogMapper.updateWxClockLog(wxClockLog);
} else {
// 当天第一次打卡
wxClockLogMapper.insertWxClockLog(wxClockLog);
/* 保存redis构建排名 */
String redisKey = CLOCK_RANK_REDIS_KEY + LocalDate.now().getYear() + LocalDate.now().getMonthValue();
redisTemplate.opsForZSet().incrementScore(redisKey, wxUserMember.getId(), 1);
// 保存打卡记录,不计算比例
List<Long> userIdList = Arrays.asList(wxUserMember.getId());
List<WxClockStatistics> wxClockStatisticsList = wxClockStatisticsMapper.selectByUserIdAndYearMonth(userIdList, LocalDate.now().getYear(), LocalDate.now().getMonthValue());
if (wxClockStatisticsList != null && wxClockStatisticsList.size() == 0) {
// 数据库不存在则新增,也就是当月第一次打卡
WxClockStatistics save = new WxClockStatistics();
save.setYear(LocalDate.now().getYear());
save.setMonth(LocalDate.now().getMonthValue());
save.setUserId(wxUserMember.getId());
save.setClockNum(1);
save.setPercentage(new BigDecimal(0));
save.setStatus(Status.OK.getCode().longValue());
save.setCreateBy(wxUserMember.getNickname());
save.setCreateTime(DateUtils.getNowDate());
save.setUpdateBy(wxUserMember.getNickname());
save.setUpdateTime(DateUtils.getNowDate());
wxClockStatisticsMapper.insertWxClockStatistics(save);
} else {
// 数据库存在则更新打卡次数,也就是当月第二次以上打卡
WxClockStatistics wxClockStatistics = wxClockStatisticsList.get(0);
WxClockStatistics update = new WxClockStatistics();
update.setId(wxClockStatistics.getId());
update.setClockNum(wxClockStatistics.getClockNum() + 1);
update.setUpdateBy(wxUserMember.getNickname());
update.setUpdateTime(DateUtils.getNowDate());
wxClockStatisticsMapper.updateWxClockStatistics(update);
}
}
/* 先删除当天的打卡图片,保存打卡图片 */
@ -142,6 +193,8 @@ public class WxClockLogServiceImpl implements IWxClockLogService {
updateClockLog.setInstrumentName(newWxClockLog.getInstrumentName() + "," + instrument.getName());
}
updateClockLog.setId(newWxClockLog.getId());
updateClockLog.setUpdateBy(SecurityUtils.getLoginUser().getWxUserMember().getNickname());
updateClockLog.setUpdateTime(DateUtils.getNowDate());
wxClockLogMapper.updateWxClockLog(updateClockLog);
}
}
@ -182,7 +235,7 @@ public class WxClockLogServiceImpl implements IWxClockLogService {
WxClockImg wxClockImg = new WxClockImg();
wxClockImg.setUserClockId(wxClockLogRet.getId());
List<WxClockImg> wxClockImgs = wxClockImgMapper.selectWxClockImgList(wxClockImg);
if (wxClockImgs!=null && wxClockImgs.size()>0) {
if (wxClockImgs != null && wxClockImgs.size() > 0) {
List<String> collect = wxClockImgs.stream().map(WxClockImg::getClockImg).collect(Collectors.toList());
wxClockLogRet.setClockImg(collect);
}
@ -190,4 +243,62 @@ public class WxClockLogServiceImpl implements IWxClockLogService {
}
return list;
}
@Override
public List<WxClockStatistics> clockStatistics(WxClockStatistics wxClockStatistics, Integer pageNum) {
// 获取历史统计信息,数据在数据库
List<WxClockStatistics> list = wxClockStatisticsMapper.selectWxClockStatisticsList(wxClockStatistics);
if (list != null && list.size() > 0 && pageNum == 1) {
/* 当前月则需要从redis中获取排名计算比例 */
WxClockStatistics isCurrent = list.get(0);
// 获取排名
String redisKey = CLOCK_RANK_REDIS_KEY + LocalDate.now().getYear() + LocalDate.now().getMonthValue();
Long rank = redisTemplate.opsForZSet().reverseRank(redisKey, SecurityUtils.getLoginUser().getWxUserMember().getId());
if (rank != null) {
// 计算超越百分比
Integer wxUserTotal = wxUserMemberMapper.selectWxUserTotal();
BigDecimal percentage = new BigDecimal(wxUserTotal - (rank + 1))
.divide(new BigDecimal(wxUserTotal), 3, RoundingMode.HALF_UP);
isCurrent.setPercentage(percentage);
}
}
return list;
}
@Override
public void clockStatisticsTimedTask(List<Long> userIdList, Integer year, Integer month) {
if (year == null || month == null) {
LocalDate localDate = LocalDate.now().minusMonths(1);
year = localDate.getYear();
month = localDate.getMonthValue();
}
List<WxClockStatistics> wxClockStatisticsList = wxClockStatisticsMapper.selectByUserIdAndYearMonth(userIdList, year, month);
if (wxClockStatisticsList != null && wxClockStatisticsList.size() > 0) {
String redisKey = CLOCK_RANK_REDIS_KEY + year + month;
for (WxClockStatistics wxClockStatistics : wxClockStatisticsList) {
redisTemplate.opsForZSet().add(redisKey, wxClockStatistics.getUserId(), wxClockStatistics.getClockNum());
}
}
if (wxClockStatisticsList != null && wxClockStatisticsList.size() > 0) {
String redisKey = CLOCK_RANK_REDIS_KEY + year + month;
WxClockStatistics update;
for (WxClockStatistics wxClockStatistics : wxClockStatisticsList) {
// 获取排名
Long rank = redisTemplate.opsForZSet().reverseRank(redisKey, wxClockStatistics.getUserId());
// 计算超越百分比
Integer wxUserTotal = wxUserMemberMapper.selectWxUserTotal();
BigDecimal percentage = new BigDecimal(wxUserTotal - (rank + 1))
.divide(new BigDecimal(wxUserTotal), 3, RoundingMode.HALF_UP);
update = new WxClockStatistics();
update.setPercentage(percentage);
update.setId(wxClockStatistics.getId());
// update.setUpdateBy(SecurityUtils.getUsername());
update.setUpdateTime(DateUtils.getNowDate());
wxClockStatisticsMapper.updateWxClockStatistics(update);
}
}
redisTemplate.delete(CLOCK_RANK_REDIS_KEY + year + month);
}
}

Loading…
Cancel
Save