commit
This commit is contained in:
@@ -56,6 +56,14 @@ public interface SchoolOaTodoService {
|
||||
*/
|
||||
void createWelfareReminderTodos(String projectId, String title, String pcUrl, String appUrl, String creatorId, List<String> receiverIds);
|
||||
|
||||
/**
|
||||
* 将用户已完成福利选择对应的学校OA提醒待办改为已办。
|
||||
*
|
||||
* @param projectId 福利项目ID
|
||||
* @param userId 完成选择的用户ID
|
||||
*/
|
||||
void completeWelfareReminderTodo(String projectId, String userId);
|
||||
|
||||
/**
|
||||
* 删除用户已完成福利选择对应的学校OA提醒待办。
|
||||
*
|
||||
|
||||
@@ -224,6 +224,18 @@ public class SchoolOaTodoServiceImpl implements SchoolOaTodoService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completeWelfareReminderTodo(String projectId, String userId) {
|
||||
if (!isSchoolOaEnabled("完成福利选择提醒待办", null, null) || StrUtil.hasBlank(projectId, userId)) {
|
||||
return;
|
||||
}
|
||||
String uniqueId = buildWelfareReminderUniqueId(projectId, userId);
|
||||
String updateUrl = requireConfig("school-oa.todo.update-url").replace("{uniqueId}", uniqueId);
|
||||
String responseBody = sendTodoRequest(updateUrl, "学校OA福利选择提醒待办完成失败", "学校OA福利选择提醒待办完成异常");
|
||||
log.info("学校OA福利选择提醒待办完成成功,projectId={},userId={},uniqueId={},response={}",
|
||||
projectId, userId, uniqueId, responseBody);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteWelfareReminderTodo(String projectId, String userId) {
|
||||
if (!isSchoolOaEnabled("删除福利选择提醒待办", null, null) || StrUtil.hasBlank(projectId, userId)) {
|
||||
|
||||
@@ -63,6 +63,16 @@ public class SysRoleController {
|
||||
|
||||
}
|
||||
|
||||
@At("/doSettingMemberRole")
|
||||
@Ok("json")
|
||||
@SaCheckPermission("sys.manager.role")
|
||||
@SLog(tag = "系统管理-角色", msg = "同步会员角色")
|
||||
@ApiOperation("同步会员角色")
|
||||
public Result doSettingMemberRole() {
|
||||
NutMap result = sysRoleService.syncMemberRole();
|
||||
return Result.success("同步完成,新增" + result.getInt("addedCount") + "个,移除" + result.getInt("removedCount") + "个");
|
||||
}
|
||||
|
||||
@At("/tree")
|
||||
@Ok("json")
|
||||
@SaCheckLogin
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.sys.models.Sys_menu;
|
||||
import com.budwk.app.sys.models.Sys_role;
|
||||
import com.budwk.app.sys.models.Sys_unit;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -121,6 +122,13 @@ public interface SysRoleService extends BaseService<Sys_role> {
|
||||
*/
|
||||
Sys_role getByCode(RoleConstant roleConstant);
|
||||
|
||||
/**
|
||||
* 根据用户表中的会员标记核对并同步会员角色关系。
|
||||
*
|
||||
* @return 同步新增、删除和会员总数
|
||||
*/
|
||||
NutMap syncMemberRole();
|
||||
|
||||
/**
|
||||
* 清空缓存
|
||||
*/
|
||||
|
||||
@@ -10,6 +10,8 @@ import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.sys.models.Sys_menu;
|
||||
import com.budwk.app.sys.models.Sys_role;
|
||||
import com.budwk.app.sys.models.Sys_unit;
|
||||
import com.budwk.app.sys.models.Sys_user;
|
||||
import com.budwk.app.sys.models.Sys_user_role;
|
||||
import com.budwk.app.sys.services.SysMenuService;
|
||||
import com.budwk.app.sys.services.SysRoleService;
|
||||
import com.budwk.app.sys.services.SysUserService;
|
||||
@@ -20,12 +22,16 @@ import org.nutz.ioc.aop.Aop;
|
||||
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.plugins.wkcache.annotation.CacheDefaults;
|
||||
import org.nutz.plugins.wkcache.annotation.CacheRemoveAll;
|
||||
import org.nutz.plugins.wkcache.annotation.CacheResult;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Created by wizzer on 2016/12/22.
|
||||
@@ -262,6 +268,63 @@ public class SysRoleServiceImpl extends BaseServiceImpl<Sys_role> implements Sys
|
||||
return getByCode(roleConstant.name());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public NutMap syncMemberRole() {
|
||||
Sys_role memberRole = getByCode(RoleConstant.MEMBER);
|
||||
Set<String> memberUserIds = dao().query(Sys_user.class, Cnd.where(Sys_user::getMember, "=", true)).stream()
|
||||
.map(Sys_user::getId)
|
||||
.filter(Strings::isNotBlank)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
List<Sys_user_role> memberRoleRelations = dao().query(Sys_user_role.class,
|
||||
Cnd.where(Sys_user_role::getRoleId, "=", memberRole.getId()));
|
||||
Set<String> existingMemberRoleUserIds = memberRoleRelations.stream()
|
||||
.map(Sys_user_role::getUserId)
|
||||
.filter(memberUserIds::contains)
|
||||
.collect(Collectors.toCollection(HashSet::new));
|
||||
|
||||
List<Sys_user_role> roleRelationsToAdd = memberUserIds.stream()
|
||||
.filter(userId -> !existingMemberRoleUserIds.contains(userId))
|
||||
.map(userId -> {
|
||||
Sys_user_role userRole = new Sys_user_role();
|
||||
userRole.setUserId(userId);
|
||||
userRole.setRoleId(memberRole.getId());
|
||||
return userRole;
|
||||
})
|
||||
.toList();
|
||||
if (!roleRelationsToAdd.isEmpty()) {
|
||||
dao().insert(roleRelationsToAdd);
|
||||
}
|
||||
|
||||
List<String> invalidUserIds = memberRoleRelations.stream()
|
||||
.map(Sys_user_role::getUserId)
|
||||
.filter(userId -> !memberUserIds.contains(userId))
|
||||
.filter(Strings::isNotBlank)
|
||||
.distinct()
|
||||
.toList();
|
||||
int removedCount = (int) memberRoleRelations.stream()
|
||||
.filter(roleRelation -> !memberUserIds.contains(roleRelation.getUserId()))
|
||||
.count();
|
||||
if (memberUserIds.isEmpty()) {
|
||||
if (!memberRoleRelations.isEmpty()) {
|
||||
dao().clear(Sys_user_role.class, Cnd.where(Sys_user_role::getRoleId, "=", memberRole.getId()));
|
||||
}
|
||||
} else if (!invalidUserIds.isEmpty()) {
|
||||
// 会员角色只保留在 sys_user.member = 1 的用户上,同时清理已删除用户的孤立关系。
|
||||
dao().clear(Sys_user_role.class,
|
||||
Cnd.where(Sys_user_role::getRoleId, "=", memberRole.getId())
|
||||
.and(Sys_user_role::getUserId, "in", invalidUserIds));
|
||||
}
|
||||
|
||||
clearCache();
|
||||
sysUserService.clearCache();
|
||||
return NutMap.NEW()
|
||||
.addv("memberCount", memberUserIds.size())
|
||||
.addv("addedCount", roleRelationsToAdd.size())
|
||||
.addv("removedCount", removedCount);
|
||||
}
|
||||
|
||||
@CacheRemoveAll
|
||||
public void clearCache() {
|
||||
|
||||
|
||||
+6
-4
@@ -120,9 +120,10 @@ public class ClubUserJoinApplyController {
|
||||
@SLog(tag = "协会管理系统-申请入会", msg = "申请协会入会")
|
||||
public Result submit(ClubUserApply clubUserApply) {
|
||||
ClubUserApply userApply = dao.fetch(ClubUserApply.class, Cnd.where("userId", "=", clubUserApply.getUserId()).and("clubId", "=", clubUserApply.getClubId()).and("mode", "=", 1).desc(ClubUserApply::getApplyDate));
|
||||
if (ObjectUtil.isNotEmpty(userApply) && StrUtil.isBlank(userApply.getId())) {
|
||||
// 新建申请时,已有同协会的草稿或进行中的申请都不能再次提交;编辑当前草稿时允许继续提交。
|
||||
if (ObjectUtil.isNotEmpty(userApply) && !StrUtil.equals(userApply.getId(), clubUserApply.getId())) {
|
||||
ProcessInstance processInstance = dao.fetch(ProcessInstance.class, Cnd.where(ProcessInstance::getBusinessNo, "=", userApply.getId()));
|
||||
if (!List.of(ProcessInstanceStateEnum.REJECT.getCode(),ProcessInstanceStateEnum.FINISHED.getCode()).contains(processInstance.getState())) {
|
||||
if (processInstance == null || !List.of(ProcessInstanceStateEnum.REJECT.getCode(),ProcessInstanceStateEnum.FINISHED.getCode()).contains(processInstance.getState())) {
|
||||
return Result.error("您有该协会的申请记录尚未完成,请到我的申请里查看!");
|
||||
}
|
||||
}
|
||||
@@ -173,11 +174,12 @@ public class ClubUserJoinApplyController {
|
||||
}
|
||||
|
||||
if (ObjectUtil.isNotEmpty(clubUser)) {
|
||||
return Result.error(99, "请勿重复申请!");
|
||||
return Result.error(99, "您已经是该协会成员,请勿重复申请!");
|
||||
}
|
||||
|
||||
ProcessInstance processInstance = dao.fetch(ProcessInstance.class, Cnd.where(ProcessInstance::getBusinessNo, "=", userApply.getId()));
|
||||
if (!List.of(ProcessInstanceStateEnum.REJECT.getCode(),ProcessInstanceStateEnum.FINISHED.getCode()).contains(processInstance.getState())) {
|
||||
// 仅保存的申请还没有流程实例,也应按未完成申请处理,避免空指针并防止重复创建草稿。
|
||||
if (processInstance == null || !List.of(ProcessInstanceStateEnum.REJECT.getCode(),ProcessInstanceStateEnum.FINISHED.getCode()).contains(processInstance.getState())) {
|
||||
return Result.error(99, "您有该协会的申请记录尚未完成,请到我的申请里查看!");
|
||||
}
|
||||
return Result.success();
|
||||
|
||||
+2
@@ -111,6 +111,8 @@ public class ClubChangeManagerController {
|
||||
} else {
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
}
|
||||
// 按理事机构变更申请主表主键分组,避免流程任务处理人关联导致同一申请重复显示。
|
||||
cnd.groupBy("info.id");
|
||||
sql.setCondition(cnd);
|
||||
Pagination pagination = infoManageService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
List<NutMap> listMap = pagination.getList(NutMap.class);
|
||||
|
||||
+27
-9
@@ -106,6 +106,8 @@ public class ClubRefreshReportController {
|
||||
} else {
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
}
|
||||
// 按换届报告申请主表主键分组,避免流程任务处理人关联导致同一申请重复显示。
|
||||
cnd.groupBy("info.id");
|
||||
sql.setCondition(cnd);
|
||||
Pagination pagination = clubInfoManageService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
return Result.success(pagination);
|
||||
@@ -117,18 +119,34 @@ public class ClubRefreshReportController {
|
||||
@SLog(tag = "协会管理系统-信息管理", msg = "提交换届报告")
|
||||
public Object submit(@Param("data") SysClubRefresh clubRefresh) {
|
||||
|
||||
Cnd cnd = Cnd.NEW();
|
||||
if(StrUtil.isNotBlank(clubRefresh.getId())) {
|
||||
cnd.and(SysClubRefresh::getId, "!=", clubRefresh.getId());
|
||||
}
|
||||
if (clubRefresh == null || StrUtil.isBlank(clubRefresh.getClubId())) {
|
||||
return Result.error("请选择协会!");
|
||||
}
|
||||
SysClub club = clubInfoManageService.dao().fetch(SysClub.class, clubRefresh.getClubId());
|
||||
if (club == null) {
|
||||
return Result.error("协会不存在,请刷新后重试!");
|
||||
}
|
||||
|
||||
// 仅检查当前用户在当前协会的其他换届报告,避免不同协会的未完成流程相互影响。
|
||||
Cnd cnd = Cnd.where(SysClubRefresh::getClubId, "=", clubRefresh.getClubId())
|
||||
.and(SysClubRefresh::getUserId, "=", SecurityUtil.getUserId());
|
||||
if (StrUtil.isNotBlank(clubRefresh.getId())) {
|
||||
// 编辑已有申请时排除当前记录,避免当前流程被误判为重复申请。
|
||||
cnd.and(SysClubRefresh::getId, "!=", clubRefresh.getId());
|
||||
}
|
||||
List<SysClubRefresh> list = dao.query(SysClubRefresh.class, cnd);
|
||||
List<String> idList = list.stream().map(SysClubRefresh::getId).toList();
|
||||
int count = dao.count(ProcessInstance.class, Cnd.where(ProcessInstance::getBusinessNo, "in", idList).and(ProcessInstance::getState, "not in", List.of(ProcessInstanceStateEnum.FINISHED.getCode(), ProcessInstanceStateEnum.REJECT.getCode())));
|
||||
if (count > 0) {
|
||||
return Result.error("您有该协会的申请记录尚未完成,请核对!");
|
||||
if (!list.isEmpty()) {
|
||||
List<String> idList = list.stream().map(SysClubRefresh::getId).toList();
|
||||
int count = dao.count(ProcessInstance.class,
|
||||
Cnd.where(ProcessInstance::getBusinessNo, "in", idList)
|
||||
.and(ProcessInstance::getState, "not in", List.of(
|
||||
ProcessInstanceStateEnum.FINISHED.getCode(),
|
||||
ProcessInstanceStateEnum.REJECT.getCode())));
|
||||
if (count > 0) {
|
||||
return Result.error("您有该协会的申请记录尚未完成,请核对!");
|
||||
}
|
||||
}
|
||||
|
||||
SysClub club = clubInfoManageService.dao().fetch(SysClub.class, clubRefresh.getClubId());
|
||||
clubRefresh.setUserId(SecurityUtil.getUserId());
|
||||
clubRefresh.setUserName(SecurityUtil.getUserUsername());
|
||||
clubRefresh.setLastFiles(club.getReplaceReport());
|
||||
|
||||
+2
@@ -107,6 +107,8 @@ public class ClubRuleUpdateController {
|
||||
} else {
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
}
|
||||
// 按章程修订申请主表主键分组,避免流程任务或处理人关联导致同一申请重复显示。
|
||||
cnd.groupBy("info.id");
|
||||
sql.setCondition(cnd);
|
||||
Pagination pagination = clubInfoManageService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
return Result.success(pagination);
|
||||
|
||||
+4
-2
@@ -86,9 +86,10 @@ public class ClubRegistApplyController {
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("club.register.apply")
|
||||
@SLog(tag = "协会管理系统-协会注册", msg = "提交注册协会")
|
||||
public Result submit(@Param("club") SysClub club,
|
||||
public Result submit(@Valid @Param("club") SysClub club,
|
||||
@Param("::deleteIds") List<String> deleteIds,
|
||||
@Param("::managePerson") List<NutMap> managePerson) {
|
||||
sysClubService.validateManagePerson(managePerson);
|
||||
SysClub sysClub;
|
||||
if (StrUtil.isBlank(club.getId())) {
|
||||
sysClub = sysClubService.doAdd(club, managePerson);
|
||||
@@ -114,10 +115,11 @@ public class ClubRegistApplyController {
|
||||
@ApiOperation("重新提交申请")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("club.register.apply")
|
||||
public Result submitAgain(@Param("club") SysClub club,
|
||||
public Result submitAgain(@Valid @Param("club") SysClub club,
|
||||
@Param("::deleteIds") List<String> deleteIds,
|
||||
@Param("::managePerson") List<NutMap> managePerson,
|
||||
@Param("taskId") Long taskId) {
|
||||
sysClubService.validateManagePerson(managePerson);
|
||||
if (StrUtil.isBlank(club.getId())) {
|
||||
sysClubService.doAdd(club, managePerson);
|
||||
} else {
|
||||
|
||||
+34
-1
@@ -6,6 +6,7 @@ import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
|
||||
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
@@ -50,9 +51,11 @@ import java.io.BufferedOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
@@ -290,9 +293,22 @@ public class ClubStatisticsController {
|
||||
response.setContentType("application/octet-stream");
|
||||
response.setHeader("Content-Disposition", "attachment;filename=" + URLUtil.encode("上传资料数据.zip"));
|
||||
LinkedHashMap<String, List<JSONObject>> fileList = new LinkedHashMap<>();
|
||||
Set<String> exportedFilePaths = new HashSet<>();
|
||||
|
||||
//查询社团
|
||||
List<SysClub> clubList = sysClubService.query(Cnd.NEW().andEX("id", "=", clubId));
|
||||
if (!clubList.isEmpty()) {
|
||||
List<String> clubIdList = clubList.stream().map(SysClub::getId).toList();
|
||||
// 资料导出只允许注册流程审核通过的协会,避免未通过审核的协会进入压缩包。
|
||||
Set<String> passedClubIdSet = sysClubService.dao().query(
|
||||
ProcessInstance.class,
|
||||
Cnd.where(ProcessInstance::getBusinessNo, "in", clubIdList)
|
||||
.and(ProcessInstance::getState, "=", ProcessInstanceStateEnum.FINISHED.getCode()))
|
||||
.stream()
|
||||
.map(ProcessInstance::getBusinessNo)
|
||||
.collect(Collectors.toSet());
|
||||
clubList = clubList.stream().filter(item -> passedClubIdSet.contains(item.getId())).toList();
|
||||
}
|
||||
clubList.forEach(item -> {
|
||||
List<JSONObject> file = new ArrayList<>();
|
||||
file.addAll(Optional.ofNullable(item.getFiles()).orElseGet(ArrayList::new));
|
||||
@@ -301,7 +317,6 @@ public class ClubStatisticsController {
|
||||
file.addAll(Optional.ofNullable(item.getManageFile()).orElseGet(ArrayList::new));
|
||||
file.addAll(Optional.ofNullable(item.getYearPlanFile()).orElseGet(ArrayList::new));
|
||||
file.addAll(Optional.ofNullable(item.getReplaceReport()).orElseGet(ArrayList::new));
|
||||
file.addAll(Optional.ofNullable(item.getRulesFile()).orElseGet(ArrayList::new));
|
||||
fileList.put(item.getId(), file);
|
||||
});
|
||||
|
||||
@@ -329,13 +344,31 @@ public class ClubStatisticsController {
|
||||
ZipOutputStream zipOutputStream = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()));
|
||||
clubList.forEach(item -> {
|
||||
List<JSONObject> sysFiles = fileList.get(item.getId());
|
||||
if (sysFiles == null || sysFiles.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
sysFiles.forEach(f -> {
|
||||
try {
|
||||
if (f == null) {
|
||||
return;
|
||||
}
|
||||
String fileName = f.getStr("name");
|
||||
String filepath = f.getStr("url");
|
||||
if (StrUtil.isBlank(fileName) || StrUtil.isBlank(filepath) || !exportedFilePaths.add(filepath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Sys_file file = sysClubService.dao().fetch(Sys_file.class, Cnd.where(Sys_file::getDownloadPath, "=", filepath));
|
||||
// 仅导出文件记录仍存在且能够读取的资料,避免失效附件进入压缩包。
|
||||
if (file == null) {
|
||||
log.warn("协会上传资料对应的文件记录不存在,跳过导出:{}", filepath);
|
||||
return;
|
||||
}
|
||||
byte[] bytes = SysFileMinIoUtil.getFileBytes(file.getBucket(), file.getStoragePath());
|
||||
if (bytes == null) {
|
||||
log.warn("协会上传资料读取失败,跳过导出:{}", filepath);
|
||||
return;
|
||||
}
|
||||
|
||||
zipOutputStream.putNextEntry(new ZipEntry(item.getClubName() + "/" + System.currentTimeMillis() + fileName));
|
||||
zipOutputStream.write(bytes);
|
||||
|
||||
@@ -82,6 +82,7 @@ public class SysClub extends BaseModel {
|
||||
@Column
|
||||
@Comment("成立时间")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
@NotEmpty(message = "成立时间不能为空")
|
||||
private String foundTime;
|
||||
|
||||
@Column
|
||||
@@ -102,11 +103,13 @@ public class SysClub extends BaseModel {
|
||||
@Column
|
||||
@Comment("申请成立报告")
|
||||
@ColDefine(type = ColType.MYSQL_JSON)
|
||||
@NotEmpty(message = "申请成立报告不能为空")
|
||||
private List<JSONObject> establishReport;
|
||||
|
||||
@Column
|
||||
@Comment("章程草案")
|
||||
@ColDefine(type = ColType.MYSQL_JSON)
|
||||
@NotEmpty(message = "章程草案不能为空")
|
||||
private List<JSONObject> rulesFile;
|
||||
|
||||
@Column
|
||||
|
||||
@@ -38,6 +38,13 @@ public interface SysClubService extends BaseService<SysClub> {
|
||||
|
||||
SysClub doEdit(SysClub club, List<String> deleteIds, List<NutMap> managePerson);
|
||||
|
||||
/**
|
||||
* 校验协会提交时理事机构中的必填职务是否已选择人员。
|
||||
*
|
||||
* @param managePerson 理事机构人员信息
|
||||
*/
|
||||
void validateManagePerson(List<NutMap> managePerson);
|
||||
|
||||
/**
|
||||
* 下载协会申请成立报告模板。
|
||||
*
|
||||
|
||||
@@ -251,6 +251,28 @@ public class SysClubServiceImpl extends BaseServiceImpl<SysClub> implements SysC
|
||||
return club;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateManagePerson(List<NutMap> managePerson) {
|
||||
boolean hasPresident = false;
|
||||
boolean hasSecretary = false;
|
||||
if (ObjectUtil.isNotEmpty(managePerson)) {
|
||||
for (NutMap person : managePerson) {
|
||||
if (person == null || StrUtil.isBlank(person.getString("userId"))) {
|
||||
continue;
|
||||
}
|
||||
if (RoleConstant.CLUB_PRESIDENT.name().equals(person.getString("roleCode"))) {
|
||||
hasPresident = true;
|
||||
}
|
||||
if (RoleConstant.CLUB_SECRETARY.name().equals(person.getString("roleCode"))) {
|
||||
hasSecretary = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hasPresident || !hasSecretary) {
|
||||
throw new BaseException("请填写协会理事机构中的会长和秘书长");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pagination<ClubRegisterPageVo> minePageData(ClubUserPageForm pageForm) {
|
||||
Sql sql = Sqls.create("""
|
||||
@@ -291,6 +313,8 @@ public class SysClubServiceImpl extends BaseServiceImpl<SysClub> implements SysC
|
||||
cnd.andEX("year(info.createTime)", "=", pageForm.getYear());
|
||||
cnd.and("info.userId", "=", SecurityUtil.getUserId());
|
||||
cnd.desc("createTime");
|
||||
// 按协会主表主键分组,避免流程任务或处理人关联导致同一申请返回多条记录。
|
||||
cnd.groupBy("info.id");
|
||||
sql.setCondition(cnd);
|
||||
return listPageVO(pageForm, sql, ClubRegisterPageVo.class);
|
||||
}
|
||||
|
||||
+1
-1
@@ -94,7 +94,7 @@ public class WelfareSelectionSituationController {
|
||||
welfareUserSelection.setSelectTime(new Date());
|
||||
}
|
||||
dao.insert(selections);
|
||||
situationService.clearReminderTodo(projectId, userId);
|
||||
situationService.completeReminderTodo(projectId, userId);
|
||||
return Result.success("选择成功");
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.welfare.model.WelfareList;
|
||||
import com.budwk.app.zhgh.welfare.model.WelfareUserSelection;
|
||||
import com.budwk.app.zhgh.welfare.service.WelfareSelectionSituationService;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Chain;
|
||||
@@ -41,6 +42,8 @@ public class WelfareUserChooseController {
|
||||
private Dao dao;
|
||||
@Inject
|
||||
private BaseService baseService;
|
||||
@Inject
|
||||
private WelfareSelectionSituationService situationService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/welfare/userChoose/index.html")
|
||||
@@ -103,6 +106,7 @@ public class WelfareUserChooseController {
|
||||
Chain.make("isReceive", true),
|
||||
Cnd.where("projectId", "=", projectId)
|
||||
.and("userId", "=", SecurityUtil.getUserId()));
|
||||
situationService.completeReminderTodo(projectId, SecurityUtil.getUserId());
|
||||
return Result.success("选择成功");
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -106,7 +106,7 @@ public class WelfareUserSelectController {
|
||||
welfareUserSelection.setSelectTime(new Date());
|
||||
}
|
||||
dao.insert(selections);
|
||||
situationService.clearReminderTodo(projectId, SecurityUtil.getUserId());
|
||||
situationService.completeReminderTodo(projectId, SecurityUtil.getUserId());
|
||||
return Result.success("选择成功");
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -34,11 +34,11 @@ public interface WelfareSelectionSituationService extends BaseService<WelfareLis
|
||||
int sendReminder(WelfareSelectionSituationPageForm pageForm, String[] userIds, String content);
|
||||
|
||||
/**
|
||||
* 用户完成福利选择后清除对应的学校OA提醒待办。
|
||||
* 用户完成福利选择后将对应的学校OA提醒待办改为已办。
|
||||
*
|
||||
* @param projectId 福利项目ID
|
||||
* @param userId 完成选择的用户ID
|
||||
*/
|
||||
void clearReminderTodo(String projectId, String userId);
|
||||
void completeReminderTodo(String projectId, String userId);
|
||||
|
||||
}
|
||||
|
||||
+9
-9
@@ -148,21 +148,21 @@ public class WelfareSelectionSituationServiceImpl extends BaseServiceImpl<Welfar
|
||||
if (Boolean.TRUE.equals(Globals.MyConfig.getBoolean("AppSms")) && !receiverUsers.isEmpty()) {
|
||||
smsService.massSendByUsers(receiverUsers, title, content, pcUrl, appUrl);
|
||||
}
|
||||
// 学校OA待办暂不发送,保留原调用以便后续恢复学校OA福利提醒。
|
||||
// if (Boolean.TRUE.equals(Globals.MyConfig.getBoolean("AppSchoolOa"))) {
|
||||
// schoolOaTodoService.createWelfareReminderTodos(pageForm.getProjectId(), title + content,
|
||||
// pcUrl, appUrl, SecurityUtil.getUserId(), recipientIds);
|
||||
// }
|
||||
// AppSchoolOa 控制学校OA福利提醒待办创建,待办与接收人按项目保持唯一。
|
||||
if (Boolean.TRUE.equals(Globals.MyConfig.getBoolean("AppSchoolOa"))) {
|
||||
schoolOaTodoService.createWelfareReminderTodos(pageForm.getProjectId(), title + content,
|
||||
pcUrl, appUrl, SecurityUtil.getUserId(), recipientIds);
|
||||
}
|
||||
return recipientIds.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearReminderTodo(String projectId, String userId) {
|
||||
public void completeReminderTodo(String projectId, String userId) {
|
||||
try {
|
||||
schoolOaTodoService.deleteWelfareReminderTodo(projectId, userId);
|
||||
schoolOaTodoService.completeWelfareReminderTodo(projectId, userId);
|
||||
} catch (Exception e) {
|
||||
// 学校OA删除失败不能影响用户完成福利选择,后续可根据日志人工处理。
|
||||
log.error("删除学校OA福利选择提醒待办失败,projectId={},userId={}", projectId, userId, e);
|
||||
// 学校OA转已办失败不能影响用户完成福利选择,后续可根据日志人工处理。
|
||||
log.error("学校OA福利选择提醒待办转已办失败,projectId={},userId={}", projectId, userId, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,9 @@ layout("/layouts/platform.html"){
|
||||
<el-button icon="el-icon-search" @click="doSearch" type="primary"></el-button>
|
||||
|
||||
<div style="margin-left: auto">
|
||||
<el-button @click="doSettingMemberRole" type="primary" size="medium">
|
||||
同步会员角色
|
||||
</el-button>
|
||||
<el-button size="medium" @click="openAdd" type="primary">
|
||||
<i class="ti-plus"></i>
|
||||
新建角色
|
||||
|
||||
@@ -110,7 +110,10 @@ layout("/layouts/platform.html"){
|
||||
id: '',
|
||||
taskId: '',
|
||||
clubList: [],
|
||||
formData: {},
|
||||
formData: {
|
||||
clubId: '',
|
||||
files: []
|
||||
},
|
||||
formRules: {
|
||||
clubId: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||
files: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||
@@ -123,7 +126,10 @@ layout("/layouts/platform.html"){
|
||||
this.id = ''
|
||||
this.taskId = ''
|
||||
this.$refs.guava.edit(() => {
|
||||
this.formData = {}
|
||||
this.$set(this, "formData", {
|
||||
clubId: '',
|
||||
files: []
|
||||
})
|
||||
})
|
||||
},
|
||||
onRevoke(row) {
|
||||
|
||||
@@ -169,6 +169,9 @@ const CLUB_FORM_TEMPLATE = {
|
||||
formData: {
|
||||
clubName: "",
|
||||
clubType: "",
|
||||
foundTime: "",
|
||||
establishReport: [],
|
||||
rulesFile: [],
|
||||
introduce: CLUB_DEFAULT_INTRODUCE
|
||||
},
|
||||
formRules: {
|
||||
|
||||
@@ -64,7 +64,7 @@ layout("/layouts/platform.html"){
|
||||
nextStep() {
|
||||
let valid = true
|
||||
this.$refs.clubFormRef.$refs.form.validateField(
|
||||
["clubName", "establishReport", "rulesFile"],
|
||||
["clubName", "clubType", "foundTime", "establishReport", "rulesFile"],
|
||||
(errMsg) => {
|
||||
if (!errMsg) {
|
||||
valid = false
|
||||
@@ -101,6 +101,19 @@ layout("/layouts/platform.html"){
|
||||
async doHandle(type) {
|
||||
let formData = {}
|
||||
try {
|
||||
const managePerson = this.$refs.clubManagerRef.managePerson
|
||||
if (['onFinishTask', 'onSubmit'].includes(type)) {
|
||||
const hasPresident = managePerson.some((item) =>
|
||||
item.roleCode === CLUB_ROLE_CONSTANT.CLUB_PRESIDENT && item.userId
|
||||
)
|
||||
const hasSecretary = managePerson.some((item) =>
|
||||
item.roleCode === CLUB_ROLE_CONSTANT.CLUB_SECRETARY && item.userId
|
||||
)
|
||||
if (!hasPresident || !hasSecretary) {
|
||||
this.$message.warning({ title: "警告", message: "请填写协会理事机构中的会长和秘书长" })
|
||||
return
|
||||
}
|
||||
}
|
||||
/*let hz = this.$refs.clubManagerRef.managePerson.filter((o) => o.roleCode === CLUB_ROLE_CONSTANT.CLUB_PRESIDENT)
|
||||
if (hz.length !== 1) {
|
||||
this.$message.warning({ title: "警告", message: "会长需要1人" })
|
||||
@@ -149,7 +162,7 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
const resp = await this.$axios.post(url, {
|
||||
club: JSON.stringify(cloneData),
|
||||
managePerson: this.$refs.clubManagerRef.managePerson,
|
||||
managePerson: managePerson,
|
||||
deleteIds: JSON.stringify(this.deleteIds),
|
||||
taskId: GetQueryString("taskId")
|
||||
})
|
||||
|
||||
@@ -19,8 +19,8 @@ layout("/layouts/platform.html"){
|
||||
<el-option v-for="item in clubList" :label="item.clubName" :value="item.id" :key="item.id"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="人员状态:">
|
||||
<dict-select clearable code="USER_STATE" placeholder="请选择人员状态" v-model="pageForm.userState"></dict-select>
|
||||
<search-item label="在职状态:">
|
||||
<dict-select clearable code="USER_STATE" placeholder="请选择在职状态" v-model="pageForm.userState"></dict-select>
|
||||
</search-item>
|
||||
<search-item label="性别:">
|
||||
<el-select clearable filterable placeholder="请选择性别" v-model="pageForm.sex">
|
||||
|
||||
@@ -464,7 +464,7 @@ layout("/layouts/platform.html"){
|
||||
this.chartResizeObserver = new ResizeObserver(() => {
|
||||
this.handleChartResize()
|
||||
})
|
||||
;["memberPercentageChart", "memberSexPercentageChart"].forEach((containerId) => {
|
||||
;["memberPercentageChart", "memberSexPercentageChart", "personTypeMemberChart"].forEach((containerId) => {
|
||||
const container = document.getElementById(containerId)
|
||||
if (container) {
|
||||
this.chartResizeObserver.observe(container)
|
||||
@@ -768,9 +768,12 @@ layout("/layouts/platform.html"){
|
||||
|
||||
if (chart.personTypeMemberChart) {
|
||||
chart.personTypeMemberChart.changeData(data)
|
||||
this.handleChartResize()
|
||||
return
|
||||
}
|
||||
|
||||
// 首次进入页面时容器可能尚未完成布局,等待尺寸有效后再创建图表。
|
||||
this.waitChartContainerReady("personTypeMemberChart", () => {
|
||||
chart.personTypeMemberChart = new G2Plot.Column("personTypeMemberChart", {
|
||||
data,
|
||||
autoFit: true,
|
||||
@@ -854,6 +857,8 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
})
|
||||
chart.personTypeMemberChart.render()
|
||||
this.handleChartResize()
|
||||
})
|
||||
} else {
|
||||
this.$message.warning(resp.msg)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,8 @@ const welfareOption = {
|
||||
<div class="welfare-option">
|
||||
<el-card shadow="never">
|
||||
<el-table :data="welfareList" border style="width: 100%; margin-top: 20px;">
|
||||
<el-table-column align="center" header-align="center" label="福利名称">
|
||||
<!-- 通过最小宽度权重按 50% / 20% / 15% / 15% 分配列宽,避免福利名称列占用过多空间。 -->
|
||||
<el-table-column align="center" header-align="center" label="福利名称" min-width="500">
|
||||
<template slot-scope="{row}">
|
||||
<el-input
|
||||
v-model="row.optionName"
|
||||
@@ -12,7 +13,7 @@ const welfareOption = {
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" header-align="center" label="图片" width="200">
|
||||
<el-table-column align="center" header-align="center" label="图片" min-width="200">
|
||||
<template slot-scope="{row}">
|
||||
<file-upload :upload_number="1" :value.sync="row.imgUrl"
|
||||
accept=".jpg,.jpeg,.png"
|
||||
@@ -23,7 +24,7 @@ const welfareOption = {
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" header-align="center" label="说明" width="120">
|
||||
<el-table-column align="center" header-align="center" label="说明" min-width="150">
|
||||
<template slot-scope="{row, $index}">
|
||||
<el-button
|
||||
type="text"
|
||||
@@ -33,7 +34,7 @@ const welfareOption = {
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" header-align="center" label="操作" width="100">
|
||||
<el-table-column align="center" header-align="center" label="操作" min-width="150">
|
||||
<template slot-scope="{$index}">
|
||||
<el-button
|
||||
type="danger"
|
||||
|
||||
@@ -49,7 +49,7 @@ const optionSelect = {
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-label">发放地点</div>
|
||||
<div class="info-label">发放部门</div>
|
||||
<div class="info-value">{{ projectInfo.provideAddress }}</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -138,7 +138,7 @@ const optionSelect = {
|
||||
append-to-body
|
||||
custom-class="welfare-confirm-dialog">
|
||||
<div class="confirm-content">
|
||||
<!-- 联系电话输入 -->
|
||||
<!-- 手机号输入 -->
|
||||
<div class="confirm-mobile-section">
|
||||
<div class="confirm-section-title">联系信息</div>
|
||||
<el-form :model="contactForm" ref="contactForm" :rules="contactRules" label-width="80px">
|
||||
@@ -160,7 +160,7 @@ const optionSelect = {
|
||||
<el-col :span="4" v-if="projectInfo.provideMode == 3">
|
||||
<el-button @click="openAddress" type="primary" size="small">添加地址</el-button>
|
||||
</el-col>
|
||||
<el-col :span="24" v-if="projectInfo.provideMode == 3">
|
||||
<el-col :span="24">
|
||||
<el-form-item prop="userName" label="收货人">
|
||||
<el-input
|
||||
v-model="contactForm.userName"
|
||||
@@ -170,7 +170,7 @@ const optionSelect = {
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item prop="mobile" label="联系电话">
|
||||
<el-form-item prop="mobile" label="手机号">
|
||||
<el-input
|
||||
v-model="contactForm.mobile"
|
||||
placeholder="请输入手机号码"
|
||||
@@ -273,7 +273,7 @@ const optionSelect = {
|
||||
{required: true, message: "请输入收货人", trigger: "blur"}
|
||||
],
|
||||
mobile: [
|
||||
{required: true, message: "请输入联系电话", trigger: "blur"},
|
||||
{required: true, message: "请输入手机号", trigger: "blur"},
|
||||
{
|
||||
pattern: /^1[3456789]\d{9}$/,
|
||||
message: "请输入正确的手机号码",
|
||||
|
||||
@@ -71,7 +71,7 @@ layout("/layouts/platform_h5.html"){
|
||||
</van-form>
|
||||
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
|
||||
<van-button type="danger" block @click="handleTaskAction(6)">退回</van-button>
|
||||
<van-button type="danger" block @click="handleTaskAction(2)">不同意</van-button>
|
||||
<van-button type="danger" block @click="handleTaskAction(2)">拒绝</van-button>
|
||||
<van-button type="primary" block @click="handleTaskAction(1)">同意</van-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -71,7 +71,7 @@ layout("/layouts/platform_h5.html"){
|
||||
</van-form>
|
||||
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
|
||||
<van-button type="danger" block @click="handleTaskAction(6)">退回</van-button>
|
||||
<van-button type="danger" block @click="handleTaskAction(20)">不同意</van-button>
|
||||
<van-button type="danger" block @click="handleTaskAction(20)">拒绝</van-button>
|
||||
<van-button type="primary" block @click="handleTaskAction(1)">同意</van-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -603,7 +603,7 @@ layout("/layouts/platform_h5.html"){
|
||||
:value="formatTimeRange(projectInfo.choiceTimeStart, projectInfo.choiceTimeEnd)"></van-cell>
|
||||
<van-cell title="发放时间"
|
||||
:value="formatTimeRange(projectInfo.provideTimeStart, projectInfo.provideTimeEnd)"></van-cell>
|
||||
<van-cell title="发放地点" :value="projectInfo.provideAddress"></van-cell>
|
||||
<van-cell title="发放部门" :value="projectInfo.provideAddress"></van-cell>
|
||||
</div>
|
||||
</van-collapse-item>
|
||||
<!-- <van-cell title="发放方式" :value="getProvideModeName(projectInfo.provideMode)"></van-cell>-->
|
||||
@@ -719,7 +719,7 @@ layout("/layouts/platform_h5.html"){
|
||||
></van-field>
|
||||
<van-field
|
||||
v-model="formData.mobile"
|
||||
label="联系电话"
|
||||
label="手机号"
|
||||
placeholder="请输入手机号码"
|
||||
:error="mobileError"
|
||||
@focus="mobileError = false"
|
||||
|
||||
Reference in New Issue
Block a user