This commit is contained in:
2026-09-11 15:56:51 +08:00
parent a12ef31f26
commit dc63a51638
31 changed files with 5433 additions and 3068 deletions
@@ -15,6 +15,10 @@ import java.lang.reflect.Method;
public class SaCheckLoginInterceptor implements MethodInterceptor { public class SaCheckLoginInterceptor implements MethodInterceptor {
@Override @Override
public void filter(InterceptorChain chain) throws Throwable { public void filter(InterceptorChain chain) throws Throwable {
if (SaTokenAuthIgnoreUtil.isIgnore()) {
chain.doChain();
return;
}
Method method = chain.getCallingMethod(); Method method = chain.getCallingMethod();
SaCheckLogin at = method.getAnnotation(SaCheckLogin.class); SaCheckLogin at = method.getAnnotation(SaCheckLogin.class);
SaManager.getStpLogic(at.type()).checkByAnnotation(at); SaManager.getStpLogic(at.type()).checkByAnnotation(at);
@@ -15,6 +15,10 @@ import java.lang.reflect.Method;
public class SaCheckPermissionInterceptor implements MethodInterceptor { public class SaCheckPermissionInterceptor implements MethodInterceptor {
@Override @Override
public void filter(InterceptorChain chain) throws Throwable { public void filter(InterceptorChain chain) throws Throwable {
if (SaTokenAuthIgnoreUtil.isIgnore()) {
chain.doChain();
return;
}
Method method = chain.getCallingMethod(); Method method = chain.getCallingMethod();
SaCheckPermission at = method.getAnnotation(SaCheckPermission.class); SaCheckPermission at = method.getAnnotation(SaCheckPermission.class);
SaManager.getStpLogic(at.type()).checkByAnnotation(at); SaManager.getStpLogic(at.type()).checkByAnnotation(at);
@@ -15,6 +15,10 @@ import java.lang.reflect.Method;
public class SaCheckRoleInterceptor implements MethodInterceptor { public class SaCheckRoleInterceptor implements MethodInterceptor {
@Override @Override
public void filter(InterceptorChain chain) throws Throwable { public void filter(InterceptorChain chain) throws Throwable {
if (SaTokenAuthIgnoreUtil.isIgnore()) {
chain.doChain();
return;
}
Method method = chain.getCallingMethod(); Method method = chain.getCallingMethod();
SaCheckRole at = method.getAnnotation(SaCheckRole.class); SaCheckRole at = method.getAnnotation(SaCheckRole.class);
SaManager.getStpLogic(at.type()).checkByAnnotation(at); SaManager.getStpLogic(at.type()).checkByAnnotation(at);
@@ -1,38 +1,26 @@
package com.budwk.app.zhgh.activity.fitnesswalk.controller; package com.budwk.app.zhgh.activity.fitnesswalk.controller;
import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.budwk.app.base.annotation.SLog; import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.result.Result; import com.budwk.app.base.result.Result;
import com.budwk.app.web.commons.auth.utils.AuthUtil; import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkBindingRecordService;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.activity.fitnesswalk.utils.WeAppCloudUtil;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param; import org.nutz.mvc.annotation.Param;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;
@IocBean @IocBean
@Ok("json") @Ok("json")
@ApiOperation("健步走-同步绑定记录")
@At("/platform/fitnessWalk/bindingRecord") @At("/platform/fitnessWalk/bindingRecord")
public class FitnessWalkActivityBindingRecordController { public class FitnessWalkActivityBindingRecordController {
@Inject @Inject
private WeAppCloudUtil weAppCloudUtil; private FitnessWalkBindingRecordService fitnessWalkBindingRecordService;
@At("") @At("")
@Ok("beetl:/platform/zhgh/activity/fitnesswalk/bindingRecord.html") @Ok("beetl:/platform/zhgh/activity/fitnesswalk/bindingRecord.html")
@@ -41,93 +29,58 @@ public class FitnessWalkActivityBindingRecordController {
} }
/** /**
* 获取用户绑定记录 * 按工号、姓名及分工会权限分页检索绑定记录
* @param keyWord *
* @param unionId * @param keyWord 绑定记录的姓名或工号关键字
* @param searchName * @param unionId 分工会ID,空值表示不追加筛选,已有数据权限仍生效
* @param searchKeyword * @param searchName 查询字段,使用页面提供的字段名
* @param pageNumber * @param searchKeyword 姓名、工号或当前查询字段的检索内容
* @param pageSize * @param pageNumber 页码,从1开始
* @param pageOrderName * @param pageSize 每页记录数
* @param pageOrderBy * @param pageOrderName 列表排序字段
* @return * @param pageOrderBy 排序方向,ascending或descending
* @throws IOException * @return Resultcode为0表示成功,data承载按工号、姓名及分工会权限分页检索绑定记录结果,失败说明见msg
*/ */
@At @At
@ApiOperation("获取用户绑定记录")
@SaCheckPermission("fitnessWalk.bindingRecord") @SaCheckPermission("fitnessWalk.bindingRecord")
@ApiOperation("获取用户绑定记录")
public Result pageData(@Param("keyWord") String keyWord, public Result pageData(@Param("keyWord") String keyWord,
@Param("unionId") String unionId, @Param("unionId") String unionId,
@Param("searchName") String searchName, @Param("searchName") String searchName,
@Param("searchKeyword") String searchKeyword, @Param("searchKeyword") String searchKeyword,
@Param("pageNumber") int pageNumber, @Param("pageSize") int pageSize, @Param("pageNumber") int pageNumber,@Param("pageSize") int pageSize,
@Param("pageOrderName") String pageOrderName, @Param("pageOrderName") String pageOrderName,
@Param("pageOrderBy") String pageOrderBy) { @Param("pageOrderBy") String pageOrderBy) throws IOException {
int skip = (pageNumber == 1 ? 0 : (pageNumber - 1)) * pageSize; return fitnessWalkBindingRecordService.pageData(keyWord, unionId, searchName, searchKeyword, pageNumber, pageSize, pageOrderName, pageOrderBy);
StringBuilder sql = new StringBuilder("db.collection('login_record')");
if (StrUtil.isNotBlank(keyWord)) {
sql.append(".where(");
sql.append("_.or([");
sql.append("{loginname:{$regex:'").append(keyWord).append("',$options:'i'}},");
sql.append("{username:{$regex:'").append(keyWord).append("',$options:'i'}}");
sql.append("])");
sql.append(")");
}
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
sql.append(".where({'data.unionid':'").append(SecurityUtil.getUnionId()).append("'})");
} else {
if (Strings.isNotBlank(unionId)) {
sql.append(".where({'data.unionid':'").append(unionId).append("'})");
}
}
sql.append(".field({ data: false })");
sql.append(".skip(").append(skip).append(")");
sql.append(".limit(").append(pageSize).append(")");
sql.append(".get()");
try {
JSONObject jsonObject = weAppCloudUtil.request(WeAppCloudUtil.CRUD.QUERY, sql.toString());
List<NutMap> data = jsonObject.getJSONArray("data").stream()
.map(v -> JSONUtil.toBean((String) v, NutMap.class))
.collect(Collectors.toList());
JSONObject pager = jsonObject.getJSONObject("pager");
Pagination pagination = new Pagination(pageNumber, pageSize, pager.getInt("Total"), data);
return Result.success().addData(pagination);
} catch (Exception e) {
return Result.error(e.getMessage());
}
} }
/** /**
* 删除绑定记录 * 按记录ID删除选中的云端绑定记录
* @param ids *
* @return * @param ids 待删除记录的主键ID数组
* @return Resultcode为0表示成功,data承载按记录ID删除选中的云端绑定记录结果,失败说明见msg
*/ */
@At @At
@SaCheckPermission("fitnessWalk.bindingRecord")
@Aop(TransAop.READ_COMMITTED)
@ApiOperation("删除绑定记录") @ApiOperation("删除绑定记录")
@SLog(tag = "健步走-同步绑定记录", msg = "删除绑定记录") @SLog(tag = "健步走-同步绑定记录", msg = "删除绑定记录")
@SaCheckPermission("fitnessWalk.bindingRecord")
public Result delete(String[] ids) { public Result delete(String[] ids) {
String sql = "db.collection('login_record').where({_id:_.in(" + Json.toJson(ids) + ")}).remove()"; return fitnessWalkBindingRecordService.delete(ids);
weAppCloudUtil.request(WeAppCloudUtil.CRUD.DELETE, sql);
return Result.success();
} }
/** /**
* 删除所有绑定记录 * 清除云端绑定记录,供管理员重新同步人员绑定。
* @return *
* @return Resultcode为0表示成功,data承载清除云端绑定记录,供管理员重新同步人员绑定结果,失败说明见msg
*/ */
@At @At
@SaCheckPermission("fitnessWalk.bindingRecord")
@Aop(TransAop.READ_COMMITTED)
@ApiOperation("删除所有绑定记录") @ApiOperation("删除所有绑定记录")
@SLog(tag = "健步走-同步绑定记录", msg = "删除所有绑定记录") @SLog(tag = "健步走-同步绑定记录", msg = "删除所有绑定记录")
@SaCheckPermission("fitnessWalk.bindingRecord")
public Result deleteAll() { public Result deleteAll() {
String sql = "db.collection('login_record').where({_id: _.neq('0')}).remove()"; return fitnessWalkBindingRecordService.deleteAll();
weAppCloudUtil.request(WeAppCloudUtil.CRUD.DELETE, sql);
return Result.success();
} }
} }
@@ -1,337 +1,160 @@
package com.budwk.app.zhgh.activity.fitnesswalk.controller; package com.budwk.app.zhgh.activity.fitnesswalk.controller;
import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.budwk.app.base.annotation.SLog; import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.result.Result; import com.budwk.app.base.result.Result;
import com.budwk.app.sys.models.Sys_task;
import com.budwk.app.sys.services.SysTaskService;
import com.budwk.app.sys.services.SysUserService;
import com.budwk.app.task.services.TaskPlatformService;
import com.budwk.app.web.commons.auth.utils.AuthUtil;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkActivity; import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkActivity;
import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkActivityService;
import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkCommonService; import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkCommonService;
import com.budwk.app.zhgh.activity.fitnesswalk.utils.WeAppCloudUtil;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.nutz.dao.Cnd; import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.AdaptBy; import org.nutz.mvc.annotation.AdaptBy;
import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param; import org.nutz.mvc.annotation.Param;
import org.nutz.mvc.upload.TempFile; import org.nutz.mvc.upload.TempFile;
import org.nutz.mvc.upload.UploadAdaptor; import org.nutz.mvc.upload.UploadAdaptor;
import java.text.SimpleDateFormat;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
@IocBean
@Ok("json")
@ApiOperation("健步走-活动管理")
@At("/platform/fitnessWalk/activityManage") @At("/platform/fitnessWalk/activityManage")
@Ok("json")
@IocBean
public class FitnessWalkActivityManageController { public class FitnessWalkActivityManageController {
@Inject
private WeAppCloudUtil weAppCloudUtil;
@Inject
private SysTaskService sysTaskService;
@Inject
private SysUserService sysUserService;
@Inject
private TaskPlatformService taskPlatformService;
@Inject @Inject
private FitnessWalkCommonService fitnessWalkCommonService; private FitnessWalkCommonService fitnessWalkCommonService;
@Inject
private FitnessWalkActivityService fitnessWalkActivityService;
@At("") @At("")
@Ok("beetl:/platform/zhgh/activity/fitnesswalk/activityManage.html") @Ok("beetl:/platform/zhgh/activity/fitnesswalk/activityManage.html")
@SaCheckPermission("fitnessWalk.activityManage") @SaCheckPermission("fitnessWalk.activityManage")
public void index() { public void index() {
} }
/**
* 分页检索云端活动并保留当前分工会数据权限。
*
* @param year 查询年度,四位年份
* @param unionId 分工会ID,空值表示不追加筛选,已有数据权限仍生效
* @param searchName 查询字段,使用页面提供的字段名
* @param searchKeyword 姓名、工号或当前查询字段的检索内容
* @param pageNumber 页码,从1开始
* @param pageSize 每页记录数
* @param pageOrderName 列表排序字段
* @param pageOrderBy 排序方向,ascending或descending
* @return Resultcode为0表示成功,data承载分页检索云端活动并保留当前分工会数据权限结果,失败说明见msg
*/
@At @At
@ApiOperation("获取活动数据")
@SaCheckPermission("fitnessWalk.activityManage") @SaCheckPermission("fitnessWalk.activityManage")
public Result pageData(@Param("year") Integer year, @Param("unionId") String unionId, @Param("searchName") String searchName, @ApiOperation("获取活动数据")
@Param("searchKeyword") String searchKeyword, @Param("pageNumber") int pageNumber, public Result pageData(@Param("year") Integer year, @Param("unionId") String unionId, @Param("searchName") String searchName, @Param("searchKeyword") String searchKeyword, @Param("pageNumber") int pageNumber, @Param("pageSize") int pageSize, @Param("pageOrderName") String pageOrderName, @Param("pageOrderBy") String pageOrderBy) {
@Param("pageSize") int pageSize, @Param("pageOrderName") String pageOrderName, return fitnessWalkActivityService.pageData(year, unionId, searchName, searchKeyword, pageNumber, pageSize, pageOrderName, pageOrderBy);
@Param("pageOrderBy") String pageOrderBy) {
int skip = (pageNumber == 1 ? 0 : (pageNumber - 1)) * pageSize;
StringBuilder sql = new StringBuilder("db.collection('activity')");
if (Strings.isNotBlank(searchName) && Strings.isNotBlank(searchKeyword)) {
sql.append("where(");
sql.append("_.or([");
sql.append("{name:{$regex:'").append(searchKeyword).append("',$options:'i'}}");
sql.append("{tag:{$regex:'").append(searchKeyword).append("',$options:'i'}}");
sql.append("])");
sql.append(")");
}
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
sql.append(".where({unionId:'").append(SecurityUtil.getUnionId()).append("'})");
} else if (StrUtil.isNotBlank(unionId)) {
sql.append(".where({unionId:'").append(unionId).append("'})");
}
sql.append(".skip(").append(skip).append(")");
sql.append(".limit(").append(pageSize).append(")");
sql.append(".get()");
try {
JSONObject jsonObject = weAppCloudUtil.request(WeAppCloudUtil.CRUD.QUERY, sql.toString());
List<FitnessWalkActivity> data = jsonObject.getJSONArray("data").stream()
.map(v -> JSONUtil.toBean((String) v, FitnessWalkActivity.class))
.collect(Collectors.toList());
JSONObject pager = jsonObject.getJSONObject("pager");
Pagination pagination = new Pagination(pageNumber, pageSize, pager.getInt("Total"), data);
return Result.success().addData(pagination);
} catch (Exception e) {
return Result.error(e.getMessage());
}
} }
/**
* 获取当前年份关联活动下拉数据。
* 下拉数据统一由 service 生成,避免页面自己拼名称或数量导致规则不一致。
* @return Resultcode为0表示成功,data为业务结果,msg为操作说明
*/
@At @At
@ApiOperation("添加活动")
@SLog(tag = "健步走-活动管理", msg = "添加活动")
@SaCheckPermission("fitnessWalk.activityManage") @SaCheckPermission("fitnessWalk.activityManage")
public Result relationActivityOptions() {
return Result.success(fitnessWalkActivityService.getCurrentYearRelationActivityOptions());
}
/**
* 获取福利项目下拉数据。
* 活动页面统一通过当前年份加载福利项目,避免前端直接跨模块取数。
* @param year 四位查询年度
* @return Resultcode为0表示成功,data为业务结果,msg为操作说明
*/
@At
@SaCheckPermission("fitnessWalk.activityManage")
public Result welfareProjectOptions(@Param("year") Integer year) {
return Result.success(fitnessWalkActivityService.getWelfareProjectOptions(year));
}
/**
* 创建云端活动并登记抽奖、连续创建任务和活动缓存。
*
* @param data 兼容原活动提交参数,活动配置以fitnessWalkActivity为准
* @param fitnessWalkActivity 页面提交的活动配置,包含模式、时间、点位和抽奖规则
* @param tempFile 活动封面上传文件,不更换时传空
* @param stepFiles 计步展示图片文件数组,不更换时传空
* @param certificateTempFile 完赛证书背景文件,不更换时传空
* @return Resultcode为0表示成功,data承载创建云端活动并登记抽奖、连续创建任务和活动缓存结果,失败说明见msg
*/
@At
@AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"}) @AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"})
public Result doAdd(@Param("fitnessWalkActivity") FitnessWalkActivity fitnessWalkActivity, @SaCheckPermission("fitnessWalk.activityManage")
@Aop(TransAop.READ_COMMITTED)
public Result doAdd(String data, @Param("fitnessWalkActivity") FitnessWalkActivity fitnessWalkActivity,
@Param("file") TempFile tempFile, @Param("file") TempFile tempFile,
@Param("stepFiles") TempFile[] stepFiles, @Param("stepFiles") TempFile[] stepFiles,
@Param("certificateFile") TempFile certificateTempFile) { @Param("certificateFile") TempFile certificateTempFile) {
try { return fitnessWalkActivityService.doAdd(data, fitnessWalkActivity, tempFile, stepFiles, certificateTempFile);
//设置时间
if ("punch".equals(fitnessWalkActivity.getActivityModel())) {
fitnessWalkActivity.setApplyStartTime(fitnessWalkActivity.getApplyTime()[0]);
fitnessWalkActivity.setApplyEndTime(fitnessWalkActivity.getApplyTime()[1]);
}
fitnessWalkActivity.setStartTime(fitnessWalkActivity.getTime()[0]);
fitnessWalkActivity.setEndTime(fitnessWalkActivity.getTime()[1]);
if (tempFile != null) {
String fileId = weAppCloudUtil.uploadFile("activity/", tempFile.getFile());
fitnessWalkActivity.setCover(fileId);
}
if (Lang.isNotEmpty(stepFiles)) {
List<String> stepFileIdList = new ArrayList<>();
for (TempFile file : stepFiles) {
String fileId = weAppCloudUtil.uploadFile("activity/", file.getFile());
stepFileIdList.add(fileId);
}
fitnessWalkActivity.setRandomPics(stepFileIdList);
}
if (certificateTempFile != null) {
String fileId = weAppCloudUtil.uploadFile("activity/", certificateTempFile.getFile());
fitnessWalkActivity.setCompletionCertificateCover(fileId);
}
if (AuthUtil.hasRoleOr(RoleConstant.BRANCH_UNION_CHAIRMAN.name(), RoleConstant.BRANCH_UNION_OPERATOR.name(), RoleConstant.BRANCH_UNION_ADMIN.name())
&& !AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
fitnessWalkActivity.setUnionId(SecurityUtil.getUnionId());
} else {
fitnessWalkActivity.setUnionId("");
}
fitnessWalkActivity.setNote(fitnessWalkActivity.getNote().replace("\"", "'"));
StringBuilder sql = new StringBuilder();
sql.append("db.collection('activity').add({data:").append(Json.toJson(fitnessWalkActivity)).append("})");
try {
JSONObject jsonObject = weAppCloudUtil.request(WeAppCloudUtil.CRUD.INSERT, sql.toString());
fitnessWalkCommonService.addLotteryTask(fitnessWalkActivity);
fitnessWalkCommonService.addOrEditDoSaveRedis(fitnessWalkActivity);
return Result.success();
} catch (Exception e) {
return Result.error(e.getMessage());
}
} catch (Exception e) {
e.printStackTrace();
return Result.error();
}
} }
@At @At
@Ok("json:full") @Ok("json:full")
@ApiOperation("根据Id获取健步走活动")
@SaCheckPermission("fitnessWalk.activityManage") @SaCheckPermission("fitnessWalk.activityManage")
@ApiOperation("根据Id获取健步走活动")
public Result findOne(String id) { public Result findOne(String id) {
return Result.success(fitnessWalkCommonService.getActivity(id)); return Result.success(fitnessWalkCommonService.getActivity(id));
} }
/**
* 将微信云存储文件ID转换为上传组件回显信息。
*
* @param pic 微信云存储文件ID
* @return Resultcode为0表示成功,data承载将微信云存储文件ID转换为上传组件回显信息结果,失败说明见msg
*/
@At @At
@Ok("json") @Ok("json")
@ApiOperation("获取附件")
@SaCheckPermission("fitnessWalk.activityManage") @SaCheckPermission("fitnessWalk.activityManage")
@ApiOperation("获取附件")
public Result getFile(String pic) { public Result getFile(String pic) {
try { return fitnessWalkActivityService.getFile(pic);
NutMap res = NutMap.NEW();
String imgurl = weAppCloudUtil.httpFile(pic);
HashMap<String, Object> imgmap = new HashMap<>();
imgmap.put("status", "success");
imgmap.put("name", imgurl.substring(imgurl.lastIndexOf("/") + 1));
imgmap.put("id", imgurl);
imgmap.put("url", imgurl);
res.setv("img", imgmap);
return Result.success().addData(res);
} catch (Exception e) {
return Result.error();
}
} }
/**
* 更新活动配置并同步关联任务和活动缓存。
*
* @param fitnessWalkActivity 页面提交的活动配置,包含模式、时间、点位和抽奖规则
* @param tempFile 活动封面上传文件,不更换时传空
* @param stepFiles 计步展示图片文件数组,不更换时传空
* @param certificateTempFile 完赛证书背景文件,不更换时传空
* @return Resultcode为0表示成功,data承载更新活动配置并同步关联任务和活动缓存结果,失败说明见msg
*/
@At @At
@ApiOperation("修改健步走活动")
@SaCheckPermission("fitnessWalk.activityManage")
@AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"}) @AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"})
@SaCheckPermission("fitnessWalk.activityManage")
@Aop(TransAop.READ_COMMITTED)
public Result doEdit(@Param("fitnessWalkActivity") FitnessWalkActivity fitnessWalkActivity, public Result doEdit(@Param("fitnessWalkActivity") FitnessWalkActivity fitnessWalkActivity,
@Param("file") TempFile tempFile, @Param("file") TempFile tempFile,
@Param("stepFiles") TempFile[] stepFiles, @Param("stepFiles") TempFile[] stepFiles,
@Param("certificateFile") TempFile certificateTempFile) { @Param("certificateFile") TempFile certificateTempFile) {
//设置时间 return fitnessWalkActivityService.doEdit(fitnessWalkActivity, tempFile, stepFiles, certificateTempFile);
if ("punch".equals(fitnessWalkActivity.getActivityModel())) {
fitnessWalkActivity.setApplyStartTime(fitnessWalkActivity.getApplyTime()[0]);
fitnessWalkActivity.setApplyEndTime(fitnessWalkActivity.getApplyTime()[1]);
}
fitnessWalkActivity.setStartTime(fitnessWalkActivity.getTime()[0]);
fitnessWalkActivity.setEndTime(fitnessWalkActivity.getTime()[1]);
if (tempFile != null) {
String fileId = weAppCloudUtil.uploadFile("activity/", tempFile.getFile());
fitnessWalkActivity.setCover(fileId);
}
if (Lang.isNotEmpty(stepFiles)) {
List<String> stepFileIdList = new ArrayList<>();
for (TempFile file : stepFiles) {
String fileId = weAppCloudUtil.uploadFile("activity/", file.getFile());
stepFileIdList.add(fileId);
}
fitnessWalkActivity.setRandomPics(stepFileIdList);
}
if (certificateTempFile != null) {
String fileId = weAppCloudUtil.uploadFile("activity/", certificateTempFile.getFile());
fitnessWalkActivity.setCompletionCertificateCover(fileId);
}
if (AuthUtil.hasRoleOr(RoleConstant.BRANCH_UNION_CHAIRMAN.name(), RoleConstant.BRANCH_UNION_OPERATOR.name(), RoleConstant.BRANCH_UNION_ADMIN.name())
&& !AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
fitnessWalkActivity.setUnionId(SecurityUtil.getUnionId());
} else {
fitnessWalkActivity.setUnionId("");
}
fitnessWalkActivity.setNote(fitnessWalkActivity.getNote().replace("\"", "'"));
StringBuilder sql = new StringBuilder();
sql.append("db.collection('activity').doc('")
.append(fitnessWalkActivity.get_id())
.append("').update({data:").append(Json.toJson(fitnessWalkActivity)).append("})");
try {
JSONObject jsonObject = weAppCloudUtil.request(WeAppCloudUtil.CRUD.UPDATE, sql.toString());
fitnessWalkCommonService.addLotteryTask(fitnessWalkActivity);
fitnessWalkCommonService.addOrEditDoSaveRedis(fitnessWalkActivity);
return Result.success();
} catch (Exception e) {
return Result.error(e.getMessage());
}
}
@At
@ApiOperation("删除健步走活动")
@SLog(tag = "健步走-活动管理", msg = "删除活动")
@SaCheckPermission("fitnessWalk.activityManage")
public Result delete(String id) {
try {
weAppCloudUtil.request(WeAppCloudUtil.CRUD.DELETE, "db.collection('activity').doc('" + id + "').remove()");
weAppCloudUtil.request(WeAppCloudUtil.CRUD.DELETE, "db.collection('register').where({activity_id:'" + id + "'}).remove()");
weAppCloudUtil.request(WeAppCloudUtil.CRUD.DELETE, "db.collection('sign').where({activity_id:'" + id + "'}).remove()");
weAppCloudUtil.request(WeAppCloudUtil.CRUD.DELETE, "db.collection('gift_voucher').where({activity_id:'" + id + "'}).remove()");
List<Sys_task> sys_tasks = sysTaskService.query(Cnd.where("note", "=", id));
if (sys_tasks != null) {
sys_tasks.forEach(v -> {
taskPlatformService.delete(v.getId(), v.getId());
sysTaskService.delete(v.getId());
});
}
return Result.success();
} catch (Exception e) {
return Result.error();
}
} }
/** /**
* 健身走健步模式通知提醒 * 删除云端活动及报名、打卡、礼品券和关联任务。
* *
* @param map * @param id 待操作记录的主键ID
* @return Resultcode为0表示成功,data承载删除云端活动及报名、打卡、礼品券和关联任务结果,失败说明见msg
*/ */
private void addNotifyTask(NutMap map) { @At
if (map.getBoolean("sendNotify")) { @SaCheckPermission("fitnessWalk.activityManage")
String id = map.getString("_id"); @Aop(TransAop.READ_COMMITTED)
String name = map.getString("name"); @ApiOperation("删除健步走活动")
String groupId = map.getString("groupId"); @SLog(tag = "健步走-活动管理", msg = "删除活动")
public Result delete(String id) {
//提醒频率 return fitnessWalkActivityService.deleteActivity(id);
int notifyGap = 10;
List<Sys_task> sys_tasks = sysTaskService.query(Cnd.where("note", "=", id));
if (Lang.isNotEmpty(sys_tasks)) {
sys_tasks.forEach(v -> {
taskPlatformService.delete(v.getId(), v.getId());
sysTaskService.delete(v.getId());
});
}
DateTime startTime = DateUtil.date(map.getLong("start_time"));
DateTime endTime = DateUtil.date(map.getLong("end_time"));
Set<DateTime> result = new HashSet<>();
DateTime offsetDay = DateUtil.offsetDay(startTime, notifyGap);
while (offsetDay.isBefore(endTime) && offsetDay.isAfter(new Date())) {
result.add(offsetDay);
offsetDay = DateUtil.offsetDay(offsetDay, notifyGap);
}
//活动结束前一天再添加一个日期提醒
result.add(DateUtil.offsetDay(endTime, -1));
for (DateTime dateTime : result) {
Sys_task sys_task = new Sys_task();
sys_task.setName(name);
sys_task.setNote(id);
sys_task.setJobClass("io.v.nutz.task.job.walking.WalkingNotifyJob");
sys_task.setData(Json.toJson(Map.of("groupId", groupId)));
sys_task.setDisabled(false);
String dateFormat = "ss mm HH dd MM ? yyyy";
SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
String corn = sdf.format(dateTime);
sys_task.setCron(corn);
sysTaskService.insert(sys_task);
taskPlatformService.add(sys_task.getId(), sys_task.getId(), sys_task.getJobClass(), sys_task.getCron(), sys_task.getNote(), sys_task.getData());
}
}
} }
} }
@@ -1,16 +1,17 @@
package com.budwk.app.zhgh.activity.fitnesswalk.controller; package com.budwk.app.zhgh.activity.fitnesswalk.controller;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.result.Result; import com.budwk.app.base.result.Result;
import com.budwk.app.sys.services.SysUserService; import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkCommonService;
import org.nutz.dao.Cnd; import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Sqls; import org.nutz.ioc.aop.Aop;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap; import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Ok;
import java.util.Date;
/** /**
* @author: Aaron * @author: Aaron
@@ -23,53 +24,60 @@ import org.nutz.mvc.annotation.Ok;
public class FitnessWalkLoginController { public class FitnessWalkLoginController {
@Inject @Inject
private SysUserService sysUserService; private FitnessWalkCommonService fitnessWalkCommonService;
/**
* 按姓名和工号匹配小程序用户并返回单位及角色资料。
*
* @param username 用户姓名,与工号共同匹配人员
* @param loginname 用户工号
* @return Resultcode为0表示成功,data承载按姓名和工号匹配小程序用户并返回单位及角色资料结果,失败说明见msg
*/
@At("/") @At("/")
public Object index(String username, String loginname) { public Result index(String username, String loginname) {
try { return fitnessWalkCommonService.login(username, loginname);
Sql sql = Sqls.create(""" }
SELECT
u.id userid,
u.username,
u.loginname,
u.sex,
u.mobile,
u.birthday,
unit.`name` unitname,
u.unitid,
u.member,
unit.unionid,
un.unionname,
group_concat(sr.`code`) roles
FROM
sys_user u
LEFT JOIN sys_unit unit ON u.unitid = unit.id
LEFT JOIN sys_union un ON unit.unionid = un.id
LEFT JOIN sys_user_role sur ON sur.userId = u.id
LEFT JOIN sys_role sr ON sr.id = sur.roleId
$condition
""").setParam("loginname", loginname).setParam("username", username);
Cnd cnd = Cnd.NEW(); /**
cnd.and("LOWER(u.loginname)", "=", loginname.trim().toLowerCase()); * 补全健步走用户基础资料。
cnd.and("LOWER(u.username)", "=", username.trim().toLowerCase()); *
sql.setCondition(cnd); * @param userId 用户ID,传登录接口返回的 userid
sql.setCallback(Sqls.callback.map()); * @param sex 性别,只能传“男”或“女”
sysUserService.dao().execute(sql); * @param birthday 出生日期,格式为 yyyy-MM-dd,且不能晚于当前日期
NutMap user = (NutMap) sql.getResult(); * @return Resultdata 中包含最终生效的 sex 和 birthday
if (StrUtil.isBlank(user.getString("userid"))) { */
return Result.error().addMsg("系统查询不到您的信息,请与工会管理员联系!"); @At("/completeUserInfo")
@Aop(TransAop.READ_COMMITTED)
public Result completeUserInfo(String userId, String sex, String birthday) {
if (StrUtil.hasBlank(userId, sex, birthday)) {
return Result.error().addMsg("请完整填写性别和出生日期!");
}
if (!"".equals(sex) && !"".equals(sex)) {
return Result.error().addMsg("性别参数不正确!");
}
Date birthdayDate;
try {
birthdayDate = DateUtil.parse(birthday, "yyyy-MM-dd");
if (!birthday.equals(DateUtil.format(birthdayDate, "yyyy-MM-dd"))) {
return Result.error().addMsg("出生日期格式不正确!");
} }
// if(user.getInt("member",0)==0){
// return Result.error().addMsg("您没有权限参加本次健步行,请与工会管理员联系!");
// }
/*if (user.getInt("member", 0) != 1 && !user.getString("sex", "").equals("女")) {
return Result.error().addMsg("您没有权限参加本次健步行,请与工会管理员联系!");
}*/
return Result.success().addData(user);
} catch (Exception e) { } catch (Exception e) {
return Result.error(); return Result.error().addMsg("出生日期格式不正确!");
}
if (birthdayDate.after(new Date())) {
return Result.error().addMsg("出生日期不能晚于当前日期!");
}
try {
NutMap userInfo = fitnessWalkCommonService.completeUserInfo(userId, sex, birthdayDate);
if (userInfo == null) {
return Result.error().addMsg("系统查询不到您的信息,请重新登录!");
}
return Result.success().addData(userInfo);
} catch (Exception e) {
return Result.error().addMsg("个人信息保存失败,请稍后重试!");
} }
} }
} }
@@ -1,258 +1,95 @@
package com.budwk.app.zhgh.activity.fitnesswalk.controller; package com.budwk.app.zhgh.activity.fitnesswalk.controller;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.budwk.app.base.result.Result; import com.budwk.app.base.result.Result;
import com.budwk.app.sys.models.Sys_user; import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkPunchLotteryService;
import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkActivity;
import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkPunchLottery;
import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkCommonService;
import com.budwk.app.zhgh.activity.fitnesswalk.utils.WeAppCloudUtil;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.nutz.dao.Chain; import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd; import org.nutz.ioc.aop.Aop;
import org.nutz.integration.jedis.RedisService;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.random.R;
import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Ok;
import java.util.*; import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
/** /**
* 打卡抽奖 * 打卡抽奖
*/ */
@IocBean @IocBean
@Ok("json") @Ok("json")
@ApiOperation("健步走打卡抽奖")
@At("/platform/fitnessWalk/punchLottery") @At("/platform/fitnessWalk/punchLottery")
public class FitnessWalkPunchLotteryController { public class FitnessWalkPunchLotteryController {
private final ReentrantLock lock = new ReentrantLock(true);
@Inject @Inject
private FitnessWalkCommonService fitnessWalkCommonService; private FitnessWalkPunchLotteryService fitnessWalkPunchLotteryService;
@Inject
private WeAppCloudUtil weAppCloudUtil;
@Inject
private RedisService redisService;
@At("") @At("")
@Ok("beetl:/platform/zhgh/activity/fitnesswalk/punchLottery.html") @Ok("beetl:/platform/zhgh/activity/fitnesswalk/punchLottery.html")
public void index() { public void index() {
} }
/** /**
* 打卡完成之后抽奖 * 按源版奖池和报名人数分配打卡抽奖结果。
* *
* @param activityId 活动Id * @param activityId 健步走云端活动ID
* @param userId 用户Id * @param userId 登录接口返回的用户ID
* @return * @return Resultcode为0表示成功,data承载按源版奖池和报名人数分配打卡抽奖结果结果,失败说明见msg
*/ */
@At @At
@ApiOperation("打卡模式的抽奖") @ApiOperation("打卡模式的抽奖")
public Result judgeWinningToPunch(String activityId, String userId) { public Result judgeWinningToPunch(String activityId, String userId) {
try { return fitnessWalkPunchLotteryService.judgeWinningToPunch(activityId, userId);
if (StrUtil.isBlank(activityId) && StrUtil.isBlank(userId)) {
return Result.error("参数错误");
}
lock.lock();
int winingCount = fitnessWalkCommonService.dao().count(FitnessWalkPunchLottery.class, Cnd.where("activityId", "=", activityId).and("userId", "=", userId));
if (winingCount > 0) {
return null;
}
// 把中奖的用户直接存到redis里面去
String redisKey = this.getClass().getName() + "#judgeWinningToPunch#activityid:" + activityId + "#PRIZELIST:";
String getPrizeIndexesKey = this.getClass().getName() + "#judgeWinningToPunch#activityid:" + activityId + "#GETPRIZEINDEXES:";
// redisService.del(getPrizeIndexesKey);
// 获取奖品列表
List<FitnessWalkActivity.PunchLotteryPrize> punchLotteryPrizes = new ArrayList<>();
String punchLotteryPrizesJson = redisService.get(redisKey);
if (StrUtil.isNotBlank(punchLotteryPrizesJson)) {
punchLotteryPrizes = JSONUtil.toList(punchLotteryPrizesJson, FitnessWalkActivity.PunchLotteryPrize.class);
} else {
JSONObject prizeJsonObject = weAppCloudUtil.request(WeAppCloudUtil.CRUD.QUERY, "db.collection('activity').doc('%s').field({punchLotteryPrizes: true}).get()".formatted(activityId));
List<FitnessWalkActivity.PunchLotteryPrize> prizeList = JSONUtil.parseObj((String) prizeJsonObject.getJSONArray("data").get(0)).getJSONArray("punchLotteryPrizes").toList(FitnessWalkActivity.PunchLotteryPrize.class);
redisService.set(redisKey, JSONUtil.toJsonStr(prizeList));
punchLotteryPrizes = prizeList;
}
List<Integer> winningUserIndexList = null;
//奖项,抽取多少个
int sum = punchLotteryPrizes.stream().mapToInt(v -> Integer.parseInt(v.getNum())).sum();
//判断是否有key,可以获得奖项的下标数组
if (!redisService.exists(getPrizeIndexesKey)) {
JSONObject jsonObject = weAppCloudUtil.request(WeAppCloudUtil.CRUD.QUERY, "db.collection('register').where({activity_id:'%s'}).count()".formatted(activityId));
JSONObject pager = jsonObject.getJSONObject("pager");
String total = pager.getStr("Total");
//报名人数的一半,从这里的人中取数(最多抽取人数)
Integer lotteryNum = (int) Math.ceil(Double.parseDouble(total) / 2);
winningUserIndexList = generateRandomNumber(1, lotteryNum, sum);
redisService.set(getPrizeIndexesKey, JSONUtil.toJsonStr(winningUserIndexList));
} else {
String data = redisService.get(getPrizeIndexesKey);
winningUserIndexList = JSONUtil.toList(data, Integer.class);
}
List<FitnessWalkPunchLottery> punchLotteryList = fitnessWalkCommonService.dao().query(FitnessWalkPunchLottery.class, Cnd.where("activityId", "=", activityId));
Sys_user user = fitnessWalkCommonService.dao().fetch(Sys_user.class, Cnd.where("id", "=", userId));
FitnessWalkPunchLottery punchLottery = new FitnessWalkPunchLottery();
punchLottery.setId(R.UU32());
punchLottery.setActivityId(activityId);
punchLottery.setUserId(userId);
punchLottery.setLoginName(user.getLoginname());
punchLottery.setUserName(user.getUsername());
punchLottery.setWinDate(new Date());
punchLottery.setIsRead(false);
punchLottery.setIsWin(false);
punchLottery.setIsExchange(false);
if (winningUserIndexList.contains((punchLotteryList.size()))) {
//奖项map
Map<String, String> prizeMap = punchLotteryPrizes.stream().collect(Collectors.toMap(FitnessWalkActivity.PunchLotteryPrize::getValue, FitnessWalkActivity.PunchLotteryPrize::getName));
//奖项池
List<String> prizeIdList = new ArrayList<>();
punchLotteryPrizes.forEach(v -> {
for (int i = 0; i < Integer.parseInt(v.getNum()); i++) {
prizeIdList.add(v.getValue());
}
});
//已经中奖的奖项ID集合
List<String> winPrizeIdList = punchLotteryList.stream().filter(FitnessWalkPunchLottery::getIsWin).map(FitnessWalkPunchLottery::getPrizeId).toList();
winPrizeIdList.forEach(prizeIdList::remove);
Random random = new Random();
if (Lang.isNotEmpty(prizeIdList.size())) {
int index = random.nextInt(prizeIdList.size());
// 获取随机元素
String winingPrizeId = prizeIdList.get(index);
String winingPrizeName = prizeMap.get(winingPrizeId);
punchLottery.setPrizeName(winingPrizeName);
punchLottery.setPrizeId(winingPrizeId);
punchLottery.setIsWin(true);
}
}
fitnessWalkCommonService.dao().insert(punchLottery);
if (punchLottery.getIsWin()) {
return Result.success().addData(punchLottery.getPrizeId());
} else {
return Result.success().addData(null);
}
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
if (lock.isLocked()) {
lock.unlock();
}
}
} }
/**
* 查询用户在指定活动中的打卡抽奖记录。
*
* @param activityId 健步走云端活动ID
* @param userId 登录接口返回的用户ID
* @return Resultcode为0表示成功,data承载查询用户在指定活动中的打卡抽奖记录结果,失败说明见msg
*/
@At @At
@ApiOperation("获取中奖记录") @ApiOperation("获取中奖记录")
public Result getLotteryRecord(String activityId, String userId) { public Result getLotteryRecord(String activityId, String userId) {
List<FitnessWalkPunchLottery> list = fitnessWalkCommonService.dao().query(FitnessWalkPunchLottery.class, Cnd.where("activityId", "=", activityId) return fitnessWalkPunchLotteryService.getLotteryRecord(activityId, userId);
.and("userId", "=", userId));
return Result.success(list);
} }
/** /**
* 兑奖 * 核销奖品并记录兑换时间,重复核销返回状态2。
* *
* @param id * @param id 待操作记录的主键ID
* @return * @return Resultcode为0表示成功,data承载核销奖品并记录兑换时间,重复核销返回状态2结果,失败说明见msg
*/ */
@At @At
@Aop(TransAop.READ_COMMITTED)
@ApiOperation("兑奖") @ApiOperation("兑奖")
public Result doExchange(String id) { public Result doExchange(String id) {
return fitnessWalkPunchLotteryService.doExchange(id);
int count = fitnessWalkCommonService.dao().count(FitnessWalkPunchLottery.class, Cnd.where("id", "=", id).and("isExchange", "=", 1));
//返回2 "该二维码已兑奖!"
if (count > 0) {
return Result.success(2);
}
int update = fitnessWalkCommonService.dao().update(FitnessWalkPunchLottery.class,
Chain.make("isExchange", 1).add("exchangeDate", new Date()),
Cnd.where("id", "=", id));
return update > 0 ? Result.success() : Result.error();
} }
/** /**
* 为已读 * 将用户在指定活动中的抽奖记录标记为已读
* *
* @param activityId * @param activityId 健步走云端活动ID
* @param userId * @param userId 登录接口返回的用户ID
* @return * @return Resultcode为0表示成功,data承载将用户在指定活动中的抽奖记录标记为已读结果,失败说明见msg
*/ */
@At @At
@Aop(TransAop.READ_COMMITTED)
@ApiOperation("改为已读") @ApiOperation("改为已读")
public Result doReadLottery(String activityId, String userId) { public Result doReadLottery(String activityId, String userId) {
fitnessWalkCommonService.dao().update(FitnessWalkPunchLottery.class, Chain.make("isRead", 1), return fitnessWalkPunchLotteryService.doReadLottery(activityId, userId);
Cnd.where("userId", "=", userId).and("activityId", "=", activityId));
return Result.success();
} }
/** /**
* 查看获奖人员 * 查询指定打卡活动中已中奖的人员
* *
* @return * @param activityId 健步走云端活动ID
* @return Resultcode为0表示成功,data承载查询指定打卡活动中已中奖的人员结果,失败说明见msg
*/ */
@At @At
@ApiOperation("查看获奖人员") @ApiOperation("查看获奖人员")
public Result getPunchWining(String activityId) { public Result getPunchWining(String activityId) {
List<FitnessWalkPunchLottery> punchLotteryList = fitnessWalkCommonService.dao().query(FitnessWalkPunchLottery.class, return fitnessWalkPunchLotteryService.getPunchWining(activityId);
Cnd.where("isWin", "=", 1).and("activityId", "=", activityId));
return Result.success(punchLotteryList);
} }
/**
* 抽奖方法的工具类,生成随机数,该随机数为中奖人
*
* @param minNum 最小值
* @param maxNum 最多抽取多少人
* @param count 抽几个
* @return
*/
public List<Integer> generateRandomNumber(Integer minNum, Integer maxNum, Integer count) {
Set<Integer> randomNumbers = new HashSet<>();
Random rand = new Random();
//如果是 抽奖人数小于了 奖品数量,会陷入死循环
if (maxNum <= count) {
for (int i = 0; i <= maxNum; i++) {
randomNumbers.add(i + 1);
}
} else {
while (randomNumbers.size() < count) {
int randomNum = rand.nextInt(maxNum - minNum + 1) + minNum;
randomNumbers.add(randomNum);
}
}
return new ArrayList<>(randomNumbers);
}
} }
@@ -1,20 +1,12 @@
package com.budwk.app.zhgh.activity.fitnesswalk.controller; package com.budwk.app.zhgh.activity.fitnesswalk.controller;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.json.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.budwk.app.base.result.Result; import com.budwk.app.base.result.Result;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.base.utils.CommonDownloadUtil;
import com.budwk.app.sys.models.Sys_union;
import com.budwk.app.zhgh.activity.fitnesswalk.contants.FitnessWalkMode; import com.budwk.app.zhgh.activity.fitnesswalk.contants.FitnessWalkMode;
import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkCommonService; import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkCommonService;
import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkPunchStatisticsService; import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkPunchStatisticsService;
import com.budwk.app.zhgh.activity.fitnesswalk.utils.WeAppCloudUtil;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.apache.poi.ss.usermodel.Workbook;
import org.nutz.dao.Dao; import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
@@ -22,34 +14,23 @@ import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param; import org.nutz.mvc.annotation.Param;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import javax.servlet.http.HttpServletResponse;
/** /**
* 打卡统计 * 打卡统计
*/ */
@IocBean @IocBean
@Ok("json") @Ok("json")
@ApiOperation("健步走打卡统计")
@At("/platform/fitnessWalk/punchStatistics") @At("/platform/fitnessWalk/punchStatistics")
public class FitnessWalkPunchStatisticsController { public class FitnessWalkPunchStatisticsController {
@Inject @Inject
private Dao dao; private Dao dao;
@Inject
private BaseService baseService;
@Inject @Inject
private FitnessWalkCommonService fitnessWalkCommonService; private FitnessWalkCommonService fitnessWalkCommonService;
@Inject
private WeAppCloudUtil weAppCloudUtil;
@Inject @Inject
private FitnessWalkPunchStatisticsService fitnessWalkPunchStatisticsService; private FitnessWalkPunchStatisticsService fitnessWalkPunchStatisticsService;
@@ -62,130 +43,97 @@ public class FitnessWalkPunchStatisticsController {
/** /**
* 分工会统计 * 分工会统计
* *
* @param activityId * @param activityId 健步走云端活动ID
* @param unionId * @param unionId 分工会ID,空值表示不追加组织筛选
* @return * @return Resultcode为0表示成功,data为业务结果,msg为操作说明
* @param mainActivityId 主活动ID或relation:关联项目ID
* @param subActivityId 分活动ID,空值表示汇总主活动
*/ */
@At @At
@Ok("json:full") @Ok("json:full")
@SaCheckPermission("fitnessWalk.punchStatistics")
@ApiOperation("打卡记录统计") @ApiOperation("打卡记录统计")
@SaCheckPermission("fitnessWalk.punchStatistics") public Result pageData(String mainActivityId, String subActivityId, String activityId, String unionId) {
public Result pageData(String activityId, String unionId) { List<NutMap> list = fitnessWalkPunchStatisticsService.unionRegCheckInNum(mainActivityId, subActivityId, activityId, unionId);
List<NutMap> list = fitnessWalkPunchStatisticsService.unionRegCheckInNum(activityId, unionId);
return Result.success(list); return Result.success(list);
} }
@At @At
@SaCheckPermission("fitnessWalk.punchStatistics")
@ApiOperation("获取活动列表") @ApiOperation("获取活动列表")
@SaCheckPermission("fitnessWalk.punchStatistics")
public Result getCascadersActivity(@Param("year") int year) { public Result getCascadersActivity(@Param("year") int year) {
return Result.success().addData(fitnessWalkCommonService.cascaderActivity(year, FitnessWalkMode.PUNCH)); return Result.success(fitnessWalkCommonService.cascaderActivity(year, FitnessWalkMode.PUNCH));
} }
@At @At
@Ok("json:full") @Ok("json:full")
@SaCheckPermission("fitnessWalk.punchStatistics")
@ApiOperation("根据工会查询获取报名人员") @ApiOperation("根据工会查询获取报名人员")
@SaCheckPermission("fitnessWalk.punchStatistics") public Result unionRegistrationData(String mainActivityId, String subActivityId, String activityId, String unionId) {
public Result unionRegistrationData(String activityId, String unionId) { List<JSONObject> list = fitnessWalkPunchStatisticsService.unionRegistrationData(mainActivityId, subActivityId, activityId, unionId);
List<JSONObject> list = fitnessWalkPunchStatisticsService.unionRegistrationData(activityId, unionId);
return Result.success(list); return Result.success(list);
} }
@At @At
@Ok("json:full") @Ok("json:full")
@ApiOperation("根据工会查询获取打卡人员")
@SaCheckPermission("fitnessWalk.punchStatistics") @SaCheckPermission("fitnessWalk.punchStatistics")
public Result unionCheckInData(String activityId, String unionId) { @ApiOperation("根据工会查询获取打卡人员")
List<JSONObject> list = fitnessWalkPunchStatisticsService.unionCheckInData(activityId, unionId); public Result unionCheckInData(String mainActivityId, String subActivityId, String activityId, String unionId) {
List<JSONObject> list = fitnessWalkPunchStatisticsService.unionCheckInData(mainActivityId, subActivityId, activityId, unionId);
return Result.success(list); return Result.success(list);
} }
/**
* 导出所选主分活动的分工会报名与打卡人数。
*
* @param response HTTP响应,用于写入XSSF格式Excel文件流
* @param mainActivityId 主活动ID或relation:关联项目ID
* @param subActivityId 分活动ID,空值表示主活动汇总
* @param activityId 健步走云端活动ID
* 无返回对象,通过response写出Excel文件流。
*/
@At @At
@Ok("void") @Ok("void")
@SaCheckPermission("fitnessWalk.punchStatistics")
@ApiOperation("导出各分工会报名人数、打卡人数") @ApiOperation("导出各分工会报名人数、打卡人数")
@SaCheckPermission("fitnessWalk.punchStatistics") public void exportUnionRegCheckInNum(HttpServletResponse response, String mainActivityId, String subActivityId, String activityId) {
public void exportUnionRegCheckInNum(HttpServletResponse response, String activityId) { fitnessWalkPunchStatisticsService.exportUnionRegCheckInNum(response, mainActivityId, subActivityId, activityId);
List<NutMap> list = fitnessWalkPunchStatisticsService.unionRegCheckInNum(activityId, null);
List<ExcelExportEntity> entities = new ArrayList<>();
entities.add(new ExcelExportEntity("分工会", "unionname", 20));
entities.add(new ExcelExportEntity("报名人数", "regCount", 20));
entities.add(new ExcelExportEntity("打卡人数", "checkInCount", 20));
try {
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), entities, list);
workbook.write(response.getOutputStream());
CommonDownloadUtil.download("各分工会统计人数.xlsx", workbook, response);
} catch (IOException e) {
throw new RuntimeException(e);
}
} }
/**
* 导出所选活动和分工会的报名人员明细。
*
* @param response HTTP响应,用于写入XSSF格式Excel文件流
* @param mainActivityId 主活动ID或relation:关联项目ID
* @param subActivityId 分活动ID,空值表示主活动汇总
* @param activityId 健步走云端活动ID
* @param unionId 分工会ID,空值表示不追加筛选,已有数据权限仍生效
* 无返回对象,通过response写出Excel文件流。
*/
@At @At
@Ok("void") @Ok("void")
@SaCheckPermission("fitnessWalk.punchStatistics")
@ApiOperation("导出某个分工会的报名人员") @ApiOperation("导出某个分工会的报名人员")
@SaCheckPermission("fitnessWalk.punchStatistics") public void exportRegUsers(HttpServletResponse response, String mainActivityId, String subActivityId, String activityId, String unionId) {
public void exportRegUsers(HttpServletResponse response, String activityId, String unionId) { fitnessWalkPunchStatisticsService.exportRegUsers(response, mainActivityId, subActivityId, activityId, unionId);
Sys_union union = dao.fetch(Sys_union.class, unionId);
String unionName = Optional.ofNullable(union).map(Sys_union::getName).orElse(null);
List<JSONObject> list = fitnessWalkPunchStatisticsService.unionRegistrationData(activityId, unionId);
List<ExcelExportEntity> entities = new ArrayList<>();
entities.add(new ExcelExportEntity("工号", "loginname", 20));
entities.add(new ExcelExportEntity("姓名", "username", 20));
entities.add(new ExcelExportEntity("单位", "unitname", 20));
entities.add(new ExcelExportEntity("手机号", "mobile", 20));
entities.add(new ExcelExportEntity("报名时间", "register_time_str", 20));
try {
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), entities, list);
workbook.write(response.getOutputStream());
CommonDownloadUtil.download("分工会报名人员.xlsx", workbook, response);
} catch (IOException e) {
throw new RuntimeException(e);
}
} }
/**
* 导出所选活动和分工会的打卡点位完成明细。
*
* @param response HTTP响应,用于写入XSSF格式Excel文件流
* @param mainActivityId 主活动ID或relation:关联项目ID
* @param subActivityId 分活动ID,空值表示主活动汇总
* @param activityId 健步走云端活动ID
* @param unionId 分工会ID,空值表示不追加筛选,已有数据权限仍生效
* 无返回对象,通过response写出Excel文件流。
*/
@At @At
@Ok("void") @Ok("void")
@ApiOperation("导出某个分工会的打卡人员")
@SaCheckPermission("fitnessWalk.punchStatistics") @SaCheckPermission("fitnessWalk.punchStatistics")
public void exportCheckInUsers(HttpServletResponse response, String activityId, String unionId) { @ApiOperation("导出某个分工会的打卡人员")
Sys_union union = dao.fetch(Sys_union.class, unionId); public void exportCheckInUsers(HttpServletResponse response, String mainActivityId, String subActivityId, String activityId, String unionId) {
String unionName = Optional.ofNullable(union).map(Sys_union::getName).orElse(null); fitnessWalkPunchStatisticsService.exportCheckInUsers(response, mainActivityId, subActivityId, activityId, unionId);
List<JSONObject> list = fitnessWalkPunchStatisticsService.unionCheckInData(activityId, unionId);
for (JSONObject jsonObject : list) {
Boolean used = jsonObject.getBool("used");
if (used == null) {
jsonObject.put("used", "未取得");
} else if (used) {
jsonObject.put("used", "已领取");
} else {
jsonObject.put("used", "未领取");
}
}
List<ExcelExportEntity> entities = new ArrayList<>();
entities.add(new ExcelExportEntity("工号", "loginname", 20));
entities.add(new ExcelExportEntity("姓名", "username", 20));
entities.add(new ExcelExportEntity("单位", "unitname", 20));
entities.add(new ExcelExportEntity("手机号", "mobile", 20));
entities.add(new ExcelExportEntity("点位总数", "pts_size", 20));
entities.add(new ExcelExportEntity("已打卡点位数", "sign_size", 20));
entities.add(new ExcelExportEntity("礼品券", "used", 20));
try {
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), entities, list);
workbook.write(response.getOutputStream());
CommonDownloadUtil.download(unionName + "分工会报名人员.xlsx", workbook, response);
} catch (IOException e) {
throw new RuntimeException(e);
}
} }
// /** // /**
@@ -203,45 +151,38 @@ public class FitnessWalkPunchStatisticsController {
// //
// } // }
/**
* 导出所选活动中尚未取得礼品券的报名人员。
*
* @param response HTTP响应,用于写入XSSF格式Excel文件流
* @param mainActivityId 主活动ID或relation:关联项目ID
* @param subActivityId 分活动ID,空值表示主活动汇总
* @param activityId 健步走云端活动ID
* 无返回对象,通过response写出Excel文件流。
*/
@At @At
@Ok("void") @Ok("void")
@ApiOperation("导出未领取得奖品券用户")
@SaCheckPermission("fitnessWalk.punchStatistics") @SaCheckPermission("fitnessWalk.punchStatistics")
public void exportNotGetGiftVoucherUsers(HttpServletResponse response, String activityId) { @ApiOperation("导出未领取得奖品券用户")
List<JSONObject> list = fitnessWalkPunchStatisticsService.exportNotGetGiftVoucherUsers(activityId); public void exportNotGetGiftVoucherUsers(HttpServletResponse response, String mainActivityId, String subActivityId, String activityId) {
List<ExcelExportEntity> entities = new ArrayList<>(); fitnessWalkPunchStatisticsService.exportNotGetGiftVoucherUsers(response, mainActivityId, subActivityId, activityId);
entities.add(new ExcelExportEntity("工号", "loginname", 20));
entities.add(new ExcelExportEntity("姓名", "username", 20));
entities.add(new ExcelExportEntity("单位", "unitname", 20));
entities.add(new ExcelExportEntity("手机号", "mobile", 20));
try {
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), entities, list);
workbook.write(response.getOutputStream());
CommonDownloadUtil.download("未领取得奖品券人员.xlsx", workbook, response);
} catch (IOException e) {
throw new RuntimeException(e);
}
} }
/**
* 导出所选活动中尚未使用礼品券的人员。
*
* @param response HTTP响应,用于写入XSSF格式Excel文件流
* @param mainActivityId 主活动ID或relation:关联项目ID
* @param subActivityId 分活动ID,空值表示主活动汇总
* @param activityId 健步走云端活动ID
* 无返回对象,通过response写出Excel文件流。
*/
@At @At
@Ok("void") @Ok("void")
@ApiOperation("导出未使用奖品券用户")
@SaCheckPermission("fitnessWalk.punchStatistics") @SaCheckPermission("fitnessWalk.punchStatistics")
public void exportNotUseGiftVoucherUsers(HttpServletResponse response, String activityId) { @ApiOperation("导出未使用奖品券用户")
List<JSONObject> list = fitnessWalkPunchStatisticsService.exportNotUseGiftVoucherUsers(activityId); public void exportNotUseGiftVoucherUsers(HttpServletResponse response, String mainActivityId, String subActivityId, String activityId) {
List<ExcelExportEntity> entities = new ArrayList<>(); fitnessWalkPunchStatisticsService.exportNotUseGiftVoucherUsers(response, mainActivityId, subActivityId, activityId);
entities.add(new ExcelExportEntity("工号", "loginname", 20));
entities.add(new ExcelExportEntity("姓名", "username", 20));
entities.add(new ExcelExportEntity("单位", "unitname", 20));
entities.add(new ExcelExportEntity("手机号", "mobile", 20));
try {
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), entities, list);
workbook.write(response.getOutputStream());
CommonDownloadUtil.download("导出未使用礼品券用户.xlsx", workbook, response);
} catch (IOException e) {
throw new RuntimeException(e);
}
} }
} }
@@ -1,66 +1,36 @@
package com.budwk.app.zhgh.activity.fitnesswalk.controller; package com.budwk.app.zhgh.activity.fitnesswalk.controller;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.annotation.SLog; import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.result.Result; import com.budwk.app.base.result.Result;
import com.budwk.app.base.service.BaseService; import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkStepManageService;
import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkActivity;
import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkStep;
import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkCommonService;
import com.budwk.app.zhgh.activity.fitnesswalk.utils.WeAppCloudUtil;
import com.budwk.app.zhgh.dayofficework.integral.model.IntegralDetail;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.nutz.aop.interceptor.ioc.TransAop; import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao; import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.integration.jedis.RedisService;
import org.nutz.ioc.aop.Aop; import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.Lang;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Ok;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.*; import java.util.*;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.stream.Collectors;
@IocBean @IocBean
@Ok("json") @Ok("json")
@ApiOperation("健步走步数管理")
@At("/platform/fitnessWalk/stepManage") @At("/platform/fitnessWalk/stepManage")
public class FitnessWalkStepManageController { public class FitnessWalkStepManageController {
@Inject @Inject
private Dao dao; private FitnessWalkStepManageService fitnessWalkStepManageService;
@Inject
private BaseService baseService;
@Inject
private RedisService redisService;
@Inject
private WeAppCloudUtil weAppCloudUtil;
@Inject
private FitnessWalkCommonService fitnessWalkCommonService;
@Inject
private Dao dao;
/** /**
* 用户上传一个近31天的步数 * 合并微信运动最近30天步数,按每天最大步数保存并计算积分。
* *
* @param activityId 活动id * @param activityId 健步走云端活动ID
* @param userId 用户id * @param userId 登录接口返回的用户ID
* @param monthSteps 步数(当天往前推30天) * @param monthSteps 微信运动步数JSON数组,每项包含step及秒级timestamp
* @return * @return Resultcode为0表示成功,data承载合并微信运动最近30天步数,按每天最大步数保存并计算积分结果,失败说明见msg
*/ */
@At @At
@Ok("json:full") @Ok("json:full")
@@ -68,336 +38,65 @@ public class FitnessWalkStepManageController {
@SLog(tag = "健步走步数管理", msg = "微信步数上传") @SLog(tag = "健步走步数管理", msg = "微信步数上传")
@ApiOperation("上传微信步数,再根据是否开启了积分,自动将步数转化成积分") @ApiOperation("上传微信步数,再根据是否开启了积分,自动将步数转化成积分")
public Result updateStepMonth(String activityId, String userId, String monthSteps) { public Result updateStepMonth(String activityId, String userId, String monthSteps) {
try { return fitnessWalkStepManageService.updateStepMonth(activityId, userId, monthSteps);
if (StrUtil.isBlank(userId) || StrUtil.isBlank(monthSteps) || StrUtil.isBlank(activityId)) {
return Result.error("必要参数未传递");
}
// 健步走的活动数据
FitnessWalkActivity activity = fitnessWalkCommonService.getActivity(activityId);
// 是否启用了积分
boolean isPoints = activity.getIsPoints() != null && activity.getIsPoints();
// 使用对象解构获取活动参数
final Integer standSteps = activity.getLotteryQualificationSteps();
final Integer standPoints = activity.getLotteryQualificationPoints();
final Integer otherSteps = activity.getOtherSteps();
final Integer otherPoints = activity.getOtherPoints();
final Integer maxPoints = activity.getMaxPoints();
String integralNotes = activity.getMasterActivityName() + "所获积分";
// 获取到的用户的步数数据
List<NutMap> steps = Json.fromJsonAsList(NutMap.class, monthSteps);
//判断数据是否完整 微信运动会在晚上10点多进行步数的更新 会导致31天前的步数获取变为0 所以这里去除掉第一个元素 即为31天前的数据 每次只保存最近30天的数据
if (Lang.isNotEmpty(steps) && steps.size() == 31) {
steps.remove(0);
}
// 传递过来的步数数据
List<FitnessWalkStep> wxSteps = steps.stream().map(v -> {
FitnessWalkStep step = new FitnessWalkStep();
step.setActivityId(activityId);
step.setUserId(userId);
step.setStep(v.getInt("step"));
// 计算积分,判断有没有设置,超过达标步数后,每达标XX步数,获得XX积分
int calculatedPoints = calculatePoints(isPoints, standSteps, standPoints, otherSteps, otherPoints, maxPoints, step.getStep());
step.setPoints(calculatedPoints);
DateTime date = DateUtil.parse(DateUtil.format(DateUtil.date(v.getLong("timestamp") * 1000), "yyyy-MM-dd"), "yyyy-MM-dd");
step.setApplyDate(date);
return step;
}).toList();
// 传递过来的所有日期的集合
List<Date> dateList = wxSteps.stream().map(FitnessWalkStep::getApplyDate).collect(Collectors.toList());
// 去数据库查询日期,这个玩意还要保证插入到数据库的单个日期只有一条,并且这个日期数据库之前有步数,传过来没步数那就要保留数据库的步数
// 上面日期集合数据库的步数
List<FitnessWalkStep> stepList = dao.query(FitnessWalkStep.class, Cnd.where("activityId", "=", activityId)
.and("userId", "=", userId).and("applyDate", "in", dateList));
// 这就是保留每天最大步数的集合,那这个集合里面applyDate就是唯一的了
List<FitnessWalkStep> dupStepList = new ArrayList<>(stepList.stream()
.collect(Collectors.toMap(FitnessWalkStep::getApplyDate, Function.identity(),
BinaryOperator.maxBy(Comparator.comparing(FitnessWalkStep::getStep))))
.values());
// 这是过滤的相同的applyDate的集合,这些数据要删除
List<String> delStepIds = stepList.stream()
.filter(step -> !dupStepList.contains(step))
.map(FitnessWalkStep::getId)
.collect(Collectors.toList());
// 数据库的数据 这个map就用于判断数据库的日期和传递过来日期的步数,两个是不是相等的,保留步数多的数据
Map<Date, FitnessWalkStep> dateStepMap = dupStepList.stream().collect(Collectors.toMap(FitnessWalkStep::getApplyDate, v -> v));
List<FitnessWalkStep> resultStepList = new ArrayList<>();
// 这里循环就是,循环的传递过来的数据
for (FitnessWalkStep step : wxSteps) {
// 数据库存储的步数
FitnessWalkStep walkStep = dateStepMap.get(step.getApplyDate());
// 如果数据库没有,那就要新增
if (Lang.isEmpty(walkStep)) {
resultStepList.add(step);
} else {
// 如果数据库有,那就要保留步数多的
if (walkStep.getStep() < step.getStep()) {
walkStep.setStep(step.getStep());
resultStepList.add(walkStep);
}
}
}
// 最后删除重复日期,更新步数数据
if (Lang.isNotEmpty(delStepIds)) {
dao.clear(FitnessWalkStep.class, Cnd.where("id", "in", delStepIds));
if (standSteps != null && standSteps > 0) {
// 删除积分明细
dao.clear(IntegralDetail.class, Cnd.where("id", "in", delStepIds));
}
}
if (Lang.isNotEmpty(resultStepList)) {
dao.insertOrUpdate(resultStepList);
if (standSteps != null && standSteps > 0) {
// 增加积分明细
int year = DateUtil.thisYear();
List<IntegralDetail> integralDetailList = resultStepList.stream().map(v -> {
IntegralDetail detail = new IntegralDetail();
detail.setId(v.getId());
detail.setYear(String.valueOf(year));
detail.setUserId(userId);
detail.setIntegral(String.valueOf(v.getPoints()));
detail.setIntegralNotes(integralNotes);
detail.setBizId(activityId);
detail.setIntegralTime(v.getApplyDate());
return detail;
}).toList();
List<IntegralDetail> list = integralDetailList.stream().filter(v -> !"0".equals(v.getIntegral())).toList();
if (Lang.isNotEmpty(list)) {
dao.insertOrUpdate(list);
}
}
}
return Result.success();
} catch (Exception e){
e.printStackTrace();
return Result.error("步数上传失败,请稍后重试,必要时请及时联系管理员");
}
} }
/** /**
* 小程序获取开始时间至今的步数 * 查询活动日期步数,返回step和毫秒级timestamp。
* *
* @param activityId * @param activityId 健步走云端活动ID
* @param userId * @param userId 登录接口返回的用户ID
* @return * @return Resultcode为0表示成功,data承载查询活动日期步数,返回step和毫秒级timestamp结果,失败说明见msg
*/ */
@At @At
@Ok("json:full") @Ok("json:full")
@ApiOperation("小程序获取开始时间至今的步数") @ApiOperation("小程序获取开始时间至今的步数")
public Result getActivityDateStep(String activityId, String userId) { public Result getActivityDateStep(String activityId, String userId) {
try { return fitnessWalkStepManageService.getActivityDateStep(activityId, userId);
Cnd cnd = Cnd.NEW();
FitnessWalkActivity activity = fitnessWalkCommonService.getActivity(activityId);
DateTime startTime = DateUtil.date(activity.getStartTime());
DateTime endTime = DateUtil.date(activity.getEndTime());
cnd.and("activityId", "=", activityId);
cnd.and("userId", "=", userId);
cnd.and("applyDate", ">=", startTime);
cnd.and("applyDate", "<=", endTime);
cnd.asc("applyDate");
cnd.groupBy("applyDate");
List<FitnessWalkStep> stepList = baseService.dao().query(FitnessWalkStep.class, cnd);
List<Map<String, ? extends Number>> collect = stepList.stream().map(v -> {
return Map.of("step", v.getStep(), "timestamp", v.getApplyDate().getTime());
}).collect(Collectors.toList());
return Result.success().addData(collect);
} catch (Exception e) {
return Result.error(e.getMessage());
}
} }
/**
* 按每日或自定义规则计算用户达标步数与完成进度。
*
* @param activityId 健步走云端活动ID
* @param userId 登录接口返回的用户ID
* @return Resultcode为0表示成功,data承载按每日或自定义规则计算用户达标步数与完成进度结果,失败说明见msg
*/
@At @At
@Ok("json:full") @Ok("json:full")
@ApiOperation("获取活动达标的进度条") @ApiOperation("获取活动达标的进度条")
public Result getActivityQualifyProgressBar(String activityId, String userId) { public Result getActivityQualifyProgressBar(String activityId, String userId) {
NutMap resultMap = NutMap.NEW(); return fitnessWalkStepManageService.getActivityQualifyProgressBar(activityId, userId);
FitnessWalkActivity activity = fitnessWalkCommonService.getActivity(activityId);
//计步的抽奖模式 everyday custom
String lotteryMode = activity.getLotteryMode();
if ("everyday".equals(lotteryMode)) {
FitnessWalkActivity.DayLotteryRule dayLotteryRule = activity.getDayLotteryRule();
//每日抽奖资格步数
Integer lotteryQualificationStep = dayLotteryRule.getLotteryQualificationStep();
FitnessWalkStep userWalkStep = baseService.dao().fetch(FitnessWalkStep.class, Cnd.where("userId", "=", userId)
.and("DATE( applyDate )", "=", DateUtil.today()).and("activityId", "=", activityId));
int complianceDay = baseService.dao().count(FitnessWalkStep.class, Cnd.where("userId", "=", userId)
.and("DATE( applyDate )", "=", DateUtil.today()).and("activityId", "=", activityId)
.and("step", ">", lotteryQualificationStep));
// 今天的步数
Integer thisDayStep = userWalkStep.getStep();
// 去计算达标的百分比
BigDecimal lotteryQualificationStepBig = new BigDecimal(lotteryQualificationStep);
BigDecimal thisDayStepBig = new BigDecimal(thisDayStep);
//达标的小数,保留四位
BigDecimal divide = thisDayStepBig.divide(lotteryQualificationStepBig, 4, RoundingMode.HALF_UP);
BigDecimal percentValue = divide.multiply(new BigDecimal("100"));
// 格式化为两位小数
DecimalFormat decimalFormat = new DecimalFormat("#.##");
//百分数
String formattedPercent = decimalFormat.format(percentValue);
long betweenDay = DateUtil.date(activity.getStartTime()).between(DateUtil.date(activity.getEndTime()), DateUnit.DAY);
NutMap map = new NutMap();
map.setv("mode", "everyDayLottery");
//当前达标步数
map.setv("userStep", thisDayStep);
//达标总步数
map.setv("complianceSumStep", lotteryQualificationStep);
//达标比例
map.setv("complianceProportion", Integer.parseInt(formattedPercent));
//活动天数
map.setv("betweenDay", betweenDay);
//达标天数
map.setv("complianceDay", complianceDay);
resultMap.addv("everyDayLotteryMode", map);
} else if ("custom".equals(lotteryMode)) {
List<FitnessWalkActivity.CustomLotteryRule> customLotteryRules = activity.getCustomLotteryRules();
List<FitnessWalkStep> userWalkSteps = baseService.dao().
query(FitnessWalkStep.class, Cnd.where("userId", "=", userId)
.and("activityId", "=", activityId)
.and("DATE(applyDate)", ">=", DateUtil.format(DateUtil.date(activity.getStartTime()), "yyyy-MM-dd"))
.and("DATE(applyDate)", "<=", DateUtil.format(DateUtil.date(activity.getEndTime()), "yyyy-MM-dd"))
);
List<NutMap> result = new ArrayList<>();
for (FitnessWalkActivity.CustomLotteryRule rule : customLotteryRules) {
NutMap nutMap = NutMap.NEW();
List<FitnessWalkStep> partSteps = userWalkSteps.stream()
.filter(s -> (DateUtil.compare(s.getApplyDate(), rule.getStartDate()) >= 0 && DateUtil.compare(s.getApplyDate(), rule.getEndDate()) <= 0))
.toList();
Integer lotteryQualificationDay = rule.getLotteryQualificationDay();
Integer lotteryQualificationStep = rule.getLotteryQualificationStep();
if (lotteryQualificationDay != null && lotteryQualificationStep != null) {
//每天步数
nutMap.put("mode", "customLotteryEveryDayStepMode");
//用户总达标步数
nutMap.put("userSumStep", partSteps.stream().filter(s -> DateUtil.compare(s.getApplyDate(), new Date(), "yyyy-MM-dd") == 0).findFirst().map(s -> s.getStep()).orElse(0));
//今天达标步数
nutMap.put("complianceStep", lotteryQualificationStep);
//总达标步数
nutMap.put("complianceSumStep", lotteryQualificationDay * lotteryQualificationStep);
//用户当前达标总天数
nutMap.put("userComplianceSumDay", partSteps.stream().filter(s -> s.getStep() > lotteryQualificationStep).count());
//总达标天数
nutMap.put("complianceSumDay", lotteryQualificationDay);
} else if (lotteryQualificationDay == null && lotteryQualificationStep != null) {
//总步数
nutMap.put("mode", "customLotterySumStepMode");
//用户总达标步数
nutMap.put("userSumStep", partSteps.stream().mapToInt(FitnessWalkStep::getStep).sum());
//总达标步数
nutMap.put("complianceSumStep", lotteryQualificationStep);
nutMap.put("title", DateUtil.format(rule.getStartDate(), "MM月dd日") + "" + DateUtil.format(rule.getEndDate(), "MM月dd日"));
}
result.add(nutMap);
}
resultMap.addv("customLotteryMode", result);
}
return Result.success().addData(resultMap);
} }
/** /**
* 获取用户未读的奖 * 查询指定用户在活动中的中奖记录。
* *
* @param activityId * @param activityId 健步走云端活动ID
* @param userId * @param userId 登录接口返回的用户ID
* @return * @return Resultcode为0表示成功,data承载查询指定用户在活动中的中奖记录结果,失败说明见msg
*/ */
@At @At
@Ok("json:full") @Ok("json:full")
@ApiOperation("获取用户未读的奖") @ApiOperation("获取用户未读的奖")
public Result winningRecord(String activityId, String userId) { public Result winningRecord(String activityId, String userId) {
Sql sql = Sqls.create(""" return fitnessWalkStepManageService.winningRecord(activityId, userId);
select awardName,startDate,endDate from fitness_walk_award_user where activityId=@activityId and userId=@userId and isRead=@isRead
""").setParam("activityId",activityId).setParam("userId", userId).setParam("isRead",true);
/* List<FitnessWalkAwardUser> awardUsers = baseService.dao().query(FitnessWalkAwardUser.class,
Cnd.where("activityId", "=", activityId)
.and("userId", "=", userId).and("isRead", "=", true));*/
return Result.success(baseService.listMap(sql));
}
/**
* 计算积分
* @param isPointsEnabled
* @param standSteps
* @param standPoints
* @param otherSteps
* @param otherPoints
* @param maxPoints
* @param actualSteps
* @return
*/
private int calculatePoints(boolean isPointsEnabled,
Integer standSteps, Integer standPoints,
Integer otherSteps, Integer otherPoints,
Integer maxPoints, int actualSteps) {
// 基础条件检查
if (!isPointsEnabled || standSteps == null || standPoints == null || actualSteps < standSteps) {
return 0;
}
// 计算基础积分
int totalPoints = standPoints;
// 计算额外积分
if (hasExtraPoints(otherSteps, otherPoints)) {
int extraSteps = actualSteps - standSteps;
int extraPoints = (extraSteps / otherSteps) * otherPoints;
totalPoints += extraPoints;
}
// 应用积分上限
if (hasMaxPointsLimit(maxPoints)) {
return Math.min(totalPoints, maxPoints);
}
return totalPoints;
} }
/** /**
* 检查是否有额外积分规则 * 标记活动奖项已读,沿用源版活动维度更新范围。
*
* @param activityId 健步走云端活动ID
* @return Resultcode为0表示成功,data承载标记活动奖项已读,沿用源版活动维度更新范围结果,失败说明见msg
*/ */
private boolean hasExtraPoints(Integer otherSteps, Integer otherPoints) { @At
return otherSteps != null && otherPoints != null && otherSteps > 0 && otherPoints > 0; @Ok("json:full")
public Result hasReadAward(String activityId) {
return fitnessWalkStepManageService.hasReadAward(activityId);
} }
/** /**
* 检查是否有积分上限 * 检查是否有积分上限
*/ */
private boolean hasMaxPointsLimit(Integer maxPoints) {
return maxPoints != null && maxPoints > 0;
}
} }
@@ -1,45 +1,23 @@
package com.budwk.app.zhgh.activity.fitnesswalk.controller; package com.budwk.app.zhgh.activity.fitnesswalk.controller;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.annotation.SLog; import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm; import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result; import com.budwk.app.base.result.Result;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.base.utils.CommonDownloadUtil;
import com.budwk.app.zhgh.activity.fitnesswalk.contants.FitnessWalkMode; import com.budwk.app.zhgh.activity.fitnesswalk.contants.FitnessWalkMode;
import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkAwardUser;
import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkRaffleRules; import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkRaffleRules;
import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkRaffleUser;
import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkCommonService; import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkCommonService;
import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkStepRaffleService; import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkStepRaffleService;
import com.budwk.app.zhgh.dayofficework.integral.model.IntegralDetail;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.apache.poi.ss.usermodel.Workbook;
import org.nutz.aop.interceptor.ioc.TransAop; import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao; import org.nutz.dao.Dao;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.ioc.aop.Aop; import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param; import org.nutz.mvc.annotation.Param;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
/** /**
* @version 1.0 * @version 1.0
@@ -48,238 +26,166 @@ import java.util.List;
* @Date 2024/12/27 14:43 * @Date 2024/12/27 14:43
* @注释 健步走抽奖控制器 * @注释 健步走抽奖控制器
*/ */
@IocBean
@Ok("json") @Ok("json")
@ApiOperation("健步走手动抽奖") @IocBean
@At("/platform/fitnessWalk/stepRaffle") @At("/platform/fitnessWalk/stepRaffle")
public class FitnessWalkStepRaffleController { public class FitnessWalkStepRaffleController {
@Inject @Inject
private Dao dao; private Dao dao;
@Inject
private BaseService baseService;
@Inject @Inject
private FitnessWalkCommonService fitnessWalkCommonService; private FitnessWalkCommonService fitnessWalkCommonService;
@Inject @Inject
private FitnessWalkStepRaffleService fitnessWalkStepRaffleService; private FitnessWalkStepRaffleService fitnessWalkStepRaffleService;
@At("") @At("")
@Ok("beetl:/platform/zhgh/activity/fitnesswalk/stepRaffle.html") @Ok("beetl:/platform/zhgh/activity/fitnesswalk/stepRaffle.html")
@SaCheckPermission("fitnessWalk.stepRaffle") @SaCheckPermission("fitnessWalk.stepRaffle")
public void index() { public void index() {
} }
/**
* 按活动达标条件分页检索具备抽奖资格的人员。
*
* @param pageForm 分页、查询字段和排序参数,页码从1开始
* @param activityId 健步走云端活动ID
* @param unionId 分工会ID,空值表示不追加筛选,已有数据权限仍生效
* @param unitId 单位ID,空值表示不追加单位筛选
* @return Resultcode为0表示成功,data承载按活动达标条件分页检索具备抽奖资格的人员结果,失败说明见msg
*/
@At @At
@ApiOperation("获取抽奖列表")
@SaCheckPermission("fitnessWalk.stepRaffle") @SaCheckPermission("fitnessWalk.stepRaffle")
@ApiOperation("获取抽奖列表")
public Result pageData(PageForm pageForm, public Result pageData(PageForm pageForm,
@Param("activityId") String activityId, @Param("activityId") String activityId,
@Param("unionId") String unionId, @Param("unionId") String unionId,
@Param("unitId") String unitId){ @Param("unitId") String unitId){
Sql sql = fitnessWalkStepRaffleService.getRaffleSql(pageForm, activityId, unionId, unitId); return fitnessWalkStepRaffleService.pageData(pageForm, activityId, unionId, unitId);
Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
return Result.success().addData(pagination);
} }
@At @At
@SaCheckPermission("fitnessWalk.stepRaffle")
@ApiOperation("获取活动级联数据") @ApiOperation("获取活动级联数据")
@SaCheckPermission("fitnessWalk.stepRaffle")
public Result getCascadersActivity(@Param("year") int year) { public Result getCascadersActivity(@Param("year") int year) {
return Result.success().addData(fitnessWalkCommonService.cascaderActivity(year, FitnessWalkMode.STEP_COUNT)); return Result.success(fitnessWalkCommonService.cascaderActivity(year, FitnessWalkMode.STEP_COUNT));
} }
@At
@Aop(TransAop.READ_COMMITTED)
@ApiOperation("设置抽奖规则,并抽奖")
@SLog(tag = "健步走手动抽奖", msg = "设置抽奖规则并抽奖")
@SaCheckPermission("fitnessWalk.stepRaffle")
public Result saveRaffle(FitnessWalkRaffleRules fitnessWalkRaffleRules){
baseService.dao().insertOrUpdate(fitnessWalkRaffleRules);
fitnessWalkStepRaffleService.manualLottery(fitnessWalkRaffleRules.getActivityId());
return null;
}
@At
@ApiOperation("获取抽奖规则")
@SaCheckPermission("fitnessWalk.stepRaffle")
public Result getRaffle(String activityId){
FitnessWalkRaffleRules raffleRules = baseService.dao().fetch(FitnessWalkRaffleRules.class, Cnd.where("activityId", "=", activityId));
return Result.success().addData(raffleRules);
}
/** /**
* 小程序获取奖项信息 * 保存手动抽奖规则并按源版排名奖和达标奖规则执行抽奖。
* @param activityId *
* @return * @param fitnessWalkRaffleRules 活动ID及手动抽奖规则,奖项配置沿用源版本
* @return Resultcode为0表示成功,data承载保存手动抽奖规则并按源版排名奖和达标奖规则执行抽奖结果,失败说明见msg
*/
@At
@Aop(TransAop.READ_COMMITTED)
@SaCheckPermission("fitnessWalk.stepRaffle")
@ApiOperation("设置抽奖规则,并抽奖")
@SLog(tag = "健步走手动抽奖", msg = "设置抽奖规则并抽奖")
public Result saveRaffle(FitnessWalkRaffleRules fitnessWalkRaffleRules){
return fitnessWalkStepRaffleService.saveRaffle(fitnessWalkRaffleRules);
}
/**
* 读取活动已保存的手动抽奖规则。
*
* @param activityId 健步走云端活动ID
* @return Resultcode为0表示成功,data承载读取活动已保存的手动抽奖规则结果,失败说明见msg
*/
@At
@SaCheckPermission("fitnessWalk.stepRaffle")
@ApiOperation("获取抽奖规则")
public Result getRaffle(String activityId){
return fitnessWalkStepRaffleService.getRaffle(activityId);
}
/**
* 读取活动可用奖项及对应中奖配置。
*
* @param activityId 健步走云端活动ID
* @return Resultcode为0表示成功,data承载读取活动可用奖项及对应中奖配置结果,失败说明见msg
*/ */
@At @At
@ApiOperation("小程序获取奖项信息") @ApiOperation("小程序获取奖项信息")
public Result getAwardList(String activityId){ public Result getAwardList(String activityId){
List<NutMap> activityAwardList = fitnessWalkStepRaffleService.getActivityAwardList(activityId); return fitnessWalkStepRaffleService.getAwardList(activityId);
return Result.success().addData(activityAwardList);
} }
/** /**
* 小程序获取自己的中奖信息 * 返回用户奖项名称和剩余抽奖次数。
* @return *
* @param activityId 健步走云端活动ID
* @param userId 登录接口返回的用户ID
* @return Resultcode为0表示成功,data承载返回用户奖项名称和剩余抽奖次数结果,失败说明见msg
*/ */
@At @At
@ApiOperation("小程序获取自己的中奖信息") @ApiOperation("小程序获取自己的中奖信息")
public Result getAwardInfo(String activityId, String userId){ public Result getAwardInfo(String activityId, String userId){
Dao dao = fitnessWalkStepRaffleService.dao(); return fitnessWalkStepRaffleService.getAwardInfo(activityId, userId);
FitnessWalkAwardUser awardUser = dao.fetch(FitnessWalkAwardUser.class, Cnd.where("activityId", "=", activityId).and("userId", "=", userId));
FitnessWalkRaffleUser raffleUser = dao.fetch(FitnessWalkRaffleUser.class, Cnd.where("activityId", "=", activityId).and("userId", "=", userId));
NutMap map = NutMap.NEW();
if (Lang.isNotEmpty(raffleUser) && !raffleUser.getIsRaffle()) {
if (Lang.isNotEmpty(awardUser)) {
map.put("awardName", awardUser.getAwardName());
} else {
map.put("awardName", "没有中奖");
}
map.put("raffleNum", 1);
} else {
map.put("raffleNum", 0);
}
return Result.success().addData(map);
} }
/** /**
* 小程序获取查询是否可以抽奖 * 判断用户是否存在尚未使用的抽奖资格。
* @return *
* @param activityId 健步走云端活动ID
* @param userId 登录接口返回的用户ID
* @return Resultcode为0表示成功,data承载判断用户是否存在尚未使用的抽奖资格结果,失败说明见msg
*/ */
@At @At
@ApiOperation("小程序获取查询是否可以抽奖") @ApiOperation("小程序获取查询是否可以抽奖")
public Result checkRaffle(String activityId, String userId){ public Result checkRaffle(String activityId, String userId){
Dao dao = fitnessWalkStepRaffleService.dao(); return fitnessWalkStepRaffleService.checkRaffle(activityId, userId);
FitnessWalkRaffleUser raffleUser = dao.fetch(FitnessWalkRaffleUser.class,
Cnd.where("activityId", "=", activityId)
.and("userId", "=", userId));
if (Lang.isNotEmpty(raffleUser)) {
return raffleUser.getIsRaffle() ? Result.error() : Result.success();
} else {
return Result.error();
}
} }
/** /**
* 抽奖成功后,修改数据库状态 * 标记奖项和抽奖资格已读并登记奖项积分。
* @param activityId *
* @param userId * @param activityId 健步走云端活动ID
* @return * @param userId 登录接口返回的用户ID
* @return Resultcode为0表示成功,data承载标记奖项和抽奖资格已读并登记奖项积分结果,失败说明见msg
*/ */
@At @At
@Aop(TransAop.READ_COMMITTED) @Aop(TransAop.READ_COMMITTED)
@ApiOperation("抽奖成功后,修改数据库状态") @ApiOperation("抽奖成功后,修改数据库状态")
@SLog(tag = "健步走手动抽奖", msg = "抽奖成功后,修改数据库状态") @SLog(tag = "健步走手动抽奖", msg = "抽奖成功后,修改数据库状态")
public Result updateUserAward(String activityId, String userId) { public Result updateUserAward(String activityId, String userId) {
fitnessWalkStepRaffleService.dao().update(FitnessWalkAwardUser.class, return fitnessWalkStepRaffleService.updateUserAward(activityId, userId);
Chain.make("isRead", true).add("applyDate", DateUtil.date()),
Cnd.where("activityId", "=", activityId).and("userId", "=", userId));
fitnessWalkStepRaffleService.dao().update(FitnessWalkRaffleUser.class,
Chain.make("isRaffle", true),
Cnd.where("activityId", "=", activityId).and("userId", "=", userId));
// 增加积分
FitnessWalkAwardUser awardUser = dao.fetch(FitnessWalkAwardUser.class, Cnd.where("activityId", "=", activityId).and("userId", "=", userId));
IntegralDetail detail = new IntegralDetail();
detail.setId(awardUser.getId());
detail.setYear(String.valueOf(DateUtil.thisYear()));
detail.setUserId(awardUser.getUserId());
detail.setIntegral(String.valueOf(awardUser.getPoints()));
detail.setIntegralNotes(awardUser.getAwardName());
detail.setBizId(awardUser.getId());
detail.setIntegralTime(DateUtil.date());
dao.insert(detail);
return null;
} }
/**
* 按活动和奖项条件导出中奖人员。
*
* @param searchKeyword 姓名、工号或当前查询字段的检索内容
* @param activityId 健步走云端活动ID
* @param lotteryTime 中奖奖项筛选值,沿用页面提交格式
* @param response HTTP响应,用于写入XSSF格式Excel文件流
* 无返回对象,通过response写出Excel文件流。
*/
@At @At
@Ok("void") @Ok("void")
@ApiOperation("导出中奖名单")
@SaCheckPermission("fitnessWalk.stepRaffle") @SaCheckPermission("fitnessWalk.stepRaffle")
@ApiOperation("导出中奖名单")
public void exportAwardExcel(String searchKeyword, String activityId, public void exportAwardExcel(String searchKeyword, String activityId,
String lotteryTime, HttpServletResponse response) { String lotteryTime, HttpServletResponse response) {
Cnd cnd = Cnd.NEW(); fitnessWalkStepRaffleService.exportAwardExcel(searchKeyword, activityId, lotteryTime, response);
cnd.andEX("activityId", "=", activityId);
cnd.andEX("awardName", "=", lotteryTime);
if (StrUtil.isNotBlank(searchKeyword)) {
SqlExpressionGroup seg = new SqlExpressionGroup();
seg.orLike("username", searchKeyword);
seg.orLike("loginName", searchKeyword);
cnd.and(seg);
}
cnd.and("isRead", "=", true);
List<FitnessWalkAwardUser> list = fitnessWalkCommonService.dao().query(FitnessWalkAwardUser.class, cnd);
for (FitnessWalkAwardUser awardUser : list) {
awardUser.setApplyDate(awardUser.getApplyDate());
}
List<ExcelExportEntity> entityList = new ArrayList<>();
ExcelExportEntity no = new ExcelExportEntity("序号", "no", 10);
no.setFormat("isAddIndex");
entityList.add(no);
entityList.add(new ExcelExportEntity("工号", "loginName", 20));
entityList.add(new ExcelExportEntity("姓名", "username", 20));
entityList.add(new ExcelExportEntity("分工会", "unionName", 20));
entityList.add(new ExcelExportEntity("单位", "unitName", 40));
entityList.add(new ExcelExportEntity("奖项名称", "awardName", 20));
entityList.add(new ExcelExportEntity("中奖时间", "applyDate2", 20));
try {
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entityList, list);
workbook.write(response.getOutputStream());
CommonDownloadUtil.download("健步走中奖人员名单.xlsx", workbook, response);
} catch (Exception e) {
e.printStackTrace();
}
} }
/**
* 导出符合活动达标条件的抽奖候选人员。
*
* @param searchKeyword 姓名、工号或当前查询字段的检索内容
* @param activityId 健步走云端活动ID
* @param unionId 分工会ID,空值表示不追加筛选,已有数据权限仍生效
* @param unitId 单位ID,空值表示不追加单位筛选
* @param response HTTP响应,用于写入XSSF格式Excel文件流
* 无返回对象,通过response写出Excel文件流。
*/
@At @At
@Ok("void") @Ok("void")
@ApiOperation("导出健步走达标人员名单")
@SaCheckPermission("fitnessWalk.stepRaffle") @SaCheckPermission("fitnessWalk.stepRaffle")
@ApiOperation("导出健步走达标人员名单")
public void exportExcel(String searchKeyword, String activityId, String unionId, public void exportExcel(String searchKeyword, String activityId, String unionId,
String unitId, HttpServletResponse response) { String unitId, HttpServletResponse response) {
PageForm pageForm = new PageForm(); fitnessWalkStepRaffleService.exportExcel(searchKeyword, activityId, unionId, unitId, response);
pageForm.setSearchKeyword(searchKeyword);
Sql sql = fitnessWalkStepRaffleService.getRaffleSql(pageForm, activityId, unionId, unitId);
List<NutMap> list = fitnessWalkStepRaffleService.listMap(sql);
List<ExcelExportEntity> entityList = new ArrayList<>();
ExcelExportEntity no = new ExcelExportEntity("序号", "no", 10);
no.setFormat("isAddIndex");
entityList.add(no);
entityList.add(new ExcelExportEntity("工号", "loginname", 20));
entityList.add(new ExcelExportEntity("姓名", "username", 20));
entityList.add(new ExcelExportEntity("分工会", "unionname", 20));
entityList.add(new ExcelExportEntity("单位", "unitname", 40));
entityList.add(new ExcelExportEntity("达标天数", "standardsDays", 20));
entityList.add(new ExcelExportEntity("步数", "total_steps", 20));
try {
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entityList, list);
workbook.write(response.getOutputStream());
CommonDownloadUtil.download("健步走达标人员名单.xlsx", workbook, response);
} catch (Exception e) {
e.printStackTrace();
}
} }
} }
@@ -1,51 +1,32 @@
package com.budwk.app.zhgh.activity.fitnesswalk.controller; package com.budwk.app.zhgh.activity.fitnesswalk.controller;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.budwk.app.base.annotation.SLog; import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm; import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result; import com.budwk.app.base.result.Result;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.base.utils.CommonDownloadUtil;
import com.budwk.app.zhgh.activity.fitnesswalk.contants.FitnessWalkMode; import com.budwk.app.zhgh.activity.fitnesswalk.contants.FitnessWalkMode;
import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkActivity;
import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkCommonService; import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkCommonService;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap; import org.nutz.lang.Strings;
import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param; import org.nutz.mvc.annotation.Param;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletResponse;
/** /**
* 步数排行榜 * 步数排行榜
*/ */
@Slf4j
@IocBean @IocBean
@Slf4j
@Ok("json") @Ok("json")
@ApiOperation("健步走步数排行榜")
@At("/platform/fitnessWalk/stepRanking") @At("/platform/fitnessWalk/stepRanking")
public class FitnessWalkStepRankingController { public class FitnessWalkStepRankingController {
@Inject
private BaseService baseService;
@Inject @Inject
private FitnessWalkCommonService fitnessWalkCommonService; private FitnessWalkCommonService fitnessWalkCommonService;
@@ -55,220 +36,178 @@ public class FitnessWalkStepRankingController {
public void index() { public void index() {
} }
/**
* 查询PC端步数排行榜。
*
* @param pageForm 分页及姓名、工号查询参数,页码从1开始
* @param activityId 活动ID,用于限定排行榜所属活动
* @param unionId 分工会ID,空字符串表示全部分工会
* @param unitId 单位ID,空字符串表示全部单位
* @param mode 排行范围:today、oneMonth、halfYear、oneYear、activityall 兼容原活动期间参数
* @param sex 性别:空字符串表示全部,男或女表示指定性别
* @param ageRange 年龄段:空字符串表示全体,under40、41to50、51to55、over55 表示指定年龄段;over55 表示年龄大于55岁
* @return Resultdata.list 为排行榜数据,data.totalCount 为符合条件的总人数
*/
@At @At
@ApiOperation("获取步数排行榜")
@SaCheckPermission("fitnessWalk.stepRanking") @SaCheckPermission("fitnessWalk.stepRanking")
@ApiOperation("获取步数排行榜")
public Result pageData(PageForm pageForm, public Result pageData(PageForm pageForm,
@Param("activityId") String activityId, @Param("activityId") String activityId,
@Param("unionId") String unionId, @Param("unionId") String unionId,
@Param("unitId") String unitId, @Param("unitId") String unitId,
@Param("mode") String mode) { @Param("mode") String mode,
Pagination pagination = fitnessWalkCommonService.getStepRankingPagination(pageForm, activityId, unionId, unitId, mode); @Param("sex") String sex,
return Result.success().addData(pagination); @Param("ageRange") String ageRange) {
if (Strings.isNotBlank(sex) && !List.of("", "").contains(sex)) {
return Result.error("性别筛选参数不正确");
}
if (Strings.isNotBlank(ageRange) && !List.of("under40", "41to50", "51to55", "over55").contains(ageRange)) {
return Result.error("年龄段筛选参数不正确");
}
String actualMode = Strings.isBlank(mode) ? "today" : mode;
if (!List.of("today", "oneMonth", "halfYear", "oneYear", "activity", "all").contains(actualMode)) {
return Result.error("时间范围参数不正确");
}
return Result.success(fitnessWalkCommonService.getStepRankingPagination(
pageForm,
activityId,
unionId,
unitId,
actualMode,
sex,
ageRange
));
} }
/** /**
* 获取所有教工 今天的步数及活动时间范围内的步数 * 查询小程序筛选排行榜。
* *
* @param activityId * @param activityId 活动ID,用于限定健步走活动数据
* @param mode day:今天 all:所有 * @param userId 当前登录用户ID,用于返回“我的指标”和“我的名次”
* @return {@link Object} * @param rankingType 排行指标:totalSteps 累计步数、completionRate 目标完成率、complianceDays 达标天数
* @param sex 性别筛选:空字符串表示全部,男或女表示指定性别
* @param ageRange 年龄段:空字符串表示全体,under40、41to50、51to55、over55 表示指定年龄段;over55 表示年龄大于55岁
* @param timeRange 时间范围:today 当日、oneMonth 近1个月、halfYear 近半年、oneYear 近1年、activity 活动开始至今
* @param pageNumber 页码,从1开始
* @param pageSize 每页条数,最大50条
* @return Resultdata 包含 list 排名列表、分页信息以及 currentUser 当前用户指标
*/ */
@At @At
@Ok("json:full") @Ok("json:full")
@SLog(type = "校工会特色活动", tag = "健身走-计步步数排行榜", msg = "小程序接口(获取活动范围内步数排行榜)", param = true, result = true)
@ApiOperation("获取今日步数及活动范围内步数") @ApiOperation("获取今日步数及活动范围内步数")
@SLog(type = "校工会特色活动", tag = "健身走-计步步数排行榜", msg = "小程序接口(获取今日步数及活动范围内步数)") public Result getUserStepRanking(String activityId,
public Result getUserStepRanking(String activityId, String mode, Integer pageNumber, Integer pageSize) { String userId,
if ("day".equals(mode)) { String rankingType,
Sql sql = Sqls.create(""" String sex,
SELECT String ageRange,
t.step, String timeRange,
t.applyDate, Integer pageNumber,
u.username Integer pageSize) {
FROM if (Strings.isBlank(activityId) || Strings.isBlank(userId)) {
`fitness_walk_step` t return Result.error("活动ID和用户ID不能为空");
LEFT JOIN sys_user u ON u.id = t.userId }
WHERE
t.activityId = @activityId
AND t.applyDate = @today
GROUP BY u.id
ORDER BY t.step DESC
""");
sql.setParam("activityId", activityId);
sql.setParam("today", DateUtil.today());
Pagination pagination = baseService.listPageMap(pageNumber, 50, sql);
return Result.success().addData(pagination);
} else if ("week".equals(mode)) {
// 周榜
Date startOfWeek = DateUtil.beginOfWeek(new Date());
Date endOfWeek = DateUtil.endOfWeek(new Date());
Sql sql = Sqls.create(""" String actualRankingType = Strings.isBlank(rankingType) ? "totalSteps" : rankingType;
SELECT if (!List.of("totalSteps", "completionRate", "complianceDays").contains(actualRankingType)) {
t.userId, return Result.error("不支持的排行榜指标");
sum( t.step ) AS step, }
u.username if (Strings.isNotBlank(sex) && !List.of("", "").contains(sex)) {
FROM return Result.error("性别筛选参数不正确");
`fitness_walk_step` t }
LEFT JOIN sys_user u ON u.id = t.userId if (Strings.isNotBlank(ageRange) && !List.of("under40", "41to50", "51to55", "over55").contains(ageRange)) {
WHERE return Result.error("年龄段筛选参数不正确");
t.activityId = @activityId }
AND t.applyDate >= @startTime String actualTimeRange = Strings.isBlank(timeRange) ? "today" : timeRange;
AND t.applyDate <= @endTime if (!List.of("today", "oneMonth", "halfYear", "oneYear", "activity").contains(actualTimeRange)) {
GROUP BY return Result.error("时间范围参数不正确");
t.userId }
ORDER BY
step DESC int actualPageNumber = pageNumber == null || pageNumber < 1 ? 1 : pageNumber;
"""); int actualPageSize = pageSize == null || pageSize < 1 ? 20 : Math.min(pageSize, 50);
sql.setParam("activityId", activityId); try {
sql.setParam("startTime", startOfWeek); return Result.success(fitnessWalkCommonService.getUserStepRanking(
sql.setParam("endTime", endOfWeek); activityId,
Pagination pagination = baseService.listPageMap(pageNumber, 50, sql); userId,
return Result.success().addData(pagination); actualRankingType,
} else if ("month".equals(mode)) { sex,
// 月榜 ageRange,
Date firstDayOfMonth = DateUtil.beginOfMonth(new Date()); actualTimeRange,
Date lastDayOfMonth = DateUtil.endOfMonth(new Date()); actualPageNumber,
Sql sql = Sqls.create(""" actualPageSize
SELECT ));
t.userId, } catch (IllegalArgumentException e) {
sum( t.step ) AS step, return Result.error(e.getMessage());
u.username
FROM
`fitness_walk_step` t
LEFT JOIN sys_user u ON u.id = t.userId
WHERE
t.activityId = @activityId
AND t.applyDate >= @startTime
AND t.applyDate <= @endTime
GROUP BY
t.userId
ORDER BY
step DESC
""");
sql.setParam("activityId", activityId);
sql.setParam("startTime", firstDayOfMonth);
sql.setParam("endTime", lastDayOfMonth);
Pagination pagination = baseService.listPageMap(pageNumber, 50, sql);
return Result.success().addData(pagination);
} else if ("all".equals(mode)) {
// 总达标榜
FitnessWalkActivity activity = fitnessWalkCommonService.getActivity(activityId);
DateTime startTime = DateUtil.date(activity.getStartTime());
DateTime endTime = DateUtil.date(activity.getEndTime());
Sql sql = Sqls.create("""
SELECT
SUM(sub.max_step) AS step,
u.username
FROM (
SELECT
userId,
activityId,
applyDate,
MAX(step) AS max_step
FROM
fitness_walk_step
WHERE
activityId = @activityId
AND applyDate >= @startTime AND applyDate <= @endTime
GROUP BY
userId,
activityId,
applyDate
) sub
left join `user` u ON u.id = sub.userId
GROUP BY
userId
ORDER BY
step desc
""");
sql.setParam("activityId", activityId);
sql.setParam("startTime", startTime);
sql.setParam("endTime", endTime);
Pagination pagination = baseService.listPageMap(pageNumber, 50, sql);
return Result.success().addData(pagination);
} else if ("points".equals(mode)) {
// 积分榜
FitnessWalkActivity activity = fitnessWalkCommonService.getActivity(activityId);
DateTime startTime = DateUtil.date(activity.getStartTime());
DateTime endTime = DateUtil.date(activity.getEndTime());
Sql sql = Sqls.create("""
SELECT
SUM(sub.max_step) AS step,
u.username
FROM (
SELECT
userId,
activityId,
applyDate,
MAX(points) AS max_step
FROM
fitness_walk_step
WHERE
activityId = @activityId
AND applyDate >= @startTime AND applyDate <= @endTime
GROUP BY
userId,
activityId,
applyDate
) sub
left join `user` u ON u.id = sub.userId
GROUP BY
userId
ORDER BY
step desc
""");
sql.setParam("activityId", activityId);
sql.setParam("startTime", startTime);
sql.setParam("endTime", endTime);
Pagination pagination = baseService.listPageMap(pageNumber, 50, sql);
return Result.success().addData(pagination);
} else {
return null;
} }
} }
/**
* 导出活动有效期内的参与人员累计步数。
*
* @param searchName 查询字段,使用页面提供的字段名
* @param searchKeyword 姓名、工号或当前查询字段的检索内容
* @param activityId 健步走云端活动ID
* @param unionId 分工会ID,空值表示不追加筛选,已有数据权限仍生效
* @param unitId 单位ID,空值表示不追加单位筛选
* @param response HTTP响应,用于写入XSSF格式Excel文件流
* 无返回对象,通过response写出Excel文件流。
*/
@At @At
@Ok("void") @Ok("void")
@ApiOperation("步数排行榜导出")
@SaCheckPermission("fitnessWalk.stepRanking")
@SLog(type = "校工会特色活动", tag = "健身走-计步步数排行榜", msg = "步数排行榜导出", param = true, result = true) @SLog(type = "校工会特色活动", tag = "健身走-计步步数排行榜", msg = "步数排行榜导出", param = true, result = true)
@SaCheckPermission("fitnessWalk.stepRanking")
public void exportExcel2(@Param("searchName") String searchName,
@Param("searchKeyword") String searchKeyword,
@Param("activityId") String activityId,
@Param("unionId") String unionId,
@Param("unitId") String unitId,
HttpServletResponse response) {
fitnessWalkCommonService.exportTotalSteps(searchName, searchKeyword, activityId, unionId, unitId, response);
}
/**
* 按时间、性别和年龄筛选导出当前步数排行榜。
*
* @param searchName 查询字段,使用页面提供的字段名
* @param searchKeyword 姓名、工号或当前查询字段的检索内容
* @param activityId 健步走云端活动ID
* @param unionId 分工会ID,空值表示不追加筛选,已有数据权限仍生效
* @param unitId 单位ID,空值表示不追加单位筛选
* @param mode 时间范围:today、oneMonth、halfYear、oneYear或activity
* @param sex 性别筛选,男、女或空字符串
* @param ageRange 年龄段筛选,under40、41to50、51to55、over55或空字符串
* @param response HTTP响应,用于写入XSSF格式Excel文件流
* 无返回对象,通过response写出Excel文件流。
*/
@At
@Ok("void")
@SLog(type = "校工会特色活动", tag = "健身走-计步步数排行榜", msg = "步数排行榜导出", param = true, result = true)
@SaCheckPermission("fitnessWalk.stepRanking")
@ApiOperation("步数排行榜导出")
public void exportExcel(@Param("searchName") String searchName, public void exportExcel(@Param("searchName") String searchName,
@Param("searchKeyword") String searchKeyword, @Param("searchKeyword") String searchKeyword,
@Param("activityId") String activityId, @Param("activityId") String activityId,
@Param("unionId") String unionId, @Param("unionId") String unionId,
@Param("unitId") String unitId, @Param("unitId") String unitId,
@Param("mode") String mode, @Param("mode") String mode,
@Param("sex") String sex,
@Param("ageRange") String ageRange,
HttpServletResponse response) { HttpServletResponse response) {
List<NutMap> stepRankingList = fitnessWalkCommonService.getStepRankingList(searchName, searchKeyword, activityId, unionId, unitId, mode); fitnessWalkCommonService.exportStepRanking(searchName, searchKeyword, activityId, unionId, unitId, mode, sex, ageRange, response);
List<ExcelExportEntity> entityList = new ArrayList<>();
ExcelExportEntity no = new ExcelExportEntity("序号", "no", 10);
no.setFormat("isAddIndex");
entityList.add(no);
entityList.add(new ExcelExportEntity("姓名", "username", 20));
entityList.add(new ExcelExportEntity("工号", "loginname", 20));
entityList.add(new ExcelExportEntity("分工会", "unionname", 20));
entityList.add(new ExcelExportEntity("单位", "unitname", 20));
entityList.add(new ExcelExportEntity("today".equals(mode) ? "今日步数" : "活动期间总步数", "total_steps", 20));
try {
String title = ("today".equals(mode) ? DateUtil.format(new Date(), "yyyy年MM月dd日") : "活动期间总") + "步数榜.xlsx";
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entityList, stepRankingList);
workbook.write(response.getOutputStream());
CommonDownloadUtil.download(title, workbook, response);
} catch (Exception e) {
e.printStackTrace();
}
} }
/**
* 将排行榜时间范围参数转换为导出文件名中的中文说明。
*
* @param mode 时间范围参数,支持 today、oneMonth、halfYear、oneYear、activity 和兼容值 all
* @return 导出文件名使用的时间范围名称
* @param year 四位查询年度
*/
@At @At
@ApiOperation("获取联级活动")
@SaCheckPermission("fitnessWalk.stepRanking") @SaCheckPermission("fitnessWalk.stepRanking")
@ApiOperation("获取联级活动")
public Result getCascadersActivity(@Param("year") int year) { public Result getCascadersActivity(@Param("year") int year) {
return Result.success().addData(fitnessWalkCommonService.cascaderActivity(year, FitnessWalkMode.STEP_COUNT)); return Result.success(fitnessWalkCommonService.cascaderActivity(year, FitnessWalkMode.STEP_COUNT));
} }
} }
@@ -1,51 +1,28 @@
package com.budwk.app.zhgh.activity.fitnesswalk.controller; package com.budwk.app.zhgh.activity.fitnesswalk.controller;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm; import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result; import com.budwk.app.base.result.Result;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.base.utils.CommonDownloadUtil;
import com.budwk.app.zhgh.activity.fitnesswalk.contants.FitnessWalkMode; import com.budwk.app.zhgh.activity.fitnesswalk.contants.FitnessWalkMode;
import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkCommonService; import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkCommonService;
import com.budwk.app.zhgh.activity.fitnesswalk.utils.WeAppCloudUtil; import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkStepStatisticsService;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.apache.poi.ss.usermodel.Workbook;
import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.integration.jedis.RedisService;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param; import org.nutz.mvc.annotation.Param;
import java.util.*;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
@IocBean @IocBean
@Ok("json") @Ok("json")
@ApiOperation("计步步数统计")
@At("/platform/fitnessWalk/stepStatistics") @At("/platform/fitnessWalk/stepStatistics")
public class FitnessWalkStepStatisticsController { public class FitnessWalkStepStatisticsController {
@Inject @Inject
private BaseService baseService; private FitnessWalkStepStatisticsService fitnessWalkStepStatisticsService;
@Inject
private RedisService redisService;
@Inject
private WeAppCloudUtil weAppCloudUtil;
@Inject @Inject
private FitnessWalkCommonService fitnessWalkCommonService; private FitnessWalkCommonService fitnessWalkCommonService;
@@ -56,110 +33,54 @@ public class FitnessWalkStepStatisticsController {
} }
/** /**
* 公共sql * 按活动、日期、工号及组织条件分页统计用户每日步数。
* @return *
* @param pageForm 分页、查询字段和排序参数,页码从1开始
* @param year 查询年度,四位年份
* @param activityId 健步走云端活动ID
* @param activityDate 起止日期数组,两项均为yyyy-MM-dd
* @param unionId 分工会ID,空值表示不追加筛选,已有数据权限仍生效
* @param unitId 单位ID,空值表示不追加单位筛选
* @return Resultcode为0表示成功,data承载按活动、日期、工号及组织条件分页统计用户每日步数结果,失败说明见msg
*/ */
private String getSql() {
return """
SELECT
u.loginname,
u.username,
u.unionName AS unionname,
u.unitName AS unitname,
al.applyDate,
al.step,
date_format(al.applyDate,'%Y-%m-%d') as prizeData
FROM
`fitness_walk_step` al
LEFT JOIN `vw_user` u ON u.id = al.userId
$condition
""";
}
@At @At
@Ok("json:full") @Ok("json:full")
@ApiOperation("计步步数统计")
@SaCheckPermission("fitnessWalk.stepStatistics") @SaCheckPermission("fitnessWalk.stepStatistics")
@ApiOperation("计步步数统计")
public Result pageData(PageForm pageForm, public Result pageData(PageForm pageForm,
@Param("year") Integer year, @Param("year") Integer year,
@Param("activityId") String activityId, @Param("activityId") String activityId,
@Param("activityDate") String[] activityDate, @Param("activityDate") String[] activityDate,
@Param("unionId") String unionId, @Param("unionId") String unionId,
@Param("unitId") String unitId) { @Param("unitId") String unitId) {
Cnd cnd = Cnd.NEW(); return fitnessWalkStepStatisticsService.pageData(pageForm, year, activityId, activityDate, unionId, unitId);
Sql sql = Sqls.create(getSql());
if (Lang.isNotEmpty(activityDate)) {
cnd.and("date_format(al.applyDate,'%Y-%m-%d')", ">=", activityDate[0]);
cnd.and("date_format(al.applyDate,'%Y-%m-%d')", "<=", activityDate[1]);
}
if(StrUtil.isNotBlank(pageForm.getSearchKeyword())){
SqlExpressionGroup seg = new SqlExpressionGroup();
seg.orLike("u.username",pageForm.getSearchKeyword());
seg.orLike("u.loginname",pageForm.getSearchKeyword());
cnd.and(seg);
}
cnd.andEX("YEAR(al.applyDate)", "=", year);
cnd.andEX("al.activityId", "=", activityId);
cnd.andEX("u.unionid", "=", unionId);
cnd.andEX("u.unitId", "=", unitId);
cnd.desc("al.applyDate");
cnd.desc("u.unioncode");
cnd.groupBy("al.applyDate", "al.userId");
sql.setCondition(cnd);
Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
return Result.success().addData(pagination);
} }
@At @At
@ApiOperation("获取联级活动")
@SaCheckPermission("fitnessWalk.stepStatistics") @SaCheckPermission("fitnessWalk.stepStatistics")
@ApiOperation("获取联级活动")
public Result getCascadersActivity(@Param("year") int year) { public Result getCascadersActivity(@Param("year") int year) {
return Result.success().addData(fitnessWalkCommonService.cascaderActivity(year, FitnessWalkMode.STEP_COUNT)); return Result.success(fitnessWalkCommonService.cascaderActivity(year, FitnessWalkMode.STEP_COUNT));
} }
/**
@Ok("void") * 按当前活动和日期条件导出计步明细。
*
* @param activityId 健步走云端活动ID
* @param activityDate 起止日期数组,两项均为yyyy-MM-dd
* @param unionId 分工会ID,空值表示不追加筛选,已有数据权限仍生效
* @param unitId 单位ID,空值表示不追加单位筛选
* @param response HTTP响应,用于写入XSSF格式Excel文件流
* 无返回对象,通过response写出Excel文件流。
*/
@At("/exportExcel") @At("/exportExcel")
@ApiOperation("计步步数统计表导出") @Ok("void")
@SaCheckPermission("fitnessWalk.stepStatistics") @SaCheckPermission("fitnessWalk.stepStatistics")
@ApiOperation("计步步数统计表导出")
public void exportExcel(@Param("activityId") String activityId, public void exportExcel(@Param("activityId") String activityId,
@Param("activityDate") String[] activityDate, @Param("activityDate") String[] activityDate,
@Param("unionId") String unionId, @Param("unionId") String unionId,
@Param("unitId") String unitId, HttpServletResponse response) { @Param("unitId") String unitId, HttpServletResponse response) {
Cnd cnd = Cnd.NEW(); fitnessWalkStepStatisticsService.exportExcel(activityId, activityDate, unionId, unitId, response);
Sql sql = Sqls.create(getSql());
if (activityDate.length > 0) {
cnd.and("date_format(al.applyDate,'%Y-%m-%d')", ">=", activityDate[0]);
cnd.and("date_format(al.applyDate,'%Y-%m-%d')", "<=", activityDate[1]);
}
cnd.andEX("al.activityId", "=", activityId);
cnd.andEX("u.unionid", "=", unionId);
cnd.andEX("u.unitId", "=", unitId);
cnd.desc("al.applyDate");
cnd.desc("u.unioncode");
sql.setCondition(cnd);
List<NutMap> exportList = baseService.listMap(sql);
List<ExcelExportEntity> entityList = new ArrayList<>() {{
add(new ExcelExportEntity("姓名", "username", 20));
add(new ExcelExportEntity("工号", "loginname", 20));
add(new ExcelExportEntity("单位", "unitname", 20));
add(new ExcelExportEntity("分工会", "unionname", 20));
add(new ExcelExportEntity("当前步数", "step", 20));
add(new ExcelExportEntity("日期", "prizeData", 20));
}};
try {
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entityList, exportList);
workbook.write(response.getOutputStream());
CommonDownloadUtil.download("计步步数统计表.xlsx", workbook, response);
} catch (Exception e) {
e.printStackTrace();
}
} }
} }
@@ -1,126 +1,79 @@
package com.budwk.app.zhgh.activity.fitnesswalk.controller; package com.budwk.app.zhgh.activity.fitnesswalk.controller;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.annotation.SLog; import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.result.Result; import com.budwk.app.base.result.Result;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.activity.fitnesswalk.contants.FitnessWalkMode; import com.budwk.app.zhgh.activity.fitnesswalk.contants.FitnessWalkMode;
import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkAwardUser;
import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkCommonService; import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkCommonService;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.apache.poi.ss.usermodel.Workbook;
import org.nutz.dao.Cnd;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap; import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param; import org.nutz.mvc.annotation.Param;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.zip.ZipEntry; import javax.servlet.http.HttpServletResponse;
import java.util.zip.ZipOutputStream;
/** /**
* 用户中奖榜 * 用户中奖榜
*/ */
@IocBean
@Ok("json") @Ok("json")
@ApiOperation("小程序计步步数中奖榜") @IocBean
@At("/platform/fitnessWalk/stepWining") @At("/platform/fitnessWalk/stepWining")
public class FitnessWalkStepWiningController { public class FitnessWalkStepWiningController {
@Inject
private BaseService baseService;
@Inject @Inject
private FitnessWalkCommonService fitnessWalkCommonService; private FitnessWalkCommonService fitnessWalkCommonService;
@At("") @At("")
@Ok("beetl:/platform/zhgh/activity/fitnesswalk/stepWining.html") @Ok("beetl:/platform/zhgh/activity/fitnesswalk/stepWining.html")
@SaCheckPermission("fitnessWalk.stepWining") @SaCheckPermission("fitnessWalk.stepWining")
public void index() { public void index() {
} }
/** /**
* 获取中奖榜 * 获取中奖榜
* *
* @param activityId * @param activityId 健步走云端活动ID
* @return {@link Object} * @return {@link Object}
*/ */
@At @At
@Ok("json:full") @Ok("json:full")
@SLog(type = "校工会特色活动",tag = "健身走-计步步数中奖榜",msg = "获取中奖榜",param = true,result = true)
@ApiOperation("小程序获取中奖榜") @ApiOperation("小程序获取中奖榜")
@SLog(type = "校工会特色活动",tag = "健身走-计步步数中奖榜",msg = "获取中奖榜")
public Result getUserStepWining(String activityId) { public Result getUserStepWining(String activityId) {
return Result.success().addData(fitnessWalkCommonService.getWiningRankingUserList(activityId)); return Result.success(fitnessWalkCommonService.getWiningRankingUserList(activityId));
} }
@At @At
@ApiOperation("获取联级活动")
@SaCheckPermission("fitnessWalk.stepWining") @SaCheckPermission("fitnessWalk.stepWining")
@ApiOperation("获取联级活动")
public Result getCascadersActivity(@Param("year") int year) { public Result getCascadersActivity(@Param("year") int year) {
return Result.success().addData(fitnessWalkCommonService.cascaderActivity(year, FitnessWalkMode.STEP_COUNT)); return Result.success(fitnessWalkCommonService.cascaderActivity(year, FitnessWalkMode.STEP_COUNT));
} }
/**
* 按活动抽奖规则导出各期中奖榜。
*
* @param activityId 健步走云端活动ID
* @param response HTTP响应,用于写入XSSF格式Excel文件流
* 无返回对象,通过response写出Excel文件流。
*/
@At @At
@Ok("void") @Ok("void")
@ApiOperation("小程序中奖榜导出") @SLog(type = "校工会特色活动",tag = "健身走-计步步数中奖榜",msg = "导出中奖榜",param = true,result = true)
@SaCheckPermission("fitnessWalk.stepWining") @SaCheckPermission("fitnessWalk.stepWining")
@SLog(type = "校工会特色活动",tag = "健身走-计步步数中奖榜",msg = "导出中奖榜") @ApiOperation("小程序中奖榜导出")
public void exportUserStepWining(String activityId, HttpServletResponse response){ public void exportUserStepWining(String activityId, HttpServletResponse response){
List<NutMap> winingRankingUserList = fitnessWalkCommonService.getWiningRankingUserList(activityId); fitnessWalkCommonService.exportUserStepWining(activityId, response);
List<ExcelExportEntity> entityList = new ArrayList<>();
ExcelExportEntity no = new ExcelExportEntity("序号", "no", 10);
no.setFormat("isAddIndex");
entityList.add(no);
entityList.add(new ExcelExportEntity("工号", "loginName", 20));
entityList.add(new ExcelExportEntity("姓名", "username", 20));
entityList.add(new ExcelExportEntity("分工会", "unionName", 20));
entityList.add(new ExcelExportEntity("单位", "unitName", 40));
entityList.add(new ExcelExportEntity("奖项名称", "awardName", 20));
entityList.add(new ExcelExportEntity("步数", "awardSteps", 20));
entityList.add(new ExcelExportEntity("中奖时间", "applyDate", 20));
try {
response.setContentType("application/octet-stream");
response.setHeader("content-disposition", "attachment;filename="
+ URLEncoder.encode("中奖明细.zip", "UTF-8"));
ZipOutputStream zipOutputStream = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()));
for (NutMap map : winingRankingUserList) {
List<NutMap> awardList = map.getAsList("awardList", NutMap.class);
awardList.forEach(v->v.setv("applyDate",DateUtil.format(v.getTime("applyDate"),"yyyy-MM-dd")));
zipOutputStream.putNextEntry(new ZipEntry(map.getString("title") + ".xlsx"));
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), entityList, awardList);
workbook.write(zipOutputStream);
zipOutputStream.closeEntry();
}
zipOutputStream.flush();
zipOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
} }
/** /**
* 中奖奖项列表 * 中奖奖项列表
* *
* @param activityId * @param activityId 健步走云端活动ID
* @return * @return Resultcode为0表示成功,data为业务结果,msg为操作说明
*/ */
@At @At
@ApiOperation("小程序获取中奖奖项列表") @ApiOperation("小程序获取中奖奖项列表")
@@ -130,26 +83,17 @@ public class FitnessWalkStepWiningController {
} }
/** /**
* 中奖用户 * 按活动、奖项和人员关键字检索中奖人员。
* @param lotteryTime *
* @param activityId * @param lotteryTime 中奖奖项筛选值,沿用页面提交格式
* @return * @param activityId 健步走云端活动ID
* @param searchKeyword 姓名、工号或当前查询字段的检索内容
* @return Resultcode为0表示成功,data承载按活动、奖项和人员关键字检索中奖人员结果,失败说明见msg
*/ */
@At @At
@ApiOperation("小程序获取中奖用户") @ApiOperation("小程序获取中奖用户")
public Result prizeUsers(String lotteryTime, String activityId, String searchKeyword) { public Result prizeUsers(String lotteryTime, String activityId, String searchKeyword) {
Cnd cnd = Cnd.NEW(); return fitnessWalkCommonService.prizeUsers(lotteryTime, activityId, searchKeyword);
cnd.andEX("activityId", "=", activityId);
cnd.andEX("awardName", "=", lotteryTime);
if (StrUtil.isNotBlank(searchKeyword)) {
SqlExpressionGroup seg = new SqlExpressionGroup();
seg.orLike("username", searchKeyword);
seg.orLike("loginName", searchKeyword);
cnd.and(seg);
}
cnd.and("isRead", "=", true);
List<FitnessWalkAwardUser> awardUserList = fitnessWalkCommonService.dao().query(FitnessWalkAwardUser.class, cnd);
return Result.success(awardUserList);
} }
} }
@@ -1,11 +1,10 @@
package com.budwk.app.zhgh.activity.fitnesswalk.model; package com.budwk.app.zhgh.activity.fitnesswalk.model;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import lombok.Data;
@Data @Data
public class FitnessWalkActivity { public class FitnessWalkActivity {
@@ -163,6 +162,36 @@ public class FitnessWalkActivity {
@ApiModelProperty(value = "封顶积分") @ApiModelProperty(value = "封顶积分")
private Integer maxPoints; private Integer maxPoints;
// 关联活动ID,创建/编辑时通过下拉选择后回填
private String relationActivityId;
// 关联活动名称,兼容源版活动数据
private String relationActivityName;
// 关联福利项目ID,创建/编辑时通过福利下拉选择后回填
private String welfareId;
// 关联活动对应的达标活动数量,兼容源版活动数据
private Integer relationStandardActivityNum;
// 是否自动连续创建活动
private Boolean autoContinuousCreate;
// 连续创建活动日期区间,页面开启自动连续创建后由用户选择开始和结束日期
private Long[] continuousCreateDate;
// 自动创建来源活动ID,仅自动复制出的活动会写入,用于编辑原活动时识别已落地的历史活动
private String autoCreateSourceActivityId;
// 自动创建对应的目标活动日期(当天00:00:00时间戳),用于避免同一天活动被重复生成
private Long autoCreateTargetDate;
// 创建时间,用于筛选当年已创建的活动
private Long createdAt;
// 修改时间,保存编辑时同步更新
private Long updatedAt;
@Data @Data
public static class Point implements Serializable { public static class Point implements Serializable {
private String type; private String type;
@@ -2,14 +2,17 @@ package com.budwk.app.zhgh.activity.fitnesswalk.service;
import com.budwk.app.base.page.Pagination; import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm; import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.service.BaseService; import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.activity.fitnesswalk.contants.Cascader; import com.budwk.app.zhgh.activity.fitnesswalk.contants.Cascader;
import com.budwk.app.zhgh.activity.fitnesswalk.contants.FitnessWalkMode; import com.budwk.app.zhgh.activity.fitnesswalk.contants.FitnessWalkMode;
import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkActivity; import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkActivity;
import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkAwardUser; import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkAwardUser;
import org.nutz.lang.util.NutMap; import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkCommonService;
import java.util.Date;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.nutz.lang.util.NutMap;
public interface FitnessWalkCommonService extends BaseService<FitnessWalkAwardUser> { public interface FitnessWalkCommonService extends BaseService<FitnessWalkAwardUser> {
@@ -24,7 +27,6 @@ public interface FitnessWalkCommonService extends BaseService<FitnessWalkAwardUs
*/ */
FitnessWalkActivity getActivity(String activityId); FitnessWalkActivity getActivity(String activityId);
/** /**
* 获取所有活动 * 获取所有活动
* *
@@ -37,7 +39,6 @@ public interface FitnessWalkCommonService extends BaseService<FitnessWalkAwardUs
*/ */
List<Cascader> cascaderActivity(int year, FitnessWalkMode mode); List<Cascader> cascaderActivity(int year, FitnessWalkMode mode);
/** /**
* 添加活动或修改活动,存放至redis * 添加活动或修改活动,存放至redis
* *
@@ -45,7 +46,6 @@ public interface FitnessWalkCommonService extends BaseService<FitnessWalkAwardUs
*/ */
void addOrEditDoSaveRedis(FitnessWalkActivity activity); void addOrEditDoSaveRedis(FitnessWalkActivity activity);
/** /**
* 健身走抽奖模式添加定时抽奖任务 * 健身走抽奖模式添加定时抽奖任务
* *
@@ -53,20 +53,77 @@ public interface FitnessWalkCommonService extends BaseService<FitnessWalkAwardUs
*/ */
void addLotteryTask(FitnessWalkActivity fitnessWalkActivity); void addLotteryTask(FitnessWalkActivity fitnessWalkActivity);
/**
* 自动连续创建活动时添加定时创建任务。
* 任务会按活动配置的连续创建日期区间逐天执行,并基于原活动复制生成新活动。
*
* @param fitnessWalkActivity 原始活动
*/
void addCreateActivityTask(FitnessWalkActivity fitnessWalkActivity);
/** /**
* 获取步数排行榜 * 获取步数排行榜
* *
* @param pageForm 分页及姓名、工号查询参数
* @param activityId 活动id * @param activityId 活动id
* @param unionId 工会id * @param unionId 工会id
* @param unitId 单位id * @param unitId 单位id
* @param mode today all * @param mode 时间范围:today、oneMonth、halfYear、oneYear、activityall兼容活动期间
* @return * @param sex 性别,空字符串表示全部
* @param ageRange 年龄段,空字符串表示全体
* @return 分页排行榜,list 中包含用户、步数、性别、年龄和达标天数
*/ */
Pagination getStepRankingPagination(PageForm pageForm, String activityId, String unionId, String unitId, String mode); Pagination getStepRankingPagination(PageForm pageForm,
String activityId,
String unionId,
String unitId,
String mode,
String sex,
String ageRange);
List<NutMap> getStepRankingList(String searchName, String searchKeyword, String activityId, String unionId, String unitId, String mode); /**
* 查询PC端排行榜导出数据,查询条件及返回字段与页面表格保持一致。
*
* @param searchName 姓名或工号对应的查询字段
* @param searchKeyword 姓名或工号查询内容
* @param activityId 活动ID
* @param unionId 分工会ID,空字符串表示全部
* @param unitId 单位ID,空字符串表示全部
* @param mode 排行范围:today、oneMonth、halfYear、oneYear、activityall兼容活动期间
* @param sex 性别:空字符串表示全部,男或女表示指定性别
* @param ageRange 年龄段:空字符串表示全部,under40、41to50、51to55、over55表示指定年龄段;over55 表示年龄大于55岁
* @return 排行榜导出数据,包含页面表格展示的用户资料、步数和达标天数
*/
List<NutMap> getStepRankingList(String searchName,
String searchKeyword,
String activityId,
String unionId,
String unitId,
String mode,
String sex,
String ageRange);
/**
* 查询小程序筛选排行榜。
*
* @param activityId 活动ID
* @param userId 当前登录用户ID
* @param rankingType 排行指标:totalSteps、completionRate、complianceDays
* @param sex 性别筛选,空字符串表示全部
* @param ageRange 年龄段筛选,空字符串表示全体
* @param timeRange 时间范围:today、oneMonth、halfYear、oneYear、activity
* @param pageNumber 页码,从1开始
* @param pageSize 每页条数
* @return 包含排名列表、分页信息以及当前用户指标的 NutMap
*/
NutMap getUserStepRanking(String activityId,
String userId,
String rankingType,
String sex,
String ageRange,
String timeRange,
Integer pageNumber,
Integer pageSize);
/** /**
* 获取中奖榜 * 获取中奖榜
@@ -83,4 +140,83 @@ public interface FitnessWalkCommonService extends BaseService<FitnessWalkAwardUs
*/ */
List<NutMap> prizeOption(String activityId); List<NutMap> prizeOption(String activityId);
/**
* 补全健步走用户的基础资料。
*
* @param userId 用户ID,用于定位 sys_user 中的当前用户
* @param sex 性别,当前接口只接受“男”或“女”
* @param birthday 出生日期,不能晚于当前日期
* @return 包含 sex、birthday 的 NutMap;用户不存在时返回 null
*/
NutMap completeUserInfo(String userId, String sex, Date birthday);
/**
* 按姓名和工号匹配小程序用户并返回单位及角色资料。
*
* @param username 用户姓名,与工号共同匹配人员
* @param loginname 用户工号
* @return Resultcode为0表示成功,data承载按姓名和工号匹配小程序用户并返回单位及角色资料结果,失败说明见msg
*/
Result login(String username, String loginname);
/**
* 导出活动有效期内的参与人员累计步数。
*
* @param searchName 查询字段,使用页面提供的字段名
* @param searchKeyword 姓名、工号或当前查询字段的检索内容
* @param activityId 健步走云端活动ID
* @param unionId 分工会ID,空值表示不追加筛选,已有数据权限仍生效
* @param unitId 单位ID,空值表示不追加单位筛选
* @param response HTTP响应,用于写入XSSF格式Excel文件流
* 无返回对象,通过response写出Excel文件流。
*/
void exportTotalSteps(String searchName,
String searchKeyword,
String activityId,
String unionId,
String unitId,
HttpServletResponse response);
/**
* 按时间、性别和年龄筛选导出当前步数排行榜。
*
* @param searchName 查询字段,使用页面提供的字段名
* @param searchKeyword 姓名、工号或当前查询字段的检索内容
* @param activityId 健步走云端活动ID
* @param unionId 分工会ID,空值表示不追加筛选,已有数据权限仍生效
* @param unitId 单位ID,空值表示不追加单位筛选
* @param mode 时间范围:today、oneMonth、halfYear、oneYear或activity
* @param sex 性别筛选,男、女或空字符串
* @param ageRange 年龄段筛选,under40、41to50、51to55、over55或空字符串
* @param response HTTP响应,用于写入XSSF格式Excel文件流
* 无返回对象,通过response写出Excel文件流。
*/
void exportStepRanking(String searchName,
String searchKeyword,
String activityId,
String unionId,
String unitId,
String mode,
String sex,
String ageRange,
HttpServletResponse response);
/**
* 按活动抽奖规则导出各期中奖榜。
*
* @param activityId 健步走云端活动ID
* @param response HTTP响应,用于写入XSSF格式Excel文件流
* 无返回对象,通过response写出Excel文件流。
*/
void exportUserStepWining(String activityId, HttpServletResponse response);
/**
* 按活动、奖项和人员关键字检索中奖人员。
*
* @param lotteryTime 中奖奖项筛选值,沿用页面提交格式
* @param activityId 健步走云端活动ID
* @param searchKeyword 姓名、工号或当前查询字段的检索内容
* @return Resultcode为0表示成功,data承载按活动、奖项和人员关键字检索中奖人员结果,失败说明见msg
*/
Result prizeUsers(String lotteryTime, String activityId, String searchKeyword);
} }
@@ -1,20 +1,182 @@
package com.budwk.app.zhgh.activity.fitnesswalk.service; package com.budwk.app.zhgh.activity.fitnesswalk.service;
import cn.hutool.json.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.service.BaseService; import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.activity.fitnesswalk.contants.Cascader;
import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkAwardUser; import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkAwardUser;
import org.nutz.lang.util.NutMap; import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkPunchStatisticsService;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.nutz.lang.util.NutMap;
public interface FitnessWalkPunchStatisticsService extends BaseService<FitnessWalkAwardUser> { public interface FitnessWalkPunchStatisticsService extends BaseService<FitnessWalkAwardUser> {
List<NutMap> unionRegCheckInNum(String activityId, String unionId); /**
* 查询人员打卡统计页专用活动级联。
* 父级使用稳定的关联项目ID,不复用公共活动级联,避免父级 value 随最新活动变化。
*
* @param year 查询年份
* @return 人员打卡统计页活动级联
*/
List<Cascader> userPunchCascaderActivity(int year);
List<JSONObject> unionRegistrationData(String activityId, String unionId); /**
* 查询分工会报名人数、打卡人数。
* 选择分活动时只查当前分活动;只选择主活动时按主活动关联项目下的全部活动汇总查询。
*
* @param mainActivityId 主活动ID
* @param subActivityId 分活动ID
* @param activityId 兼容原页面保留的最终活动ID
* @param unionId 分工会ID
* @return 分工会统计结果
*/
List<NutMap> unionRegCheckInNum(String mainActivityId, String subActivityId, String activityId, String unionId);
List<JSONObject> unionCheckInData(String activityId, String unionId); /**
* 查询某个分工会的报名明细。
* 选择分活动时只查当前分活动;只选择主活动时按主活动关联项目下的全部活动汇总查询。
*
* @param mainActivityId 主活动ID
* @param subActivityId 分活动ID
* @param activityId 兼容原页面保留的最终活动ID
* @param unionId 分工会ID
* @return 报名明细
*/
List<JSONObject> unionRegistrationData(String mainActivityId, String subActivityId, String activityId, String unionId);
List<JSONObject> exportNotGetGiftVoucherUsers(String activityId); /**
List<JSONObject> exportNotUseGiftVoucherUsers(String activityId); * 查询某个分工会的打卡明细。
* 选择分活动时只查当前分活动;只选择主活动时按主活动关联项目下的全部活动汇总查询。
*
* @param mainActivityId 主活动ID
* @param subActivityId 分活动ID
* @param activityId 兼容原页面保留的最终活动ID
* @param unionId 分工会ID
* @return 打卡明细
*/
List<JSONObject> unionCheckInData(String mainActivityId, String subActivityId, String activityId, String unionId);
/**
* 导出未取得礼品券用户。
*
* @param mainActivityId 主活动ID
* @param subActivityId 分活动ID
* @param activityId 兼容原页面保留的最终活动ID
* @return 未取得礼品券用户
*/
List<JSONObject> exportNotGetGiftVoucherUsers(String mainActivityId, String subActivityId, String activityId);
/**
* 导出未使用礼品券用户。
*
* @param mainActivityId 主活动ID
* @param subActivityId 分活动ID
* @param activityId 兼容原页面保留的最终活动ID
* @return 未使用礼品券用户
*/
List<JSONObject> exportNotUseGiftVoucherUsers(String mainActivityId, String subActivityId, String activityId);
/**
* 查询人员打卡情况列表。
* 选择分活动时只查当前分活动;只选择主活动时按主活动关联项目下的全部活动汇总到人员维度。
*
* @param mainActivityId 主活动ID
* @param subActivityId 分活动ID
* @param activityId 兼容页面保留的最终活动ID
* @param unionId 分工会ID
* @param searchKeyword 姓名或工号关键字,空表示不过滤
* @param qualifiedStatus 达标筛选:qualified=已达标,unqualified=未达标,all/空=全部
* @param pageNumber 页码,从 1 开始
* @param pageSize 每页条数
* @return 人员打卡情况分页结果
*/
Pagination userPunchPageData(String mainActivityId, String subActivityId, String activityId, String unionId,
String searchKeyword, String qualifiedStatus, int pageNumber, int pageSize);
/**
* 导出人员打卡情况列表。
* 导出会按当前筛选条件返回全部人员,不能只返回页面当前页。
*
* @param mainActivityId 主活动ID
* @param subActivityId 分活动ID
* @param activityId 兼容页面保留的最终活动ID
* @param unionId 分工会ID
* @param searchKeyword 姓名或工号关键字,空表示不过滤
* @param qualifiedStatus 达标筛选:qualified=已达标,unqualified=未达标,all/空=全部
* @return 人员打卡情况全量列表
*/
List<NutMap> userPunchExportData(String mainActivityId, String subActivityId, String activityId, String unionId, String searchKeyword, String qualifiedStatus);
/**
* 导出所选主分活动的分工会报名与打卡人数。
*
* @param response HTTP响应,用于写入XSSF格式Excel文件流
* @param mainActivityId 主活动ID或relation:关联项目ID
* @param subActivityId 分活动ID,空值表示主活动汇总
* @param activityId 健步走云端活动ID
* 无返回对象,通过response写出Excel文件流。
*/
void exportUnionRegCheckInNum(HttpServletResponse response, String mainActivityId, String subActivityId, String activityId);
/**
* 导出所选活动和分工会的报名人员明细。
*
* @param response HTTP响应,用于写入XSSF格式Excel文件流
* @param mainActivityId 主活动ID或relation:关联项目ID
* @param subActivityId 分活动ID,空值表示主活动汇总
* @param activityId 健步走云端活动ID
* @param unionId 分工会ID,空值表示不追加筛选,已有数据权限仍生效
* 无返回对象,通过response写出Excel文件流。
*/
void exportRegUsers(HttpServletResponse response, String mainActivityId, String subActivityId, String activityId, String unionId);
/**
* 导出所选活动和分工会的打卡点位完成明细。
*
* @param response HTTP响应,用于写入XSSF格式Excel文件流
* @param mainActivityId 主活动ID或relation:关联项目ID
* @param subActivityId 分活动ID,空值表示主活动汇总
* @param activityId 健步走云端活动ID
* @param unionId 分工会ID,空值表示不追加筛选,已有数据权限仍生效
* 无返回对象,通过response写出Excel文件流。
*/
void exportCheckInUsers(HttpServletResponse response, String mainActivityId, String subActivityId, String activityId, String unionId);
/**
* 导出所选活动中尚未取得礼品券的报名人员。
*
* @param response HTTP响应,用于写入XSSF格式Excel文件流
* @param mainActivityId 主活动ID或relation:关联项目ID
* @param subActivityId 分活动ID,空值表示主活动汇总
* @param activityId 健步走云端活动ID
* 无返回对象,通过response写出Excel文件流。
*/
void exportNotGetGiftVoucherUsers(HttpServletResponse response, String mainActivityId, String subActivityId, String activityId);
/**
* 导出所选活动中尚未使用礼品券的人员。
*
* @param response HTTP响应,用于写入XSSF格式Excel文件流
* @param mainActivityId 主活动ID或relation:关联项目ID
* @param subActivityId 分活动ID,空值表示主活动汇总
* @param activityId 健步走云端活动ID
* 无返回对象,通过response写出Excel文件流。
*/
void exportNotUseGiftVoucherUsers(HttpServletResponse response, String mainActivityId, String subActivityId, String activityId);
/**
* 按主分活动和达标筛选导出全部人员打卡汇总。
*
* @param mainActivityId 主活动ID或relation:关联项目ID
* @param subActivityId 分活动ID,空值表示主活动汇总
* @param activityId 健步走云端活动ID
* @param unionId 分工会ID,空值表示不追加筛选,已有数据权限仍生效
* @param searchKeyword 姓名、工号或当前查询字段的检索内容
* @param qualifiedStatus 达标筛选,qualified、unqualified或all
* @param response HTTP响应,用于写入XSSF格式Excel文件流
* 无返回对象,通过response写出Excel文件流。
*/
void exportUserPunchExcel(String mainActivityId, String subActivityId, String activityId, String unionId, String searchKeyword, String qualifiedStatus,
HttpServletResponse response);
} }
@@ -1,13 +1,15 @@
package com.budwk.app.zhgh.activity.fitnesswalk.service; package com.budwk.app.zhgh.activity.fitnesswalk.service;
import com.budwk.app.base.param.PageForm; import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.service.BaseService; import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkRaffleRules; import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkRaffleRules;
import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkStepRaffleService;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.nutz.dao.sql.Sql; import org.nutz.dao.sql.Sql;
import org.nutz.lang.util.NutMap; import org.nutz.lang.util.NutMap;
import java.util.List;
/** /**
* @version 1.0 * @version 1.0
* @Author zzr * @Author zzr
@@ -31,4 +33,94 @@ public interface FitnessWalkStepRaffleService extends BaseService<FitnessWalkRaf
* @param activityId 活动id * @param activityId 活动id
*/ */
void manualLottery(String activityId); void manualLottery(String activityId);
/**
* 按活动达标条件分页检索具备抽奖资格的人员。
*
* @param pageForm 分页、查询字段和排序参数,页码从1开始
* @param activityId 健步走云端活动ID
* @param unionId 分工会ID,空值表示不追加筛选,已有数据权限仍生效
* @param unitId 单位ID,空值表示不追加单位筛选
* @return Resultcode为0表示成功,data承载按活动达标条件分页检索具备抽奖资格的人员结果,失败说明见msg
*/
Result pageData(PageForm pageForm,
String activityId,
String unionId,
String unitId);
/**
* 保存手动抽奖规则并按源版排名奖和达标奖规则执行抽奖。
*
* @param fitnessWalkRaffleRules 活动ID及手动抽奖规则,奖项配置沿用源版本
* @return Resultcode为0表示成功,data承载保存手动抽奖规则并按源版排名奖和达标奖规则执行抽奖结果,失败说明见msg
*/
Result saveRaffle(FitnessWalkRaffleRules fitnessWalkRaffleRules);
/**
* 读取活动已保存的手动抽奖规则。
*
* @param activityId 健步走云端活动ID
* @return Resultcode为0表示成功,data承载读取活动已保存的手动抽奖规则结果,失败说明见msg
*/
Result getRaffle(String activityId);
/**
* 读取活动可用奖项及对应中奖配置。
*
* @param activityId 健步走云端活动ID
* @return Resultcode为0表示成功,data承载读取活动可用奖项及对应中奖配置结果,失败说明见msg
*/
Result getAwardList(String activityId);
/**
* 返回用户奖项名称和剩余抽奖次数。
*
* @param activityId 健步走云端活动ID
* @param userId 登录接口返回的用户ID
* @return Resultcode为0表示成功,data承载返回用户奖项名称和剩余抽奖次数结果,失败说明见msg
*/
Result getAwardInfo(String activityId, String userId);
/**
* 判断用户是否存在尚未使用的抽奖资格。
*
* @param activityId 健步走云端活动ID
* @param userId 登录接口返回的用户ID
* @return Resultcode为0表示成功,data承载判断用户是否存在尚未使用的抽奖资格结果,失败说明见msg
*/
Result checkRaffle(String activityId, String userId);
/**
* 标记奖项和抽奖资格已读并登记奖项积分。
*
* @param activityId 健步走云端活动ID
* @param userId 登录接口返回的用户ID
* @return Resultcode为0表示成功,data承载标记奖项和抽奖资格已读并登记奖项积分结果,失败说明见msg
*/
Result updateUserAward(String activityId, String userId);
/**
* 按活动和奖项条件导出中奖人员。
*
* @param searchKeyword 姓名、工号或当前查询字段的检索内容
* @param activityId 健步走云端活动ID
* @param lotteryTime 中奖奖项筛选值,沿用页面提交格式
* @param response HTTP响应,用于写入XSSF格式Excel文件流
* 无返回对象,通过response写出Excel文件流。
*/
void exportAwardExcel(String searchKeyword, String activityId,
String lotteryTime, HttpServletResponse response);
/**
* 导出符合活动达标条件的抽奖候选人员。
*
* @param searchKeyword 姓名、工号或当前查询字段的检索内容
* @param activityId 健步走云端活动ID
* @param unionId 分工会ID,空值表示不追加筛选,已有数据权限仍生效
* @param unitId 单位ID,空值表示不追加单位筛选
* @param response HTTP响应,用于写入XSSF格式Excel文件流
* 无返回对象,通过response写出Excel文件流。
*/
void exportExcel(String searchKeyword, String activityId, String unionId,
String unitId, HttpServletResponse response);
} }
@@ -1,15 +1,27 @@
package com.budwk.app.zhgh.activity.fitnesswalk.service.impl; package com.budwk.app.zhgh.activity.fitnesswalk.service.impl;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.dao.CndPlus;
import com.budwk.app.base.param.PageForm; import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.base.service.impl.BaseServiceImpl; import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.base.utils.CommonDownloadUtil;
import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkActivity; import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkActivity;
import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkAwardUser; import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkAwardUser;
import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkRaffleRules; import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkRaffleRules;
import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkRaffleUser; import com.budwk.app.zhgh.activity.fitnesswalk.model.FitnessWalkRaffleUser;
import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkCommonService; import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkCommonService;
import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkStepRaffleService; import com.budwk.app.zhgh.activity.fitnesswalk.service.FitnessWalkStepRaffleService;
import com.budwk.app.zhgh.dayofficework.integral.model.IntegralDetail;
import org.apache.poi.ss.usermodel.Workbook;
import org.nutz.aop.interceptor.ioc.TransAop; import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd; import org.nutz.dao.Cnd;
import org.nutz.dao.Dao; import org.nutz.dao.Dao;
import org.nutz.dao.Sqls; import org.nutz.dao.Sqls;
@@ -19,13 +31,17 @@ import org.nutz.dao.util.cri.Static;
import org.nutz.ioc.aop.Aop; import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings; import org.nutz.lang.Strings;
import org.nutz.lang.random.R; import org.nutz.lang.random.R;
import org.nutz.lang.util.NutMap; import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.Ok;
import java.util.*; import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import javax.servlet.http.HttpServletResponse;
/** /**
* @version 1.0 * @version 1.0
@@ -36,6 +52,9 @@ import java.util.stream.IntStream;
*/ */
@IocBean(args = {"refer:dao"}) @IocBean(args = {"refer:dao"})
public class FitnessWalkStepRaffleServiceImpl extends BaseServiceImpl<FitnessWalkRaffleRules> implements FitnessWalkStepRaffleService { public class FitnessWalkStepRaffleServiceImpl extends BaseServiceImpl<FitnessWalkRaffleRules> implements FitnessWalkStepRaffleService {
@Inject
private BaseService baseService;
public FitnessWalkStepRaffleServiceImpl(Dao dao) { public FitnessWalkStepRaffleServiceImpl(Dao dao) {
super(dao); super(dao);
} }
@@ -43,14 +62,6 @@ public class FitnessWalkStepRaffleServiceImpl extends BaseServiceImpl<FitnessWal
@Inject @Inject
private FitnessWalkCommonService fitnessWalkCommonService; private FitnessWalkCommonService fitnessWalkCommonService;
/**
* 获取可抽奖用户,那就是达标用户
* @param pageForm
* @param activityId
* @param unionId
* @param unitId
* @return
*/
@Override @Override
public Sql getRaffleSql(PageForm pageForm, String activityId, String unionId, String unitId) { public Sql getRaffleSql(PageForm pageForm, String activityId, String unionId, String unitId) {
FitnessWalkActivity activity = fitnessWalkCommonService.getActivity(activityId); FitnessWalkActivity activity = fitnessWalkCommonService.getActivity(activityId);
@@ -67,10 +78,10 @@ public class FitnessWalkStepRaffleServiceImpl extends BaseServiceImpl<FitnessWal
COALESCE(SUM(sub.step), 0) AS total_steps, COALESCE(SUM(sub.step), 0) AS total_steps,
u.loginname, u.loginname,
u.username, u.username,
u.unionId, u.unionid,
u.unionName, u.unionname,
u.unitId, u.unitid,
u.unitName, u.unitname,
over3k.standardsDays over3k.standardsDays
FROM FROM
`vw_user` u `vw_user` u
@@ -134,16 +145,15 @@ public class FitnessWalkStepRaffleServiceImpl extends BaseServiceImpl<FitnessWal
cnd.and(seg); cnd.and(seg);
} }
// cnd.and("u.id","in",Sqls.create("select userId from activity_user_scope where groupId = @groupId").setParam("groupId",activity.getGroupId())); // cnd.and("u.id","in",Sqls.create("select userId from activity_user_scope where groupId = @groupId").setParam("groupId",activity.getGroupId()));
cnd.groupBy("u.id", "u.username", "u.loginname", "u.unionName", "u.unitName"); cnd.groupBy("u.id", "u.username", "u.loginname", "u.unionname", "u.unitname");
cnd.desc("total_steps"); cnd.desc("total_steps");
sql.setCondition(cnd); sql.setCondition(cnd);
return sql; return sql;
} }
/** /**
* 获取活动的奖项,然后再将奖项去遍历出来 * 获取活动的奖项
* @param activityId * @param activityId 健步走云端活动ID
* @return { index: 0, name: '奖项名称', type: 0 } * @return { index: 0, name: '奖项名称', type: 0 }
*/ */
@Override @Override
@@ -290,9 +300,9 @@ public class FitnessWalkStepRaffleServiceImpl extends BaseServiceImpl<FitnessWal
awardUser.setStartDate(startDate); awardUser.setStartDate(startDate);
awardUser.setEndDate(endDate); awardUser.setEndDate(endDate);
awardUser.setUnionId(v.getString("unionid")); awardUser.setUnionId(v.getString("unionid"));
awardUser.setUnionName(v.getString("unionName")); awardUser.setUnionName(v.getString("unionname"));
awardUser.setUnitId(v.getString("unitId")); awardUser.setUnitId(v.getString("unitid"));
awardUser.setUnitName(v.getString("unitName")); awardUser.setUnitName(v.getString("unitname"));
awardUser.setStandardsDays(v.getInt("standardsDays")); awardUser.setStandardsDays(v.getInt("standardsDays"));
awardUser.setAwardSteps(v.getString("total_steps")); awardUser.setAwardSteps(v.getString("total_steps"));
awardUser.setPoints(rank.getPoints()); awardUser.setPoints(rank.getPoints());
@@ -304,30 +314,26 @@ public class FitnessWalkStepRaffleServiceImpl extends BaseServiceImpl<FitnessWal
winningUsers.addAll(collect); winningUsers.addAll(collect);
} }
// 达标奖项不使用排名位次,按页面配置顺序处理,避免对空的 rankingPosition 进行排序。
List<FitnessWalkRaffleRules.ManualLotteryRules> reachList = manualLotteryRules.stream().filter(v -> "达标".equals(v.getRaffleType())) List<FitnessWalkRaffleRules.ManualLotteryRules> reachList = manualLotteryRules.stream()
.sorted(Comparator.comparing(FitnessWalkRaffleRules.ManualLotteryRules::getRankingPosition)).toList(); .filter(v -> "达标".equals(v.getRaffleType())).toList();
for (FitnessWalkRaffleRules.ManualLotteryRules reach : reachList) { for (FitnessWalkRaffleRules.ManualLotteryRules reach : reachList) {
List<NutMap> nutMaps; List<NutMap> nutMaps;
if (reach.getIsSimultaneously() != null && reach.getIsSimultaneously()) { if (reach.getIsSimultaneously() != null && reach.getIsSimultaneously()) {
// 可以兼得, 达标了的抽奖就是全部达标的人 // 可以兼得
nutMaps = list; nutMaps = list;
} else { } else {
// 不可兼得 这里要排除其他奖项的中奖人员 // 不可兼得
nutMaps = list.stream().filter(v -> !winningRankLoginNames.contains(v.getString("loginname"))).collect(Collectors.toList()); nutMaps = list.stream().filter(v -> !winningRankLoginNames.contains(v.getString("loginname"))).collect(Collectors.toList());
} }
// 抽奖人数
Integer lotteryUserNum = reach.getLotteryUserNum(); Integer lotteryUserNum = reach.getLotteryUserNum();
// 奖项名称
String awardName = reach.getAwardName(); String awardName = reach.getAwardName();
// 这里是随机打乱了再去抽奖
List<NutMap> reachNutMaps = nutMaps.stream().collect(Collectors.collectingAndThen(Collectors.toList(), collected -> { List<NutMap> reachNutMaps = nutMaps.stream().collect(Collectors.collectingAndThen(Collectors.toList(), collected -> {
int size = Math.min(lotteryUserNum, collected.size());
Collections.shuffle(collected); Collections.shuffle(collected);
return collected.subList(0, size); return collected.subList(0, lotteryUserNum - 1);
})); }));
List<FitnessWalkAwardUser> collect = reachNutMaps.stream().map(v -> { List<FitnessWalkAwardUser> collect = reachNutMaps.stream().map(v -> {
@@ -341,20 +347,263 @@ public class FitnessWalkStepRaffleServiceImpl extends BaseServiceImpl<FitnessWal
awardUser.setStartDate(startDate); awardUser.setStartDate(startDate);
awardUser.setEndDate(endDate); awardUser.setEndDate(endDate);
awardUser.setUnionId(v.getString("unionid")); awardUser.setUnionId(v.getString("unionid"));
awardUser.setUnionName(v.getString("unionName")); awardUser.setUnionName(v.getString("unionname"));
awardUser.setUnitId(v.getString("unitId")); awardUser.setUnitId(v.getString("unitid"));
awardUser.setUnitName(v.getString("unitName")); awardUser.setUnitName(v.getString("unitname"));
awardUser.setStandardsDays(v.getInt("standardsDays")); awardUser.setStandardsDays(v.getInt("standardsDays"));
awardUser.setAwardSteps(v.getString("total_steps")); awardUser.setAwardSteps(v.getString("total_steps"));
awardUser.setPoints(reach.getPoints()); awardUser.setPoints(reach.getPoints());
return awardUser; return awardUser;
}).toList(); }).toList();
winningRankLoginNames.addAll(collect.stream().map(FitnessWalkAwardUser::getLoginName).toList()); winningRankLoginNames.addAll(collect.stream().map(FitnessWalkAwardUser::getLoginName).collect(Collectors.toList()));
winningUsers.addAll(collect); winningUsers.addAll(collect);
} }
dao().fastInsert(winningUsers); dao().fastInsert(winningUsers);
} }
/**
* 按活动达标条件分页检索具备抽奖资格的人员。
*
* @param pageForm 分页、查询字段和排序参数,页码从1开始
* @param activityId 健步走云端活动ID
* @param unionId 分工会ID,空值表示不追加筛选,已有数据权限仍生效
* @param unitId 单位ID,空值表示不追加单位筛选
* @return Resultcode为0表示成功,data承载按活动达标条件分页检索具备抽奖资格的人员结果,失败说明见msg
*/
@Override
public Result pageData(PageForm pageForm,
String activityId,
String unionId,
String unitId) {
Sql sql = this.getRaffleSql(pageForm, activityId, unionId, unitId);
return Result.success(baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql));
}
/**
* 保存手动抽奖规则并按源版排名奖和达标奖规则执行抽奖。
*
* @param fitnessWalkRaffleRules 活动ID及手动抽奖规则,奖项配置沿用源版本
* @return Resultcode为0表示成功,data承载保存手动抽奖规则并按源版排名奖和达标奖规则执行抽奖结果,失败说明见msg
*/
@Override
@Aop(TransAop.READ_COMMITTED)
public Result saveRaffle(FitnessWalkRaffleRules fitnessWalkRaffleRules) {
baseService.dao().insertOrUpdate(fitnessWalkRaffleRules);
this.manualLottery(fitnessWalkRaffleRules.getActivityId());
return Result.success();
}
/**
* 读取活动已保存的手动抽奖规则。
*
* @param activityId 健步走云端活动ID
* @return Resultcode为0表示成功,data承载读取活动已保存的手动抽奖规则结果,失败说明见msg
*/
@Override
public Result getRaffle(String activityId) {
return Result.success(baseService.dao().fetch(FitnessWalkRaffleRules.class, Cnd.where("activityId", "=", activityId)));
}
/**
* 读取活动可用奖项及对应中奖配置。
*
* @param activityId 健步走云端活动ID
* @return Resultcode为0表示成功,data承载读取活动可用奖项及对应中奖配置结果,失败说明见msg
*/
@Override
public Result getAwardList(String activityId) {
return Result.success(this.getActivityAwardList(activityId));
}
/**
* 返回用户奖项名称和剩余抽奖次数。
*
* @param activityId 健步走云端活动ID
* @param userId 登录接口返回的用户ID
* @return Resultcode为0表示成功,data承载返回用户奖项名称和剩余抽奖次数结果,失败说明见msg
*/
@Override
public Result getAwardInfo(String activityId, String userId) {
Dao dao = this.dao();
FitnessWalkAwardUser awardUser = dao().fetch(FitnessWalkAwardUser.class, Cnd.where("activityId", "=", activityId).and("userId", "=", userId));
FitnessWalkRaffleUser raffleUser = dao().fetch(FitnessWalkRaffleUser.class, Cnd.where("activityId", "=", activityId).and("userId", "=", userId));
NutMap map = NutMap.NEW();
if (Lang.isNotEmpty(raffleUser) && !raffleUser.getIsRaffle()) {
if (Lang.isNotEmpty(awardUser)) {
map.put("awardName", awardUser.getAwardName());
} else {
map.put("awardName", "没有中奖");
}
map.put("raffleNum", 1);
} else {
map.put("raffleNum", 0);
}
return Result.success(map);
}
/**
* 判断用户是否存在尚未使用的抽奖资格。
*
* @param activityId 健步走云端活动ID
* @param userId 登录接口返回的用户ID
* @return Resultcode为0表示成功,data承载判断用户是否存在尚未使用的抽奖资格结果,失败说明见msg
*/
@Override
public Result checkRaffle(String activityId, String userId) {
Dao dao = this.dao();
FitnessWalkRaffleUser raffleUser = dao().fetch(FitnessWalkRaffleUser.class,
Cnd.where("activityId", "=", activityId)
.and("userId", "=", userId));
if (Lang.isNotEmpty(raffleUser)) {
return raffleUser.getIsRaffle() ? Result.error() : Result.success();
} else {
return Result.error();
}
}
/**
* 标记奖项和抽奖资格已读并登记奖项积分。
*
* @param activityId 健步走云端活动ID
* @param userId 登录接口返回的用户ID
* @return Resultcode为0表示成功,data承载标记奖项和抽奖资格已读并登记奖项积分结果,失败说明见msg
*/
@Override
@Aop(TransAop.READ_COMMITTED)
public Result updateUserAward(String activityId, String userId) {
this.dao().update(FitnessWalkAwardUser.class,
Chain.make("isRead", true).add("applyDate", DateUtil.date()),
Cnd.where("activityId", "=", activityId).and("userId", "=", userId));
this.dao().update(FitnessWalkRaffleUser.class,
Chain.make("isRaffle", true),
Cnd.where("activityId", "=", activityId).and("userId", "=", userId));
// 增加积分
FitnessWalkAwardUser awardUser = dao().fetch(FitnessWalkAwardUser.class, Cnd.where("activityId", "=", activityId).and("userId", "=", userId));
IntegralDetail detail = new IntegralDetail();
detail.setYear(String.valueOf(DateUtil.thisYear()));
detail.setUserId(awardUser.getUserId());
detail.setIntegral(String.valueOf(awardUser.getPoints()));
detail.setIntegralNotes(awardUser.getAwardName());
detail.setBizId(awardUser.getId());
detail.setIntegralTime(DateUtil.date());
dao().insert(detail);
return Result.success();
}
/**
* 按活动和奖项条件导出中奖人员。
*
* @param searchKeyword 姓名、工号或当前查询字段的检索内容
* @param activityId 健步走云端活动ID
* @param lotteryTime 中奖奖项筛选值,沿用页面提交格式
* @param response HTTP响应,用于写入XSSF格式Excel文件流
* 无返回对象,通过response写出Excel文件流。
*/
@Override
@Ok("void")
public void exportAwardExcel(String searchKeyword, String activityId,
String lotteryTime, HttpServletResponse response) {
CndPlus cnd = CndPlus.create();
cnd.andEX("activityId", "=", activityId);
cnd.andEX("awardName", "=", lotteryTime);
if (StrUtil.isNotBlank(searchKeyword)) {
SqlExpressionGroup seg = new SqlExpressionGroup();
seg.orLike("username", searchKeyword);
seg.orLike("loginName", searchKeyword);
cnd.and(seg);
}
cnd.and("isRead", "=", true);
List<FitnessWalkAwardUser> list = fitnessWalkCommonService.dao().query(FitnessWalkAwardUser.class, cnd);
for (FitnessWalkAwardUser awardUser : list) {
awardUser.setApplyDate(awardUser.getApplyDate());
}
List<ExcelExportEntity> entityList = new ArrayList<>();
ExcelExportEntity no = new ExcelExportEntity("序号", "no", 10);
no.setFormat("isAddIndex");
entityList.add(no);
entityList.add(new ExcelExportEntity("工号", "loginName", 20));
entityList.add(new ExcelExportEntity("姓名", "username", 20));
entityList.add(new ExcelExportEntity("分工会", "unionName", 20));
entityList.add(new ExcelExportEntity("单位", "unitName", 40));
entityList.add(new ExcelExportEntity("奖项名称", "awardName", 20));
entityList.add(new ExcelExportEntity("中奖时间", "applyDate2", 20));
try {
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entityList, list);
CommonDownloadUtil.download("健步走中奖人员名单.xlsx", workbook, response);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 导出符合活动达标条件的抽奖候选人员。
*
* @param searchKeyword 姓名、工号或当前查询字段的检索内容
* @param activityId 健步走云端活动ID
* @param unionId 分工会ID,空值表示不追加筛选,已有数据权限仍生效
* @param unitId 单位ID,空值表示不追加单位筛选
* @param response HTTP响应,用于写入XSSF格式Excel文件流
* 无返回对象,通过response写出Excel文件流。
*/
@Override
@Ok("void")
public void exportExcel(String searchKeyword, String activityId, String unionId,
String unitId, HttpServletResponse response) {
PageForm pageForm = new PageForm();
pageForm.setSearchKeyword(searchKeyword);
Sql sql = this.getRaffleSql(pageForm, activityId, unionId, unitId);
// Sql sql = Sqls.create("""
// SELECT
// ru.*,
// u.sex,
// u.unionname AS unionName,
// u.unitname AS unitName
// FROM
// fitness_walk_raffle_user ru left join vw_user u on ru.userId = u.id
// $condition
// """);
// CndPlus cnd = CndPlus.create();
// cnd.andEX("ru.activityId", "=", activityId);
// cnd.andEX("u.unionid", "=", unionId);
// cnd.andEX("u.unitid", "=", unitId);
// if (StrUtil.isNotBlank(searchKeyword)) {
// SqlExpressionGroup seg = new SqlExpressionGroup();
// seg.orLike("ru.username", searchKeyword);
// seg.orLike("ru.loginName", searchKeyword);
// cnd.and(seg);
// }
// sql.setCondition(cnd);
List<NutMap> list = this.listMap(sql);
List<ExcelExportEntity> entityList = new ArrayList<>();
ExcelExportEntity no = new ExcelExportEntity("序号", "no", 10);
no.setFormat("isAddIndex");
entityList.add(no);
entityList.add(new ExcelExportEntity("工号", "loginname", 20));
entityList.add(new ExcelExportEntity("姓名", "username", 20));
entityList.add(new ExcelExportEntity("分工会", "unionname", 20));
entityList.add(new ExcelExportEntity("单位", "unitname", 40));
entityList.add(new ExcelExportEntity("达标天数", "standardsDays", 20));
entityList.add(new ExcelExportEntity("步数", "total_steps", 20));
try {
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entityList, list);
CommonDownloadUtil.download("健步走达标人员名单.xlsx", workbook, response);
} catch (Exception e) {
e.printStackTrace();
}
}
} }
@@ -1,22 +1,25 @@
package com.budwk.app.zhgh.activity.fitnesswalk.utils; package com.budwk.app.zhgh.activity.fitnesswalk.utils;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.ioc.aop.Aop;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil; import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject; import com.alibaba.fastjson.JSON;
import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSONObject;
import com.budwk.app.base.constant.RedisConstant; import com.budwk.app.base.constant.RedisConstant;
import java.io.File;
import java.util.*;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import org.nutz.http.Http;
import org.nutz.integration.jedis.RedisService; import org.nutz.integration.jedis.RedisService;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
/** /**
* 微信小程序云开发工具类 * 微信小程序云开发工具类
@@ -32,18 +35,18 @@ public class WeAppCloudUtil {
@Inject @Inject
public RedisService redisService; public RedisService redisService;
@Aop(TransAop.READ_COMMITTED)
public JSONObject request(CRUD crud, String sql) { public JSONObject request(CRUD crud, String sql) {
String url = crud.url.replace("ACCESS_TOKEN", getAccessToken()); String url = crud.url.replace("ACCESS_TOKEN", getAccessToken());
String responseJson = HttpUtil.createPost(url).header("Content-Type", "application/json") String responseJson = HttpUtil.createPost(url).header("Content-Type", "application/json").body(JSON.toJSONString(Map.of("env", ENV, "query", sql))).execute().body();
.body(JSONUtil.toJsonStr(Map.of("env", ENV, "query", sql))).execute().body(); JSONObject response = JSON.parseObject(responseJson);
JSONObject response = JSONUtil.parseObj(responseJson); if (response.getIntValue("errcode") == 42001) {
if (response.getInt("errcode") == 42001) {
redisService.del(RedisConstant.REDIS_KEY_WE_APP_ACCESS_TOKEN); redisService.del(RedisConstant.REDIS_KEY_WE_APP_ACCESS_TOKEN);
// request(crud, sql); // request(crud, sql);
} else if (response.getInt("errcode") == 40001) { } else if (response.getIntValue("errcode") == 40001) {
redisService.del(RedisConstant.REDIS_KEY_WE_APP_ACCESS_TOKEN); redisService.del(RedisConstant.REDIS_KEY_WE_APP_ACCESS_TOKEN);
} else if (response.getInt("errcode") != 0) { } else if (response.getIntValue("errcode") != 0) {
throw new RuntimeException("小程序云函数接口调用失败,errcode:" + response.getStr("errcode") + ",errmsg:" + response.getStr("errmsg")); throw new RuntimeException("小程序云函数接口调用失败,errcode:" + response.getString("errcode") + ",errmsg:" + response.getString("errmsg"));
} }
return response; return response;
} }
@@ -60,9 +63,7 @@ public class WeAppCloudUtil {
} }
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET".replace("APPID", APPID).replace("APPSECRET", APP_SECRET); String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET".replace("APPID", APPID).replace("APPSECRET", APP_SECRET);
String responseJson = HttpUtil.createGet(url).execute().body(); String responseJson = HttpUtil.createGet(url).execute().body();
TokenResponse tokenResponse = JSON.parseObject(responseJson, TokenResponse.class);
TokenResponse tokenResponse = JSONUtil.toBean(responseJson, TokenResponse.class);
// 微信的Access_token,两个小时过期,也就是7200秒
redisService.setex(RedisConstant.REDIS_KEY_WE_APP_ACCESS_TOKEN, 7000, tokenResponse.getAccess_token()); redisService.setex(RedisConstant.REDIS_KEY_WE_APP_ACCESS_TOKEN, 7000, tokenResponse.getAccess_token());
return tokenResponse.getAccess_token(); return tokenResponse.getAccess_token();
@@ -109,26 +110,26 @@ public class WeAppCloudUtil {
* @param file * @param file
* @return * @return
*/ */
@Aop(TransAop.READ_COMMITTED)
public String uploadFile(String rootPath, File file) { public String uploadFile(String rootPath, File file) {
String path = rootPath + file.getName(); String path = rootPath + file.getName();
String url = "https://api.weixin.qq.com/tcb/uploadfile?access_token=ACCESS_TOKEN".replace("ACCESS_TOKEN", getAccessToken()); String url = "https://api.weixin.qq.com/tcb/uploadfile?access_token=ACCESS_TOKEN".replace("ACCESS_TOKEN", getAccessToken());
String responseJson = HttpUtil.createPost(url).header("Content-Type", "application/json") String responseJson = HttpUtil.createPost(url).header("Content-Type", "application/json").body(JSON.toJSONString(Map.of("env", ENV, "path", path))).execute().body();
.body(JSONUtil.toJsonStr(Map.of("env", ENV, "path", path))).execute().body(); JSONObject jsonObject = JSON.parseObject(responseJson);
JSONObject jsonObject = JSONUtil.parseObj(responseJson); if (jsonObject.getIntValue("errcode") != 0) {
if (jsonObject.getInt("errcode") != 0) { throw new RuntimeException(jsonObject.getString("errmsg"));
throw new RuntimeException(jsonObject.getStr("errmsg"));
} }
try{ try{
HttpUtil.createPost(jsonObject.getStr("url")) HttpUtil.createPost(jsonObject.getString("url"))
.form("key", path) .form("key", path)
.form("Signature", jsonObject.getStr("authorization")) .form("Signature", jsonObject.getString("authorization"))
.form("x-cos-security-token", jsonObject.getStr("token")) .form("x-cos-security-token", jsonObject.getString("token"))
.form("x-cos-meta-fileid", jsonObject.getStr("cos_file_id")) .form("x-cos-meta-fileid", jsonObject.getString("cos_file_id"))
.form("file", file) .form("file", file)
.execute().body(); .execute().body();
return jsonObject.getStr("file_id"); return jsonObject.getString("file_id");
}catch (Exception e){ }catch (Exception e){
return jsonObject.getStr("file_id"); return jsonObject.getString("file_id");
} }
} }
@@ -153,18 +154,16 @@ public class WeAppCloudUtil {
body.put("file_list", fm); body.put("file_list", fm);
String responseJson = HttpUtil.createPost(url) String responseJson = HttpUtil.createPost(url)
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.body(JSONUtil.toJsonStr(body)) .body(JSON.toJSONString(body))
.execute().body(); .execute().body();
System.out.println(JSONUtil.toJsonStr(body)); System.out.println(JSON.toJSONString(body));
JSONObject jsonObject = JSONUtil.parseObj(responseJson); JSONObject jsonObject = JSON.parseObject(responseJson);
if (jsonObject.getInt("errcode") != 0) { if (jsonObject.getIntValue("errcode") != 0) {
throw new RuntimeException(jsonObject.getStr("errmsg")); throw new RuntimeException(jsonObject.getString("errmsg"));
} }
return jsonObject.getJSONArray("file_list").toList(JSONObject.class).get(0).getStr("download_url"); return jsonObject.getJSONArray("file_list").toJavaList(JSONObject.class).get(0).getString("download_url");
} }
} }
@@ -69,11 +69,12 @@ const initTableMixins = {
const address = this.pageDataUrl ? this.pageDataUrl : loc() + "/pageData" const address = this.pageDataUrl ? this.pageDataUrl : loc() + "/pageData"
this.tableLoading = true this.tableLoading = true
this.$axios.post(address, data ? data : this.pageForm).then((res) => { this.$axios.post(address, data ? data : this.pageForm).then((res) => {
this.tableLoading = false
if (res.code === 0) { if (res.code === 0) {
this.tableData = res.data.list this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount this.pageForm.totalCount = res.data.totalCount
} }
}).finally(() => {
this.tableLoading = false
}) })
}, },
notifySuccess(msg) { notifySuccess(msg) {
File diff suppressed because it is too large Load Diff
@@ -4,47 +4,57 @@ layout("/layouts/platform.html"){
<style> <style>
</style> </style>
<div id="app" v-cloak> <div id="app" v-cloak>
<guava> <guava>
<el-card shadow="never"> <el-card shadow="never">
<div class="search">
<search @search="doSearch"> <div class="search-item">
<search-item label="姓名工号"> <div class="search-item-label">姓名工号:</div>
<el-input placeholder="请输入关键字查询" v-model="pageForm.keyWord"></el-input> <div class="search-item-option">
</search-item> <el-input placeholder="请输入关键字查询" v-model="pageForm.keyWord"></el-input>
<search-item label="所属工会"> </div>
<el-select v-model="pageForm.unionId" clearable filterable placeholder="请选择所属工会" </div>
style="width: 100%"> <div class="search-item">
<el-option <div class="search-item-label">所属工会:</div>
v-for="item in unionList" <div class="search-item-option">
:key="item.id" <el-select v-model="pageForm.unionId" clearable filterable placeholder="请选择院级工会"
:label="item.name" style="width: 100%">
:value="item.id"> <el-option
</el-option> v-for="item in unionList"
</el-select> :key="item.id"
</search-item> :label="item.unionname"
</search> :value="item.id">
</el-option>
</el-select>
</div>
</div>
<div class="search-query">
<el-button icon="el-icon-search" type="primary" @click="doSearch"></el-button>
</div>
</div>
</el-card> </el-card>
<el-card shadow="never" class="mt10"> <el-card shadow="never" class="mt10">
<table-tool label="绑定列表"> <table-tool :app="this" label="绑定列表">
<el-dropdown @command="dropdownCommand"> <el-dropdown @command="dropdownCommand">
<el-button size="medium" type="danger"> <el-button size="medium" type="danger">
批量删除&emsp; 批量删除&emsp;
<span class="ti-angle-down"></span> <span class="ti-angle-down"></span>
</el-button> </el-button>
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<el-dropdown-item :command="{type:'delete2'}"> <el-dropdown-item :command="{type:'delete2'}">
删除已选 删除已选
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item :command="{type:'delete3'}"> <el-dropdown-item :command="{type:'delete3'}">
全部删除 全部删除
</el-dropdown-item> </el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</el-dropdown> </el-dropdown>
</table-tool> </table-tool>
<el-table :data="tableData" style="width: 100%" row-key="_id" @sort-change="pageOrder" <el-table :data="tableData" style="width: 100%" row-key="_id" @sort-change="pageOrder"
v-loading="tabLoading" @selection-change="handleSelectionChange"> v-loading="tableLoading" @selection-change="handleSelectionChange">
<el-table-column :reserve-selection="true" <el-table-column :reserve-selection="true"
type="selection" type="selection"
width="55"> width="55">
@@ -88,18 +98,13 @@ layout("/layouts/platform.html"){
</guava> </guava>
</div> </div>
<script> <script nonce="${cspNonce!}">
const vue = new Vue({ const vue = new Vue({
el: '#app', el: '#app',
mixins: [initTableMixins],
data() { data() {
return { return {
v: "index",
stepActive: 0,
tabLoading: false,
subDis: false,
formData: {},
tableData: [],
pageForm: { pageForm: {
searchName: "name", searchName: "name",
searchKeyword: "", searchKeyword: "",
@@ -114,7 +119,7 @@ layout("/layouts/platform.html"){
} }
}, },
methods: { methods: {
dropdownCommand: function (command) { dropdownCommand(command) {
const {type, data} = command const {type, data} = command
if (type == 'delete2') { if (type == 'delete2') {
this.doDelete2() this.doDelete2()
@@ -122,30 +127,36 @@ layout("/layouts/platform.html"){
this.doDelete3() this.doDelete3()
} }
}, },
async doDelete(id) { doDelete(id) {
this.$confirm('是否确定删除!', '提示', { this.$confirm('是否确定删除!', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning', type: 'warning',
callback: async (a, b) => { callback: (a, b) => {
if ("confirm" == a) {//确认后再执行 if ("confirm" == a) {//确认后再执行
const { this.$set(this, "formLoading", true)
code, this.$axios.post(loc() + "/delete", {ids: JSON.stringify([id])}).then((res) => {
data, if (res.code == 0) {
msg this.$message({
} = await this.$axios.post(loc() + "/delete", {ids: JSON.stringify([id])}) message: res.msg,
if (code === 0) { type: 'success'
this.$message({message: msg, type: 'success'}); });
this.pageData() this.pageData()
} else { } else {
this.$message({message: data.msg, type: 'error'}); this.$message({
} message: res.data.msg,
type: 'error'
});
}
}).finally(() => {
this.$set(this, "formLoading", false)
})
} }
} }
}) })
}, },
async doDelete2() { doDelete2() {
if (!this.multipleSelection.length) { if (!this.multipleSelection.length) {
this.$notify({ this.$notify({
@@ -160,104 +171,73 @@ layout("/layouts/platform.html"){
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning', type: 'warning',
callback: async (a, b) => { callback: (a, b) => {
if ("confirm" === a) {//确认后再执行 if ("confirm" === a) {//确认后再执行
const arr = this.multipleSelection.map(v => { const arr = this.multipleSelection.map(v => {
return v._id return v._id
}) })
const {code, data, msg} = await this.$axios.post(loc() + "/delete", {ids: JSON.stringify(arr)}) this.$set(this, "formLoading", true)
if (code === 0) { this.$axios.post(loc() + "/delete", {ids: JSON.stringify(arr)}).then((res) => {
this.multipleSelection = [] if (res.code == 0) {
this.$message({ this.$set(this, "multipleSelection", [])
message: msg, this.$message({
type: 'success' message: res.msg,
}); type: 'success'
this.pageData() });
} else { this.pageData()
this.$message({ } else {
message: data.msg, this.$message({
type: 'error' message: res.data.msg,
}); type: 'error'
} });
}
}).finally(() => {
this.$set(this, "formLoading", false)
})
} }
} }
}) })
}, },
async doDelete3() { doDelete3() {
this.$confirm('是否确定删除全部登录记录!', '提示', { this.$confirm('是否确定删除全部登录记录!', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning', type: 'warning',
callback: async (a, b) => { callback: (a, b) => {
if ("confirm" == a) {//确认后再执行 if ("confirm" == a) {//确认后再执行
const {code, data, msg} = await this.$axios.post(loc() + "/deleteAll") this.$set(this, "formLoading", true)
if (code === 0) { this.$axios.post(loc() + "/deleteAll").then((res) => {
this.multipleSelection = [] if (res.code == 0) {
this.$message({ this.$set(this, "multipleSelection", [])
message: msg, this.$message({
type: 'success' message: res.msg,
}); type: 'success'
this.pageData() });
} else { this.pageData()
this.$message({ } else {
message: data.msg, this.$message({
type: 'error' message: res.data.msg,
}); type: 'error'
} });
}
}).finally(() => {
this.$set(this, "formLoading", false)
})
} }
} }
}) })
}, },
handleSelectionChange(val) { handleSelectionChange(val) {
this.multipleSelection = val; this.$set(this, "multipleSelection", val);
}, }
doSearch() {
this.tabKey = new Date().getTime()
this.pageForm.pageNumber = 1
this.pageData()
},
pageOrder(column) {//按字段排序
this.pageForm.pageOrderName = column.prop;
this.pageForm.pageOrderBy = column.order;
this.pageData();
},
pageNumberChange(val) {//页码更新操作
this.pageForm.pageNumber = val;
this.pageData();
},
pageSizeChange(val) {//分页大小更新操作
this.pageForm.pageSize = val;
this.pageData();
},
pageData() {//加载分页数据
this.tabLoading = true
this.$axios.post(loc() + "/pageData", this.pageForm)
.then(res => {
this.tabLoading = false
if (res.code === 0) {
this.tableData = data.data.list;
this.pageForm.totalCount = data.data.totalCount;
} else {
this.$message({
message: data.msg,
type: 'error'
});
}
})
},
}, },
async created() { created() {
this.pageData(); this.pageData();
this.$businessTool.listUnion(null).then((res) => {
const hasAdminRole = this.$auth.hasRoleOr("SYSADMIN, SCHOOL_UNION_ADMIN") this.$set(this, "unionList", res)
if (hasAdminRole) { })
this.unionList = await this.$businessTool.listUnion()
} else {
this.unionList = await this.$businessTool.listUnion(this.$store.user.union.id)
}
} }
}) })
</script> </script>
@@ -1,59 +1,90 @@
<!--# <!--#
layout("/layouts/platform.html"){ layout("/layouts/platform.html"){
#--> #-->
<div id="app" v-cloak> <div id="app" v-cloak>
<guava ref="guava"> <guava ref="guava">
<template> <template>
<el-card shadow="never"> <el-card shadow="never">
<search @search="doSearch"> <div class="search">
<search-item label="年份"> <div class="search-item">
<el-date-picker <div class="search-item-label">年份:</div>
:clearable="false" <div class="search-item-option">
placeholder="选择年" <el-date-picker
style="width: 100%" :clearable="false"
@change="getCascadersActivity" placeholder="选择年"
type="year" v-model="pageForm.year" style="width: 100%"
value-format="yyyy"> @change="getCascadersActivity"
</el-date-picker> type="year" v-model="pageForm.year"
</search-item> value-format="yyyy">
</el-date-picker>
<search-item label="活动"> </div>
<el-cascader </div>
style="width: 100%" <div class="search-item">
@change="doSearch" <div class="search-item-label">活动:</div>
v-model="pageForm.activityId" <div class="search-item-option">
:options="activityOptions" <div style="display: flex; align-items: center; gap: 10px;">
:props="{ checkStrictly: true,emitPath:false}" <el-select
clearable></el-cascader> :style="{width: subActivityOptions.length > 0 ? '50%' : '100%'}"
</search-item> placeholder="请选择主活动"
</search> @change="mainActivityChange"
v-model="pageForm.mainActivityId"
clearable>
<el-option
:key="item.value"
:label="item.label"
:value="item.value"
v-for="item in activityOptions"></el-option>
</el-select>
<el-select
v-if="subActivityOptions.length > 0"
style="width: 50%"
placeholder="请选择分活动"
@change="subActivityChange"
v-model="pageForm.subActivityId"
clearable>
<el-option
:key="item.value"
:label="item.label"
:value="item.value"
v-for="item in subActivityOptions"></el-option>
</el-select>
</div>
</div>
</div>
<div class="search-query">
<el-button @click="doSearch" icon="el-icon-search" type="primary"></el-button>
</div>
</div>
</el-card> </el-card>
<el-card class="mt10" shadow="never"> <el-card class="mt10" shadow="never">
<table-tool label="参与列表"> <table-tool :app="this" label="参与列表">
<el-button @click="$downLoad(loc() + '/exportUnionRegCheckInNum', {activityId : pageForm.activityId})" <el-button @click="window.open(loc()+'/exportUnionRegCheckInNum?'+buildActivityQueryString())"
class="ml10" class="ml10"
size="small" size="small"
type="primary" type="primary"
icon="el-icon-download"> icon="el-icon-download">
导出报名及打卡人数 导出报名及打卡人数
</el-button> </el-button>
<el-button @click="$downLoad(loc() + '/exportNotGetGiftVoucherUsers', {activityId : pageForm.activityId})"
class="ml10" <el-button
size="small" @click="window.open(loc()+'/exportNotGetGiftVoucherUsers?'+buildActivityQueryString())"
type="primary" class="ml10"
icon="el-icon-download"> size="small"
type="primary"
icon="el-icon-download">
导出未取得礼品券人员 导出未取得礼品券人员
</el-button> </el-button>
<el-button @click="$downLoad(loc() + '/exportNotGetGiftVoucherUsers', {activityId : pageForm.activityId})" <el-button
class="ml10" @click="window.open(loc()+'/exportNotUseGiftVoucherUsers?'+buildActivityQueryString())"
size="small" class="ml10"
type="primary" size="small"
icon="el-icon-download"> type="primary"
icon="el-icon-download">
导出未使用礼品券用户 导出未使用礼品券用户
</el-button> </el-button>
</table-tool> </table-tool>
<el-table :data="tableData" :size="tableSize" show-summary> <el-table :data="tableData" :size="tableSize" show-summary v-loading="tableLoading">
<el-table-column :index="indexMethod" align="center" header-align="center" label="序号" type="index" <el-table-column :index="indexMethod" align="center" header-align="center" label="序号" type="index"
width="80px"></el-table-column> width="80px"></el-table-column>
<el-table-column <el-table-column
@@ -90,13 +121,21 @@ layout("/layouts/platform.html"){
</el-button> </el-button>
</div> </div>
</template> </template>
<el-table :data="regTableData" style="width: 100%" row-key="_id" max-height="600px"> <el-table :data="regTableData" style="width: 100%" row-key="_id" max-height="600px"
<el-table-column label="工号" prop="loginname"></el-table-column> v-loading="tableLoading">
<el-table-column label="姓名" prop="username"></el-table-column> <el-table-column label="活动名称" prop="activityName" show-overflow-tooltip align="center"
<el-table-column label="性别" prop="sex"></el-table-column> header-align="center"></el-table-column>
<el-table-column label="单位" prop="unitname" show-overflow-tooltip></el-table-column> <el-table-column label="工号" prop="loginname" align="center"
<el-table-column label="电话" prop="mobile"></el-table-column> header-align="center"></el-table-column>
<el-table-column label="报名时间" prop="register_time_str"></el-table-column> <el-table-column label="姓名" prop="username" align="center"
header-align="center"></el-table-column>
<el-table-column label="性别" prop="sex" align="center"
header-align="center"></el-table-column>
<el-table-column label="单位" prop="unitname" show-overflow-tooltip align="center"
header-align="center"></el-table-column>
<!-- <el-table-column label="电话" prop="mobile"></el-table-column>-->
<el-table-column label="报名时间" prop="register_time_str" align="center"
header-align="center"></el-table-column>
</el-table> </el-table>
</el-card> </el-card>
<el-card shadow="never" v-else-if="viewIndex==='checkInTableShow'"> <el-card shadow="never" v-else-if="viewIndex==='checkInTableShow'">
@@ -111,15 +150,24 @@ layout("/layouts/platform.html"){
</el-button> </el-button>
</div> </div>
</template> </template>
<el-table :data="regTableData" style="width: 100%" row-key="_id" max-height="600px"> <el-table :data="regTableData" style="width: 100%" row-key="_id" max-height="600px"
<el-table-column label="工号" prop="loginname"></el-table-column> v-loading="tableLoading">
<el-table-column label="姓名" prop="username"></el-table-column> <el-table-column label="活动名称" prop="activityName" show-overflow-tooltip align="center"
<el-table-column label="性别" prop="sex"></el-table-column> header-align="center"></el-table-column>
<el-table-column label="单位" prop="unitname" show-overflow-tooltip></el-table-column> <el-table-column label="工号" prop="loginname" align="center"
<el-table-column label="电话" prop="mobile"></el-table-column> header-align="center"></el-table-column>
<el-table-column label="点位总数" prop="pts_size"></el-table-column> <el-table-column label="姓名" prop="username" align="center"
<el-table-column label="已打卡点位数" prop="sign_size"></el-table-column> header-align="center"></el-table-column>
<el-table-column label="礼品券" prop="used"> <el-table-column label="性别" prop="sex" align="center"
header-align="center"></el-table-column>
<el-table-column label="单位" prop="unitname" show-overflow-tooltip align="center"
header-align="center"></el-table-column>
<!-- <el-table-column label="电话" prop="mobile"></el-table-column>-->
<el-table-column label="点位总数" prop="pts_size" align="center"
header-align="center"></el-table-column>
<el-table-column label="已打卡点位数" prop="sign_size" align="center"
header-align="center"></el-table-column>
<el-table-column v-if="showGiftVoucherColumn" label="礼品券" prop="used">
<template scope="{row}"> <template scope="{row}">
<span v-if="row.used==null" class="text-danger">未取得</span> <span v-if="row.used==null" class="text-danger">未取得</span>
<span v-else-if="row.used" class="text-success">已使用</span> <span v-else-if="row.used" class="text-success">已使用</span>
@@ -132,7 +180,7 @@ layout("/layouts/platform.html"){
</guava> </guava>
</div> </div>
<script> <script nonce="${cspNonce!}">
let vue = new Vue({ let vue = new Vue({
el: '#app', el: '#app',
mixins: [initTableMixins], mixins: [initTableMixins],
@@ -143,6 +191,8 @@ layout("/layouts/platform.html"){
{label: '报名人数', prop: 'regCount'}, {label: '报名人数', prop: 'regCount'},
{label: '打卡人数', prop: 'checkInCount'}, {label: '打卡人数', prop: 'checkInCount'},
], ],
// 礼品券列按当前需求先隐藏,代码保留便于后续恢复。
showGiftVoucherColumn: false,
unionOptions: [], unionOptions: [],
unitOptions: [], unitOptions: [],
pageForm: { pageForm: {
@@ -150,9 +200,13 @@ layout("/layouts/platform.html"){
unitId: '', unitId: '',
activityDate: [], activityDate: [],
year: new Date().getFullYear() + '', year: new Date().getFullYear() + '',
mainActivityId: '',
subActivityId: '',
activityId: '',
}, },
activityOptions: [], activityOptions: [],
subActivityOptions: [],
regTableData: [], regTableData: [],
checkInTableData: [], checkInTableData: [],
@@ -163,38 +217,34 @@ layout("/layouts/platform.html"){
}, },
methods: { methods: {
viewReg({id, unionname}) { viewReg({id, unionname}) {
this.viewUnion.unionId = id this.$set(this.viewUnion, "unionId", id)
this.viewUnion.unionname = unionname this.$set(this.viewUnion, "unionname", unionname)
this.$refs.guava.view(() => { this.$set(this, "viewIndex", 'regTableShow')
this.viewIndex = 'regTableShow' this.$axios.post(loc() + '/unionRegistrationData', Object.assign({
this.$axios.post(loc() + '/unionRegistrationData', { unionId: id
unionId: id, }, this.buildActivityRequestParams())).then(res => {
activityId: this.pageForm.activityId if (res.code === 0) {
}).then(res => { this.$set(this, "regTableData", res.data)
if (res.code === 0) { } else {
this.regTableData = res.data this.$message.error(res.msg)
} else { }
this.$message.error(res.msg)
}
})
}) })
this.$refs.guava.view()
}, },
viewCheckIn({id, unionname}) { viewCheckIn({id, unionname}) {
this.viewUnion.unionId = id this.$set(this.viewUnion, "unionId", id)
this.viewUnion.unionname = unionname this.$set(this.viewUnion, "unionname", unionname)
this.$refs.guava.view(() => { this.$set(this, "viewIndex", 'checkInTableShow')
this.viewIndex = 'checkInTableShow' this.$axios.post(loc() + '/unionCheckInData', Object.assign({
this.$axios.post(loc() + '/unionCheckInData', { unionId: id
unionId: id, }, this.buildActivityRequestParams())).then(res => {
activityId: this.pageForm.activityId if (res.code === 0) {
}).then(res => { this.$set(this, "regTableData", res.data)
if (res.code === 0) { } else {
this.regTableData = res.data this.$message.error(res.msg)
} else { }
this.$message.error(res.msg)
}
})
}) })
this.$refs.guava.view()
}, },
exportExcel() { exportExcel() {
const {hdid, unionId, unitId, activityDate} = this.pageForm const {hdid, unionId, unitId, activityDate} = this.pageForm
@@ -202,58 +252,133 @@ layout("/layouts/platform.html"){
if (activityDate && activityDate.length > 0) { if (activityDate && activityDate.length > 0) {
activityDate1 = JSON.stringify(activityDate) activityDate1 = JSON.stringify(activityDate)
} }
window.open(loc() + '/exportExcel?hdid=' + hdid + '&unionId=' + unionId + '&unitId=' + unitId + '&activityDate=' + activityDate1)
this.$downLoad(loc() + "/exportExcel", {
hdid: hdid,
unionId: unionId,
unitId: unitId,
activityDate: activityDate1
})
}, },
activityDateChange() { activityDateChange() {
}, },
async unionChange(val) { /**
this.pageForm.unitId = null * 统一返回当前活动查询参数。
this.unitOptions = await this.$businessTool.listUnit(val) * 后端会根据主活动、分活动和最终 activityId 决定查单条活动还是查关联活动集合。
*/
buildActivityRequestParams() {
return {
mainActivityId: this.pageForm.mainActivityId,
subActivityId: this.pageForm.subActivityId,
activityId: this.pageForm.activityId
}
},
/**
* 导出接口使用 queryString 传参,这里统一拼接,避免多个按钮重复维护。
*/
buildActivityQueryString() {
const params = this.buildActivityRequestParams()
return 'mainActivityId=' + encodeURIComponent(params.mainActivityId || '')
+ '&subActivityId=' + encodeURIComponent(params.subActivityId || '')
+ '&activityId=' + encodeURIComponent(params.activityId || '')
},
/**
* 根据主活动构建分活动选项,并同步当前真正查询用的活动id。
* 如果主活动下没有分活动,则直接使用主活动id作为查询条件。
*/
syncActivitySelection(mainActivityId, needSearch) {
const currentMainActivity = this.activityOptions.find((item) => {
return item.value === mainActivityId
})
const children = currentMainActivity && currentMainActivity.children ? currentMainActivity.children : []
this.$set(this, 'subActivityOptions', children)
if (!currentMainActivity) {
this.$set(this.pageForm, 'mainActivityId', '')
this.$set(this.pageForm, 'subActivityId', '')
this.$set(this.pageForm, 'activityId', '')
this.$set(this, "tableData", [])
return
}
if (children.length > 0) {
const currentSubActivityId = this.pageForm.subActivityId
const subActivityId = currentSubActivityId && children.some((item) => {
return item.value === currentSubActivityId
}) ? currentSubActivityId : children[0].value
this.$set(this.pageForm, 'subActivityId', subActivityId)
this.$set(this.pageForm, 'activityId', subActivityId)
} else {
this.$set(this.pageForm, 'subActivityId', '')
this.$set(this.pageForm, 'activityId', mainActivityId)
}
if (needSearch) {
this.doSearch()
}
},
/**
* 主活动切换后,重新加载对应的分活动,并默认选中第一条可用分活动。
*/
mainActivityChange(val) {
this.$set(this.pageForm, 'mainActivityId', val || '')
this.$set(this.pageForm, 'subActivityId', '')
this.syncActivitySelection(this.pageForm.mainActivityId, true)
},
/**
* 分活动切换后,同步最终查询用的活动id。
*/
subActivityChange(val) {
this.$set(this.pageForm, 'subActivityId', val || '')
this.$set(this.pageForm, 'activityId', val || this.pageForm.mainActivityId || '')
this.doSearch() this.doSearch()
}, },
unionChange(val) {
this.$set(this.pageForm, "unitId", null)
this.$businessTool.listUnit(val).then((res) => {
this.$set(this, "unitOptions", res)
this.doSearch()
})
},
pageData() { pageData() {
this.$set(this, "tableLoading", true)
this.$axios.post(loc() + '/pageData', this.pageForm).then(res => { this.$axios.post(loc() + '/pageData', this.pageForm).then(res => {
if (res.code === 0) { if (res.code === 0) {
this.tableData = res.data this.$set(this, "tableData", res.data)
} else { } else {
this.$message.error(res.msg) this.$message.error(res.msg)
} }
}).finally(() => {
this.$set(this, "tableLoading", false)
}) })
}, },
async getCascadersActivity() { getCascadersActivity() {
const {code, data} = await this.$axios.post(loc() + '/getCascadersActivity', {year: this.pageForm.year}) this.$axios.post(loc() + '/getCascadersActivity', {year: this.pageForm.year}).then((res) => {
this.activityOptions = data this.$set(this, 'activityOptions', res.data || [])
if (this.activityOptions && this.activityOptions.length > 0) { if (this.activityOptions && this.activityOptions.length > 0) {
this.pageForm.activityId = this.activityOptions[0].value this.$set(this.pageForm, 'mainActivityId', this.activityOptions[0].value)
this.pageData() this.$set(this.pageForm, 'subActivityId', '')
} else { this.syncActivitySelection(this.pageForm.mainActivityId, false)
this.tableData = [] this.pageData()
} } else {
this.$set(this, 'subActivityOptions', [])
this.$set(this.pageForm, 'mainActivityId', '')
this.$set(this.pageForm, 'subActivityId', '')
this.$set(this.pageForm, 'activityId', '')
this.$set(this, "tableData", [])
}
})
}, },
exportCheckInUsers() { exportCheckInUsers() {
this.$downLoad(loc() + '/exportCheckInUsers', { window.open(loc() + '/exportCheckInUsers?unionId=' + this.viewUnion.unionId + '&' + this.buildActivityQueryString())
unionId: this.viewUnion.unionId,
activityId: this.pageForm.activityId
})
}, },
exportRegUsers(){ exportRegUsers() {
this.$downLoad(loc() + '/exportRegUsers', { window.open(loc() + '/exportRegUsers?unionId=' + this.viewUnion.unionId + '&' + this.buildActivityQueryString())
unionId: this.viewUnion.unionId,
activityId: this.pageForm.activityId
})
} }
}, },
async created() { created() {
this.unionOptions = await this.$businessTool.listUnion() this.$businessTool.listUnion().then((res) => {
this.unitOptions = await this.$businessTool.listUnit() this.$set(this, "unionOptions", res)
await this.getCascadersActivity() return this.$businessTool.listUnit()
}).then((res) => {
this.$set(this, "unitOptions", res)
this.getCascadersActivity()
})
} }
}) })
</script> </script>
@@ -7,64 +7,79 @@ layout("/layouts/platform.html"){
<div id="app" v-cloak> <div id="app" v-cloak>
<guava ref="guava"> <guava ref="guava">
<el-card shadow="never"> <el-card shadow="never">
<div class="search">
<div class="search-item">
<div class="search-item-label">年份:</div>
<div class="search-item-option">
<el-date-picker style="width: 100%"
class="mr5"
:picker-options="pickerOptions"
v-model="pageForm.year" :clearable="false"
type="year"
value-format="yyyy" @change="getCascadersActivity"
placeholder="选择年">
</el-date-picker>
</div>
</div>
<div class="search-item">
<div class="search-item-label">活动:</div>
<div class="search-item-option">
<el-cascader
style="width: 100%"
@change="doSearch()"
v-model="pageForm.activityId"
:options="activityOptions"
:props="{ checkStrictly: true,emitPath:false}"
:clearable="false"></el-cascader>
</div>
</div>
<search @search="doSearch"> <div class="search-item">
<search-item label="年份"> <div class="search-item-label">姓名工号:</div>
<el-date-picker style="width: 100%" <div class="search-item-option">
class="mr5" <el-input placeholder="请输入姓名或工号查询" clearable v-model="pageForm.searchKeyword"
:picker-options="pickerOptions" style="width: 100%" @keyup.enter.native="doSearch">
v-model="pageForm.year" :clearable="false" </el-input>
type="year" </div>
value-format="yyyy" @change="getCascadersActivity" </div>
placeholder="选择年">
</el-date-picker>
</search-item>
<search-item label="活动">
<el-cascader
style="width: 100%"
@change="doSearch()"
v-model="pageForm.activityId"
:options="activityOptions"
:props="{ checkStrictly: true,emitPath:false}"
:clearable="false"></el-cascader>
</search-item>
<search-item label="姓名工号"> <div class="search-item">
<el-input placeholder="请输入姓名或工号查询" clearable v-model="pageForm.searchKeyword" <div class="search-item-label">所属工会:</div>
style="width: 100%" @keyup.enter.native="doSearch"> <div class="search-item-option">
</el-input> <el-select @change="unionChange" clearable filterable style="width: 100%"
</search-item> placeholder="请选择所属工会" v-model="pageForm.unionId">
<el-option
:key="item.id"
:label="item.unionname"
:value="item.id"
v-for="item in unionOptions">
</el-option>
</el-select>
</div>
</div>
<div class="search-item">
<div class="search-item-label">所属单位:</div>
<div class="search-item-option">
<el-select @change="doSearch" clearable filterable style="width: 100%"
placeholder="请选择所属单位" v-model="pageForm.unitId">
<el-option
:key="item.id"
:label="item.name"
:value="item.id"
v-for="item in unitOptions">
</el-option>
</el-select>
</div>
</div>
<template v-if="$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')"> <div class="search-query">
<search-item label="所属工会"> <el-button @click="doSearch" icon="el-icon-search" type="primary"></el-button>
<el-select @change="unionChange" clearable filterable style="width: 100%" </div>
placeholder="请选择所属工会" v-model="pageForm.unionId"> </div>
<el-option
:key="item.id"
:label="item.name"
:value="item.id"
v-for="item in unionOptions">
</el-option>
</el-select>
</search-item>
<search-item label="所属单位">
<el-select @change="doSearch" clearable filterable style="width: 100%"
placeholder="请选择所属单位" v-model="pageForm.unitId">
<el-option
:key="item.id"
:label="item.name"
:value="item.id"
v-for="item in unitOptions">
</el-option>
</el-select>
</search-item>
</template>
</search>
</el-card> </el-card>
<el-card class="mt10" shadow="never"> <el-card class="mt10" shadow="never">
<table-tool label="达标人员列表"> <table-tool :app="this" label="达标人员列表">
<el-button @click="setRaffle" class="ml10" size="small" type="primary">设置抽奖条件</el-button> <el-button @click="setRaffle" class="ml10" size="small" type="primary">设置抽奖条件</el-button>
<el-button @click="viewLotteryUsers" class="ml10" size="small" type="primary">查看中奖人员</el-button> <el-button @click="viewLotteryUsers" class="ml10" size="small" type="primary">查看中奖人员</el-button>
<el-button @click="exportExcel" class="ml10" size="small" type="primary">导出达标人员</el-button> <el-button @click="exportExcel" class="ml10" size="small" type="primary">导出达标人员</el-button>
@@ -95,15 +110,17 @@ layout("/layouts/platform.html"){
<el-table tooltip-effect="dark" style="width: 100%" :data="formData.manualLotteryRules"> <el-table tooltip-effect="dark" style="width: 100%" :data="formData.manualLotteryRules">
<el-table-column label="奖项名称" align="center"> <el-table-column label="奖项名称" align="center">
<template scope="scope"> <template scope="scope">
<el-input v-model="scope.row.awardName" placeholder="请输入奖项名称" max="50" clearable></el-input> <el-input v-model="scope.row.awardName" placeholder="请输入奖项名称" max="50"
clearable></el-input>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="奖项积分" align="center"> <el-table-column label="奖项积分" align="center">
<template scope="scope"> <template scope="scope">
<el-input-number v-model="scope.row.points" placeholder="请输入奖项积分" style="width: 100%"></el-input-number> <el-input-number v-model="scope.row.points" placeholder="请输入奖项积分"
</template> style="width: 100%"></el-input-number>
</el-table-column> </template>
</el-table-column>
<el-table-column label="抽奖人数" align="center"> <el-table-column label="抽奖人数" align="center">
<template scope="scope"> <template scope="scope">
@@ -128,8 +145,8 @@ layout("/layouts/platform.html"){
<el-table-column label="排名位次" align="center"> <el-table-column label="排名位次" align="center">
<template scope="scope"> <template scope="scope">
<el-input-number v-if="scope.row.raffleType == '排名'" <el-input-number v-if="scope.row.raffleType == '排名'"
v-model="scope.row.rankingPosition" v-model="scope.row.rankingPosition"
style="width: 100%"></el-input-number> style="width: 100%"></el-input-number>
</template> </template>
</el-table-column> </el-table-column>
@@ -158,7 +175,7 @@ layout("/layouts/platform.html"){
</el-form> </el-form>
<div style="text-align: right"> <div style="text-align: right">
<el-button @click="$refs.guava.index()" class="ml10">返回</el-button> <el-button @click="$refs.guava.index()" class="ml10">返回</el-button>
<el-button @click="saveRaffle" class="ml10" type="primary">提交</el-button> <el-button @click="saveRaffle" class="ml10" type="primary" :loading="formLoading">提交</el-button>
</div> </div>
</el-card> </el-card>
</template> </template>
@@ -194,27 +211,28 @@ layout("/layouts/platform.html"){
</el-card> </el-card>
<el-card class="mt10" shadow="never"> <el-card class="mt10" shadow="never">
<table-tool :app="this" label="中奖人员列表"> <table-tool :app="this" label="中奖人员列表">
<template #func> <el-button @click="exportAwardExcel" icon="el-icon-download" type="primary" size="small">导出中奖人员
<el-button @click="exportAwardExcel" icon="el-icon-download" type="primary" size="small">导出中奖人员</el-button> </el-button>
</template>
</table-tool> </table-tool>
<el-table :data="awardTableData"> <el-table :data="awardTableData">
<el-table-column :index="indexMethod" align="center" header-align="center" label="排名" type="index" <el-table-column :index="indexMethod" align="center" header-align="center" label="排名" type="index"
width="80px"></el-table-column> width="80px"></el-table-column>
<el-table-column align="center" header-align="center" label="工号" prop="loginName"></el-table-column> <el-table-column align="center" header-align="center" label="工号" prop="loginName"></el-table-column>
<el-table-column align="center" header-align="center" label="姓名" prop="username"></el-table-column> <el-table-column align="center" header-align="center" label="姓名" prop="username"></el-table-column>
<el-table-column align="center" header-align="center" label="分工会" prop="unionName"></el-table-column> <el-table-column align="center" header-align="center" label="分工会"
prop="unionName"></el-table-column>
<el-table-column align="center" header-align="center" label="单位" prop="unitName"></el-table-column> <el-table-column align="center" header-align="center" label="单位" prop="unitName"></el-table-column>
<el-table-column align="center" header-align="center" label="奖项名称" prop="awardName"></el-table-column> <el-table-column align="center" header-align="center" label="奖项名称"
prop="awardName"></el-table-column>
</el-table> </el-table>
</el-card> </el-card>
</template> </template>
</guava> </guava>
</div> </div>
<script> <script nonce="${cspNonce!}">
const vue = new Vue({ const vue = new Vue({
el: '#app', el: '#app',
mixins:[initTableMixins], mixins: [initTableMixins],
data() { data() {
return { return {
pickerOptions: { pickerOptions: {
@@ -225,9 +243,11 @@ layout("/layouts/platform.html"){
} }
}, },
pageForm: { pageForm: {
year: moment().format('YYYY'), year: new Date().getFullYear() + '',
unionId:'', activityId: null,
unitId:'' searchKeyword: '',
unionId: '',
unitId: ''
}, },
unionOptions: [], unionOptions: [],
unitOptions: [], unitOptions: [],
@@ -241,8 +261,8 @@ layout("/layouts/platform.html"){
{label: '达标天数', prop: 'standardsDays', sortable: true}, {label: '达标天数', prop: 'standardsDays', sortable: true},
], ],
raffleTypeOptions: [ raffleTypeOptions: [
{ value: '排名', label: '排名' }, {value: '排名', label: '排名'},
{ value: '达标', label: '达标' }, {value: '达标', label: '达标'},
], ],
formData: { formData: {
manualLotteryRules: [] manualLotteryRules: []
@@ -261,119 +281,131 @@ layout("/layouts/platform.html"){
/** /**
* 设置抽奖条件 * 设置抽奖条件
*/ */
async setRaffle(){ setRaffle() {
this.$refs.guava.edit(async () => { this.$refs.guava.edit()
// 获取该活动的抽奖条件 // 获取该活动的抽奖条件
const resp = await this.$axios.post('/platform/fitnessWalk/stepRaffle/getRaffle', { this.$axios.post('/platform/fitnessWalk/stepRaffle/getRaffle', {
activityId: this.pageForm.activityId activityId: this.pageForm.activityId
}) }).then((resp) => {
if (resp.code === 0) { if (resp.code === 0) {
if (resp.data) { if (resp.data) {
this.formData = resp.data this.$set(this, "formData", resp.data)
} }
} else { } else {
this.formData = { this.$set(this, "formData", {
manualLotteryRules: [] manualLotteryRules: []
} })
} }
}) })
}, },
/** /**
* 查看中奖人员 * 查看中奖人员
*/ */
viewLotteryUsers(){ viewLotteryUsers() {
this.$refs.guava.view(() => { this.$refs.guava.view()
this.awardPageData() this.$nextTick(() => {
this.awardPageData()
}) })
}, },
async awardPageData() { awardPageData() {
this.awardPageForm.activityId = this.pageForm.activityId this.$set(this.awardPageForm, "activityId", this.pageForm.activityId)
const resp = await this.$axios.post('/platform/fitnessWalk/stepWining/prizeUsers', this.awardPageForm) this.$axios.post('/platform/fitnessWalk/stepWining/prizeUsers', this.awardPageForm).then((resp) => {
if (resp.code === 0) { if (resp.code === 0) {
this.awardTableData = resp.data this.$set(this, "awardTableData", resp.data)
} }
})
}, },
exportAwardExcel(){ exportAwardExcel() {
const {searchKeyword,activityId,lotteryTime} = this.awardPageForm const {searchKeyword, activityId, lotteryTime} = this.awardPageForm
this.$downLoad(loc() + '/exportAwardExcel', { window.open(loc() + '/exportAwardExcel?searchKeyword=' + searchKeyword +
searchKeyword: searchKeyword, '&activityId=' + activityId + '&lotteryTime=' + lotteryTime)
activityId: activityId,
lotteryTime: lotteryTime
})
}, },
async saveRaffle() { saveRaffle() {
const formData = this.formData console.log(this.formData)
formData.activityId = this.pageForm.activityId const formData = Object.assign({}, this.formData)
formData.manualLotteryRules = JSON.stringify(this.formData.manualLotteryRules) this.$set(formData, "activityId", this.pageForm.activityId)
const resp = await this.$axios.post('/platform/fitnessWalk/stepRaffle/saveRaffle', this.formData) this.$set(formData, "manualLotteryRules", JSON.stringify(this.formData.manualLotteryRules))
if (resp.code === 0) { this.$set(this, "formLoading", true)
this.$message.success('保存成功') this.$axios.post('/platform/fitnessWalk/stepRaffle/saveRaffle', formData).then((resp) => {
this.$refs.guava.index() if (resp.code === 0) {
} else { this.$message.success('保存成功')
this.$message.warning(resp.msg) this.$refs.guava.index()
} } else {
this.$message.warning(resp.msg)
}
}).finally(() => {
this.$set(this, "formLoading", false)
})
}, },
exportExcel(){ exportExcel() {
const {searchKeyword,activityId,unionId,unitId} = this.pageForm const {searchKeyword, activityId, unionId, unitId} = this.pageForm
this.$downLoad(loc() + '/exportExcel', { window.open(loc() + '/exportExcel?searchKeyword=' + searchKeyword +
searchKeyword: searchKeyword, '&activityId=' + activityId + '&unionId=' + unionId + '&unitId=' + unitId)
activityId: activityId,
unionId: unionId,
unitId: unitId
})
}, },
async getAllActivity() { getAllActivity() {
this.pageForm.activityId = '' this.$set(this.pageForm, "activityId", '')
this.activityOptions = [] this.$set(this, "activityOptions", [])
const {data} = await this.$axios.post('/platform/fitnessWalk/activityManage/getAllActivity', this.pageForm) this.$axios.post('/platform/fitnessWalk/activityManage/getAllActivity', this.pageForm).then((res) => {
if (data == null || data.length === 0) { const data = res.data
this.tableData = [] if (data == null || data.length === 0) {
return this.$set(this, "tableData", [])
} else { return
this.activityOptions = data.filter(item => item.activityModel === 'stepCount') } else {
} this.$set(this, "activityOptions", data.filter(item => item.activityModel === 'stepCount'))
}
if (this.activityOptions) { if (this.activityOptions) {
this.pageForm.activityId = this.activityOptions[0]._id this.$set(this.pageForm, "activityId", this.activityOptions[0]._id)
} }
})
}, },
async unionChange(val) { unionChange(val) {
this.pageForm.unitId = null this.$set(this.pageForm, "unitId", null)
this.unitOptions = await this.$businessTool.listUnit(val) this.$businessTool.listUnit(val).then((res) => {
this.doSearch() this.$set(this, "unitOptions", res)
},
async getCascadersActivity() {
const {code, data} = await this.$axios.post(loc() + '/getCascadersActivity', {year: this.pageForm.year})
this.activityOptions = data
if (this.activityOptions && this.activityOptions.length > 0) {
this.pageForm.activityId = this.activityOptions[0].value
this.doSearch() this.doSearch()
} else {
this.tableData = []
}
},
async getAwardUserNum(){
const resp = await this.$axios.post('/platform/fitnessWalk/stepRaffle/getAwardUserNum')
if (resp.code === 0) {
}
},
async getAwardNameOptions(){
const resp = await this.$axios.post('/platform/fitnessWalk/stepWining/prizeOption', {
activityId: this.pageForm.activityId
}) })
if (resp.code === 0) { },
this.awardNameOptions = resp.data getCascadersActivity() {
} this.$axios.post(loc() + '/getCascadersActivity', {year: this.pageForm.year}).then((res) => {
this.$set(this, "activityOptions", res.data)
if (this.activityOptions && this.activityOptions.length > 0) {
this.$set(this.pageForm, "activityId", this.activityOptions[0].value)
this.getAwardNameOptions()
this.doSearch()
} else {
this.$set(this, "tableData", [])
}
})
},
getAwardUserNum() {
this.$axios.post('/platform/fitnessWalk/stepRaffle/getAwardUserNum').then((resp) => {
if (resp.code === 0) {
}
})
},
getAwardNameOptions() {
this.$axios.post('/platform/fitnessWalk/stepWining/prizeOption', {
activityId: this.pageForm.activityId
}).then((resp) => {
if (resp.code === 0) {
this.$set(this, "awardNameOptions", resp.data)
}
})
}, },
}, },
async created() { created() {
this.unionOptions = await this.$businessTool.listUnion() this.$businessTool.listUnion().then((res) => {
this.unitOptions = await this.$businessTool.listUnit() this.$set(this, "unionOptions", res)
await this.getCascadersActivity() return this.$businessTool.listUnit()
await this.getAwardNameOptions() }).then((res) => {
this.$set(this, "unitOptions", res)
this.getCascadersActivity()
this.getAwardNameOptions()
})
} }
}) })
</script> </script>
@@ -7,69 +7,121 @@ layout("/layouts/platform.html"){
<div id="app" v-cloak> <div id="app" v-cloak>
<guava> <guava>
<el-card shadow="never"> <el-card shadow="never">
<search @search="doSearch"> <div class="search">
<search-item label="年份"> <div class="search-item">
<el-date-picker style="width: 100%" <div class="search-item-label">年份:</div>
class="mr5" <div class="search-item-option">
:picker-options="pickerOptions" <el-date-picker style="width: 100%"
v-model="pageForm.year" :clearable="false" class="mr5"
type="year" :picker-options="pickerOptions"
value-format="yyyy" @change="getAllActivity" v-model="pageForm.year" :clearable="false"
placeholder="选择年"> type="year"
</el-date-picker> value-format="yyyy" @change="getCascadersActivity"
</search-item> placeholder="选择年">
</el-date-picker>
</div>
</div>
<div class="search-item">
<div class="search-item-label">活动:</div>
<div class="search-item-option">
<el-cascader
style="width: 100%"
@change="doSearch()"
v-model="pageForm.activityId"
:options="activityOptions"
:props="{ checkStrictly: true,emitPath:false}"
:clearable="false"></el-cascader>
</div>
</div>
<search-item label="活动"> <div class="search-item">
<el-cascader <div class="search-item-label">性别:</div>
style="width: 100%" <div class="search-item-option">
@change="doSearch()" <el-select @change="doSearch" clearable style="width: 100%"
v-model="pageForm.activityId" placeholder="请选择性别" v-model="pageForm.sex">
:options="activityOptions" <el-option label="男" value="男"></el-option>
:props="{ checkStrictly: true,emitPath:false}" <el-option label="女" value="女"></el-option>
:clearable="false"></el-cascader> </el-select>
</search-item> </div>
</div>
<search-item label="姓名/工号"> <div class="search-item">
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.searchKeyword" <div class="search-item-label">年龄:</div>
@keyup.enter.native="doSearch"></el-input> <div class="search-item-option">
</search-item> <el-select @change="doSearch" clearable style="width: 100%"
placeholder="请选择年龄段" v-model="pageForm.ageRange">
<el-option label="40岁及以下" value="under40"></el-option>
<el-option label="41-50岁" value="41to50"></el-option>
<el-option label="51-55岁" value="51to55"></el-option>
<el-option label="55岁以上" value="over55"></el-option>
</el-select>
</div>
</div>
<template v-if="$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')"> <div class="search-item">
<search-item label="所属工会"> <div class="search-item-label">姓名工号:</div>
<el-select @change="unionChange" clearable filterable style="width: 100%" <div class="search-item-option">
placeholder="请选择所属工会" v-model="pageForm.unionId"> <el-input placeholder="请输入内容" clearable v-model="pageForm.searchKeyword"
<el-option style="width: 100%" @keyup.enter.native="doSearch">
:key="item.id" <el-select v-model="pageForm.searchName" slot="prepend" placeholder="查询类型"
:label="item.name" style="width: 110px;">
:value="item.id" <el-option label="姓名" value="u.username"></el-option>
v-for="item in unionOptions"> <el-option label="工号" value="u.loginname"></el-option>
</el-option> </el-select>
</el-select> </el-input>
</search-item> </div>
</div>
<search-item label="所属单位">
<el-select @change="doSearch" clearable filterable style="width: 100%" <div class="search-item">
placeholder="请选择所属单位" v-model="pageForm.unitId"> <div class="search-item-label">所属工会:</div>
<el-option <div class="search-item-option">
:key="item.id" <el-select @change="unionChange" clearable filterable style="width: 100%"
:label="item.name" placeholder="请选择所属工会" v-model="pageForm.unionId">
:value="item.id" <el-option
v-for="item in unitOptions"> :key="item.id"
</el-option> :label="item.unionname"
</el-select> :value="item.id"
</search-item> v-for="item in unionOptions">
</template> </el-option>
</search> </el-select>
</div>
</div>
<div class="search-item">
<div class="search-item-label">所属单位:</div>
<div class="search-item-option">
<el-select @change="doSearch" clearable filterable style="width: 100%"
placeholder="请选择所属单位" v-model="pageForm.unitId">
<el-option
:key="item.id"
:label="item.name"
:value="item.id"
v-for="item in unitOptions">
</el-option>
</el-select>
</div>
</div>
<div class="search-query">
<el-button @click="doSearch" icon="el-icon-search" type="primary"></el-button>
</div>
</div>
</el-card> </el-card>
<el-card class="mt10" shadow="never"> <el-card class="mt10" shadow="never">
<table-tool label="排行榜"> <table-tool :app="this" label="排行榜">
<el-radio-group v-model="pageForm.mode" size="small" @change="doSearch" class="mr10"> <el-radio-group v-model="pageForm.mode" size="small" @change="doSearch">
<el-radio-button label="today">今日排行榜</el-radio-button> <el-radio-button v-for="item in rankingTimeOptions"
<el-radio-button label="all">总排行榜</el-radio-button> :key="item.value"
:label="item.value">{{item.name}}</el-radio-button>
</el-radio-group> </el-radio-group>
<el-button @click="exportExcel" size="small" type="primary">导出{{pageForm.mode == 'today' ? '今日排行榜' : '总排行榜'}}</el-button> <el-button @click="exportExcel" class="ml10" size="small" type="primary">导出{{rankingTimeRangeName}}</el-button>
<!-- 独立导出查询尚未修复,暂时隐藏入口,避免用户导出只有表头的空文件。 -->
<!-- <el-button @click="exportExcel2" class="ml10" size="small" type="primary">导出参与人员总步数</el-button> -->
</table-tool> </table-tool>
<el-table :data="tableData" :size="tableSize"> <el-table :data="tableData"
:size="tableSize"
v-loading="tableLoading"
element-loading-text="数据加载中">
<el-table-column :index="indexMethod" align="center" header-align="center" label="排名" type="index" <el-table-column :index="indexMethod" align="center" header-align="center" label="排名" type="index"
width="80px"></el-table-column> width="80px"></el-table-column>
<el-table-column <el-table-column
@@ -87,7 +139,7 @@ layout("/layouts/platform.html"){
</el-card> </el-card>
</guava> </guava>
</div> </div>
<script> <script nonce="${cspNonce!}">
const vue = new Vue({ const vue = new Vue({
el: '#app', el: '#app',
mixins:[initTableMixins], mixins:[initTableMixins],
@@ -105,69 +157,96 @@ layout("/layouts/platform.html"){
mode:'today', mode:'today',
searchName:'u.username', searchName:'u.username',
unionId:'', unionId:'',
unitId:'' unitId:'',
sex:'',
ageRange:''
}, },
unionOptions: [], unionOptions: [],
unitOptions: [], unitOptions: [],
activityOptions: [], activityOptions: [],
rankingTimeOptions: [
{name: '今日排行榜', value: 'today'},
{name: '近1个月', value: 'oneMonth'},
{name: '近半年', value: 'halfYear'},
{name: '近1年', value: 'oneYear'},
{name: '活动开始至今', value: 'activity'}
],
tableColumns: [ tableColumns: [
{label: '姓名', prop: 'username'}, {label: '姓名', prop: 'username'},
{label: '工号', prop: 'loginname'}, {label: '工号', prop: 'loginname'},
{label: '性别', prop: 'sex'},
{label: '年龄', prop: 'age', sortable: true},
{label: '分工会', prop: 'unionname', sortable: true}, {label: '分工会', prop: 'unionname', sortable: true},
{label: '单位', prop: 'unitname'}, {label: '单位', prop: 'unitname'},
{label: '步数', prop: 'total_steps', sortable: true}, {label: '步数', prop: 'total_steps', sortable: true},
{label: '达标天数', prop: 'standardsDays', sortable: true},
], ],
} }
}, },
computed: {
rankingTimeRangeName() {
const currentOption = this.rankingTimeOptions.find((item) => item.value === this.pageForm.mode)
return currentOption ? currentOption.name : '今日排行榜'
}
},
methods: { methods: {
exportExcel(){ exportExcel(){
const {searchName,searchKeyword,activityId,unionId,unitId,mode,sex,ageRange} = this.pageForm
window.open( loc() + '/exportExcel?searchName=' + searchName + '&searchKeyword=' + searchKeyword +
'&activityId=' + activityId +'&unionId=' + unionId + '&unitId=' + unitId + '&mode=' + mode +
'&sex=' + sex + '&ageRange=' + ageRange)
},
exportExcel2(){
const {searchName,searchKeyword,activityId,unionId,unitId,mode} = this.pageForm const {searchName,searchKeyword,activityId,unionId,unitId,mode} = this.pageForm
this.$downLoad(loc() + '/exportExcel', { window.open( loc() + '/exportExcel2?searchName=' + searchName + '&searchKeyword=' + searchKeyword +
searchName: searchName, '&activityId=' + activityId +'&unionId=' + unionId + '&unitId=' + unitId + '&mode=' + mode)
searchKeyword: searchKeyword,
activityId: activityId,
unionId: unionId,
unitId: unitId,
mode: mode
})
}, },
async getAllActivity() { getAllActivity() {
this.pageForm.activityId = '' this.$set(this.pageForm, "activityId", '')
this.activityOptions = [] this.$set(this, "activityOptions", [])
const {data} = await this.$axios.post('/platform/fitnessWalk/activityManage/getAllActivity', this.pageForm) this.$axios.post('/platform/fitnessWalk/activityManage/getAllActivity', this.pageForm).then((res) => {
if (data == null || data.length === 0) { const data = res.data
this.tableData = [] if (data == null || data.length === 0) {
return this.$set(this, "tableData", [])
} else { return
this.activityOptions = data.filter(item => item.activityModel === 'stepCount') } else {
} this.$set(this, "activityOptions", data.filter(item => item.activityModel === 'stepCount'))
}
if (this.activityOptions) { if (this.activityOptions) {
this.pageForm.activityId = this.activityOptions[0]._id this.$set(this.pageForm, "activityId", this.activityOptions[0]._id)
} }
})
}, },
async unionChange(val) { unionChange(val) {
this.pageForm.unitId = null this.$set(this.pageForm, "unitId", null)
this.unitOptions = await this.$businessTool.listUnit(val) this.$businessTool.listUnit(val).then((res) => {
this.doSearch() this.$set(this, "unitOptions", res)
},
async getCascadersActivity() {
const {code, data} = await this.$axios.post(loc() + '/getCascadersActivity', {year: this.pageForm.year})
this.activityOptions = data
if (this.activityOptions && this.activityOptions.length > 0) {
this.pageForm.activityId = this.activityOptions[0].value
this.doSearch() this.doSearch()
} else { })
this.tableData = [] },
} getCascadersActivity() {
this.$axios.post(loc() + '/getCascadersActivity', {year: this.pageForm.year}).then((res) => {
this.$set(this, "activityOptions", res.data)
if (this.activityOptions && this.activityOptions.length > 0) {
this.$set(this.pageForm, "activityId", this.activityOptions[0].value)
this.doSearch()
} else {
this.$set(this, "tableData", [])
}
})
} }
}, },
async created() { created() {
this.unionOptions = await this.$businessTool.listUnion() this.$businessTool.listUnion().then((res) => {
this.unitOptions = await this.$businessTool.listUnit() this.$set(this, "unionOptions", res)
await this.getCascadersActivity() return this.$businessTool.listUnit()
}).then((res) => {
this.$set(this, "unitOptions", res)
this.getCascadersActivity()
})
} }
}) })
</script> </script>
@@ -5,73 +5,92 @@ layout("/layouts/platform.html"){
<guava ref="guava"> <guava ref="guava">
<template> <template>
<el-card shadow="never"> <el-card shadow="never">
<div class="search">
<div class="search-item">
<div class="search-item-label">年份:</div>
<div class="search-item-option">
<el-date-picker
:clearable="false"
placeholder="选择年"
style="width: 100%"
@change="getCascadersActivity"
type="year" v-model="pageForm.year"
value-format="yyyy">
</el-date-picker>
</div>
</div>
<div class="search-item">
<div class="search-item-label">活动:</div>
<div class="search-item-option">
<el-cascader
style="width: 100%"
@change="activityChange"
v-model="pageForm.activityId"
:options="activityOptions"
:props="{ checkStrictly: true,emitPath:false}"
:clearable="false"></el-cascader>
</div>
</div>
<div class="search-item">
<div class="search-item-label">日期范围:</div>
<div class="search-item-option">
<el-date-picker
end-placeholder="结束日期"
range-separator="至"
start-placeholder="开始日期"
type="daterange"
style="width: 100%"
@change="activityDateChange"
value-format="yyyy-MM-dd"
v-model="pageForm.activityDate">
</el-date-picker>
</div>
</div>
<search @search="doSearch"> <div class="search-item">
<search-item label="年份"> <div class="search-item-label">姓名工号:</div>
<el-date-picker <div class="search-item-option">
:clearable="false" <el-input v-model="pageForm.searchKeyword" max="20" placeholder="请输入工号或者姓名查询" clearable></el-input>
placeholder="选择年" </div>
style="width: 100%" </div>
@change="getCascadersActivity"
type="year" v-model="pageForm.year"
value-format="yyyy">
</el-date-picker>
</search-item>
<search-item label="活动">
<el-cascader
style="width: 100%"
@change="doSearch();getActivityById()"
v-model="pageForm.activityId"
:options="activityOptions"
:props="{ checkStrictly: true,emitPath:false}"
:clearable="false"></el-cascader>
</search-item>
<search-item label="日期范围">
<el-date-picker
end-placeholder="结束日期"
range-separator="至"
start-placeholder="开始日期"
type="daterange"
style="width: 100%"
@change="activityDateChange"
value-format="yyyy-MM-dd"
v-model="pageForm.activityDate">
</el-date-picker>
</search-item>
<search-item label="姓名工号">
<el-input v-model="pageForm.searchKeyword" max="20" placeholder="请输入工号或者姓名查询" clearable></el-input>
</search-item>
<template v-if="$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')"> <div class="search-item">
<search-item label="所属工会"> <div class="search-item-label">所属工会:</div>
<el-select @change="unionChange" clearable filterable style="width: 100%" <div class="search-item-option">
placeholder="请选择所属工会" v-model="pageForm.unionId"> <el-select @change="unionChange" clearable filterable style="width: 100%"
<el-option placeholder="请选择所属工会" v-model="pageForm.unionId">
:key="item.id" <el-option
:label="item.unionname" :key="item.id"
:value="item.id" :label="item.name"
v-for="item in unionOptions"> :value="item.id"
</el-option> v-for="item in unionOptions">
</el-select> </el-option>
</search-item> </el-select>
<search-item label="所属单位"> </div>
<el-select @change="doSearch" clearable filterable style="width: 100%" </div>
placeholder="请选择所属单位" v-model="pageForm.unitId"> <div class="search-item">
<el-option <div class="search-item-label">所属单位:</div>
:key="item.id" <div class="search-item-option">
:label="item.name" <el-select @change="doSearch" clearable filterable style="width: 100%"
:value="item.id" placeholder="请选择所属单位" v-model="pageForm.unitId">
v-for="item in unitOptions"> <el-option
</el-option> :key="item.id"
</el-select> :label="item.name"
</search-item> :value="item.id"
</template> v-for="item in unitOptions">
</el-option>
</el-select>
</div>
</div>
</search> <div class="search-query">
<el-button @click="doSearch" icon="el-icon-search" type="primary"></el-button>
</div>
</div>
</el-card> </el-card>
<el-card class="mt20" shadow="never"> <el-card class="mt20" shadow="never">
<table-tool label="步数列表"> <table-tool :app="this" label="步数列表">
<el-button @click="exportExcel" class="ml10" size="small" type="primary">导出</el-button> <el-button @click="exportExcel" class="ml10" size="small" type="primary">导出</el-button>
</table-tool> </table-tool>
<el-table :data="tableData" :size="tableSize"> <el-table :data="tableData" :size="tableSize">
<el-table-column :index="indexMethod" align="center" header-align="center" label="序号" type="index" <el-table-column :index="indexMethod" align="center" header-align="center" label="序号" type="index"
@@ -99,7 +118,7 @@ layout("/layouts/platform.html"){
</div> </div>
<script> <script nonce="${cspNonce!}">
let vue = new Vue({ let vue = new Vue({
el: '#app', el: '#app',
mixins: [initTableMixins], mixins: [initTableMixins],
@@ -125,9 +144,10 @@ layout("/layouts/platform.html"){
activityOptions: [], activityOptions: [],
activityDatePickerOptions: { activityDatePickerOptions: {
disabledDate: time => { disabledDate: time => {
return ( if (!this.activityInfo.startTime || !this.activityInfo.endTime) {
time <= moment(this.activityInfo.endTime) || time >= moment(this.activityInfo.startTime) return false
); }
return time < $moment(this.activityInfo.startTime) || time > $moment(this.activityInfo.endTime)
} }
}, },
activityInfo:{}, activityInfo:{},
@@ -140,58 +160,68 @@ layout("/layouts/platform.html"){
if (activityDate && activityDate.length > 0) { if (activityDate && activityDate.length > 0) {
activityDate1 = JSON.stringify(activityDate) activityDate1 = JSON.stringify(activityDate)
} }
this.$downLoad(loc() + '/exportExcel', { window.open(loc() + '/exportExcel?activityId=' + activityId + '&unionId=' + unionId + '&unitId=' + unitId + '&activityDate=' + activityDate1)
activityId: activityId,
unionId: unionId,
unitId: unitId,
activityDate: activityDate1
})
}, },
activityDateChange() { activityDateChange() {
// this.$set(this.pageForm, "activityDate", []) // this.$set(this.pageForm, "activityDate", [])
}, },
async unionChange(val) { activityChange() {
this.pageForm.unitId = null
this.unitOptions = await this.$businessTool.listUnit(val)
this.doSearch() this.doSearch()
this.getActivityById()
}, },
async getCascadersActivity() { unionChange(val) {
const {code, data} = await this.$axios.post(loc() + '/getCascadersActivity', {year: this.pageForm.year}) this.$set(this.pageForm, "unitId", null)
this.activityOptions = data this.$businessTool.listUnit(val).then((res) => {
if (this.activityOptions && this.activityOptions.length > 0) { this.$set(this, "unitOptions", res)
this.pageForm.activityId = this.activityOptions[0].value
this.doSearch() this.doSearch()
} else { })
this.tableData = [] },
} getCascadersActivity() {
this.$axios.post(loc() + '/getCascadersActivity', {year: this.pageForm.year}).then((res) => {
this.$set(this, "activityOptions", res.data)
if (this.activityOptions && this.activityOptions.length > 0) {
this.$set(this.pageForm, "activityId", this.activityOptions[0].value)
this.doSearch()
} else {
this.$set(this, "tableData", [])
}
})
}, },
pageData() { pageData() {
this.$set(this, "tableLoading", true)
let pageForm = clone(this.pageForm) let pageForm = clone(this.pageForm)
if (pageForm.activityDate && pageForm.activityDate.length > 0) { if (pageForm.activityDate && pageForm.activityDate.length > 0) {
pageForm.activityDate = JSON.stringify(pageForm.activityDate) this.$set(pageForm, "activityDate", JSON.stringify(pageForm.activityDate))
} }
this.$axios.post(loc() + "/pageData", pageForm, (data) => { this.$axios.post(loc() + "/pageData", pageForm).then((data) => {
if (data.code === 0) { if (data.code === 0) {
this.tableData = data.data.list; this.$set(this, "tableData", data.data.list);
this.pageForm.totalCount = data.data.totalCount; this.$set(this.pageForm, "totalCount", data.data.totalCount);
} else { } else {
this.$message.error(data.msg); this.$message.error(data.msg);
} }
}, "json"); }).finally(() => {
this.$set(this, "tableLoading", false)
});
}, },
async getActivityById(){ getActivityById(){
const resp = await this.$axios.post('/platform/fitnessWalk/activityManage/findOne',{id:this.pageForm.activityId}) this.$axios.post('/platform/fitnessWalk/activityManage/findOne', {id:this.pageForm.activityId}).then((resp) => {
if (resp.code === 0){ if (resp.code === 0){
this.activityInfo = resp.data this.$set(this, "activityInfo", resp.data)
} }
})
} }
}, },
async created() { created() {
this.unionOptions = await this.$businessTool.listUnion() this.$businessTool.listUnion().then((res) => {
this.unitOptions = await this.$businessTool.listUnit() this.$set(this, "unionOptions", res)
await this.getCascadersActivity() return this.$businessTool.listUnit()
await this.getActivityById(); }).then((res) => {
this.$set(this, "unitOptions", res)
this.getCascadersActivity()
this.getActivityById();
})
} }
}) })
</script> </script>
@@ -21,29 +21,80 @@ layout("/layouts/platform.html"){
<div id="app" v-cloak> <div id="app" v-cloak>
<guava> <guava>
<el-card shadow="never"> <el-card shadow="never">
<div class="search">
<div class="search-item">
<div class="search-item-label">年份:</div>
<div class="search-item-option">
<el-date-picker style="width: 100%"
class="mr5"
:picker-options="pickerOptions"
v-model="pageForm.year" :clearable="false"
type="year"
value-format="yyyy" @change="getCascadersActivity"
placeholder="选择年">
</el-date-picker>
</div>
</div>
<div class="search-item">
<div class="search-item-label">活动:</div>
<div class="search-item-option">
<el-cascader
style="width: 100%"
@change="doSearch()"
v-model="pageForm.activityId"
:options="activityOptions"
:props="{ checkStrictly: true,emitPath:false}"
:clearable="false"></el-cascader>
</div>
</div>
<!--<div class="search-item">
<div class="search-item-label">姓名工号:</div>
<div class="search-item-option">
<el-input placeholder="请输入内容" clearable v-model="pageForm.searchKeyword"
style="width: 100%" @keyup.enter.native="doSearch">
<el-select v-model="pageForm.searchName" slot="prepend" placeholder="查询类型"
style="width: 110px;">
<el-option label="姓名" value="u.username"></el-option>
<el-option label="工号" value="u.loginname"></el-option>
</el-select>
</el-input>
</div>
</div>
<search @search="doSearch"> <template>
<search-item label="年份"> <div class="search-item">
<el-date-picker style="width: 100%" <div class="search-item-label">所属工会:</div>
class="mr5" <div class="search-item-option">
:picker-options="pickerOptions" <el-select @change="unionChange" clearable filterable style="width: 100%"
v-model="pageForm.year" :clearable="false" placeholder="请选择所属工会" v-model="pageForm.unionId">
type="year" <el-option
value-format="yyyy" @change="getAllActivity" :key="item.id"
placeholder="选择年"> :label="item.unionname"
</el-date-picker> :value="item.id"
</search-item> v-for="item in unionOptions">
</el-option>
<search-item label="活动"> </el-select>
<el-cascader </div>
style="width: 100%" </div>
@change="doSearch()" <div class="search-item">
v-model="pageForm.activityId" <div class="search-item-label">所属单位:</div>
:options="activityOptions" <div class="search-item-option">
:props="{ checkStrictly: true,emitPath:false}" <el-select @change="doSearch" clearable filterable style="width: 100%"
:clearable="false"></el-cascader> placeholder="请选择所属单位" v-model="pageForm.unitId">
</search-item> <el-option
</search> :key="item.id"
:label="item.name"
:value="item.id"
v-for="item in unitOptions">
</el-option>
</el-select>
</div>
</div>
</template>-->
<div class="search-query">
<el-button @click="doSearch" icon="el-icon-search" type="primary"></el-button>
</div>
</div>
</el-card> </el-card>
<el-card class="mt10" shadow="never" style="height: 100px"> <el-card class="mt10" shadow="never" style="height: 100px">
@@ -65,7 +116,7 @@ layout("/layouts/platform.html"){
</el-card> </el-card>
<el-card class="mt10" shadow="never"> <el-card class="mt10" shadow="never">
<table-tool label="中奖榜"> <table-tool :app="this" label="中奖榜">
<el-button @click="exportUserStepWining" class="ml10" size="small" type="primary">导出中奖名单</el-button> <el-button @click="exportUserStepWining" class="ml10" size="small" type="primary">导出中奖名单</el-button>
</table-tool> </table-tool>
<el-table :data="tableData" :size="tableSize"> <el-table :data="tableData" :size="tableSize">
@@ -84,7 +135,7 @@ layout("/layouts/platform.html"){
</el-card> </el-card>
</guava> </guava>
</div> </div>
<script> <script nonce="${cspNonce!}">
const vue = new Vue({ const vue = new Vue({
el: '#app', el: '#app',
mixins:[initTableMixins], mixins:[initTableMixins],
@@ -122,62 +173,78 @@ layout("/layouts/platform.html"){
}, },
methods: { methods: {
exportUserStepWining(){ exportUserStepWining(){
this.$downLoad(loc() + '/exportUserStepWining', { window.open( loc() + '/exportUserStepWining?activityId=' + this.pageForm.activityId)
activityId: this.pageForm.activityId
})
}, },
async getAllActivity() { getAllActivity() {
this.pageForm.activityId = '' this.$set(this.pageForm, "activityId", '')
this.activityOptions = [] this.$set(this, "activityOptions", [])
const {data} = await this.$axios.post('/platform/fitnessWalk/activityManage/getAllActivity', this.pageForm) this.$axios.post('/platform/fitnessWalk/activityManage/getAllActivity', this.pageForm).then((res) => {
if (data == null || data.length === 0) { const data = res.data
this.tableData = [] if (data == null || data.length === 0) {
return this.$set(this, "tableData", [])
} else { return
this.activityOptions = data.filter(item => item.activityModel === 'stepCount') } else {
} this.$set(this, "activityOptions", data.filter(item => item.activityModel === 'stepCount'))
if (this.activityOptions) { }
this.pageForm.activityId = this.activityOptions[0]._id if (this.activityOptions) {
} this.$set(this.pageForm, "activityId", this.activityOptions[0]._id)
}
})
}, },
async unionChange(val) { unionChange(val) {
this.pageForm.unitId = null this.$set(this.pageForm, "unitId", null)
this.unitOptions = await this.$businessTool.listUnit(val) this.$businessTool.listUnit(val).then((res) => {
this.doSearch() this.$set(this, "unitOptions", res)
this.doSearch()
})
}, },
subsectionChange(key) { subsectionChange(key) {
const data = this.allDataList.find(item => item.title === key) const data = this.allDataList.find(item => item.title === key)
this.tableData = data.awardList this.$set(this, "tableData", data ? data.awardList || [] : [])
}, },
async pageData(){ pageData(){
const resp = await this.$axios.post(loc() + '/getUserStepWining',this.pageForm) this.$set(this, "tableLoading", true)
if (resp.code === 0){ this.$axios.post(loc() + '/getUserStepWining', this.pageForm).then((resp) => {
this.allDataList = resp.data if (resp.code === 0){
this.subsectionList = resp.data.map(v => { this.$set(this, "allDataList", resp.data || [])
return { this.$set(this, "subsectionList", this.allDataList.map(v => {
name: v.title, return {
key: v.title name: v.title,
key: v.title
}
}))
if (this.allDataList.length > 0) {
this.$set(this, "tableData", this.allDataList[0].awardList || [])
this.$set(this, "changKeyItem", this.allDataList[0].title)
} else {
this.$set(this, "tableData", [])
this.$set(this, "changKeyItem", '')
} }
}) }
this.tableData = this.allDataList[0].awardList }).finally(() => {
this.changKeyItem = this.allDataList[0].title this.$set(this, "tableLoading", false)
} })
}, },
async getCascadersActivity() { getCascadersActivity() {
const {code, data} = await this.$axios.post(loc() + '/getCascadersActivity', {year: this.pageForm.year}) this.$axios.post(loc() + '/getCascadersActivity', {year: this.pageForm.year}).then((res) => {
this.activityOptions = data this.$set(this, "activityOptions", res.data)
if (this.activityOptions && this.activityOptions.length > 0) { if (this.activityOptions && this.activityOptions.length > 0) {
this.pageForm.activityId = this.activityOptions[0].value this.$set(this.pageForm, "activityId", this.activityOptions[0].value)
this.doSearch() this.doSearch()
} else { } else {
this.tableData = [] this.$set(this, "tableData", [])
} }
})
}, },
}, },
async created() { created() {
this.unionOptions = await this.$businessTool.listUnion() this.$businessTool.listUnion().then((res) => {
this.unitOptions = await this.$businessTool.listUnit() this.$set(this, "unionOptions", res)
await this.getCascadersActivity() return this.$businessTool.listUnit()
}).then((res) => {
this.$set(this, "unitOptions", res)
this.getCascadersActivity()
})
} }
}) })
</script> </script>
@@ -329,7 +329,8 @@ layout("/layouts/platform.html"){
this.$set(this.formData, 'parentalLeave', 10); this.$set(this.formData, 'parentalLeave', 10);
} else { } else {
this.$set(this.formData, 'maternityLeave', 98); this.$set(this.formData, 'maternityLeave', 98);
this.$set(this.formData, 'extendLeave', 60); // 三胎申请的延长假为90天,其他申请保持60天。
this.$set(this.formData, 'extendLeave', row.isThreeChildren ? 90 : 60);
} }
this.$refs.maternityLeaveInfoRef.onOpen(row) this.$refs.maternityLeaveInfoRef.onOpen(row)
}) })
@@ -358,7 +358,8 @@ layout("/layouts/platform_h5.html"){
this.$set(this.formData, 'parentalLeave', 10); this.$set(this.formData, 'parentalLeave', 10);
} else { } else {
this.$set(this.formData, 'maternityLeave', 98); this.$set(this.formData, 'maternityLeave', 98);
this.$set(this.formData, 'extendLeave', 60); // 三胎申请的延长假为90天,其他申请保持60天。
this.$set(this.formData, 'extendLeave', row.isThreeChildren ? 90 : 60);
} }
this.$refs.maternityLeaveInfoRef.onOpen(row) this.$refs.maternityLeaveInfoRef.onOpen(row)
}, },