This commit is contained in:
=
2026-08-26 14:27:42 +08:00
parent 8d6a4d55c2
commit 35e65076b0
30 changed files with 278 additions and 49 deletions
@@ -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() {
@@ -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();
@@ -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);
@@ -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());
@@ -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);
@@ -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 {
@@ -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);
}
@@ -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("选择成功");
}
@@ -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("选择成功");
}
@@ -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);
}
@@ -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"