Merge remote-tracking branch 'origin/test' into test

This commit is contained in:
张松
2024-12-26 14:11:32 +08:00
10 changed files with 457 additions and 20 deletions

View File

@@ -0,0 +1,142 @@
package com.sqx.common.utils;
import cn.hutool.core.date.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* 数据出现次数
*/
@Component
public class DataLimitUtil {
private static final String ACCESS_COUNT_KEY_PREFIX = "sys:data:";
private static RedisUtils redisUtils;
private static final int DEFAULT_ACCESS_COUNT = 5;
private static final String DATE_TIME_FORMAT = "month";
@Autowired
public void setRedisUtils(RedisUtils redisUtils) {
DataLimitUtil.redisUtils = redisUtils;
}
/**
* 默认 当月5次
* @param key 名称 sys:data:名称
* @return
*/
public static boolean isAccessAllowed(String key) {
String redisKey = generateRedisKey(key);
Object countObj = redisUtils.get(redisKey);
if (countObj == null) {
// 根据不同时间周期设置过期时间并初始化访问次数为1
long expireAt = calculateExpireAt(DATE_TIME_FORMAT);
redisUtils.set(redisKey, 1, expireAt);
return true;
}
if ((int) countObj < DEFAULT_ACCESS_COUNT) {
// 访问次数未达上限次数加1
redisUtils.incr(redisKey);
return true;
}
return false;
}
/**
* 默认月 month/月/自然月
* @param key 名称 sys:data:名称
* @param count 次数限制
* @return
*/
public static boolean isAccessAllowed(String key, Integer count) {
String redisKey = generateRedisKey(key);
Object countObj = redisUtils.get(redisKey);
if (countObj == null) {
// 根据不同时间周期设置过期时间并初始化访问次数为1
long expireAt = calculateExpireAt(DATE_TIME_FORMAT);
redisUtils.set(redisKey, 1, expireAt);
return true;
}
if ((int) countObj < count) {
// 访问次数未达上限次数加1
redisUtils.incr(redisKey);
return true;
}
return false;
}
/**
* 默认 5次
* @param key 名称 sys:data:名称
* @param timeFormat day/天/自然天 week/周/本周日 month/月/自然月 year/年/自然年
* @return
*/
public static boolean isAccessAllowed(String key, String timeFormat) {
String redisKey = generateRedisKey(key);
Object countObj = redisUtils.get(redisKey);
if (countObj == null) {
// 根据不同时间周期设置过期时间并初始化访问次数为1
long expireAt = calculateExpireAt(timeFormat);
redisUtils.set(redisKey, 1, expireAt);
return true;
}
if ((int) countObj < DEFAULT_ACCESS_COUNT) {
// 访问次数未达上限次数加1
redisUtils.incr(redisKey);
return true;
}
return false;
}
/**
* @param key 名称 sys:data:名称
* @param count 次数限制
* @param timeFormat day/天/自然天 week/周/本周日 month/月/自然月 year/年/自然年
* @return
*/
public static boolean isAccessAllowed(String key, Integer count, String timeFormat) {
String redisKey = generateRedisKey(key);
Object countObj = redisUtils.get(redisKey);
if (countObj == null) {
// 根据不同时间周期设置过期时间并初始化访问次数为1
long expireAt = calculateExpireAt(timeFormat);
redisUtils.set(redisKey, 1, expireAt);
return true;
}
if (Integer.parseInt(countObj.toString()) < count) {
// 访问次数未达上限次数加1
redisUtils.incr(redisKey);
return true;
}
return false;
}
private static String generateRedisKey(String key) {
return ACCESS_COUNT_KEY_PREFIX + key;
}
private static long calculateExpireAt(String timePeriod) {
Date now = DateUtil.beginOfDay(DateUtil.date());
Date expireDate = null;
if ("day".equals(timePeriod)) {
expireDate = DateUtil.endOfDay(now);
} else if ("week".equals(timePeriod)) {
expireDate = DateUtil.endOfWeek(now);
} else if ("month".equals(timePeriod)) {
expireDate = DateUtil.endOfMonth(now);
} else if ("year".equals(timePeriod)) {
expireDate = DateUtil.endOfYear(now);
}
long endTimeStamp = DateUtil.endOfDay(expireDate).getTime() / 1000L;
long currentTimeStamp = DateUtil.currentSeconds();
return endTimeStamp - currentTimeStamp;
}
}

