diff --git a/backend/src/main/java/com/budwk/app/module/activity/controller/ActGroupController.java b/backend/src/main/java/com/budwk/app/module/activity/controller/ActGroupController.java index 5859bdd..72fd33f 100644 --- a/backend/src/main/java/com/budwk/app/module/activity/controller/ActGroupController.java +++ b/backend/src/main/java/com/budwk/app/module/activity/controller/ActGroupController.java @@ -3,14 +3,26 @@ package com.budwk.app.module.activity.controller; import cn.dev33.satoken.annotation.SaCheckPermission; import com.budwk.app.base.page.PageForm; import com.budwk.app.base.result.Result; +import com.budwk.app.module.activity.models.ActGroup; +import com.budwk.app.module.activity.models.ActUser; +import com.budwk.app.module.activity.service.ActGroupService; import com.budwk.app.module.activity.service.ActUserService; +import com.budwk.app.module.activity.vo.ActGroupVo; +import com.budwk.app.web.commons.slog.annotation.SLog; import lombok.extern.slf4j.Slf4j; +import org.nutz.dao.Cnd; import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.util.NutMap; import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.Ok; +import java.util.ArrayList; +import java.util.List; + /** * @version 1.0 * @Author zzr @@ -28,6 +40,8 @@ public class ActGroupController { private Dao dao; @Inject private ActUserService actUserService; + @Inject + private ActGroupService actGroupService; @At("") @SaCheckPermission("activity.group") @@ -41,4 +55,42 @@ public class ActGroupController { public Result pageData(PageForm pageForm, String activityId){ return null; } + + + /** + * 查询签到人员 + * @param activityId + * @return + */ + @At + @SaCheckPermission("activity.group") + public Result querySingUpData(String activityId){ + Sql sql = Sqls.create(""" + SELECT + act.id AS activityId, + act.title AS activityName, + COUNT(u.id) AS signUpNum, + SUM(CASE WHEN u.sex = '男' THEN 1 ELSE 0 END) AS manNum, + SUM(CASE WHEN u.sex = '女' THEN 1 ELSE 0 END) AS womanNum + FROM + act_user u + LEFT JOIN activity act ON act.id = u.activityId + WHERE + u.isSignIn = 1 AND u.activityId = @activityId + """).setParam("activityId", activityId); + sql.setCallback(Sqls.callback.map()); + dao.execute(sql); + NutMap map = (NutMap) sql.getResult(); + return Result.success().addData(map); + } + + + @At + @SaCheckPermission("activity.group") + @SLog(tag = "活动分组", msg = "随机分组") + public Result groupSetting(ActGroupVo actGroupVo){ + // 查询所有签到的用户,按照分组参数进行分组 + actGroupService.groupSetting(actGroupVo); + return Result.success(); + } } diff --git a/backend/src/main/java/com/budwk/app/module/activity/models/ActUnGroupUser.java b/backend/src/main/java/com/budwk/app/module/activity/models/ActUnGroupUser.java new file mode 100644 index 0000000..dcddb5b --- /dev/null +++ b/backend/src/main/java/com/budwk/app/module/activity/models/ActUnGroupUser.java @@ -0,0 +1,35 @@ +package com.budwk.app.module.activity.models; + +import com.budwk.app.base.model.BaseModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.nutz.dao.entity.annotation.*; + +/** + * @version 1.0 + * @Author zzr + * @name:ActUnGroupUser + * @Date 2025/4/29 14:12 + * @注释 :未分组人员 + */ +@Data +@Table("act_un_group_user") +@Comment("活动未分组人员") +@EqualsAndHashCode(callSuper = true) +@TableMeta("{'mysql-charset':'utf8mb4'}") +public class ActUnGroupUser extends BaseModel { + + @Id + @Comment("ID") + private Long id; + + @Column + @Comment("活动ID") + @ColDefine(customType = "bigint") + private Long activityId; + + @Column + @Comment("用户ID") + @ColDefine(customType = "bigint") + private Long userId; +} diff --git a/backend/src/main/java/com/budwk/app/module/activity/service/ActGroupService.java b/backend/src/main/java/com/budwk/app/module/activity/service/ActGroupService.java index a45619a..2ae2559 100644 --- a/backend/src/main/java/com/budwk/app/module/activity/service/ActGroupService.java +++ b/backend/src/main/java/com/budwk/app/module/activity/service/ActGroupService.java @@ -2,6 +2,7 @@ package com.budwk.app.module.activity.service; import com.budwk.app.base.service.BaseService; import com.budwk.app.module.activity.models.ActGroup; +import com.budwk.app.module.activity.vo.ActGroupVo; /** * @ClassName ActGroupService @@ -11,4 +12,7 @@ import com.budwk.app.module.activity.models.ActGroup; * @Description TODO */ public interface ActGroupService extends BaseService { + + + void groupSetting(ActGroupVo groupVo); } diff --git a/backend/src/main/java/com/budwk/app/module/activity/service/impl/ActGroupServiceImpl.java b/backend/src/main/java/com/budwk/app/module/activity/service/impl/ActGroupServiceImpl.java index f7e6b57..85bf43c 100644 --- a/backend/src/main/java/com/budwk/app/module/activity/service/impl/ActGroupServiceImpl.java +++ b/backend/src/main/java/com/budwk/app/module/activity/service/impl/ActGroupServiceImpl.java @@ -2,10 +2,24 @@ package com.budwk.app.module.activity.service.impl; import com.budwk.app.base.service.impl.BaseServiceImpl; import com.budwk.app.module.activity.models.ActGroup; +import com.budwk.app.module.activity.models.ActGroupUser; +import com.budwk.app.module.activity.models.ActUnGroupUser; +import com.budwk.app.module.activity.models.ActUser; import com.budwk.app.module.activity.service.ActGroupService; +import com.budwk.app.module.activity.vo.ActGroupVo; +import org.nutz.aop.interceptor.ioc.TransAop; +import org.nutz.dao.Cnd; import org.nutz.dao.Dao; +import org.nutz.ioc.aop.Aop; import org.nutz.ioc.loader.annotation.IocBean; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + /** * @ClassName ActGroupServiceImpl * @Author JyuHsin @@ -19,4 +33,98 @@ public class ActGroupServiceImpl extends BaseServiceImpl implements Ac public ActGroupServiceImpl(Dao dao) { super(dao); } + + + @Override + @Aop(TransAop.READ_COMMITTED) + public void groupSetting(ActGroupVo groupVo) { + // 删除已经存在的分组信息 + dao().clear(ActGroup.class, Cnd.where(ActGroup::getActivityId, "=", groupVo.getActivityId())); + dao().clear(ActGroupUser.class, Cnd.where(ActGroupUser::getActivityId, "=", groupVo.getActivityId())); + dao().clear(ActUnGroupUser.class, Cnd.where(ActUnGroupUser::getActivityId, "=", groupVo.getActivityId())); + + // 查询报名了并且已经完成签到的人员 + List signUpUserList = dao().query(ActUser.class, Cnd.where(ActUser::getActivityId, "=", groupVo.getActivityId()) + .and(ActUser::getIsSignIn, "=", 1)); + + int size = signUpUserList.size(); + Integer oneGroupLimitUserNum = groupVo.getOneGroupLimitUserNum(); + + int result = Math.floorDiv(size, oneGroupLimitUserNum); + // 初始化分组 + List> groups = Collections.nCopies(result, new ArrayList<>()); + + // 分离男女用户 + Map> genderMap = signUpUserList.stream() + .collect(Collectors.groupingBy(user -> "男".equals(user.getSex()) ? "男" : "女")); + + List males = genderMap.getOrDefault("男", Collections.emptyList()); + List females = genderMap.getOrDefault("女", Collections.emptyList()); + + // 随机化列表 + Collections.shuffle(males); + Collections.shuffle(females); + + // 尝试分配 + List unassignedUsers = new ArrayList<>(); + + int maleIndex = 0, femaleIndex = 0; + while (maleIndex < males.size() || femaleIndex < females.size()) { + boolean assigned = false; + for (List group : groups) { + if (group.size() < groupVo.getOneGroupLimitUserNum()) { + int currentMaleCount = (int) group.stream().filter(u -> "男".equals(u.getSex())).count(); + int currentFemaleCount = (int) group.stream().filter(u -> "女".equals(u.getSex())).count(); + + if (maleIndex < males.size() && (groupVo.getManUserNum() == -1 || currentMaleCount < groupVo.getManUserNum())) { + group.add(males.get(maleIndex++)); + assigned = true; + } else if (femaleIndex < females.size() && (groupVo.getWomanUserNum() == -1 || currentFemaleCount < groupVo.getWomanUserNum())) { + group.add(females.get(femaleIndex++)); + assigned = true; + } + } + } + if (!assigned) { + break; + } + } + + // 收集未分配的用户 + unassignedUsers.addAll(males.subList(maleIndex, males.size())); + unassignedUsers.addAll(females.subList(femaleIndex, females.size())); + + // 往组别表里面添加记录 + List groupList = IntStream.range(0, groups.size()) + .mapToObj(index -> { + ActGroup actGroup = new ActGroup(); + actGroup.setActivityId(groupVo.getActivityId()); + actGroup.setGroupName("第" + (index + 1) + "组"); + + List userList = groups.get(index).stream().map(v -> { + ActGroupUser user = new ActGroupUser(); + user.setUserId(v.getId()); + user.setActivityId(groupVo.getActivityId()); + return user; + }).collect(Collectors.toList()); + + actGroup.setGroupUsers(userList); + return actGroup; + }).toList(); + + + for (ActGroup group : groupList) { + dao().insertWith(group, "groupUsers"); + } + + + // 添加未能正确分组的人员 + List userList = unassignedUsers.stream().map(v -> { + ActUnGroupUser user = new ActUnGroupUser(); + user.setUserId(v.getUserId()); + user.setActivityId(groupVo.getActivityId()); + return user; + }).toList(); + dao().insert(userList); + } } diff --git a/backend/src/main/java/com/budwk/app/module/activity/vo/ActGroupVo.java b/backend/src/main/java/com/budwk/app/module/activity/vo/ActGroupVo.java new file mode 100644 index 0000000..d9a28f1 --- /dev/null +++ b/backend/src/main/java/com/budwk/app/module/activity/vo/ActGroupVo.java @@ -0,0 +1,26 @@ +package com.budwk.app.module.activity.vo; + +import lombok.Data; + +/** + * @version 1.0 + * @Author zzr + * @name:ActGroupVo + * @Date 2025/4/29 11:12 + * @注释 + */ +@Data +public class ActGroupVo { + + // 活动ID + private Long activityId; + + // 单个小组限制人数 + private Integer oneGroupLimitUserNum; + + // 限制男用户人数,设-1为不限制 + private Integer manUserNum; + + // 限制女用户人数,设-1为不限制 + private Integer womanUserNum; +} diff --git a/backend/src/main/resources/views/platform/activity/group/groupSetting.js b/backend/src/main/resources/views/platform/activity/group/groupSetting.js new file mode 100644 index 0000000..7d80338 --- /dev/null +++ b/backend/src/main/resources/views/platform/activity/group/groupSetting.js @@ -0,0 +1,100 @@ +const GROUP_SETTING = { + template: /*language=HTML*/ ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 设-1则标识不限制 + + + + + + + + + + + 取消 + 分组 + + + `, + data(){ + return{ + groupingDialog: false, + form: { + activityId: '', + activityName: '', + groupNum: 0, + oneGroupLimitUserNum: 0, + manUserNum: 0, + womanUserNum: 0 + }, + formRules: { + oneGroupLimitUserNum: [{ required: true, message: '请输入单个小组限制总人数', trigger: ['blur', 'change'] }], + manUserNum: [{ required: true, message: '请输入男用户限制人数', trigger: ['blur', 'change'] }], + womanUserNum: [{ required: true, message: '请输入女用户限制人数', trigger: ['blur', 'change'] }] + }, + } + }, + methods: { + async onOpen(activityId){ + const resp = await $.post('/platform/activity/group/querySingUpData', {activityId}) + if (resp.code === 0) { + this.form = {...resp.data} + this.groupingDialog = true + } + }, + async onGroupingSubmit(){ + console.log(this.form) + const loading = this.$loading({ + lock: true, + text: '分组确认中,请稍后...', + spinner: 'el-icon-loading', + background: 'rgba(0, 0, 0, 0.7)' + }); + const resp = await $.post('/platform/activity/group/groupSetting', this.form) + loading.close() + if (resp.code === 0) { + this.groupingDialog = false + this.$refs.formRef.resetFields() + this.$message.success(resp.msg) + } else { + this.$message.error('操作失败') + } + } + } +} diff --git a/backend/src/main/resources/views/platform/activity/group/index.html b/backend/src/main/resources/views/platform/activity/group/index.html index e69de29..0f0fa01 100644 --- a/backend/src/main/resources/views/platform/activity/group/index.html +++ b/backend/src/main/resources/views/platform/activity/group/index.html @@ -0,0 +1,90 @@ + +
+ + + + + + + 开始分组 + + + + + + +
+ + diff --git a/backend/src/main/resources/views/platform/activity/user/index.html b/backend/src/main/resources/views/platform/activity/user/index.html index 5d87f53..30048be 100644 --- a/backend/src/main/resources/views/platform/activity/user/index.html +++ b/backend/src/main/resources/views/platform/activity/user/index.html @@ -388,7 +388,6 @@ layout("/layouts/platform_1.html"){ this.$set(this.pageForm, 'activityId', this.activityList[0].id) } else { this.$set(this.pageForm, 'activityId', '') - console.log(resp.msg) } this.pageData() }