commit
This commit is contained in:
+52
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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<ActGroup> {
|
||||
|
||||
|
||||
void groupSetting(ActGroupVo groupVo);
|
||||
}
|
||||
|
||||
+108
@@ -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<ActGroup> 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<ActUser> 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<List<ActUser>> groups = Collections.nCopies(result, new ArrayList<>());
|
||||
|
||||
// 分离男女用户
|
||||
Map<String, List<ActUser>> genderMap = signUpUserList.stream()
|
||||
.collect(Collectors.groupingBy(user -> "男".equals(user.getSex()) ? "男" : "女"));
|
||||
|
||||
List<ActUser> males = genderMap.getOrDefault("男", Collections.emptyList());
|
||||
List<ActUser> females = genderMap.getOrDefault("女", Collections.emptyList());
|
||||
|
||||
// 随机化列表
|
||||
Collections.shuffle(males);
|
||||
Collections.shuffle(females);
|
||||
|
||||
// 尝试分配
|
||||
List<ActUser> unassignedUsers = new ArrayList<>();
|
||||
|
||||
int maleIndex = 0, femaleIndex = 0;
|
||||
while (maleIndex < males.size() || femaleIndex < females.size()) {
|
||||
boolean assigned = false;
|
||||
for (List<ActUser> 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<ActGroup> groupList = IntStream.range(0, groups.size())
|
||||
.mapToObj(index -> {
|
||||
ActGroup actGroup = new ActGroup();
|
||||
actGroup.setActivityId(groupVo.getActivityId());
|
||||
actGroup.setGroupName("第" + (index + 1) + "组");
|
||||
|
||||
List<ActGroupUser> 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<ActUnGroupUser> userList = unassignedUsers.stream().map(v -> {
|
||||
ActUnGroupUser user = new ActUnGroupUser();
|
||||
user.setUserId(v.getUserId());
|
||||
user.setActivityId(groupVo.getActivityId());
|
||||
return user;
|
||||
}).toList();
|
||||
dao().insert(userList);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
const GROUP_SETTING = {
|
||||
template: /*language=HTML*/ `
|
||||
<el-dialog title="设定随机分组参数" :visible.sync="groupingDialog" width="50%">
|
||||
<el-form :model="form" :rules="formRules" label-width="150px" ref="formRef">
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="活动名称" prop="activityName">
|
||||
<el-input v-model="form.activityName" readonly></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="活动签到总人数" prop="signUpNum">
|
||||
<el-input v-model="form.signUpNum" readonly></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="签到男用户数" prop="manNum">
|
||||
<el-input v-model="form.manNum" readonly></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="签到女用户数" prop="womanNum">
|
||||
<el-input v-model="form.womanNum" readonly></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="24">
|
||||
<el-form-item label="单个小组限制总人数" prop="oneGroupLimitUserNum">
|
||||
<el-input-number style="width: 100%" v-model="form.oneGroupLimitUserNum"
|
||||
placeholder="请输入单个小组限制总人数"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12">
|
||||
<el-form-item label="男用户限制人数" prop="manUserNum">
|
||||
<el-input-number style="width: 100%" v-model="form.manUserNum"
|
||||
placeholder="请输入男用户限制人数"></el-input-number>
|
||||
<span style="color: #bc2a25">设-1则标识不限制</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="女用户限制人数" prop="womanUserNum">
|
||||
<el-input-number style="width: 100%" v-model="form.womanUserNum"
|
||||
placeholder="请输入女用户限制人数"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="groupingDialog = false">取消</el-button>
|
||||
<el-button type="primary" @click="onGroupingSubmit">分组</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
`,
|
||||
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('操作失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_1.html"){
|
||||
#-->
|
||||
<div id="app">
|
||||
<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%"
|
||||
type="year"
|
||||
@change="getActivityList"
|
||||
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-select @change="doSearch"
|
||||
placeholder="请选择活动查询"
|
||||
style="width: 100%;"
|
||||
v-model="pageForm.activityId">
|
||||
<el-option :label="item.title" :value="item.id"
|
||||
v-for="item in activityList"></el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="mt-3">
|
||||
<el-row type="flex" class="mb-3" style="justify-content: flex-end">
|
||||
<el-button icon="el-icon-plus" type="primary" size="small" @click="openGrouping">开始分组</el-button>
|
||||
</el-row>
|
||||
<el-table v-loading="tableLoading" show-overflow-tooltip :data="tableData">
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
<group-setting ref="groupSettingRef"></group-setting>
|
||||
</div>
|
||||
<script>
|
||||
<!--#include('groupSetting.js'){}#-->
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
components: {
|
||||
"group-setting": GROUP_SETTING
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pageForm: {
|
||||
year: new Date().getFullYear() + ""
|
||||
},
|
||||
activityList: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openGrouping(){
|
||||
if (!this.pageForm.activityId) {
|
||||
this.$message.error("请选择活动")
|
||||
return
|
||||
}
|
||||
this.$refs.groupSettingRef.onOpen(this.pageForm.activityId)
|
||||
},
|
||||
async getActivityList(){
|
||||
const resp = await $.post('/platform/activity/user/getActivityList', {
|
||||
year: this.pageForm.year
|
||||
})
|
||||
if (resp.code === 0 && resp.data && resp.data.length > 0) {
|
||||
this.activityList = resp.data
|
||||
this.$set(this.pageForm, 'activityId', this.activityList[0].id)
|
||||
} else {
|
||||
this.$set(this.pageForm, 'activityId', '')
|
||||
}
|
||||
// this.pageData()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getActivityList()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user