commit
This commit is contained in:
+16
-2
@@ -18,6 +18,7 @@ import com.budwk.app.zhgh.activity.basic.models.ActivityUserScope;
|
||||
import com.budwk.app.zhgh.activity.trainSignUp.models.*;
|
||||
import com.budwk.app.zhgh.activity.trainSignUp.service.TrainSignUpActivityService;
|
||||
import com.budwk.app.zhgh.activity.trainSignUp.service.TrainSignUpActivityStatisticsService;
|
||||
import com.budwk.app.zhgh.activity.trainSignUp.service.TrainSignUpBlackListService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -48,10 +49,13 @@ import java.util.stream.Collectors;
|
||||
public class TrainSignUpApplyController {
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(true);
|
||||
private static final String SIGN_UP_LIMIT_MSG = "您已被限制报名香樟工会讲堂,请联系校工会。";
|
||||
|
||||
@Inject
|
||||
private TrainSignUpActivityService trainSignUpActivityService;
|
||||
@Inject
|
||||
private TrainSignUpBlackListService trainSignUpBlackListService;
|
||||
@Inject
|
||||
private SysDictService dictService;
|
||||
@Inject
|
||||
private TrainSignUpActivityStatisticsService statisticsService;
|
||||
@@ -218,6 +222,9 @@ public class TrainSignUpApplyController {
|
||||
@Param(value = "currentFamilyNumber") Integer currentFamilyNumber,String IsVerifyUserApply) {
|
||||
try {
|
||||
lock.lock();
|
||||
if (isLimitedByAbsenceBlackList()) {
|
||||
return Result.error(SIGN_UP_LIMIT_MSG);
|
||||
}
|
||||
if (StrUtil.isBlank(courseId)) {
|
||||
return Result.error("报名信息为空");
|
||||
}
|
||||
@@ -350,6 +357,9 @@ public class TrainSignUpApplyController {
|
||||
public Result doSignUp(TrainSignUpUser trainSignUpUser) {
|
||||
try {
|
||||
lock.lock();
|
||||
if (isLimitedByAbsenceBlackList()) {
|
||||
return Result.error(SIGN_UP_LIMIT_MSG);
|
||||
}
|
||||
boolean courseByUser = trainSignUpActivityService.isSignCourseByUser(trainSignUpUser.getCourseId(), SecurityUtil.getUserId());
|
||||
if (courseByUser) {
|
||||
return Result.error("您已报过该活动");
|
||||
@@ -430,12 +440,16 @@ public class TrainSignUpApplyController {
|
||||
@SaCheckPermission(value = {"trainSignUp.apply", "h5.trainSignUp.apply"}, mode = SaMode.OR)
|
||||
@SLog(tag = "品牌活动-活动报名", msg = "判断缺席次数")
|
||||
public Result validSignCount(@Param("activityId") String activityId) {
|
||||
if (trainSignUpActivityService.isAbsenceSignUpLimited(SecurityUtil.getUserId())) {
|
||||
return Result.error(99, "您已连续2次未签到活动,不能报名,请联系校工会");
|
||||
if (isLimitedByAbsenceBlackList()) {
|
||||
return Result.error(99, SIGN_UP_LIMIT_MSG);
|
||||
}
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
private boolean isLimitedByAbsenceBlackList() {
|
||||
return trainSignUpBlackListService.autoBlackByYearAndUser(DateUtil.year(new Date()), SecurityUtil.getUserId());
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("活动代人报名")
|
||||
@SaCheckPermission(value = {"trainSignUp.apply"}, mode = SaMode.OR)
|
||||
|
||||
+8
-21
@@ -10,11 +10,8 @@ import com.budwk.app.flow.entity.ProcessInstance;
|
||||
import com.budwk.app.flow.enums.ProcessInstanceStateEnum;
|
||||
import com.budwk.app.sys.models.Sys_home_activity;
|
||||
import com.budwk.app.sys.models.Sys_unit;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.activity.trainSignUp.models.*;
|
||||
import com.budwk.app.zhgh.activity.trainSignUp.service.TrainSignUpActivityService;
|
||||
import com.budwk.app.sys.models.Sys_user;
|
||||
import com.budwk.app.sys.services.SysMsgService;
|
||||
import com.budwk.app.zhgh.club.model.SysClub;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
@@ -26,6 +23,8 @@ 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.json.Json;
|
||||
import org.nutz.lang.Lang;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
@@ -53,8 +52,6 @@ public class TrainSignUpManageController {
|
||||
@Inject
|
||||
private TrainSignUpActivityService trainSignUpActivityManageService;
|
||||
@Inject
|
||||
private SysMsgService sysMsgService;
|
||||
@Inject
|
||||
private Dao dao;
|
||||
|
||||
@At("")
|
||||
@@ -245,24 +242,14 @@ public class TrainSignUpManageController {
|
||||
@Ok("json:full")
|
||||
@ApiOperation("通知报名人员")
|
||||
@SaCheckPermission("trainSignUp.manage")
|
||||
public Result sendNotify(@Param("activityId") String activityId, @Param("content") String content) {
|
||||
if (StrUtil.isBlank(activityId) || StrUtil.isBlank(content)) {
|
||||
public Result sendNotify(@Param("activityId") String activityId, @Param("courseIds") String courseIds, @Param("content") String content) {
|
||||
if (StrUtil.isBlank(activityId) || StrUtil.isBlank(courseIds) || StrUtil.isBlank(content)) {
|
||||
return Result.error("参数不完整");
|
||||
}
|
||||
// 查询该活动下所有报名人员(state=1为正常报名)
|
||||
List<TrainSignUpUser> userList = dao.query(TrainSignUpUser.class, Cnd.where("activityId", "=", activityId).and("state", "=", 1));
|
||||
if (userList.isEmpty()) {
|
||||
return Result.error("该活动暂无报名人员");
|
||||
List<String> courseIdList = Json.fromJsonAsList(String.class, courseIds);
|
||||
if (Lang.isEmpty(courseIdList)) {
|
||||
return Result.error("请选择要通知的分活动");
|
||||
}
|
||||
// 获取所有报名人员的userId
|
||||
List<String> userIds = userList.stream().map(TrainSignUpUser::getUserId).distinct().toList();
|
||||
// 查询用户信息获取loginname
|
||||
List<Sys_user> sysUsers = dao.query(Sys_user.class, Cnd.where("id", "in", userIds));
|
||||
List<String> loginNames = sysUsers.stream().map(Sys_user::getLoginname).filter(StrUtil::isNotBlank).toList();
|
||||
if (loginNames.isEmpty()) {
|
||||
return Result.error("未找到有效的报名人员");
|
||||
}
|
||||
sysMsgService.sendMsg(loginNames, "香樟工会讲堂活动通知", content, SecurityUtil.getUserId());
|
||||
return Result.success("通知发送成功");
|
||||
return trainSignUpActivityManageService.sendNotify(activityId, courseIdList, content);
|
||||
}
|
||||
}
|
||||
|
||||
+13
-287
@@ -1,42 +1,24 @@
|
||||
package com.budwk.app.zhgh.activity.trainSignUp.controller.manage;
|
||||
|
||||
import cn.afterturn.easypoi.excel.entity.ExportParams;
|
||||
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
|
||||
import cn.afterturn.easypoi.excel.export.ExcelExportService;
|
||||
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.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.zhgh.activity.trainSignUp.models.TrainSignUpActivity;
|
||||
import com.budwk.app.zhgh.activity.trainSignUp.models.TrainSignUpCourse;
|
||||
import com.budwk.app.zhgh.activity.trainSignUp.models.TrainSignUpUser;
|
||||
import com.budwk.app.zhgh.activity.trainSignUp.service.TrainSignUpBlackListService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.nutz.dao.Chain;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.dao.util.cri.Static;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Strings;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author zxy
|
||||
* @Description 人员管理
|
||||
@@ -48,8 +30,6 @@ import java.util.stream.Collectors;
|
||||
@At("/platform/trainSignUp/userManage")
|
||||
public class TrainSignUpUserManageController {
|
||||
|
||||
@Inject
|
||||
private Dao dao;
|
||||
@Inject
|
||||
private TrainSignUpBlackListService trainSignUpBlackListService;
|
||||
|
||||
@@ -63,288 +43,34 @@ public class TrainSignUpUserManageController {
|
||||
@ApiOperation("分页查询")
|
||||
@SaCheckPermission("trainSignUp.userManage")
|
||||
public Result pageData(PageForm pageForm,
|
||||
@Param(value = "activityId") String activityId,
|
||||
@Param(value = "courseId") String courseId,
|
||||
@Param(value = "year") Integer year,
|
||||
@Param(value = "userKeyWord") String userKeyWord) {
|
||||
// 接口参数:pageForm 传分页和排序参数,year 传统计年度,userKeyWord 传姓名或工号关键字;
|
||||
// 返回 Result<Pagination>,列表包含用户信息、年度签到统计、当前黑名单状态和最近解封时间。
|
||||
Integer queryYear = year == null ? DateUtil.thisYear() : year;
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.andEX("tsuu.activityId", "=", activityId);
|
||||
cnd.andEX("tsuu.courseId", "=", courseId);
|
||||
cnd.andEX("act.year", "=", year);
|
||||
if (StrUtil.isNotBlank(userKeyWord)) {
|
||||
// 人员关键词支持姓名和工号;搜索时允许展示未报名但存在于用户视图中的人员,便于管理员手动拉黑。
|
||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||
cnd.and(seg.andLike("u.username", userKeyWord).orLike("u.loginname", userKeyWord));
|
||||
}
|
||||
if(Strings.isNotBlank(pageForm.getPageOrderName()) && Strings.isNotBlank(pageForm.getPageOrderBy())){
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
} else {
|
||||
// 默认列表只展示本年度有报名统计或已有黑名单记录的人员,避免一次性铺开全部用户。
|
||||
cnd.and(new Static("(signStats.userId is not null OR tsubl.userId is not null)"));
|
||||
}
|
||||
|
||||
Pagination pagination = trainSignUpBlackListService.pageData(pageForm, cnd, activityId, courseId);
|
||||
Pagination pagination = trainSignUpBlackListService.pageData(pageForm, cnd, queryYear);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("报名人员处理")
|
||||
@SaCheckPermission("trainSignUp.userManage")
|
||||
@SLog(tag = "品牌活动-人员管理", msg = "报名人员处理")
|
||||
@SLog(tag = "品牌活动-人员管理", msg = "报名人员处理")
|
||||
public Result doHandleUser(@Param("userId") String userId) {
|
||||
// 接口参数:userId 传被处理人员ID;返回 Result,code=0 表示本次拉黑或解封处理成功。
|
||||
// 手动处理只切换当前黑名单状态:拉黑时禁止后续报名;解封时记录 lastUnblockTime,后续自动拉黑从该时间重新累计缺席。
|
||||
trainSignUpBlackListService.doHandleUser(userId);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("根据活动Id获取子活动")
|
||||
@SaCheckPermission("trainSignUp.userManage")
|
||||
public Result getCourseByActivityId(@Param("activityId") String activityId) {
|
||||
List<TrainSignUpCourse> list = dao.query(TrainSignUpCourse.class, Cnd.where("activityId", "=", activityId));
|
||||
return Result.success(list);
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("获取子活动具体时间")
|
||||
@SaCheckPermission("trainSignUp.userManage")
|
||||
public Result attendClassRecord(String userId) {
|
||||
trainSignUpBlackListService.attendClassRecord(userId);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("获取候补人员")
|
||||
@SaCheckPermission("trainSignUp.userManage")
|
||||
public Result getReserveUser(String courseId) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
uc.* ,
|
||||
(select signUpTime from train_sign_up_user su where su.activityId=uc.activityId and su.courseId = uc.courseId and su.userId=uc.userId) as signUpTime,
|
||||
(select state from train_sign_up_user su where su.activityId=uc.activityId and su.courseId = uc.courseId and su.userId=uc.userId) as state,
|
||||
u.username,
|
||||
u.loginname,
|
||||
u.mobile,
|
||||
u.unitName,
|
||||
u.unionName
|
||||
FROM
|
||||
train_sign_up_user_course uc LEFT JOIN `vw_user` u on uc.userId = u.id
|
||||
WHERE uc.courseId = @courseId and uc.isAttend = false HAVING state = 2 order by signUpTime desc
|
||||
""").setParam("courseId", courseId);
|
||||
return Result.success(trainSignUpBlackListService.listMap(sql));
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("补充人员")
|
||||
@SaCheckPermission("trainSignUp.userManage")
|
||||
@SLog(tag = "品牌活动-人员管理", msg = "补充人员")
|
||||
public Result reserveSingUp(String[] ids, String courseId) {
|
||||
//先查询这个课程有多少个未签到的人员
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
uc.* ,
|
||||
(select signUpTime from train_sign_up_user su where su.activityId=uc.activityId and su.courseId = uc.courseId and su.userId=uc.userId) as signUpTime,
|
||||
(select state from train_sign_up_user su where su.activityId=uc.activityId and su.courseId = uc.courseId and su.userId=uc.userId) as state
|
||||
FROM
|
||||
train_sign_up_user_course uc
|
||||
WHERE uc.courseId = @courseId and uc.isAttend = false HAVING state = 1 order by signUpTime desc
|
||||
""").setParam("courseId", courseId);
|
||||
List<NutMap> list = trainSignUpBlackListService.listMap(sql);
|
||||
if(ids.length > list.size()) {
|
||||
return Result.error("您选择了" + ids.length + "位,未签到人员只有" + list.size() + "位");
|
||||
}
|
||||
//ids的长度为几,就搞几个
|
||||
List<NutMap> mapList = list.subList(0, ids.length);
|
||||
List<String> idList = mapList.stream().map(o -> o.getString("userId")).collect(Collectors.toList());
|
||||
//将这几个没签到的设置为4
|
||||
dao.update(TrainSignUpUser.class, Chain.make("state", 4), Cnd.where("courseId", "=", courseId)
|
||||
.and("userId", "in", idList));
|
||||
//将补充的设置为1
|
||||
dao.update(TrainSignUpUser.class, Chain.make("state", 1), Cnd.where("courseId", "=", courseId)
|
||||
.and("userId", "in", ids));
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@Ok("void")
|
||||
@ApiOperation("导出签到人员")
|
||||
public void exportSignPerson(@Param(value = "activityId") String activityId,
|
||||
HttpServletResponse response) {
|
||||
TrainSignUpActivity activity = dao.fetch(TrainSignUpActivity.class, activityId);
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
uc.*,
|
||||
DATE_FORMAT(uc.courseStartTime, '%Y-%m-%d %H:%i:%s') as courseStartTimeExcel,
|
||||
DATE_FORMAT(uc.courseEndTime, '%Y-%m-%d %H:%i:%s') as courseEndTimeExcel,
|
||||
DATE_FORMAT(uc.attendTime, '%Y-%m-%d %H:%i:%s') as attendTimeExcel,
|
||||
u.username,
|
||||
u.loginname,
|
||||
u.unitName,
|
||||
u.unionName,
|
||||
u.sex
|
||||
FROM
|
||||
train_sign_up_user_course uc
|
||||
left join train_sign_up_course course on uc.courseId = course.id
|
||||
left join `vw_user` u on u.id = uc.userId
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("uc.activityId", "=", activityId);
|
||||
cnd.and("course.isMobileSign", "=", true);
|
||||
cnd.desc("isAttend").desc("attendTime");
|
||||
sql.setCondition(cnd);
|
||||
|
||||
List<NutMap> userList = trainSignUpBlackListService.listMap(sql);
|
||||
|
||||
List<TrainSignUpCourse> courseList = dao.query(TrainSignUpCourse.class, Cnd.where("activityId", "=", activityId));
|
||||
|
||||
List<Map<String, Object>> sheetsList = new ArrayList<>();
|
||||
|
||||
List<ExcelExportEntity> excelCommonExportEntity = new ArrayList<>();
|
||||
excelCommonExportEntity.add(new ExcelExportEntity("姓名", "username", 20));
|
||||
excelCommonExportEntity.add(new ExcelExportEntity("工号", "loginname", 20));
|
||||
excelCommonExportEntity.add(new ExcelExportEntity("单位", "unitName", 20));
|
||||
excelCommonExportEntity.add(new ExcelExportEntity("分工会", "unionName", 20));
|
||||
excelCommonExportEntity.add(new ExcelExportEntity("性别", "sex", 20));
|
||||
excelCommonExportEntity.add(new ExcelExportEntity("开始时间", "courseStartTimeExcel", 22));
|
||||
excelCommonExportEntity.add(new ExcelExportEntity("结束时间", "courseEndTimeExcel", 22));
|
||||
excelCommonExportEntity.add(new ExcelExportEntity("是否签到", "isAttend", 20));
|
||||
excelCommonExportEntity.add(new ExcelExportEntity("签到时间", "attendTimeExcel", 22));
|
||||
|
||||
for (TrainSignUpCourse c : courseList) {
|
||||
if(!c.isMobileSign()) {
|
||||
continue;
|
||||
}
|
||||
String courseId = c.getId();
|
||||
String courseName = c.getCourseName();
|
||||
List<NutMap> v = userList.stream().filter(x -> x.getString("courseId").equals(courseId)).collect(Collectors.toList());
|
||||
ExportParams userExportParams = new ExportParams();
|
||||
userExportParams.setSheetName(courseName);
|
||||
|
||||
List<ExcelExportEntity> currentEntities = new ArrayList<>(excelCommonExportEntity);
|
||||
for (NutMap userSignData : v) {
|
||||
if(!userSignData.getBoolean("isAttend")) {
|
||||
userSignData.put("isAttend", "未签到");
|
||||
userSignData.put("attendTimeExcel", "未签到");
|
||||
}else {
|
||||
userSignData.put("isAttend", "已签到");
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Object> userExportMap = new HashMap<>();
|
||||
userExportMap.put("name", courseName);
|
||||
userExportMap.put("title", userExportParams);
|
||||
userExportMap.put("entity", currentEntities);
|
||||
userExportMap.put("data", v);
|
||||
|
||||
sheetsList.add(userExportMap);
|
||||
}
|
||||
try {
|
||||
String fileName = activity.getActivityName() + "签到人员名单.xls";
|
||||
String disposition = "attachment;filename=" + URLEncoder.encode(fileName, "utf-8");
|
||||
response.setCharacterEncoding("utf-8");
|
||||
response.setContentType("application/octet-stream");
|
||||
response.setHeader("Content-Disposition", disposition);
|
||||
|
||||
Workbook workbook = new HSSFWorkbook();
|
||||
for (Map<String, Object> map : sheetsList) {
|
||||
ExcelExportService service = new ExcelExportService();
|
||||
service.createSheetForMap(workbook,(ExportParams) map.get("title"),(List<ExcelExportEntity>) map.get("entity"),(Collection<?>) map.get("data"));
|
||||
}
|
||||
|
||||
workbook.write(response.getOutputStream());
|
||||
workbook.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@At
|
||||
@Ok("void")
|
||||
@ApiOperation("导出领取人员")
|
||||
public void exportGiftPerson(@Param(value = "activityId") String activityId,
|
||||
HttpServletResponse response) {
|
||||
TrainSignUpActivity activity = dao.fetch(TrainSignUpActivity.class, activityId);
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
uc.*,
|
||||
DATE_FORMAT(uc.courseStartTime, '%Y-%m-%d %H:%i:%s') as courseStartTimeExcel,
|
||||
DATE_FORMAT(uc.courseEndTime, '%Y-%m-%d %H:%i:%s') as courseEndTimeExcel,
|
||||
DATE_FORMAT(uc.receiveTime, '%Y-%m-%d %H:%i:%s') as receiveTimeExcel,
|
||||
u.username,
|
||||
u.loginname,
|
||||
u.unitName,
|
||||
u.unionName,
|
||||
u.sex
|
||||
FROM
|
||||
train_sign_up_user_course uc
|
||||
left join train_sign_up_course course on uc.courseId = course.id
|
||||
left join `vw_user` u on u.id = uc.userId
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("uc.activityId", "=", activityId);
|
||||
cnd.and("course.isReceiveGift", "=", true).and("course.giftType" ,"=", 1);
|
||||
cnd.desc("isReceive").desc("receiveTime");
|
||||
sql.setCondition(cnd);
|
||||
|
||||
List<NutMap> userList = trainSignUpBlackListService.listMap(sql);
|
||||
|
||||
List<TrainSignUpCourse> courseList = dao.query(TrainSignUpCourse.class, Cnd.where("activityId", "=", activityId));
|
||||
|
||||
List<Map<String, Object>> sheetsList = new ArrayList<>();
|
||||
|
||||
List<ExcelExportEntity> excelCommonExportEntity = new ArrayList<>();
|
||||
excelCommonExportEntity.add(new ExcelExportEntity("姓名", "username", 20));
|
||||
excelCommonExportEntity.add(new ExcelExportEntity("工号", "loginname", 20));
|
||||
excelCommonExportEntity.add(new ExcelExportEntity("单位", "unitName", 20));
|
||||
excelCommonExportEntity.add(new ExcelExportEntity("分工会", "unionName", 20));
|
||||
excelCommonExportEntity.add(new ExcelExportEntity("性别", "sex", 20));
|
||||
excelCommonExportEntity.add(new ExcelExportEntity("开始时间", "courseStartTimeExcel", 22));
|
||||
excelCommonExportEntity.add(new ExcelExportEntity("结束时间", "courseEndTimeExcel", 22));
|
||||
excelCommonExportEntity.add(new ExcelExportEntity("是否领取", "isReceive", 20));
|
||||
excelCommonExportEntity.add(new ExcelExportEntity("领取时间", "receiveTimeExcel", 22));
|
||||
|
||||
for (TrainSignUpCourse c : courseList) {
|
||||
String courseId = c.getId();
|
||||
String courseName = c.getCourseName();
|
||||
List<NutMap> v = userList.stream().filter(x -> x.getString("courseId").equals(courseId)).collect(Collectors.toList());
|
||||
ExportParams userExportParams = new ExportParams();
|
||||
userExportParams.setSheetName(courseName);
|
||||
|
||||
List<ExcelExportEntity> currentEntities = new ArrayList<>(excelCommonExportEntity);
|
||||
for (NutMap userSignData : v) {
|
||||
if(!userSignData.getBoolean("isReceive")) {
|
||||
userSignData.put("isReceive", "未领取");
|
||||
userSignData.put("receiveTimeExcel", "未领取");
|
||||
}else {
|
||||
userSignData.put("isReceive", "已领取");
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Object> userExportMap = new HashMap<>();
|
||||
userExportMap.put("name", courseName);
|
||||
userExportMap.put("title", userExportParams);
|
||||
userExportMap.put("entity", currentEntities);
|
||||
userExportMap.put("data", v);
|
||||
|
||||
sheetsList.add(userExportMap);
|
||||
}
|
||||
try {
|
||||
String fileName = activity.getActivityName() + "礼品领取人员名单.xls";
|
||||
String disposition = "attachment;filename=" + URLEncoder.encode(fileName, "utf-8");
|
||||
response.setCharacterEncoding("utf-8");
|
||||
response.setContentType("application/octet-stream");
|
||||
response.setHeader("Content-Disposition", disposition);
|
||||
|
||||
Workbook workbook = new HSSFWorkbook();
|
||||
for (Map<String, Object> map : sheetsList) {
|
||||
ExcelExportService service = new ExcelExportService();
|
||||
service.createSheetForMap(workbook,(ExportParams) map.get("title"),(List<ExcelExportEntity>) map.get("entity"),(Collection<?>) map.get("data"));
|
||||
}
|
||||
|
||||
workbook.write(response.getOutputStream());
|
||||
workbook.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import lombok.experimental.Accessors;
|
||||
import org.nutz.dao.entity.annotation.*;
|
||||
import org.nutz.dao.interceptor.annotation.PrevInsert;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Comment("品牌活动黑名单(香樟工会)")
|
||||
@@ -28,4 +30,10 @@ public class TrainSignUpBlackList {
|
||||
@Comment("是否禁用")
|
||||
private Boolean isDisabled;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.DATETIME)
|
||||
@Comment("最近解封时间,用于重置本年度自动拉黑缺席统计起点")
|
||||
private Date lastUnblockTime;
|
||||
|
||||
|
||||
}
|
||||
|
||||
+11
@@ -2,6 +2,7 @@ package com.budwk.app.zhgh.activity.trainSignUp.service;
|
||||
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
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.zhgh.activity.trainSignUp.models.TrainSignUpActivity;
|
||||
import com.budwk.app.zhgh.activity.trainSignUp.models.TrainSignUpCourse;
|
||||
@@ -140,4 +141,14 @@ public interface TrainSignUpActivityService extends BaseService<TrainSignUpActiv
|
||||
* @param trainSignUpUser
|
||||
*/
|
||||
void doSignUpInsteadApply(TrainSignUpUser trainSignUpUser);
|
||||
|
||||
/**
|
||||
* 按活动下的分活动通知报名人员。
|
||||
*
|
||||
* @param activityId 主活动ID,用于限定本次通知所属活动
|
||||
* @param courseIds 分活动ID列表,至少选择一个;仅通知这些分活动下正常报名人员
|
||||
* @param content 通知正文内容
|
||||
* @return Result,成功时返回通知发送成功,失败时返回无报名人员或无有效接收人等原因
|
||||
*/
|
||||
Result sendNotify(String activityId, List<String> courseIds, String content);
|
||||
}
|
||||
|
||||
+25
-6
@@ -17,20 +17,39 @@ import java.util.List;
|
||||
public interface TrainSignUpBlackListService extends BaseService<TrainSignUpBlackList> {
|
||||
|
||||
/**
|
||||
* 分页
|
||||
* 年度人员黑名单分页。
|
||||
*
|
||||
* @param pageForm 分页
|
||||
* @return Pagination
|
||||
* @param pageForm 分页参数,包含页码、每页数量、排序字段和排序方向
|
||||
* @param cnd 人员查询条件,搜索时按姓名/工号过滤,未搜索时只展示年度报名人员或已有黑名单记录人员
|
||||
* @param year 统计年度,对应 train_sign_up_activity.year
|
||||
* @return Pagination 列表字段包含用户基础信息、年度报名统计、当前黑名单状态和最近解封时间
|
||||
*/
|
||||
Pagination pageData(PageForm pageForm, Cnd cnd, String activityId, String courseId);
|
||||
Pagination pageData(PageForm pageForm, Cnd cnd, Integer year);
|
||||
|
||||
/**
|
||||
* 拉黑、解封用户
|
||||
* 手动拉黑或解封用户。
|
||||
*
|
||||
* @param userId
|
||||
* @param userId 用户ID;当前无记录时新增拉黑,当前已拉黑时解封并记录 lastUnblockTime,当前已解封时再次拉黑
|
||||
*/
|
||||
void doHandleUser(String userId);
|
||||
|
||||
/**
|
||||
* 判断用户是否处于品牌活动黑名单中。
|
||||
*
|
||||
* @param userId 当前报名用户ID
|
||||
* @return true 表示用户已被拉黑,不能继续报名品牌活动
|
||||
*/
|
||||
boolean isBlackListed(String userId);
|
||||
|
||||
/**
|
||||
* 按年度自动判断用户是否应被拉黑。
|
||||
*
|
||||
* @param year 当前统计年度,统计 train_sign_up_activity.year 等于该年度的报名签到记录
|
||||
* @param userId 当前报名用户ID
|
||||
* @return true 表示用户当前已被拉黑或已达到年度自动拉黑条件,不能继续报名
|
||||
*/
|
||||
boolean autoBlackByYearAndUser(Integer year, String userId);
|
||||
|
||||
/**
|
||||
* 上课记录
|
||||
*
|
||||
|
||||
+46
@@ -6,9 +6,12 @@ import cn.hutool.core.date.DateUtil;
|
||||
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.result.Result;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.sys.models.Sys_home_activity;
|
||||
import com.budwk.app.sys.models.Sys_config;
|
||||
import com.budwk.app.sys.models.Sys_user;
|
||||
import com.budwk.app.sys.services.SysMsgService;
|
||||
import com.budwk.app.sys.views.View_user;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.activity.trainSignUp.models.*;
|
||||
@@ -48,6 +51,8 @@ public class TrainSignUpActivityServiceImpl extends BaseServiceImpl<TrainSignUpA
|
||||
|
||||
@Inject
|
||||
private TrainSignUpActivityStatisticsService statisticsService;
|
||||
@Inject
|
||||
private SysMsgService sysMsgService;
|
||||
|
||||
public TrainSignUpActivityServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
@@ -621,4 +626,45 @@ public class TrainSignUpActivityServiceImpl extends BaseServiceImpl<TrainSignUpA
|
||||
asyncInsertUserCourse(trainSignUpUser.getActivityId(), trainSignUpUser.getCourseId(), trainSignUpUser.getUserId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result sendNotify(String activityId, List<String> courseIds, String content) {
|
||||
if (StrUtil.isBlank(activityId) || Lang.isEmpty(courseIds) || StrUtil.isBlank(content)) {
|
||||
return Result.error("参数不完整");
|
||||
}
|
||||
|
||||
// 按主活动和所选分活动限定通知范围,仅发送给正常报名人员;state=3 是候补转正常后的状态。
|
||||
List<TrainSignUpUser> userList = dao().query(
|
||||
TrainSignUpUser.class,
|
||||
Cnd.where("activityId", "=", activityId)
|
||||
.and("courseId", "in", courseIds)
|
||||
.and("state", "in", List.of(1, 3))
|
||||
);
|
||||
if (Lang.isEmpty(userList)) {
|
||||
return Result.error("所选分活动暂无报名人员");
|
||||
}
|
||||
|
||||
List<String> userIds = userList.stream()
|
||||
.map(TrainSignUpUser::getUserId)
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.distinct()
|
||||
.toList();
|
||||
if (Lang.isEmpty(userIds)) {
|
||||
return Result.error("未找到有效的报名人员");
|
||||
}
|
||||
|
||||
List<Sys_user> sysUsers = dao().query(Sys_user.class, Cnd.where("id", "in", userIds));
|
||||
List<String> loginNames = sysUsers.stream()
|
||||
.map(Sys_user::getLoginname)
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.distinct()
|
||||
.toList();
|
||||
if (Lang.isEmpty(loginNames)) {
|
||||
return Result.error("未找到有效的报名人员");
|
||||
}
|
||||
|
||||
sysMsgService.sendMsg(loginNames, "香樟工会讲堂活动通知", content, SecurityUtil.getUserId());
|
||||
return Result.success("通知发送成功");
|
||||
}
|
||||
}
|
||||
|
||||
+148
-32
@@ -7,15 +7,19 @@ import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.zhgh.activity.trainSignUp.models.TrainSignUpBlackList;
|
||||
import com.budwk.app.zhgh.activity.trainSignUp.service.TrainSignUpBlackListService;
|
||||
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.Sqls;
|
||||
import org.nutz.dao.sql.Criteria;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Lang;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -31,41 +35,63 @@ public class TrainSignUpUserServiceImpl extends BaseServiceImpl<TrainSignUpBlack
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pagination pageData(PageForm pageForm, Cnd cnd, String activityId, String courseId) {
|
||||
public Pagination pageData(PageForm pageForm, Cnd cnd, Integer year) {
|
||||
// 年度黑名单列表按一次报名统计签到结果:同一 userId + activityId + courseId 下多个签到时间段只算一次。
|
||||
// 只要该报名任意时间段已签到,就算已签到;全部未签到且最后一个时间段已结束,才算缺席。
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
u.id AS userId,
|
||||
u.username,
|
||||
u.loginname,
|
||||
ifnull(tsuu.mobile, u.mobile) as mobile,
|
||||
u.unitName,
|
||||
u.unionName,
|
||||
tsuc.courseName,
|
||||
tsuu.state,
|
||||
( SELECT count( 1 ) FROM train_sign_up_user_course WHERE userId = tsuu.userId $var) courseTotal,
|
||||
( SELECT count( 1 ) FROM train_sign_up_user_course WHERE userId = tsuu.userId AND isAttend = 0 and tsuu.state!=2 AND now()> courseEndTime $var) AS absentCount,
|
||||
( SELECT count( 1 ) FROM train_sign_up_user_course WHERE userId = tsuu.userId AND isAttend = 1 and tsuu.state!=2 AND now()> courseEndTime $var) AS signCount,
|
||||
( SELECT count( 1 ) FROM train_sign_up_user_course WHERE userId = tsuu.userId and tsuu.state!=2 $var) AS totalCount,
|
||||
if(tsubl.isDisabled=1,true,false) isDisabled,
|
||||
group_CONCAT( tsuc.courseName ) AS courseNames
|
||||
u.username,
|
||||
u.loginname,
|
||||
u.mobile,
|
||||
u.unitName,
|
||||
u.unionName,
|
||||
IFNULL(signStats.totalCount, 0) AS totalCount,
|
||||
IFNULL(signStats.signCount, 0) AS signCount,
|
||||
IFNULL(signStats.absentCount, 0) AS absentCount,
|
||||
if(tsubl.isDisabled=1,true,false) isDisabled,
|
||||
tsubl.lastUnblockTime
|
||||
FROM
|
||||
`train_sign_up_user` tsuu
|
||||
LEFT JOIN `vw_user` u ON u.id = tsuu.userId
|
||||
LEFT JOIN train_sign_up_activity act on act.id = tsuu.activityId
|
||||
LEFT JOIN train_sign_up_course tsuc ON tsuc.id = tsuu.courseId
|
||||
LEFT JOIN train_sign_up_black_list tsubl on tsubl.userId = tsuu.userId
|
||||
`vw_user` u
|
||||
LEFT JOIN train_sign_up_black_list tsubl on tsubl.userId = u.id
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
applyStats.userId,
|
||||
sum(case when applyStats.lastCourseEndTime < now() then 1 else 0 end) AS totalCount,
|
||||
sum(case when applyStats.lastCourseEndTime < now() and applyStats.hasAttend = 1 then 1 else 0 end) AS signCount,
|
||||
sum(case when applyStats.lastCourseEndTime < now() and applyStats.hasAttend = 0 then 1 else 0 end) AS absentCount
|
||||
FROM
|
||||
(
|
||||
SELECT
|
||||
su.userId,
|
||||
su.activityId,
|
||||
su.courseId,
|
||||
max(case when uc.isAttend = true then 1 else 0 end) AS hasAttend,
|
||||
max(uc.courseEndTime) AS lastCourseEndTime
|
||||
FROM
|
||||
train_sign_up_user su
|
||||
LEFT JOIN train_sign_up_activity act ON act.id = su.activityId
|
||||
LEFT JOIN train_sign_up_course course ON course.id = su.courseId
|
||||
LEFT JOIN train_sign_up_user_course uc ON uc.activityId = su.activityId
|
||||
AND uc.courseId = su.courseId
|
||||
AND uc.userId = su.userId
|
||||
WHERE
|
||||
act.year = @year
|
||||
AND su.state != 2
|
||||
AND course.isMobileSign = 1
|
||||
GROUP BY
|
||||
su.userId,
|
||||
su.activityId,
|
||||
su.courseId
|
||||
) applyStats
|
||||
GROUP BY
|
||||
applyStats.userId
|
||||
) signStats ON signStats.userId = u.id
|
||||
$condition
|
||||
""");
|
||||
cnd.groupBy("tsuu.userId");
|
||||
Criteria varCnd = Cnd.cri();
|
||||
varCnd.where().setTop(false);
|
||||
varCnd.where().andEX("activityId", "=", activityId);
|
||||
varCnd.where().andEX("courseId", "=", courseId);
|
||||
if (!varCnd.where().isEmpty()) {
|
||||
sql.vars().set("var", "and " + varCnd.toSql(null));
|
||||
}
|
||||
sql.setParam("year", year);
|
||||
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
|
||||
cnd.desc("tsuu.unitId");
|
||||
cnd.desc("u.unitName").asc("u.loginname");
|
||||
} else {
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
}
|
||||
@@ -75,6 +101,7 @@ public class TrainSignUpUserServiceImpl extends BaseServiceImpl<TrainSignUpBlack
|
||||
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void doHandleUser(String userId) {
|
||||
TrainSignUpBlackList blackRecord = dao().fetch(TrainSignUpBlackList.class, Cnd.where("userId", "=", userId));
|
||||
if (Lang.isEmpty(blackRecord)) {
|
||||
@@ -82,14 +109,103 @@ public class TrainSignUpUserServiceImpl extends BaseServiceImpl<TrainSignUpBlack
|
||||
blackList.setUserId(userId);
|
||||
blackList.setIsDisabled(true);
|
||||
dao().insert(blackList);
|
||||
} else if (Boolean.TRUE.equals(blackRecord.getIsDisabled())) {
|
||||
dao().update(TrainSignUpBlackList.class,
|
||||
Chain.make("isDisabled", false).add("lastUnblockTime", new Date()),
|
||||
Cnd.where("userId", "=", userId));
|
||||
} else {
|
||||
// blackRecord.setIsDisabled(!blackRecord.getIsDisabled());
|
||||
// dao().update(blackRecord);
|
||||
dao().delete(blackRecord);
|
||||
dao().update(TrainSignUpBlackList.class,
|
||||
Chain.make("isDisabled", true),
|
||||
Cnd.where("userId", "=", userId));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBlackListed(String userId) {
|
||||
return dao().count(TrainSignUpBlackList.class, Cnd.where("userId", "=", userId)
|
||||
.and("isDisabled", "=", true)) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public boolean autoBlackByYearAndUser(Integer year, String userId) {
|
||||
TrainSignUpBlackList blackRecord = dao().fetch(TrainSignUpBlackList.class, Cnd.where("userId", "=", userId));
|
||||
if (blackRecord != null && Boolean.TRUE.equals(blackRecord.getIsDisabled())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Date yearStartTime = getYearStartTime(year);
|
||||
Date countStartTime = yearStartTime;
|
||||
if (blackRecord != null && blackRecord.getLastUnblockTime() != null
|
||||
&& blackRecord.getLastUnblockTime().after(yearStartTime)) {
|
||||
countStartTime = blackRecord.getLastUnblockTime();
|
||||
}
|
||||
|
||||
// 自动拉黑按一次报名累计缺席:同一报名下多个签到时间段全部未签到,只计 1 次缺席。
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
count(1)
|
||||
FROM
|
||||
(
|
||||
SELECT
|
||||
su.userId,
|
||||
su.activityId,
|
||||
su.courseId,
|
||||
max(case when uc.isAttend = true then 1 else 0 end) AS hasAttend,
|
||||
max(uc.courseEndTime) AS lastCourseEndTime
|
||||
FROM
|
||||
train_sign_up_user su
|
||||
LEFT JOIN train_sign_up_activity act ON act.id = su.activityId
|
||||
LEFT JOIN train_sign_up_course course ON course.id = su.courseId
|
||||
LEFT JOIN train_sign_up_user_course uc ON uc.activityId = su.activityId
|
||||
AND uc.courseId = su.courseId
|
||||
AND uc.userId = su.userId
|
||||
WHERE
|
||||
su.userId = @userId
|
||||
AND act.year = @year
|
||||
AND su.state != 2
|
||||
AND course.isMobileSign = 1
|
||||
GROUP BY
|
||||
su.userId,
|
||||
su.activityId,
|
||||
su.courseId
|
||||
) applyStats
|
||||
WHERE
|
||||
applyStats.hasAttend = 0
|
||||
AND applyStats.lastCourseEndTime < now()
|
||||
AND applyStats.lastCourseEndTime > @countStartTime
|
||||
""");
|
||||
sql.setParam("userId", userId);
|
||||
sql.setParam("year", year);
|
||||
sql.setParam("countStartTime", countStartTime);
|
||||
|
||||
if (count(sql) < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (blackRecord == null) {
|
||||
TrainSignUpBlackList blackList = new TrainSignUpBlackList();
|
||||
blackList.setUserId(userId);
|
||||
blackList.setIsDisabled(true);
|
||||
dao().insert(blackList);
|
||||
} else {
|
||||
dao().update(TrainSignUpBlackList.class,
|
||||
Chain.make("isDisabled", true),
|
||||
Cnd.where("userId", "=", userId));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private Date getYearStartTime(Integer year) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.clear();
|
||||
calendar.set(Calendar.YEAR, year);
|
||||
calendar.set(Calendar.MONTH, Calendar.JANUARY);
|
||||
calendar.set(Calendar.DAY_OF_MONTH, 1);
|
||||
return calendar.getTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NutMap> attendClassRecord(String userId) {
|
||||
Sql sql = Sqls.create("""
|
||||
|
||||
@@ -130,6 +130,21 @@ layout("/layouts/platform.html"){
|
||||
:visible.sync="notifyDialogVisible"
|
||||
:close-on-click-modal="false"
|
||||
width="50%">
|
||||
<el-select
|
||||
v-model="notifyCourseIds"
|
||||
multiple
|
||||
filterable
|
||||
clearable
|
||||
:loading="notifyCourseLoading"
|
||||
placeholder="请选择要通知的分活动"
|
||||
style="width: 100%; margin-bottom: 15px">
|
||||
<el-option
|
||||
v-for="item in notifyCourseList"
|
||||
:key="item.id"
|
||||
:label="item.courseName"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-input
|
||||
type="textarea"
|
||||
:rows="6"
|
||||
@@ -138,7 +153,7 @@ layout("/layouts/platform.html"){
|
||||
</el-input>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="notifyDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="sendNotify">发 送</el-button>
|
||||
<el-button type="primary" :loading="notifyLoading" @click="sendNotify">发 送</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</guava>
|
||||
@@ -175,6 +190,10 @@ layout("/layouts/platform.html"){
|
||||
notifyDialogVisible: false,
|
||||
notifyContent: '',
|
||||
notifyActivityId: '',
|
||||
notifyCourseIds: [],
|
||||
notifyCourseList: [],
|
||||
notifyCourseLoading: false,
|
||||
notifyLoading: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -206,28 +225,51 @@ layout("/layouts/platform.html"){
|
||||
openNotifyDialog(row) {
|
||||
this.notifyActivityId = row.id
|
||||
this.notifyContent = ''
|
||||
this.notifyCourseIds = []
|
||||
this.notifyCourseList = []
|
||||
this.notifyDialogVisible = true
|
||||
this.notifyCourseLoading = true
|
||||
this.$axios.post("/platform/trainSignUp/manage/findOne", { id: row.id })
|
||||
.then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.notifyCourseList = resp.data.courseList || []
|
||||
} else {
|
||||
this.$message.warning(resp.msg)
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.notifyCourseLoading = false
|
||||
})
|
||||
},
|
||||
async sendNotify() {
|
||||
sendNotify() {
|
||||
if (this.notifyCourseIds.length === 0) {
|
||||
this.$message.warning('请选择要通知的分活动')
|
||||
return
|
||||
}
|
||||
if (!this.notifyContent.trim()) {
|
||||
this.$message.warning('请输入通知内容')
|
||||
return
|
||||
}
|
||||
this.$confirm("确认发送通知给所有报名人员吗?", "提示", {
|
||||
this.$confirm("确认发送通知给所选分活动的报名人员吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(async () => {
|
||||
const resp = await this.$axios.post(loc() + "/sendNotify", {
|
||||
}).then(() => {
|
||||
this.notifyLoading = true
|
||||
this.$axios.post(loc() + "/sendNotify", {
|
||||
activityId: this.notifyActivityId,
|
||||
courseIds: JSON.stringify(this.notifyCourseIds),
|
||||
content: this.notifyContent
|
||||
}).then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.notifyDialogVisible = false
|
||||
} else {
|
||||
this.$message.warning(resp.msg)
|
||||
}
|
||||
}).finally(() => {
|
||||
this.notifyLoading = false
|
||||
})
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.notifyDialogVisible = false
|
||||
} else {
|
||||
this.$message.warning(resp.msg)
|
||||
}
|
||||
}).catch(() => {})
|
||||
},
|
||||
async activityStatusChange(notice, val, id) {
|
||||
|
||||
+69
-159
@@ -8,6 +8,7 @@ layout("/layouts/platform.html"){
|
||||
<search @search="doSearch">
|
||||
<search-item label="年度">
|
||||
<el-date-picker
|
||||
@change="doSearch"
|
||||
placeholder="请选择年度"
|
||||
type="year"
|
||||
style="width: 100%"
|
||||
@@ -15,31 +16,17 @@ layout("/layouts/platform.html"){
|
||||
value-format="yyyy"
|
||||
></el-date-picker>
|
||||
</search-item>
|
||||
<search-item label="活动名称">
|
||||
<el-select @change="activityChange" style="width: 100%" v-model="pageForm.activityId" filterable>
|
||||
<el-option :label="item.activityName" :value="item.id" v-for="item in activityList" :key="item.id"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item :label="trainType + ':'">
|
||||
<el-select @change="courseChange" :placeholder="'请选择' + trainType" style="width: 100%" v-model="pageForm.courseId" filterable>
|
||||
<el-option :label="item.courseName" :value="item.id" v-for="item in courseList" :key="item.id"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="人员信息">
|
||||
<el-input clearable placeholder="输入姓名或者工号搜索" v-model="pageForm.userKeyWord"></el-input>
|
||||
</search-item>
|
||||
</search>
|
||||
</el-card>
|
||||
<el-card class="mt10" shadow="never">
|
||||
<table-tool ref="tool" :label="trainType + '(温馨提示:如需补充人员,请在上面选择具体的' + trainType + ')'">
|
||||
<el-button @click="openReserve" type="primary" v-if="reserveMode === 2" size="small">补充人员</el-button>
|
||||
<el-button @click="exportSignPerson" type="primary" size="small">导出签到名单</el-button>
|
||||
<el-button @click="exportGiftPerson" type="primary" size="small">导出领取名单</el-button>
|
||||
</table-tool>
|
||||
<table-tool ref="tool" label="年度人员黑名单管理"></table-tool>
|
||||
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder">
|
||||
<el-table-column :index="indexMethod" label="序号" type="index" width="80px"></el-table-column>
|
||||
<el-table-column
|
||||
:label="column.prop === 'courseNames' ? trainType : column.label"
|
||||
:label="column.label"
|
||||
:prop="column.prop"
|
||||
:sortable="column.sortable"
|
||||
align="center"
|
||||
@@ -48,59 +35,47 @@ layout("/layouts/platform.html"){
|
||||
v-for="(column,index) in tableColumns"
|
||||
:key="index"
|
||||
>
|
||||
<template v-slot:header>
|
||||
<span>{{ column.label }}</span>
|
||||
<el-tooltip
|
||||
:content="column.help"
|
||||
effect="dark"
|
||||
placement="top"
|
||||
v-if="column.help"
|
||||
>
|
||||
<i class="el-icon-question text-info ml5" style="cursor: pointer"></i>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<template v-slot="{row}" v-if="column.prop==='isDisabled'">
|
||||
<span class="text-danger" v-if="row.isDisabled">是</span>
|
||||
<span class="text-success" v-else>否</span>
|
||||
</template>
|
||||
<template v-slot="{row}" v-else-if="column.prop==='state'">
|
||||
<span class="text-success" v-if="row.state === 1">正常报名</span>
|
||||
<span class="text-warning" v-else-if="row.state === 2">候补报名</span>
|
||||
<span class="text-success" v-else-if="row.state === 3">正常报名(候补)</span>
|
||||
<span class="text-info" v-else-if="row.state === 4">无效报名(缺席)</span>
|
||||
<template v-slot="{row}" v-else-if="column.prop==='lastUnblockTime'">
|
||||
<span v-if="row.lastUnblockTime">{{ formatDateTime(row.lastUnblockTime) }}</span>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="150px">
|
||||
<template v-slot="{row}">
|
||||
<el-button @click="handleUser(row.userId)" size="mini" type="danger" v-if="!row.isDisabled">拉黑</el-button>
|
||||
<el-button @click="handleUser(row.userId)" size="mini" type="success" v-if="row.isDisabled">解封</el-button>
|
||||
<el-button @click="handleUser(row)" size="mini" type="danger" v-if="!row.isDisabled">拉黑</el-button>
|
||||
<el-button @click="handleUser(row)" size="mini" type="success" v-if="row.isDisabled">解封</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--#include("/layouts/pagination.html"){}#-->
|
||||
</el-card>
|
||||
</guava>
|
||||
|
||||
<el-dialog title="补充人员" :visible.sync="reserveDialogVisible" width="55%" top="3%">
|
||||
<vi-title title="以下为候补人员,已为您按照报名时间降序排列"></vi-title>
|
||||
<el-table :data="reserveTableData" ref="multipleTable" @selection-change="handleSelectionChange">
|
||||
<el-table-column :selectable="(row, index) => {return row.state === 2}" type="selection" width="55"></el-table-column>
|
||||
<el-table-column prop="username" label="姓名"></el-table-column>
|
||||
<el-table-column prop="loginname" label="工号"></el-table-column>
|
||||
<el-table-column prop="mobile" label="联系方式"></el-table-column>
|
||||
<el-table-column prop="unitName" label="单位"></el-table-column>
|
||||
<el-table-column prop="unionName" label="工会"></el-table-column>
|
||||
<el-table-column prop="signUpTime" label="报名时间"></el-table-column>
|
||||
</el-table>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="reserveDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="reserveDo">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
dicts: ["TRAIN_SIGNUP_TYPE"],
|
||||
mixins: [initTableMixins],
|
||||
data() {
|
||||
return {
|
||||
reserveDialogVisible: false,
|
||||
reserveTableData: [],
|
||||
activityList: [],
|
||||
pageForm: {
|
||||
year: new Date().getFullYear().toString(),
|
||||
activityId: null
|
||||
userKeyWord: ""
|
||||
},
|
||||
tableColumns: [
|
||||
{ label: "姓名", prop: "username" },
|
||||
@@ -108,131 +83,66 @@ layout("/layouts/platform.html"){
|
||||
{ label: "联系方式", prop: "mobile" },
|
||||
{ label: "单位", prop: "unitName", sortable: true },
|
||||
{ label: "分工会", prop: "unionName", sortable: true },
|
||||
{ label: "课程", prop: "courseNames", sortable: true },
|
||||
{ label: "总次数", prop: "totalCount", sortable: true },
|
||||
{ label: "签到次数", prop: "signCount", sortable: true },
|
||||
{ label: "缺席次数", prop: "absentCount", sortable: true },
|
||||
{ label: "是否黑名单", prop: "isDisabled", sortable: true }
|
||||
],
|
||||
trainType: "培训班",
|
||||
courseList: [],
|
||||
course: {},
|
||||
reserveMode: 1,
|
||||
multipleSelection: [],
|
||||
{
|
||||
label: "年度总次数",
|
||||
prop: "totalCount",
|
||||
sortable: true,
|
||||
help: "所选年度内,非候补报名、课程已结束、开启手机签到的报名活动/课程次数。同一报名下多个签到时间段只算一次。"
|
||||
},
|
||||
{
|
||||
label: "签到次数",
|
||||
prop: "signCount",
|
||||
sortable: true,
|
||||
help: "所选年度内,课程已结束、开启手机签到,并且人员至少完成一次签到的报名活动/课程次数。"
|
||||
},
|
||||
{
|
||||
label: "缺席次数",
|
||||
prop: "absentCount",
|
||||
sortable: true,
|
||||
help: "所选年度内,课程已结束、开启手机签到,并且人员没有任何签到记录的报名活动/课程次数。候补报名不计入。"
|
||||
},
|
||||
{
|
||||
label: "是否黑名单",
|
||||
prop: "isDisabled",
|
||||
sortable: true,
|
||||
help: "是表示当前人员已被限制报名香樟工会讲堂;否表示当前未被限制。"
|
||||
},
|
||||
{
|
||||
label: "最近解封时间",
|
||||
prop: "lastUnblockTime",
|
||||
sortable: true,
|
||||
help: "管理员最近一次手动解封时间。解封后,自动拉黑的缺席次数会从该时间之后重新累计。"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleSelectionChange(val) {
|
||||
this.multipleSelection = val
|
||||
formatDateTime(val) {
|
||||
return this.$moment(val).format("YYYY-MM-DD HH:mm:ss")
|
||||
},
|
||||
async openReserve() {
|
||||
const activity = this.activityList.find((o) => o.id === this.pageForm.activityId)
|
||||
if (this.$moment().unix() < this.$moment(activity.activityEndTime).unix()) {
|
||||
this.$alert("此活动还未结束,无法补充", "提示", {
|
||||
confirmButtonText: "确定"
|
||||
})
|
||||
return
|
||||
}
|
||||
const resp = await this.$axios.post("/platform/trainSignUp/userManage/getReserveUser", { courseId: this.course.id })
|
||||
this.reserveTableData = resp.data
|
||||
this.reserveDialogVisible = true
|
||||
},
|
||||
reserveDo() {
|
||||
if (this.multipleSelection.length === 0) {
|
||||
this.$message.warning("请先在左侧多选框中选择要补充的人员")
|
||||
return
|
||||
}
|
||||
this.$confirm("您选择了" + this.multipleSelection.length + "位教职工,确定要进行补充操作吗?", "提示", {
|
||||
handleUser(row) {
|
||||
const actionName = row.isDisabled ? "解封" : "拉黑"
|
||||
const userName = row.username + "(" + row.loginname + ")"
|
||||
this.$confirm("确定要" + actionName + userName + "吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
})
|
||||
.then(async () => {
|
||||
const ids = this.multipleSelection.map((o) => o.userId)
|
||||
const resp = await this.$axios.post("/platform/trainSignUp/userManage/reserveSingUp", {
|
||||
ids: JSON.stringify(ids),
|
||||
courseId: this.course.id
|
||||
})
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.doSearch()
|
||||
this.multipleSelection = []
|
||||
this.$refs.multipleTable.clearSelection()
|
||||
this.reserveDialogVisible = false
|
||||
}
|
||||
.then(() => {
|
||||
$.post(loc() + "/doHandleUser", { userId: row.userId })
|
||||
.then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.doSearch()
|
||||
}
|
||||
})
|
||||
.always(() => {})
|
||||
})
|
||||
.catch(() => {})
|
||||
},
|
||||
courseChange(val) {
|
||||
const course = this.courseList.find((o) => o.id === val)
|
||||
this.course = course
|
||||
this.reserveMode = course.reserveMode
|
||||
if (this.reserveMode === 2) {
|
||||
this.tableColumns.push({ label: "报名状态", prop: "state", sortable: true })
|
||||
} else {
|
||||
const o = this.tableColumns.find((o) => o.label === "报名状态")
|
||||
if (o !== null && o !== undefined) {
|
||||
this.tableColumns.splice(this.tableColumns.length - 1, 1)
|
||||
}
|
||||
}
|
||||
this.$refs.tool.app = this
|
||||
this.doSearch()
|
||||
},
|
||||
exportSignPerson() {
|
||||
this.exportPro(loc() + "/exportSignPerson", { activityId: this.pageForm.activityId })
|
||||
},
|
||||
exportGiftPerson() {
|
||||
this.exportPro(loc() + "/exportGiftPerson", { activityId: this.pageForm.activityId })
|
||||
},
|
||||
exportPro(url, param) {
|
||||
if (param.activityId === null) {
|
||||
this.$message.warning("请选择活动")
|
||||
return
|
||||
}
|
||||
this.$downLoad(url, param)
|
||||
},
|
||||
async activityChange(val) {
|
||||
this.$nextTick(async () => {
|
||||
const activity = this.activityList.find((o) => o.id === val)
|
||||
const type = this.dict.type.TRAIN_SIGNUP_TYPE?.find(o => o.code === activity.trainType)
|
||||
this.trainType = type?.name || "培训班"
|
||||
const resp = await this.$axios.post(loc() + "/getCourseByActivityId", { activityId: val })
|
||||
this.courseList = resp.data
|
||||
if(this.courseList.length > 0) {
|
||||
this.$set(this.pageForm, "courseId", this.courseList[0].id)
|
||||
} else {
|
||||
this.pageForm.courseId = ""
|
||||
}
|
||||
this.doSearch()
|
||||
})
|
||||
},
|
||||
async handleUser(userId) {
|
||||
const resp = await $.post(loc() + "/doHandleUser", { userId })
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.doSearch()
|
||||
}
|
||||
},
|
||||
async yearChange() {
|
||||
this.pageForm.activityId = null
|
||||
await this.getActivityList()
|
||||
await this.doSearch()
|
||||
},
|
||||
async getActivityList() {
|
||||
const resp = await this.$axios.post("/platform/trainSignUp/statistics/activityList", { year: this.pageForm.year })
|
||||
this.activityList = resp.data
|
||||
if (this.activityList && this.activityList.length > 0) {
|
||||
this.pageForm.activityId = this.activityList[0].id
|
||||
await this.activityChange(this.activityList[0].id)
|
||||
}
|
||||
},
|
||||
async initData() {
|
||||
await this.getActivityList()
|
||||
},
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
await this.initData()
|
||||
await this.pageData()
|
||||
created() {
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user