香樟工会讲堂:
1、活动管理:微信二维码删除无效 2、活动报名控制不签到两次,一年之内不能报名。一年之后,自动解除限制。 3、报名统计 查看页面添加工号/姓名查询
This commit is contained in:
+2
-25
@@ -2,8 +2,6 @@ package com.budwk.app.zhgh.activity.trainSignUp.controller.manage;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
import cn.hutool.core.date.DateField;
|
||||
import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.annotation.SLog;
|
||||
@@ -432,31 +430,10 @@ public class TrainSignUpApplyController {
|
||||
@SaCheckPermission(value = {"trainSignUp.apply", "h5.trainSignUp.apply"}, mode = SaMode.OR)
|
||||
@SLog(tag = "品牌活动-活动报名", msg = "判断缺席次数")
|
||||
public Result validSignCount(@Param("activityId") String activityId) {
|
||||
// 缺席2次,就1年内不能报名
|
||||
// 查询今天,然后往前推1年,这段时间有没有缺席超过2次
|
||||
DateTime today = DateUtil.date();
|
||||
DateTime lastYear = DateUtil.offset(today, DateField.YEAR, -1);
|
||||
|
||||
// 找需要签到的分活动
|
||||
List<TrainSignUpActivity> activityList = dao.query(TrainSignUpActivity.class, Cnd.where("year", "in", Lang.array(DateUtil.thisYear(), DateUtil.thisYear() - 1)));
|
||||
List<String> activityIdList = activityList.stream().map(TrainSignUpActivity::getId).toList();
|
||||
|
||||
List<TrainSignUpCourse> courses = dao.query(TrainSignUpCourse.class, Cnd.where("isMobileSign", "=", true).and("activityId", "in", activityIdList));
|
||||
List<String> courseIdList = courses.stream().map(TrainSignUpCourse::getId).toList();
|
||||
|
||||
int count = dao.count(
|
||||
TrainSignUpUserCourse.class,
|
||||
Cnd.where("userId", "=", SecurityUtil.getUserId())
|
||||
.and("courseStartTime", ">", DateUtil.format(lastYear, "yyyy-MM-dd HH:mm:ss"))
|
||||
.and("courseEndTime", "<", DateUtil.format(today, "yyyy-MM-dd HH:mm:ss"))
|
||||
.and("isAttend", "=", false)
|
||||
.and("courseId", "in", courseIdList)
|
||||
);
|
||||
|
||||
if(count >= 2) {
|
||||
if (trainSignUpActivityService.isAbsenceSignUpLimited(SecurityUtil.getUserId())) {
|
||||
return Result.error(99, "您已连续2次未签到活动,不能报名,请联系校工会");
|
||||
}
|
||||
return Result.success();
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
|
||||
+6
-4
@@ -121,8 +121,9 @@ public class TrainSignUpActivityStatisticsController {
|
||||
@At
|
||||
@ApiOperation("报名人员列表")
|
||||
@SaCheckPermission("trainSignUp.statistics")
|
||||
public Result registerUserList(@Param(value = "courseId") String courseId) {
|
||||
return Result.success(trainSignUpActivityStatisticsService.registerUserList(courseId));
|
||||
public Result registerUserList(@Param(value = "courseId") String courseId,
|
||||
@Param("keyword") String keyword) {
|
||||
return Result.success(trainSignUpActivityStatisticsService.registerUserList(courseId, keyword));
|
||||
}
|
||||
|
||||
@At
|
||||
@@ -151,8 +152,9 @@ public class TrainSignUpActivityStatisticsController {
|
||||
@SaCheckPermission("trainSignUp.statistics")
|
||||
public Result getSignInfo(PageForm pageForm,
|
||||
@Param("courseId") String courseId,
|
||||
String timeId) {
|
||||
return Result.success(trainSignUpActivityStatisticsService.getSignInfo(pageForm, courseId, timeId));
|
||||
@Param("timeId") String timeId,
|
||||
@Param("keyword") String keyword) {
|
||||
return Result.success(trainSignUpActivityStatisticsService.getSignInfo(pageForm, courseId, timeId, keyword));
|
||||
}
|
||||
|
||||
@At
|
||||
|
||||
+8
@@ -110,6 +110,14 @@ public interface TrainSignUpActivityService extends BaseService<TrainSignUpActiv
|
||||
*/
|
||||
boolean isSignCourseByUser(String courseId, String userId);
|
||||
|
||||
/**
|
||||
* 判断用户是否在配置年限内缺席达到限制次数。
|
||||
*
|
||||
* @param userId 当前报名用户ID
|
||||
* @return true 表示用户被缺席规则限制报名
|
||||
*/
|
||||
boolean isAbsenceSignUpLimited(String userId);
|
||||
|
||||
/**
|
||||
* 手机端签到
|
||||
*
|
||||
|
||||
+10
-6
@@ -27,10 +27,11 @@ public interface TrainSignUpActivityStatisticsService extends BaseService<TrainS
|
||||
/**
|
||||
* 该课程下的报名人员信息
|
||||
*
|
||||
* @param courseId
|
||||
* @return
|
||||
* @param courseId 培训班ID
|
||||
* @param keyword 工号/姓名,支持模糊查询
|
||||
* @return 报名人员列表
|
||||
*/
|
||||
List<NutMap> registerUserList(String courseId);
|
||||
List<NutMap> registerUserList(String courseId, String keyword);
|
||||
|
||||
List<NutMap> getTaleColumnInfo(String courseId);
|
||||
|
||||
@@ -45,10 +46,13 @@ public interface TrainSignUpActivityStatisticsService extends BaseService<TrainS
|
||||
/**
|
||||
* 获取每个课程的签到情况
|
||||
*
|
||||
* @param courseId
|
||||
* @return k->每个培训班每节课的上课时间 v->上课记录list
|
||||
* @param pageForm 分页参数
|
||||
* @param courseId 培训班ID
|
||||
* @param timeId 课次ID
|
||||
* @param keyword 工号/姓名,支持模糊查询
|
||||
* @return 签到分页列表
|
||||
*/
|
||||
Pagination getSignInfo(PageForm pageForm, String courseId, String timeId);
|
||||
Pagination getSignInfo(PageForm pageForm, String courseId, String timeId, String keyword);
|
||||
|
||||
/**
|
||||
* 报名人员list 导出
|
||||
|
||||
+41
@@ -1,10 +1,14 @@
|
||||
package com.budwk.app.zhgh.activity.trainSignUp.service.impl;
|
||||
|
||||
import cn.hutool.core.date.DateField;
|
||||
import cn.hutool.core.date.DateTime;
|
||||
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.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.views.View_user;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.activity.trainSignUp.models.*;
|
||||
@@ -38,6 +42,10 @@ import java.util.stream.Collectors;
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class TrainSignUpActivityServiceImpl extends BaseServiceImpl<TrainSignUpActivity> implements TrainSignUpActivityService {
|
||||
|
||||
private static final String ABSENCE_LIMIT_YEARS_CONFIG_KEY = "train_sign_up_absence_limit_years";
|
||||
private static final int DEFAULT_ABSENCE_LIMIT_YEARS = 1;
|
||||
private static final int ABSENCE_LIMIT_COUNT = 2;
|
||||
|
||||
@Inject
|
||||
private TrainSignUpActivityStatisticsService statisticsService;
|
||||
|
||||
@@ -486,6 +494,39 @@ public class TrainSignUpActivityServiceImpl extends BaseServiceImpl<TrainSignUpA
|
||||
return dao().count(TrainSignUpUser.class, Cnd.where("courseId", "=", courseId).and("userId", "=", userId)) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAbsenceSignUpLimited(String userId) {
|
||||
int limitYears = getAbsenceLimitYears();
|
||||
DateTime today = DateUtil.date();
|
||||
DateTime limitStartTime = DateUtil.offset(today, DateField.YEAR, -limitYears);
|
||||
|
||||
// 只统计配置年限内、需要手机签到且课程已结束的未签到记录,超过期限的缺席自动解除限制。
|
||||
int count = dao().count(
|
||||
TrainSignUpUserCourse.class,
|
||||
Cnd.where("userId", "=", userId)
|
||||
.and("courseStartTime", ">", DateUtil.format(limitStartTime, "yyyy-MM-dd HH:mm:ss"))
|
||||
.and("courseEndTime", "<", DateUtil.format(today, "yyyy-MM-dd HH:mm:ss"))
|
||||
.and("isAttend", "=", false)
|
||||
.and(new Static("courseId in (select id from train_sign_up_course where isMobileSign = 1)"))
|
||||
);
|
||||
return count >= ABSENCE_LIMIT_COUNT;
|
||||
}
|
||||
|
||||
private int getAbsenceLimitYears() {
|
||||
Sys_config config = dao().fetch(Sys_config.class, ABSENCE_LIMIT_YEARS_CONFIG_KEY);
|
||||
if (config == null || StrUtil.isBlank(config.getConfigValue())) {
|
||||
return DEFAULT_ABSENCE_LIMIT_YEARS;
|
||||
}
|
||||
try {
|
||||
int limitYears = Integer.parseInt(config.getConfigValue().trim());
|
||||
// 配置必须为正整数;缺失或非法时使用默认1年,避免误放开报名限制。
|
||||
return limitYears > 0 ? limitYears : DEFAULT_ABSENCE_LIMIT_YEARS;
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("培训报名缺席限制年限配置非法,configKey={}, configValue={}", ABSENCE_LIMIT_YEARS_CONFIG_KEY, config.getConfigValue());
|
||||
return DEFAULT_ABSENCE_LIMIT_YEARS;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doQd(String id) {
|
||||
NutMap updateMap = NutMap.NEW();
|
||||
|
||||
+15
-3
@@ -75,7 +75,7 @@ public class TrainSignUpActivityStatisticsServiceImpl extends BaseServiceImpl<Tr
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NutMap> registerUserList(String courseId) {
|
||||
public List<NutMap> registerUserList(String courseId, String keyword) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
u.loginname,
|
||||
@@ -94,9 +94,15 @@ public class TrainSignUpActivityStatisticsServiceImpl extends BaseServiceImpl<Tr
|
||||
LEFT JOIN `vw_user` u ON u.id = tsuu.userId
|
||||
$condition
|
||||
ORDER BY FIELD( tsuu.state, 1, 3, 2, 4 ),tsuu.signUpTime desc,u.unionid desc, u.unitid desc
|
||||
""");
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.andEX("tsuu.courseId", "=", courseId);
|
||||
// 工号/姓名共用一个搜索框,输入内容命中任一字段即可返回。
|
||||
if (StrUtil.isNotBlank(keyword)) {
|
||||
SqlExpressionGroup group = new SqlExpressionGroup();
|
||||
group.andLike("u.loginname", keyword).orLike("u.username", keyword);
|
||||
cnd.and(group);
|
||||
}
|
||||
sql.setCondition(cnd);
|
||||
List<NutMap> list = listMap(sql);
|
||||
for (NutMap o : list) {
|
||||
@@ -158,7 +164,7 @@ public class TrainSignUpActivityStatisticsServiceImpl extends BaseServiceImpl<Tr
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pagination getSignInfo(PageForm pageForm, String courseId, String timeId) {
|
||||
public Pagination getSignInfo(PageForm pageForm, String courseId, String timeId, String keyword) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
tsuuc.id,
|
||||
@@ -178,6 +184,12 @@ public class TrainSignUpActivityStatisticsServiceImpl extends BaseServiceImpl<Tr
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("tsuuc.courseId", "=", courseId);
|
||||
cnd.and("tsuuc.activityCourseId", "=", timeId);
|
||||
// 签到情况页签使用独立关键字,只过滤当前课次的签到列表。
|
||||
if (StrUtil.isNotBlank(keyword)) {
|
||||
SqlExpressionGroup group = new SqlExpressionGroup();
|
||||
group.andLike("u.loginname", keyword).orLike("u.username", keyword);
|
||||
cnd.and(group);
|
||||
}
|
||||
cnd.desc("isAttend");
|
||||
cnd.desc("attendTime");
|
||||
sql.setCondition(cnd);
|
||||
|
||||
+24
@@ -28,11 +28,15 @@ import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.mvc.annotation.AdaptBy;
|
||||
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 org.nutz.mvc.upload.TempFile;
|
||||
import org.nutz.mvc.upload.UploadAdaptor;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.Valid;
|
||||
|
||||
/**
|
||||
@@ -55,6 +59,8 @@ public class OpinionMineController {
|
||||
private OpinionCommonService opinionCommonService;
|
||||
@Inject
|
||||
private FlowEngine flowEngine;
|
||||
@Inject
|
||||
private OpinionWriteService opinionWriteService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/democratic/opinion/transact/mine/index.html")
|
||||
@@ -139,4 +145,22 @@ public class OpinionMineController {
|
||||
OpinionInfo info = dao.fetch(OpinionInfo.class, id);
|
||||
return Result.success(info);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("opinion.mine")
|
||||
@ApiOperation("意见导入")
|
||||
@SLog(tag = "教代会意见系统-我的意见", msg = "意见导入")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"})
|
||||
public Result importOpinion(@Param("file") TempFile file) {
|
||||
return Result.success(opinionWriteService.importOpinion(file));
|
||||
}
|
||||
|
||||
@At
|
||||
@Ok("void")
|
||||
@SaCheckPermission("opinion.mine")
|
||||
@ApiOperation("意见导入模板下载")
|
||||
public void downloadImportTemplate(HttpServletResponse response) {
|
||||
opinionWriteService.downloadImportTemplate(response);
|
||||
}
|
||||
}
|
||||
|
||||
+19
-3
@@ -1,11 +1,12 @@
|
||||
package com.budwk.app.zhgh.democratic.opinion.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.sys.models.Sys_dict;
|
||||
import com.budwk.app.base.model.ExcelImportRes;
|
||||
import com.budwk.app.zhgh.democratic.opinion.mode.OpinionImportExcelMode;
|
||||
import com.budwk.app.zhgh.democratic.opinion.models.OpinionInfo;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalInfo;
|
||||
import org.nutz.mvc.upload.TempFile;
|
||||
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
public interface OpinionWriteService extends BaseService<OpinionInfo> {
|
||||
|
||||
@@ -17,4 +18,19 @@ public interface OpinionWriteService extends BaseService<OpinionInfo> {
|
||||
*/
|
||||
String generateOpinionCode(String sessionId,String delegationId);
|
||||
|
||||
/**
|
||||
* 下载意见导入模板。
|
||||
*
|
||||
* @param response 文件响应对象
|
||||
*/
|
||||
void downloadImportTemplate(HttpServletResponse response);
|
||||
|
||||
/**
|
||||
* 导入意见并在校验全部通过后直接提交流程。
|
||||
*
|
||||
* @param file 上传的 Excel 文件
|
||||
* @return 导入结果,包含成功数和失败明细
|
||||
*/
|
||||
ExcelImportRes<OpinionImportExcelMode> importOpinion(TempFile file);
|
||||
|
||||
}
|
||||
|
||||
+295
-5
@@ -1,30 +1,54 @@
|
||||
package com.budwk.app.zhgh.democratic.opinion.service.impl;
|
||||
|
||||
import cn.afterturn.easypoi.excel.ExcelExportUtil;
|
||||
import cn.afterturn.easypoi.excel.ExcelImportUtil;
|
||||
import cn.afterturn.easypoi.excel.entity.ExportParams;
|
||||
import cn.afterturn.easypoi.excel.entity.ImportParams;
|
||||
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
|
||||
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.model.ExcelImportRes;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.sys.models.Sys_dict;
|
||||
import com.budwk.app.sys.services.SysDictService;
|
||||
import com.budwk.app.base.utils.CommonDownloadUtil;
|
||||
import com.budwk.app.flow.constant.FlowConst;
|
||||
import com.budwk.app.flow.engine.FlowEngine;
|
||||
import com.budwk.app.flow.entity.ProcessInstance;
|
||||
import com.budwk.app.flow.entity.ProcessTask;
|
||||
import com.budwk.app.flow.enums.ProcessSubmitTypeEnum;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.democratic.opinion.mode.OpinionImportExcelMode;
|
||||
import com.budwk.app.zhgh.democratic.opinion.models.OpinionInfo;
|
||||
import com.budwk.app.zhgh.democratic.opinion.models.OpinionType;
|
||||
import com.budwk.app.zhgh.democratic.opinion.service.OpinionWriteService;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalInfo;
|
||||
import com.budwk.app.zhgh.democratic.proposal.service.ProposalWriteService;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalUndertake;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.delegate.models.Teacher_congress_delegate;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.delegation.models.Teacher_congress_delegation;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.discussiongroup.models.Teacher_congress_discussion_group;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.prepare.models.Teacher_congress_session;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.entity.Record;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.mvc.upload.TempFile;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class OpinionWriteServiceImpl extends BaseServiceImpl<OpinionInfo> implements OpinionWriteService {
|
||||
|
||||
@Inject
|
||||
private FlowEngine flowEngine;
|
||||
|
||||
public OpinionWriteServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
@@ -57,4 +81,270 @@ public class OpinionWriteServiceImpl extends BaseServiceImpl<OpinionInfo> implem
|
||||
}
|
||||
return opinionCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void downloadImportTemplate(HttpServletResponse response) {
|
||||
List<ExcelExportEntity> entities = new ArrayList<>();
|
||||
entities.add(new ExcelExportEntity("所属讨论组", "discussionGroupName", 25));
|
||||
entities.add(new ExcelExportEntity("建议人", "suggestUserName", 20));
|
||||
entities.add(new ExcelExportEntity("建议人所属代表团", "delegationName", 25));
|
||||
entities.add(new ExcelExportEntity("所属教代会", "sessionName", 25));
|
||||
entities.add(new ExcelExportEntity("意见类别", "typeName", 20));
|
||||
entities.add(new ExcelExportEntity("意见时间", "createTime", 20));
|
||||
entities.add(new ExcelExportEntity("建议承办单位", "suggestUnits", 35));
|
||||
entities.add(new ExcelExportEntity("意见和建议", "name", 50));
|
||||
|
||||
ExportParams exportParams = new ExportParams();
|
||||
exportParams.setType(ExcelType.XSSF);
|
||||
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entities, Collections.emptyList());
|
||||
CommonDownloadUtil.download("意见导入模板.xlsx", workbook, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExcelImportRes<OpinionImportExcelMode> importOpinion(TempFile file) {
|
||||
List<OpinionImportExcelMode> importRows = ExcelImportUtil.importExcel(file.getFile(), OpinionImportExcelMode.class, new ImportParams());
|
||||
List<OpinionInfo> opinionList = new ArrayList<>();
|
||||
ExcelImportRes<OpinionImportExcelMode> excelImportRes = new ExcelImportRes<>();
|
||||
excelImportRes.setTotalRecords(importRows.size());
|
||||
|
||||
// 先整表校验并组装入库对象;存在任意错误时不启动流程,避免导入半成功。
|
||||
for (int i = 0; i < importRows.size(); i++) {
|
||||
OpinionImportExcelMode row = importRows.get(i);
|
||||
if (isEmptyRow(row)) {
|
||||
continue;
|
||||
}
|
||||
OpinionInfo opinionInfo = buildOpinionInfo(row, i);
|
||||
if (StrUtil.isBlank(row.getErrMsg())) {
|
||||
opinionList.add(opinionInfo);
|
||||
}
|
||||
}
|
||||
|
||||
List<OpinionImportExcelMode> errorDetails = importRows.stream()
|
||||
.filter(row -> StrUtil.isNotBlank(row.getErrMsg()))
|
||||
.collect(Collectors.toList());
|
||||
excelImportRes.setErrorDetails(errorDetails);
|
||||
excelImportRes.setFailedCount(errorDetails.size());
|
||||
if (excelImportRes.getFailedCount() > 0) {
|
||||
excelImportRes.setSuccessCount(0);
|
||||
return excelImportRes;
|
||||
}
|
||||
|
||||
for (OpinionInfo opinionInfo : opinionList) {
|
||||
submitImportedOpinion(opinionInfo);
|
||||
}
|
||||
excelImportRes.setSuccessCount(opinionList.size());
|
||||
return excelImportRes;
|
||||
}
|
||||
|
||||
private OpinionInfo buildOpinionInfo(OpinionImportExcelMode row, int rowIndex) {
|
||||
List<String> errors = new ArrayList<>();
|
||||
// 导入模板只填写业务字段,记录人固定取当前登录人并统一校验跨表关系。
|
||||
Teacher_congress_session session = fetchSession(row.getSessionName());
|
||||
if (session == null) {
|
||||
errors.add("所属教代会不存在");
|
||||
}
|
||||
|
||||
Teacher_congress_discussion_group discussionGroup = session == null ? null : fetchDiscussionGroup(session.getId(), row.getDiscussionGroupName());
|
||||
if (discussionGroup == null) {
|
||||
errors.add("所属讨论组不存在");
|
||||
}
|
||||
|
||||
Record recorderUser = fetchCurrentUser();
|
||||
if (recorderUser == null) {
|
||||
errors.add("当前登录人信息不存在");
|
||||
}
|
||||
if (discussionGroup != null && recorderUser != null && !isRecorderInDiscussionGroup(recorderUser, discussionGroup)) {
|
||||
errors.add("当前登录人不属于所属讨论组");
|
||||
}
|
||||
|
||||
Teacher_congress_delegation delegation = session == null ? null : fetchDelegation(session.getId(), row.getDelegationName());
|
||||
if (delegation == null) {
|
||||
errors.add("建议人所属代表团不存在");
|
||||
}
|
||||
|
||||
Teacher_congress_delegate suggestUser = session == null || delegation == null ? null : fetchDelegate(session.getId(), delegation.getId(), row.getSuggestUserName());
|
||||
if (suggestUser == null) {
|
||||
errors.add("建议人不存在或不属于建议人所属代表团");
|
||||
}
|
||||
|
||||
OpinionType type = fetchOpinionType(row.getTypeName());
|
||||
if (type == null) {
|
||||
errors.add("意见类别不存在");
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(row.getCreateTime())) {
|
||||
errors.add("意见时间不能为空");
|
||||
}
|
||||
|
||||
List<String> suggestUnits = parseSuggestUnits(row.getSuggestUnits(), errors);
|
||||
if (StrUtil.isBlank(row.getName())) {
|
||||
errors.add("意见和建议不能为空");
|
||||
}
|
||||
|
||||
if (!errors.isEmpty()) {
|
||||
// Excel 行号按用户看到的表头后第一行数据计算,便于直接定位错误。
|
||||
row.setErrInfo(StrUtil.join(";", errors), rowIndex + 2);
|
||||
return null;
|
||||
}
|
||||
|
||||
OpinionInfo opinionInfo = new OpinionInfo();
|
||||
opinionInfo.setName(StrUtil.trim(row.getName()));
|
||||
opinionInfo.setBrief(StrUtil.trim(row.getName()));
|
||||
opinionInfo.setTypeId(type.getId());
|
||||
opinionInfo.setSessionId(session.getId());
|
||||
opinionInfo.setCreateTime(StrUtil.trim(row.getCreateTime()));
|
||||
opinionInfo.setSuggestUnits(suggestUnits);
|
||||
opinionInfo.setCreateUserId(suggestUser.getUserId());
|
||||
opinionInfo.setCreateUserName(suggestUser.getUserName());
|
||||
opinionInfo.setCreateUserLoginName(suggestUser.getLoginName());
|
||||
opinionInfo.setDelegationId(delegation.getId());
|
||||
opinionInfo.setMobile(suggestUser.getMobile());
|
||||
opinionInfo.setUnitName(suggestUser.getUnitName());
|
||||
opinionInfo.setSuggestUserId(recorderUser.getString("id"));
|
||||
opinionInfo.setSuggestUserName(recorderUser.getString("username"));
|
||||
opinionInfo.setSuggestUserLoginName(recorderUser.getString("loginname"));
|
||||
opinionInfo.setSuggestUserDelegationId(discussionGroup.getId());
|
||||
opinionInfo.setSuggestUserDelegationName(discussionGroup.getName());
|
||||
return opinionInfo;
|
||||
}
|
||||
|
||||
private void submitImportedOpinion(OpinionInfo opinionInfo) {
|
||||
// 编号必须在逐条入库前生成,确保同一代表团连续导入时序号不会重复。
|
||||
if (StrUtil.isBlank(opinionInfo.getCode())) {
|
||||
opinionInfo.setCode(generateOpinionCode(opinionInfo.getSessionId(), opinionInfo.getDelegationId()));
|
||||
}
|
||||
insert(opinionInfo);
|
||||
Dict args = Dict.create();
|
||||
args.set(FlowConst.SUBMIT_TYPE, ProcessSubmitTypeEnum.APPLY.getCode());
|
||||
args.set(FlowConst.FORM_DATA, opinionInfo);
|
||||
|
||||
ProcessInstance instance = flowEngine.startProcessInstanceByKey("JDHYJ", opinionInfo.getId(), SecurityUtil.getUserId(), args);
|
||||
List<ProcessTask> doingTaskList = flowEngine.processTaskService().getDoingTaskList(instance.getId(), null);
|
||||
for (ProcessTask task : doingTaskList) {
|
||||
flowEngine.executeProcessTask(task.getId(), SecurityUtil.getUserId(), args);
|
||||
}
|
||||
}
|
||||
|
||||
private Teacher_congress_session fetchSession(String sessionName) {
|
||||
if (StrUtil.isBlank(sessionName)) {
|
||||
return null;
|
||||
}
|
||||
return dao().fetch(Teacher_congress_session.class,
|
||||
Cnd.where("fullName", "=", StrUtil.trim(sessionName)).and("delFlag", "=", false));
|
||||
}
|
||||
|
||||
private Teacher_congress_discussion_group fetchDiscussionGroup(String sessionId, String discussionGroupName) {
|
||||
if (StrUtil.isBlank(discussionGroupName)) {
|
||||
return null;
|
||||
}
|
||||
return dao().fetch(Teacher_congress_discussion_group.class,
|
||||
Cnd.where("sessionId", "=", sessionId)
|
||||
.and("name", "=", StrUtil.trim(discussionGroupName))
|
||||
.and("delFlag", "=", false));
|
||||
}
|
||||
|
||||
private Teacher_congress_delegation fetchDelegation(String sessionId, String delegationName) {
|
||||
if (StrUtil.isBlank(delegationName)) {
|
||||
return null;
|
||||
}
|
||||
return dao().fetch(Teacher_congress_delegation.class,
|
||||
Cnd.where("sessionId", "=", sessionId)
|
||||
.and("name", "=", StrUtil.trim(delegationName))
|
||||
.and("delFlag", "=", false));
|
||||
}
|
||||
|
||||
private Teacher_congress_delegate fetchDelegate(String sessionId, String delegationId, String suggestUserName) {
|
||||
if (StrUtil.isBlank(suggestUserName)) {
|
||||
return null;
|
||||
}
|
||||
String userKey = normalizeUserKey(suggestUserName);
|
||||
List<Teacher_congress_delegate> delegates = dao().query(Teacher_congress_delegate.class,
|
||||
Cnd.where("sessionId", "=", sessionId)
|
||||
.and("delegationId", "=", delegationId)
|
||||
.and("delFlag", "=", false)
|
||||
.and(Cnd.exps("userName", "=", userKey).or("loginName", "=", userKey)));
|
||||
return delegates.size() == 1 ? delegates.get(0) : null;
|
||||
}
|
||||
|
||||
private OpinionType fetchOpinionType(String typeName) {
|
||||
if (StrUtil.isBlank(typeName)) {
|
||||
return null;
|
||||
}
|
||||
String name = StrUtil.trim(typeName);
|
||||
List<OpinionType> types = dao().query(OpinionType.class,
|
||||
Cnd.where("name", "=", name).or("code", "=", name).and("delFlag", "=", false));
|
||||
return types.size() == 1 ? types.get(0) : null;
|
||||
}
|
||||
|
||||
private List<String> parseSuggestUnits(String suggestUnitText, List<String> errors) {
|
||||
List<String> unitNames = new ArrayList<>();
|
||||
if (StrUtil.isBlank(suggestUnitText)) {
|
||||
errors.add("建议承办单位不能为空");
|
||||
return unitNames;
|
||||
}
|
||||
String[] items = suggestUnitText.split("[,,]");
|
||||
for (String item : items) {
|
||||
String unitName = StrUtil.trim(item);
|
||||
if (StrUtil.isBlank(unitName)) {
|
||||
continue;
|
||||
}
|
||||
ProposalUndertake undertake = dao().fetch(ProposalUndertake.class,
|
||||
Cnd.where("name", "=", unitName).and("delFlag", "=", false));
|
||||
if (undertake == null) {
|
||||
errors.add("建议承办单位不存在:" + unitName);
|
||||
continue;
|
||||
}
|
||||
unitNames.add(undertake.getName());
|
||||
}
|
||||
if (unitNames.isEmpty()) {
|
||||
errors.add("建议承办单位不能为空");
|
||||
}
|
||||
return unitNames;
|
||||
}
|
||||
|
||||
private Record fetchCurrentUser() {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
id,
|
||||
username,
|
||||
loginname
|
||||
FROM vw_user
|
||||
WHERE id = @userId
|
||||
""");
|
||||
sql.setParam("userId", SecurityUtil.getUserId());
|
||||
sql.setCallback(Sqls.callback.record());
|
||||
dao().execute(sql);
|
||||
return sql.getObject(Record.class);
|
||||
}
|
||||
|
||||
private boolean isRecorderInDiscussionGroup(Record recorderUser, Teacher_congress_discussion_group discussionGroup) {
|
||||
String userId = recorderUser.getString("id");
|
||||
String loginName = recorderUser.getString("loginname");
|
||||
String userName = recorderUser.getString("username");
|
||||
return StrUtil.equals(userId, discussionGroup.getRecorderUserId())
|
||||
|| StrUtil.equals(loginName, discussionGroup.getRecorderUserCode())
|
||||
|| StrUtil.equals(userName, discussionGroup.getRecorderUserName());
|
||||
}
|
||||
|
||||
private String normalizeUserKey(String userText) {
|
||||
String value = StrUtil.trim(userText);
|
||||
if (value.contains(" - ")) {
|
||||
return StrUtil.trim(StrUtil.subAfter(value, " - ", true));
|
||||
}
|
||||
if (value.contains("-")) {
|
||||
return StrUtil.trim(StrUtil.subAfter(value, "-", true));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private boolean isEmptyRow(OpinionImportExcelMode row) {
|
||||
return StrUtil.isBlank(row.getDiscussionGroupName())
|
||||
&& StrUtil.isBlank(row.getSuggestUserName())
|
||||
&& StrUtil.isBlank(row.getDelegationName())
|
||||
&& StrUtil.isBlank(row.getSessionName())
|
||||
&& StrUtil.isBlank(row.getTypeName())
|
||||
&& StrUtil.isBlank(row.getCreateTime())
|
||||
&& StrUtil.isBlank(row.getSuggestUnits())
|
||||
&& StrUtil.isBlank(row.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,13 +106,14 @@ layout("/layouts/platform.html"){
|
||||
},
|
||||
methods: {
|
||||
async openSign(row) {
|
||||
const resp = await this.$axios.post(loc() + "/signChange", { courseId: row.id, openOtherUnion: !row.openOtherUnion })
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.doSearch()
|
||||
} else {
|
||||
this.$message.warning(resp.msg)
|
||||
}
|
||||
return this.$axios.post(loc() + "/signChange", { courseId: row.id, openOtherUnion: !row.openOtherUnion }).then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.doSearch()
|
||||
} else {
|
||||
this.$message.warning(resp.msg)
|
||||
}
|
||||
})
|
||||
},
|
||||
activityChange(val) {
|
||||
this.$nextTick(() => {
|
||||
@@ -130,12 +131,13 @@ layout("/layouts/platform.html"){
|
||||
await this.doSearch()
|
||||
},
|
||||
async getActivityList() {
|
||||
const resp = await this.$axios.post(loc() + "/activityList", { year: this.pageForm.year })
|
||||
this.activityList = resp.data
|
||||
if (this.activityList && this.activityList.length > 0) {
|
||||
this.pageForm.activityId = this.activityList[0].id
|
||||
this.activityChange(this.activityList[0].id)
|
||||
}
|
||||
return this.$axios.post(loc() + "/activityList", { year: this.pageForm.year }).then((resp) => {
|
||||
this.activityList = resp.data
|
||||
if (this.activityList && this.activityList.length > 0) {
|
||||
this.pageForm.activityId = this.activityList[0].id
|
||||
this.activityChange(this.activityList[0].id)
|
||||
}
|
||||
})
|
||||
},
|
||||
async initData() {
|
||||
await this.getActivityList()
|
||||
|
||||
@@ -3,6 +3,15 @@ const info = {
|
||||
<div>
|
||||
<el-tabs>
|
||||
<el-tab-pane label="报名人员">
|
||||
<el-form :inline="true" :model="registerQueryForm" class="mt20" size="small" @submit.native.prevent>
|
||||
<el-form-item label="工号/姓名">
|
||||
<el-input clearable placeholder="请输入工号或姓名" v-model="registerQueryForm.keyword" @keyup.enter.native.prevent="registerUserList()"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="registerUserList" type="primary">查询</el-button>
|
||||
<el-button @click="resetRegisterQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table :data="registerUserTableData" class="mt20" max-height="600">
|
||||
<el-table-column
|
||||
:label="column.label"
|
||||
@@ -24,6 +33,15 @@ const info = {
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="签到情况" v-if="clickRow.isMobileSign === true && timeList.length > 0">
|
||||
<el-form :inline="true" :model="signQueryForm" class="mt20" size="small" @submit.native.prevent>
|
||||
<el-form-item label="工号/姓名">
|
||||
<el-input clearable placeholder="请输入工号或姓名" v-model="signQueryForm.keyword" @keyup.enter.native.prevent="doSearch()"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="doSearch" type="primary">查询</el-button>
|
||||
<el-button @click="resetSignQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-tabs style="height: 660px" tab-position="left" class="mt20" @tab-click="tabClick">
|
||||
<el-tab-pane v-for="item,index in timeList" :key="index">
|
||||
<span slot="label">
|
||||
@@ -87,11 +105,20 @@ const info = {
|
||||
signUserList: [],
|
||||
timeId: '',
|
||||
pageForm: {},
|
||||
registerQueryForm: {
|
||||
keyword: ""
|
||||
},
|
||||
signQueryForm: {
|
||||
keyword: ""
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async onOpen(row) {
|
||||
this.clickRow = row
|
||||
this.registerQueryForm.keyword = ""
|
||||
this.signQueryForm.keyword = ""
|
||||
this.pageForm.pageNumber = 1
|
||||
await this.registerUserList()
|
||||
await this.selectTimes()
|
||||
await this.getTaleColumnInfo()
|
||||
@@ -100,6 +127,14 @@ const info = {
|
||||
this.pageForm.pageNumber = 1
|
||||
await this.selectSignUsers(this.timeId)
|
||||
},
|
||||
async resetRegisterQuery() {
|
||||
this.registerQueryForm.keyword = ""
|
||||
await this.registerUserList()
|
||||
},
|
||||
async resetSignQuery() {
|
||||
this.signQueryForm.keyword = ""
|
||||
await this.doSearch()
|
||||
},
|
||||
async pageNumberChange(val) {
|
||||
this.pageForm.pageNumber = val
|
||||
await this.selectSignUsers(this.timeId)
|
||||
@@ -126,25 +161,41 @@ const info = {
|
||||
await this.selectSignUsers(this.timeList[val.index].id)
|
||||
},
|
||||
async registerUserList() {
|
||||
const res = await this.$axios.post(loc() + "/registerUserList", { courseId: this.clickRow.id })
|
||||
this.registerUserTableData = res.data
|
||||
const params = {
|
||||
courseId: this.clickRow.id
|
||||
}
|
||||
const keyword = this.registerQueryForm.keyword ? this.registerQueryForm.keyword.trim() : ""
|
||||
if (keyword) {
|
||||
params.keyword = keyword
|
||||
}
|
||||
return this.$axios.post(loc() + "/registerUserList", params).then((res) => {
|
||||
this.registerUserTableData = res.data
|
||||
})
|
||||
},
|
||||
async selectTimes() {
|
||||
const res = await this.$axios.post(loc() + "/selectTimes", { courseId: this.clickRow.id })
|
||||
this.timeList = res.data
|
||||
if(this.timeList.length > 0) {
|
||||
await this.selectSignUsers(this.timeList[0].id)
|
||||
}
|
||||
return this.$axios.post(loc() + "/selectTimes", { courseId: this.clickRow.id }).then(async (res) => {
|
||||
this.timeList = res.data
|
||||
if(this.timeList.length > 0) {
|
||||
await this.selectSignUsers(this.timeList[0].id)
|
||||
}
|
||||
})
|
||||
},
|
||||
async selectSignUsers(timeId) {
|
||||
this.timeId = timeId
|
||||
this.$set(this.pageForm, 'courseId', this.clickRow.id)
|
||||
this.$set(this.pageForm, 'timeId', timeId)
|
||||
const res = await this.$axios.post(loc() + "/getSignInfo", this.pageForm)
|
||||
if (res.code === 0) {
|
||||
this.signUserList = res.data.list
|
||||
this.pageForm.totalCount = res.data.totalCount
|
||||
const keyword = this.signQueryForm.keyword ? this.signQueryForm.keyword.trim() : ""
|
||||
if (keyword) {
|
||||
this.$set(this.pageForm, 'keyword', keyword)
|
||||
} else {
|
||||
this.$delete(this.pageForm, 'keyword')
|
||||
}
|
||||
return this.$axios.post(loc() + "/getSignInfo", this.pageForm).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.signUserList = res.data.list
|
||||
this.pageForm.totalCount = res.data.totalCount
|
||||
}
|
||||
})
|
||||
},
|
||||
async getTaleColumnInfo() {
|
||||
const res = await $.get(loc() + '/getTaleColumnInfo', { courseId: this.clickRow.id })
|
||||
|
||||
@@ -22,7 +22,9 @@ layout("/layouts/platform.html"){
|
||||
</search>
|
||||
</el-card>
|
||||
<el-card shadow="never">
|
||||
<table-tool :columns.sync="tableColumns"></table-tool>
|
||||
<table-tool :columns.sync="tableColumns">
|
||||
<el-button size="small" type="primary" icon="el-icon-upload2" @click="showImportDialog = true">导入意见</el-button>
|
||||
</table-tool>
|
||||
<el-table :data="tableData" @sort-change="pageOrder" header-align="center" style="width: 100%" row-key="id">
|
||||
<el-table-column label="序号" width="50" type="index" :index="indexMethod" fixed="left"></el-table-column>
|
||||
<el-table-column
|
||||
@@ -66,6 +68,17 @@ layout("/layouts/platform.html"){
|
||||
</template>
|
||||
|
||||
</guava>
|
||||
|
||||
<excel-import
|
||||
ref="excelImportRef"
|
||||
url="/platform/opinion/mine/importOpinion"
|
||||
template_url="/platform/opinion/mine/downloadImportTemplate"
|
||||
:visible.sync="showImportDialog"
|
||||
title="意见导入"
|
||||
width="700px"
|
||||
@import-success="doSearch"
|
||||
:extra_params="{}"
|
||||
></excel-import>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
@@ -82,6 +95,7 @@ layout("/layouts/platform.html"){
|
||||
return {
|
||||
sessionOptions: [],
|
||||
businessNo: null,
|
||||
showImportDialog: false,
|
||||
tableColumns: [
|
||||
{label: "意见编号", prop: "code"},
|
||||
{label: "意见和建议", prop: "name", width: "200px"},
|
||||
|
||||
Reference in New Issue
Block a user