View File

@@ -4,7 +4,9 @@ package com.sqx.modules.app.controller.app;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.sqx.common.annotation.Debounce;
import com.sqx.common.utils.ApiAccessLimitUtil;
import com.sqx.common.utils.DataLimitUtil;
import com.sqx.common.utils.Result;
import com.sqx.modules.app.annotation.Login;
import com.sqx.modules.app.annotation.LoginUser;
@@ -73,10 +75,14 @@ public class AppController {
@RequestMapping(value = "/updateUser", method = RequestMethod.POST)
@ApiOperation("用户修改个人信息")
@ResponseBody
@Debounce(interval = 3000, value = "#userId")
public Result updateUserImageUrl(@RequestAttribute("userId") Long userId, String zhiFuBao, String zhiFuBaoName) {
if(StrUtil.isEmpty(zhiFuBao) || StrUtil.isEmpty(zhiFuBaoName)){
if (StrUtil.isEmpty(zhiFuBao) || StrUtil.isEmpty(zhiFuBaoName)) {
return Result.error("支付宝账户及姓名不能为空!");
}
if (!DataLimitUtil.isAccessAllowed(zhiFuBao+zhiFuBaoName, 1, "month")) {
return Result.error("修改失败,相同支付宝账号每月仅可绑定一次");
}
int count = userService.count(new QueryWrapper<UserEntity>()
.ne("user_id", userId)
.eq("zhi_fu_bao_name", zhiFuBaoName)

View File

@@ -159,11 +159,7 @@ public class InviteServiceImpl extends ServiceImpl<InviteDao, Invite> implements
// 金币
int money = Integer.parseInt(commonInfoService.findOne(911).getValue());
if (money > 0) {
UpdateWrapper<UserMoney> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("user_id", userEntity.getUserId())
.setSql("money = money + " + money);
userMoneyService.update(updateWrapper);
userMoneyService.updateMoney(1, userEntity.getUserId(), money);
UserMoneyDetails userMoneyDetails = new UserMoneyDetails();
userMoneyDetails.setUserId(userEntity.getUserId());
userMoneyDetails.setType(1);
@@ -316,7 +312,7 @@ public class InviteServiceImpl extends ServiceImpl<InviteDao, Invite> implements
BigDecimal rateMoney = sysUserEntity.getQdRate();
BigDecimal sumMoney = rateMoney.subtract(oneMoney);
sumMoney = sumMoney.subtract(twoMoney);
if (sumMoney.compareTo(BigDecimal.ZERO)<=0) {
if (sumMoney.compareTo(BigDecimal.ZERO) <= 0) {
return result;
}
userMoneyService.updateSysAmount(1, sysUserEntity.getUserId(), sumMoney.doubleValue());

View File

@@ -0,0 +1,47 @@
package com.sqx.modules.job.task;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.sqx.modules.app.service.UserMoneyDetailsService;
import com.sqx.modules.app.service.UserMoneyService;
import com.sqx.modules.pay.dao.CashOutDao;
import com.sqx.modules.pay.entity.CashOut;
import com.sqx.modules.pay.wuyou.BaseResp;
import com.sqx.modules.pay.wuyou.WuyouPay;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
@Component("TempCashOutTask")
public class TempCashOutTask implements ITask {
@Resource
private CashOutDao cashOutDao;
@Resource
private UserMoneyService userMoneyService;
@Resource
private UserMoneyDetailsService userMoneyDetailsService;
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void run(String params) {
logger.info("提现开始");
List<CashOut> cashOuts = cashOutDao.selectTemp();
for (CashOut cashOut : cashOuts) {
BaseResp baseResp = WuyouPay.queryExtractOrder(cashOut.getOrderNumber(), cashOut.getMoney());
logger.info("baseResp{} ", JSONUtil.toJsonStr(baseResp));
if (baseResp.getStatus() != null && (baseResp.getStatus().equals(2) || baseResp.getStatus().equals(10000))){
logger.info("success{} ", cashOut.getOrderNumber());
cashOut.setState(1);
cashOut.setOutAt(DateUtil.now());
cashOut.setRefund(null);
cashOutDao.updateById(cashOut);
}
}
logger.info("提现结束");
}
}

View File

@@ -0,0 +1,213 @@
package com.sqx.modules.job.task;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.sqx.common.utils.DateUtils;
import com.sqx.modules.app.entity.UserEntity;
import com.sqx.modules.app.entity.UserMoneyDetails;
import com.sqx.modules.app.service.UserMoneyDetailsService;
import com.sqx.modules.app.service.UserMoneyService;
import com.sqx.modules.app.service.UserService;
import com.sqx.modules.common.service.CommonInfoService;
import com.sqx.modules.complet.entity.CompletAward;
import com.sqx.modules.complet.service.CompletAwardService;
import com.sqx.modules.invite.dao.InviteDao;
import com.sqx.modules.invite.entity.Invite;
import com.sqx.modules.invite.service.InviteService;
import com.sqx.modules.orders.dao.OrdersDao;
import com.sqx.modules.orders.entity.Orders;
import com.sqx.modules.orders.service.OrdersService;
import com.sqx.modules.pay.dao.PayDetailsDao;
import com.sqx.modules.pay.entity.PayDetails;
import com.sqx.modules.pay.wuyou.BaseResp;
import com.sqx.modules.pay.wuyou.WuyouPay;
import com.sqx.modules.sys.entity.SysUserEntity;
import com.sqx.modules.sys.service.SysUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
@Component("TempOrdersTask")
public class TempOrdersTask implements ITask {
@Resource
private OrdersDao ordersDao;
@Resource
private PayDetailsDao payDetailsDao;
@Resource
private OrdersService ordersService;
@Resource
private UserMoneyDetailsService userMoneyDetailsService;
@Resource
private UserService userService;
@Resource
private InviteService inviteService;
@Resource
private CommonInfoService commonRepository;
@Resource
private UserMoneyService userMoneyService;
@Resource
private SysUserService sysUserService;
@Resource
private InviteDao inviteDao;
@Resource
private CompletAwardService completAwardService;
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void run(String params) {
logger.info("订单表数据处理开始");
List<Orders> orders = ordersDao.selectList(Wrappers.<Orders>lambdaQuery().eq(Orders::getStatus, 0));
if (CollUtil.isEmpty(orders)) {
return;
}
for (Orders order : orders) {
PayDetails payDetails = payDetailsDao.selectByOrderId(order.getOrdersNo());
if (payDetails == null) {
continue;
}
if (payDetails.getState() == 1) {
continue;
}
BaseResp baseResp = WuyouPay.queryOrder(payDetails.getTradeNo(), order.getPayMoney().toString(), "Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1 Edg/131.0.0.0");
if (baseResp.getCode() == null || baseResp.getCode() != 200) {
continue;
}
if ("SUCCESS".equals(baseResp.getPayStatus())) {
if (payDetails.getState() == 1) {
continue;
}
logger.info("payDetails{} ", JSONUtil.toJsonStr(payDetails));
logger.info("order{} ", JSONUtil.toJsonStr(order));
updateOrderStatus(payDetails, order);
}
}
logger.info("订单表数据处理完毕");
}
private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private void updateOrderStatus(PayDetails payDetails, Orders order) {
String format = sdf.format(new Date());
payDetailsDao.updateState(payDetails.getId(), 1, format, payDetails.getTradeNo());
order.setPayWay(9);
order.setStatus(1);
order.setPayTime(DateUtils.format(new Date()));
UserEntity user = userService.selectUserById(order.getUserId());
UserEntity byUser = userService.queryByInvitationCode(user.getInviterCode());
Map<String, Object> map = inviteService.updateInvite(byUser, format, user.getUserId(), order.getPayMoney());
Object oneUserId = map.get("oneUserId");
if (oneUserId != null) {
order.setOneUserId(Long.parseLong(String.valueOf(oneUserId)));
order.setOneMoney(new BigDecimal(String.valueOf(map.get("oneMoney"))));
}
Object twoUserId = map.get("twoUserId");
if (twoUserId != null) {
order.setTwoUserId(Long.parseLong(String.valueOf(twoUserId)));
order.setTwoMoney(new BigDecimal(String.valueOf(map.get("twoMoney"))));
}
Object sysUserId = map.get("sysUserId");
if (sysUserId != null) {
order.setSysUserId(Long.parseLong(String.valueOf(sysUserId)));
order.setQdMoney(new BigDecimal(String.valueOf(map.get("qdMoney"))));
}
ordersService.updateById(order);
ordersService.insertOrders(order);
CompletableFuture.runAsync(() -> {
activities(user, byUser);
});
}
@Transactional
public void activities(UserEntity user, UserEntity sourceUser) {
//分享达标
if (sourceUser != null && sourceUser.getUserId() != 1) {
QueryWrapper<UserMoneyDetails> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("classify", 6);
queryWrapper.eq("user_id", sourceUser.getUserId());
queryWrapper.eq("by_user_id", user.getUserId());
int count = userMoneyDetailsService.count(queryWrapper);
if (count == 0) {
//满3笔
Integer sumOrderNum = ordersService.countOrderNum(user.getUserId(), null);
if (sumOrderNum >= Integer.parseInt(commonRepository.findOne(913).getValue())) {
String amount = commonRepository.findOne(912).getValue();
UserMoneyDetails userMoneyDetails = new UserMoneyDetails();
userMoneyDetails.setClassify(6);
userMoneyDetails.setMoney(new BigDecimal(amount));
userMoneyDetails.setUserId(sourceUser.getUserId());
userMoneyDetails.setByUserId(user.getUserId());
userMoneyDetails.setCreateTime(DateUtil.now());
userMoneyDetails.setContent("分享达标奖励" + amount + "");
userMoneyDetails.setTitle("分享达标奖励");
userMoneyDetails.setState(2);
userMoneyDetails.setType(1);
userMoneyDetails.setMoneyType(1);
userMoneyDetailsService.save(userMoneyDetails);
//存入余额 钱
userMoneyService.updateAmount(1, sourceUser.getUserId(), Double.parseDouble(amount));
SysUserEntity sysUser = sysUserService.selectSysUserByQdCode(user.getQdCode());
String qdAward = commonRepository.findOne(915).getValue();
UserMoneyDetails userMoneyDetails4 = new UserMoneyDetails(
null, sysUser.getUserId(), null, "[分享达标额外奖励]", 6, 1, 2,
new BigDecimal(qdAward), "推广人员首次达标,额外奖励现金红包" + qdAward, 2);
userMoneyService.updateSysAmount(1, sysUser.getUserId(), Double.valueOf(qdAward));
userMoneyDetailsService.save(userMoneyDetails4);
Invite invite = inviteService.selectInviteByUser(sourceUser.getUserId(), user.getUserId(), 1);
if (invite != null) {
invite.setMoney(Double.valueOf(amount));
invite.setState(1);
inviteDao.updateById(invite);
}
}
}
QueryWrapper<UserMoneyDetails> moneyDetailsQuery = new QueryWrapper<>();
moneyDetailsQuery.eq("classify", 6);
moneyDetailsQuery.eq("user_id", sourceUser.getUserId());
//达标人数
int completeCount = userMoneyDetailsService.count(moneyDetailsQuery);
completAwardService.list(new QueryWrapper<CompletAward>().eq("invite_count", completeCount)).forEach(completAward -> {
switch (completAward.getType()) {
case 1:
UserMoneyDetails userMoneyDetails1 = new UserMoneyDetails(
sourceUser.getUserId(), null, null, "[分享达标额外奖励]", 6, 1, 2,
completAward.getAwardNumber(), "邀请人员已有" + completAward.getInviteCount() + "人完成达标任务,额外奖励金币" + completAward.getAwardNumber(), 2);
userMoneyService.updateMoney(1, sourceUser.getUserId(), completAward.getAwardNumber().doubleValue());
userMoneyDetailsService.save(userMoneyDetails1);
break;
case 2:
UserMoneyDetails userMoneyDetails2 = new UserMoneyDetails(
sourceUser.getUserId(), null, null, "[分享达标额外奖励]", 6, 1, 2,
completAward.getAwardNumber(), "邀请人员已有" + completAward.getInviteCount() + "人完成达标任务,额外奖励现金红包" + completAward.getAwardNumber(), 1);
userMoneyService.updateAmount(1, sourceUser.getUserId(), completAward.getAwardNumber().doubleValue());
userMoneyDetailsService.save(userMoneyDetails2);
break;
}
});
}
}
}

View File

@@ -62,7 +62,7 @@ public class AppMessageController {
}
@Login
@PostMapping("/insertMessage")
//@PostMapping("/insertMessage")
@ApiOperation("添加投诉")
public Result insertMessage(@RequestBody MessageInfo messageInfo){
messageService.saveBody(messageInfo);

View File

@@ -21,6 +21,8 @@ public interface CashOutDao extends BaseMapper<CashOut> {
List<CashOut> selectYesterday();
List<CashOut> selectTemp();
Double selectCashOutSum(@Param("userId") Long userId, @Param("startTime") Date startTime, @Param("endTime") Date endTime);
Integer selectTodayCashCount(@Param("userId") Long userId, @Param("state") Integer state);
Double selectSysUserCashOutSum(@Param("sysUserId") Long sysUserId, @Param("time") String time);

View File

@@ -12,7 +12,6 @@ import com.sqx.modules.app.dao.UserDao;
import com.sqx.modules.app.entity.UserEntity;
import com.sqx.modules.common.dao.CommonInfoDao;
import com.sqx.modules.common.entity.CommonInfo;
import com.sqx.modules.taskCenter.entity.TaskCenterReward;
import com.sqx.modules.userSign.dao.UserSignRecordDao;
import com.sqx.modules.userSign.dto.UserSignDTO;
import com.sqx.modules.userSign.dto.UserSignRecordDTO;
@@ -24,10 +23,7 @@ import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
@Service
@@ -62,7 +58,7 @@ public class UserSignRecordServiceImpl extends ServiceImpl<UserSignRecordDao, Us
// 连续签到日期
List<String> flowDays = buildFlowDays(beginDay, activeDays);
// 实际签到记录
List<UserSignRecord> list = baseMapper.selectList(Wrappers.<UserSignRecord>lambdaQuery().eq(UserSignRecord::getUserId, currentUser.getUserId()).orderByAsc(UserSignRecord::getCreateTime));
List<UserSignRecord> list = baseMapper.selectList(Wrappers.<UserSignRecord>lambdaQuery().eq(UserSignRecord::getUserId, currentUser.getUserId()).orderByAsc(UserSignRecord::getSignDay).orderByAsc(UserSignRecord::getCreateTime).orderByAsc(UserSignRecord::getId));
// 第x天
int index = 1;
// 连续签到天数
@@ -81,8 +77,10 @@ public class UserSignRecordServiceImpl extends ServiceImpl<UserSignRecordDao, Us
dto.setSignDays(signDays);
return dto;
}
flowDays = buildFlowDays(beginDay.plusDays(-6), activeDays);
index = 1;
LocalDate beginSignDay = LocalDate.parse(list.get(0).getSignDay(), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
//LocalDate endDay = LocalDate.parse(list.get(list.size() - 1).getSignDay(), DateTimeFormatter.ofPattern("yyyy-MM-dd")).plusDays(activeDays);
LocalDate endDay = LocalDate.now().plusDays(activeDays - 1);
flowDays = buildFlowDays(beginSignDay, endDay);
Map<String, Date> signMap = list.stream().collect(Collectors.toMap(UserSignRecord::getSignDay, UserSignRecord::getCreateTime));
for (String day : flowDays) {
Date date = signMap.get(day);
@@ -107,16 +105,29 @@ public class UserSignRecordServiceImpl extends ServiceImpl<UserSignRecordDao, Us
} else if (daysBetween == 0) {
record.setShowText("待签到");
} else {
record.setShowText(StrUtil.format("第{}天", index));
record.setShowText("第{}天");
}
}
recordList.add(record);
if (signDays == activeDays) {
break;
}
if (LocalDate.parse(record.getSignDay(), DateTimeFormatter.ofPattern("yyyy-MM-dd")).isEqual(endDay.plusDays(0 - signDays))) {
break;
}
}
Collections.reverse(recordList);
recordList = recordList.stream().limit(activeDays).collect(Collectors.toList());
Collections.reverse(recordList);
index = 1;
for (UserSignRecordDTO record : recordList) {
record.setShowText(StrUtil.format(record.getShowText(), index));
index++;
}
dto.setRecordList(recordList);
dto.setSignDays(signDays);
// 该用户是否可以继续签到
if (signDays >= 7) {
if (signDays >= activeDays) {
dto.setEnable(0);
}
return dto;
@@ -133,7 +144,7 @@ public class UserSignRecordServiceImpl extends ServiceImpl<UserSignRecordDao, Us
}
@Override
public Map<Long,Integer> getTaskWCount(long userId,int wCount) {
public Map<Long, Integer> getTaskWCount(long userId, int wCount) {
Date thirtyDaysAgo = DateUtil.offsetDay(new Date(), -30);
List<Long> noRecordTasks = baseMapper.getNoRecordTask(userId, DateUtil.format(thirtyDaysAgo, "yyyy-MM-dd") + " 00:00:00");
List<UserSignRecord> taskWCount = baseMapper.getTaskWCount(userId, wCount, DateUtil.format(thirtyDaysAgo, "yyyy-MM-dd") + " 00:00:00", noRecordTasks);
@@ -166,5 +177,19 @@ public class UserSignRecordServiceImpl extends ServiceImpl<UserSignRecordDao, Us
}
return flowDays;
}
private List<String> buildFlowDays(LocalDate beginDay, LocalDate endDay) {
List<String> flowDays = new ArrayList<>();
LocalDate tempDay = beginDay;
flowDays.add(tempDay.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
while (true) {
if (tempDay.isEqual(endDay)) {
break;
}
tempDay = tempDay.plusDays(1);
flowDays.add(tempDay.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
}
return flowDays;
}
}

View File

@@ -11,7 +11,7 @@ server:
connection-timeout: 5000ms
port: 8100
servlet:
context-path: /sqx_fast
context-path: /czg
spring:
main:

View File

@@ -15,6 +15,12 @@
AND create_at &gt; DATE_FORMAT(DATE_SUB(NOW(), INTERVAL 1 DAY), '%Y-%m-%d 00:00:00')
</select>
<select id="selectTemp" resultType="com.sqx.modules.pay.entity.CashOut">
SELECT * FROM cash_out
WHERE
state = 0 and order_number is not null and order_number != ''
</select>
<select id="selectCashOutSum" resultType="Double">
select sum(money) from cash_out where state in (0,1) and user_id=#{userId} and date_format(create_at,'%Y-%m-%d') between #{startTime} and #{endTime}
</select>