慰问、会员入会接入待办
This commit is contained in:
@@ -49,7 +49,9 @@ public class MemberAgendaController {
|
||||
final String title = "【会员系统】";
|
||||
|
||||
List<NutMap> list = new ArrayList<>();
|
||||
if (!ShiroUtil.hasAnyRoles("sysadmin,A06,gh01,H03")) {
|
||||
if (!ShiroUtil.hasAnyRoles("sysadmin,A06,gh01,H03")
|
||||
&& !org.apache.shiro.SecurityUtils.getSubject().isPermitted("member.apply.audit.union")
|
||||
&& !org.apache.shiro.SecurityUtils.getSubject().isPermitted("member.apply.audit.school")) {
|
||||
return list;
|
||||
}
|
||||
boolean anyRoles = ShiroUtil.hasAnyRoles("sysadmin,A06,H03");
|
||||
@@ -67,20 +69,26 @@ public class MemberAgendaController {
|
||||
|
||||
int marUnionNum = 0;
|
||||
Cnd marUnionCnd = Cnd.where("mar.stateId", "=", MemberApplyState.UNION);
|
||||
if (!anyRoles) {
|
||||
marUnionCnd.and("u.unionid", "=", Vi.getUnionId());
|
||||
// 入会审核范围与 PC 部门审核列表一致,校级角色不能自动越过部门权限。
|
||||
if (!ShiroUtil.hasAnyRoles("sysadmin")) {
|
||||
marUnionCnd.and("mar.unionId", "=", Vi.getUnionId());
|
||||
}
|
||||
marSql.setCondition(marUnionCnd);
|
||||
marUnionNum = memberService.count(marSql);
|
||||
list.add(new NutMap().addv("title", title).addv("iconClass", vi.getIconByPath("/platform/member/apply/audit/union")).addv("label", "待部门工会入会审核").addv("number", marUnionNum).addv("url", "/platform/member/apply/audit/union"));
|
||||
if (org.apache.shiro.SecurityUtils.getSubject().isPermitted("member.apply.audit.union"))
|
||||
list.add(new NutMap().addv("title", title).addv("iconClass", vi.getIconByPath("/platform/member/apply/audit/union")).addv("label", "待部门工会入会审核").addv("number", marUnionNum).addv("url", "/platform/member/apply/audit/union"));
|
||||
|
||||
int marSchoolNum = 0;
|
||||
Cnd marSchoolCnd = Cnd.where("mar.stateId", "=", MemberApplyState.SCHOOL_UNION);
|
||||
marSql.setCondition(marSchoolCnd);
|
||||
marSchoolNum = memberService.count(marSql);
|
||||
list.add(new NutMap().addv("title", title).addv("iconClass", vi.getIconByPath("/platform/member/apply/audit/school")).addv("label", "待校工会入会审核").addv("number", marSchoolNum).addv("url", "/platform/member/apply/audit/school"));
|
||||
if (org.apache.shiro.SecurityUtils.getSubject().isPermitted("member.apply.audit.school"))
|
||||
list.add(new NutMap().addv("title", title).addv("iconClass", vi.getIconByPath("/platform/member/apply/audit/school")).addv("label", "待校工会入会审核").addv("number", marSchoolNum).addv("url", "/platform/member/apply/audit/school"));
|
||||
|
||||
|
||||
// 非原会员变更管理角色仅返回按权限计算的入会待办。
|
||||
if (!ShiroUtil.hasAnyRoles("sysadmin,A06,gh01,H03")) return list;
|
||||
|
||||
// 会员变更
|
||||
Sql mcrSql = Sqls.create("""
|
||||
SELECT
|
||||
@@ -111,4 +119,24 @@ public class MemberAgendaController {
|
||||
List<Sys_menu> menus = Optional.ofNullable(user).orElse(new Sys_user()).getMenus();
|
||||
return list.stream().filter(v -> Strings.isNotBlank(v.getString("url")) && menus.stream().anyMatch(x -> Strings.isNotBlank(x.getHref()) && v.getString("url").contains(x.getHref()))).distinct().collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 无需参数,返回当前登录人今年可办理的入会审核节点。
|
||||
* 每项 title/name/count/mobileHref 分别表示业务标题、节点名称、待办数量和手机入口。
|
||||
*/
|
||||
@At
|
||||
@ViReturn
|
||||
public Object getMobileAgenda() {
|
||||
return memberService.getCurrentYearApplyAgenda();
|
||||
}
|
||||
|
||||
/**
|
||||
* 无需传入办理人,身份从登录会话获取;返回本人今年实际办理的会员入会记录。
|
||||
* 每项 moduleName/auditState/auditTime/mobileUrl 为业务名称、办理节点、办理时间和只读详情地址。
|
||||
*/
|
||||
@At
|
||||
@ViReturn
|
||||
public Object getCompletes() {
|
||||
return memberService.getCurrentYearApplyCompletes();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ import io.v.nutz.util.ShiroUtil;
|
||||
import org.apache.shiro.authz.annotation.RequiresAuthentication;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
@@ -130,6 +132,7 @@ public class MemberApplyAuditController {
|
||||
|
||||
@At
|
||||
@ViReturn
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Object doAudit(@ViRequired String recordId, Audit audit) {
|
||||
MemberApplyRecord record = memberApplyRecordViService.fetch(recordId);
|
||||
MemberApplyAuditHandle applyHandle = Enum.instance(MemberApplyAuditHandle.class, record.getStateId());
|
||||
|
||||
@@ -7,6 +7,7 @@ import io.v.nutz.diseaseaid.constant.AidFundMemberAuditState;
|
||||
import io.v.nutz.diseaseaid.mode.AidFundMemberMode;
|
||||
import io.v.nutz.diseaseaid.model.AidFundMemberAuditRecord;
|
||||
import io.v.nutz.member.UserMode;
|
||||
import io.v.nutz.member.service.MemberService;
|
||||
import io.v.nutz.member.constant.MemberApplyState;
|
||||
import io.v.nutz.member.constant.MemberOrigin;
|
||||
import io.v.nutz.member.model.MemberApplyRecord;
|
||||
@@ -25,6 +26,8 @@ import io.v.nutz.util.ShiroUtil;
|
||||
import io.v.nutz.util.ViResource;
|
||||
import io.v.nutz.web.commons.base.Globals;
|
||||
import lombok.Getter;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Chain;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
@@ -55,6 +58,7 @@ public enum MemberApplyAuditHandle {
|
||||
*/
|
||||
CREATE(null) {
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public MemberApplyRecord next(MemberApplyRecord record, Audit audit) {
|
||||
record.setUserId(ShiroUtil.getPrincipalProperty("id").toString());
|
||||
record.setStateId(MemberApplyState.UNION);
|
||||
@@ -64,22 +68,8 @@ public enum MemberApplyAuditHandle {
|
||||
Sys_user user = sysUserService.fetch(record.getUserId());
|
||||
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
su.loginname,
|
||||
su.username
|
||||
FROM
|
||||
sys_user_role sur
|
||||
LEFT JOIN sys_user su ON su.id = sur.userId
|
||||
WHERE
|
||||
sur.roleId = @roleId
|
||||
AND sur.unionid = @unionId
|
||||
""")
|
||||
// .setParam("roleId", Roles.UNION_MANGER)
|
||||
.setParam("roleId", Roles.GH01)
|
||||
.setParam("unionId", record.getUnionId());
|
||||
|
||||
List<NutMap> mapList = sysUserService.listMap(sql);
|
||||
// 接收人由 PC 部门审核权限关联的角色确定,并限定申请所属工会。
|
||||
List<NutMap> mapList = memberService.applyAuditRecipients(false, record.getUnionId());
|
||||
|
||||
if (Lang.isNotEmpty(mapList)) {
|
||||
List<TodoTask.Processor> processors = new ArrayList<>();
|
||||
@@ -102,6 +92,8 @@ public enum MemberApplyAuditHandle {
|
||||
todoTask.setInitiatorId(user.getLoginname());
|
||||
todoTask.setPcViewUrl(Globals.AppDomain + "/platform/member/apply/audit/union");
|
||||
todoTask.setH5ViewUrl(Globals.AppDomain + "/mobile/member/audit");
|
||||
todoTask.setDoneH5Url(Globals.AppDomain + "/mobile/member/audit?isAudit=true");
|
||||
todoTask.setDonePcUrl(todoTask.getPcViewUrl() + "?audit=1");
|
||||
todoTask.setBizId(insert.getId());
|
||||
todoTask.setBizType("申请入会部门工会审核");
|
||||
todoTask.setStatus(TodoTaskEnum.TaskStatus.ACTIVE.name());
|
||||
@@ -121,6 +113,7 @@ public enum MemberApplyAuditHandle {
|
||||
*/
|
||||
AUDIT_UNION(MemberApplyState.UNION) {
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public MemberApplyRecord next(MemberApplyRecord record, Audit audit) {
|
||||
|
||||
record.setStateId(audit.getAuditPass() ? MemberApplyState.SCHOOL_UNION : MemberApplyState.UNION_FAIL);
|
||||
@@ -130,18 +123,8 @@ public enum MemberApplyAuditHandle {
|
||||
|
||||
if (audit.getAuditPass()) {
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
su.loginname,
|
||||
su.username
|
||||
FROM
|
||||
sys_user_role sur
|
||||
LEFT JOIN sys_user su ON su.id = sur.userId
|
||||
WHERE
|
||||
sur.roleId = @roleId
|
||||
""").setParam("roleId", Roles.H03);
|
||||
|
||||
List<NutMap> mapList = sysUserService.listMap(sql);
|
||||
// 部门通过后仅向具有 PC 校工会审核权限的角色成员派发下一阶段待办。
|
||||
List<NutMap> mapList = memberService.applyAuditRecipients(true, record.getUnionId());
|
||||
|
||||
if (Lang.isNotEmpty(mapList)) {
|
||||
List<TodoTask.Processor> processors = new ArrayList<>();
|
||||
@@ -163,6 +146,8 @@ public enum MemberApplyAuditHandle {
|
||||
todoTask.setInitiatorId(user.getLoginname());
|
||||
todoTask.setPcViewUrl(Globals.AppDomain + "/platform/member/apply/audit/school");
|
||||
todoTask.setH5ViewUrl(Globals.AppDomain + "/mobile/member/audit");
|
||||
todoTask.setDoneH5Url(Globals.AppDomain + "/mobile/member/audit?isAudit=true");
|
||||
todoTask.setDonePcUrl(todoTask.getPcViewUrl() + "?audit=1");
|
||||
todoTask.setBizId(record.getId());
|
||||
todoTask.setBizType("申请入会校工会审核");
|
||||
todoTask.setStatus(TodoTaskEnum.TaskStatus.ACTIVE.name());
|
||||
@@ -178,14 +163,7 @@ public enum MemberApplyAuditHandle {
|
||||
List.of(Map.of("tool", MsgApi.sendTool.wechat_enterprise.name())));
|
||||
}
|
||||
|
||||
//部门工会的待办设置为完成
|
||||
TodoTask todoTask = dao.fetch(TodoTask.class, Cnd.where("bizId", "=", record.getId())
|
||||
.and("bizType", "=", "申请入会部门工会审核"));
|
||||
if (todoTask != null) {
|
||||
todoTask.setProcessorId(ShiroUtil.getPrincipalProperty("loginname").toString());
|
||||
todoTask.setStatus(TodoTaskEnum.TaskStatus.COMPLETE.name());
|
||||
todoTaskInterface.updateTask(todoTask);
|
||||
}
|
||||
memberService.completeApplyAuditTasks(record.getId(), false);
|
||||
return record;
|
||||
}
|
||||
},
|
||||
@@ -194,6 +172,7 @@ public enum MemberApplyAuditHandle {
|
||||
*/
|
||||
AUDIT_SCHOOL(MemberApplyState.SCHOOL_UNION) {
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public MemberApplyRecord next(MemberApplyRecord record, Audit audit) {
|
||||
|
||||
memberApplyRecordViService.transactional(() -> {
|
||||
@@ -242,14 +221,7 @@ public enum MemberApplyAuditHandle {
|
||||
List.of(Map.of("tool", MsgApi.sendTool.wechat_enterprise.name())));
|
||||
}
|
||||
|
||||
//校工会的待办设置为完成
|
||||
TodoTask todoTask = dao.fetch(TodoTask.class, Cnd.where("bizId", "=", record.getId())
|
||||
.and("bizType", "=", "申请入会校工会审核"));
|
||||
if (todoTask != null) {
|
||||
todoTask.setProcessorId(ShiroUtil.getPrincipalProperty("loginname").toString());
|
||||
todoTask.setStatus(TodoTaskEnum.TaskStatus.COMPLETE.name());
|
||||
todoTaskInterface.updateTask(todoTask);
|
||||
}
|
||||
memberService.completeApplyAuditTasks(record.getId(), true);
|
||||
});
|
||||
|
||||
sysUserService.deleteCache(record.getUserId());
|
||||
@@ -270,6 +242,7 @@ public enum MemberApplyAuditHandle {
|
||||
public TodoTaskInterface todoTaskInterface = ViResource.ioc.getByType(TodoTaskInterface.class);
|
||||
public MsgApi msgApi = ViResource.ioc.getByType(MsgApi.class);
|
||||
public Dao dao = ViResource.dao;
|
||||
public MemberService memberService = ViResource.ioc.getByType(MemberService.class);
|
||||
|
||||
public abstract MemberApplyRecord next(MemberApplyRecord record, Audit audit);
|
||||
|
||||
|
||||
@@ -34,4 +34,21 @@ public interface MemberService extends ViService<Sys_user> {
|
||||
* @return
|
||||
*/
|
||||
Pagination memberChangeRecords(PageForm pageForm, CndPlus cnd);
|
||||
/** 按当前用户 PC 审核权限查询手机列表;isAudit 为已审标记,year 可空,返回 list/totalCount 分页数据。 */
|
||||
Object mobileApplyAuditPage(int pageNumber, int pageSize, boolean isAudit, Integer year);
|
||||
|
||||
/** 按申请记录校验访问范围并返回审核/只读视图,userId 必须属于该记录,done 强制只读。 */
|
||||
String mobileApplyAuditView(String recordId, String userId, boolean done);
|
||||
|
||||
/** 查询拥有指定阶段审核权限的启用角色成员;部门阶段限定 unionId,返回 loginname/username。 */
|
||||
List<NutMap> applyAuditRecipients(boolean school, String unionId);
|
||||
|
||||
/** 关闭指定申请当前阶段的全部有效待办,保留接收人并记录实际办理人和已办地址。 */
|
||||
void completeApplyAuditTasks(String recordId, boolean school);
|
||||
|
||||
/** 返回当前年份入会待办卡片;身份取当前会话,部门限定本工会,超管可查看两级范围。 */
|
||||
List<NutMap> getCurrentYearApplyAgenda();
|
||||
|
||||
/** 返回当前登录人本年度实际审核的入会记录及只读详情地址,不把角色范围内的已审视作本人已办。 */
|
||||
List<NutMap> getCurrentYearApplyCompletes();
|
||||
}
|
||||
|
||||
@@ -15,6 +15,21 @@ import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.plugins.wkcache.annotation.CacheDefaults;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import io.v.nutz.base.utils.Vi;
|
||||
import io.v.nutz.member.constant.MemberApplyState;
|
||||
import io.v.nutz.member.model.MemberApplyRecord;
|
||||
import io.v.nutz.todoTask.TodoTask;
|
||||
import io.v.nutz.todoTask.TodoTaskInterface;
|
||||
import io.v.nutz.web.commons.base.Globals;
|
||||
import io.v.nutz.web.commons.utils.ShiroUtil;
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
import org.apache.shiro.authz.permission.WildcardPermission;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.lang.Strings;
|
||||
|
||||
|
||||
/**
|
||||
@@ -70,4 +85,151 @@ public class MemberServiceImpl extends ViServiceImpl<Sys_user> implements Member
|
||||
Sql sql = Sqls.create(MEMBER_CHANGE_RECORDS).setCondition(cnd);
|
||||
return list(pageForm, sql);
|
||||
}
|
||||
|
||||
@Inject
|
||||
private TodoTaskInterface todoTaskInterface;
|
||||
|
||||
/** 与 PC 页面的权限注解一致,不能用待办角色名称替代审核权限。 */
|
||||
private boolean canApplyAudit(boolean school) {
|
||||
return ShiroUtil.hasPermission("member.apply.audit." + (school ? "school" : "union"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object mobileApplyAuditPage(int pageNumber, int pageSize, boolean isAudit, Integer year) {
|
||||
boolean union = canApplyAudit(false);
|
||||
boolean school = canApplyAudit(true);
|
||||
if (!union && !school) throw new UnauthorizedException("无会员审核权限");
|
||||
Sql sql = Sqls.create("SELECT mar.*, st.stateName, st.stateColor, u.unionname, u.username, "
|
||||
+ "u.loginname, u.personType FROM member_apply_record mar "
|
||||
+ "LEFT JOIN audit_state st ON st.stateId=mar.stateId LEFT JOIN `user` u ON u.id=mar.userId $condition");
|
||||
SqlExpressionGroup scope = new SqlExpressionGroup();
|
||||
// 已审沿用 PC 各阶段 stateId > 当前阶段的口径;双权限取并集,避免重复记录。
|
||||
if (union && (ShiroUtil.hasRole("sysadmin") || Strings.isNotBlank(Vi.getUnionId()))) {
|
||||
Cnd department = Cnd.where("mar.stateId", isAudit ? ">" : "=", MemberApplyState.UNION);
|
||||
if (!ShiroUtil.hasRole("sysadmin")) department.and("mar.unionId", "=", Vi.getUnionId());
|
||||
scope.or(department.where());
|
||||
} else if (!school) {
|
||||
return listPageMap(Math.max(1, pageNumber), Math.max(1, pageSize), sql.setCondition(Cnd.where("1", "=", 0)));
|
||||
}
|
||||
if (school) scope.or("mar.stateId", isAudit ? ">" : "=", MemberApplyState.SCHOOL_UNION);
|
||||
CndPlus cnd = CndPlus.create();
|
||||
cnd.and(scope);
|
||||
cnd.andExcludeEmpty("YEAR(mar.applyTime)", "=", year);
|
||||
cnd.asc("mar.stateId").desc("mar.applyTime");
|
||||
return listPageMap(Math.max(1, pageNumber), Math.max(1, Math.min(pageSize, 100)), sql.setCondition(cnd));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mobileApplyAuditView(String recordId, String userId, boolean done) {
|
||||
MemberApplyRecord record = Strings.isBlank(recordId) ? null : dao().fetch(MemberApplyRecord.class, recordId);
|
||||
if (record == null || !Objects.equals(record.getUserId(), userId)) {
|
||||
throw new IllegalArgumentException("申请记录不存在或申请人不匹配");
|
||||
}
|
||||
boolean union = canApplyAudit(false) && (ShiroUtil.hasRole("sysadmin")
|
||||
|| Strings.isNotBlank(Vi.getUnionId()) && Objects.equals(Vi.getUnionId(), record.getUnionId()));
|
||||
boolean school = canApplyAudit(true) && record.getStateId() != null
|
||||
&& record.getStateId() >= MemberApplyState.SCHOOL_UNION;
|
||||
if (!union && !school) throw new UnauthorizedException("无权查看该申请");
|
||||
if (!done && union && Objects.equals(record.getStateId(), MemberApplyState.UNION)) {
|
||||
return "beetl:/mobile/member/union_Audit.html";
|
||||
}
|
||||
if (!done && school && Objects.equals(record.getStateId(), MemberApplyState.SCHOOL_UNION)) {
|
||||
return "beetl:/mobile/member/school_Audit.html";
|
||||
}
|
||||
return "beetl:/mobile/member/detail.html";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NutMap> applyAuditRecipients(boolean school, String unionId) {
|
||||
// 从 PC 权限对应的角色成员取接收人,兼容 Shiro 通配权限并排除禁用角色、菜单和账号。
|
||||
Sql sql = Sqls.create("SELECT DISTINCT su.loginname, su.username, sm.permission FROM sys_user_role sur "
|
||||
+ "JOIN sys_user su ON su.id=sur.userId JOIN sys_role sr ON sr.id=sur.roleId "
|
||||
+ "JOIN sys_role_menu srm ON srm.roleId=sr.id JOIN sys_menu sm ON sm.id=srm.menuId "
|
||||
+ "WHERE sr.disabled=false AND sm.disabled=false AND su.disabled=false "
|
||||
+ (school ? "" : "AND sur.unionid=@unionId AND su.unionid=@unionId "));
|
||||
sql.setParam("unionId", unionId);
|
||||
WildcardPermission required = new WildcardPermission("member.apply.audit." + (school ? "school" : "union"));
|
||||
java.util.Map<String, NutMap> recipients = new java.util.LinkedHashMap<>();
|
||||
for (NutMap row : listMap(sql)) {
|
||||
String permission = row.getString("permission");
|
||||
if (Strings.isNotBlank(permission) && Strings.isNotBlank(row.getString("loginname"))
|
||||
&& new WildcardPermission(permission).implies(required)) {
|
||||
recipients.putIfAbsent(row.getString("loginname"), row);
|
||||
}
|
||||
}
|
||||
return new java.util.ArrayList<>(recipients.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void completeApplyAuditTasks(String recordId, boolean school) {
|
||||
// 同阶段可能存在历史重复待办,只关闭 ACTIVE 项,保留接收角色成员列表用于已办归属。
|
||||
List<TodoTask> tasks = dao().query(TodoTask.class, Cnd.where("bizId", "=", recordId)
|
||||
.and("bizType", "=", school ? "申请入会校工会审核" : "申请入会部门工会审核")
|
||||
.and("status", "=", "ACTIVE").and(Cnd.exps("delFlag", "=", false).or("delFlag", "is", null)));
|
||||
for (TodoTask task : tasks) {
|
||||
task.setProcessorId(ShiroUtil.getPrincipalProperty("loginname").toString());
|
||||
task.setStatus("COMPLETE");
|
||||
task.setDonePcUrl(Globals.AppDomain + "/platform/member/apply/audit/" + (school ? "school" : "union") + "?audit=1");
|
||||
task.setDoneH5Url(Globals.AppDomain + "/mobile/member/audit?isAudit=true");
|
||||
todoTaskInterface.updateTask(task);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NutMap> getCurrentYearApplyAgenda() {
|
||||
int year = java.time.LocalDate.now().getYear();
|
||||
boolean admin = ShiroUtil.hasRole("sysadmin");
|
||||
List<NutMap> items = new java.util.ArrayList<>();
|
||||
for (boolean school : new boolean[]{false, true}) {
|
||||
if (!admin && !canApplyAudit(school)) continue;
|
||||
// 没有工会归属的部门审核人不能因空条件而获得全校范围。
|
||||
if (!school && !admin && Strings.isBlank(Vi.getUnionId())) continue;
|
||||
Cnd cnd = Cnd.where("stateId", "=", school ? MemberApplyState.SCHOOL_UNION : MemberApplyState.UNION)
|
||||
.and("applyTime", ">=", year + "-01-01")
|
||||
.and("applyTime", "<", (year + 1) + "-01-01");
|
||||
if (!school && !admin) cnd.and("unionId", "=", Vi.getUnionId());
|
||||
int count = dao().count(MemberApplyRecord.class, cnd);
|
||||
items.add(new NutMap().setv("title", "【会员入会】")
|
||||
.setv("name", school ? "待校工会入会审核" : "待部门工会入会审核")
|
||||
.setv("count", count).setv("mobileHref", "/mobile/member/audit"));
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NutMap> getCurrentYearApplyCompletes() {
|
||||
Object principalLoginname = ShiroUtil.getPrincipalProperty("loginname");
|
||||
String loginname = principalLoginname == null ? "" : principalLoginname.toString();
|
||||
boolean admin = ShiroUtil.hasRole("sysadmin");
|
||||
boolean union = admin || canApplyAudit(false);
|
||||
boolean school = admin || canApplyAudit(true);
|
||||
if (Strings.isBlank(loginname) || !union && !school) return java.util.Collections.emptyList();
|
||||
int year = java.time.LocalDate.now().getYear();
|
||||
// 只读取当前申请实际关联的审核记录,按办理工号和办理年份筛选;同人办理两级保留两个节点。
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT mar.id, a.id auditId, nodes.nodeId,
|
||||
CONCAT('【会员入会】', COALESCE(u.username, '')) moduleName,
|
||||
nodes.nodeName auditState, a.auditTime,
|
||||
CONCAT('/mobile/member/audit/findOne?record_id=', mar.id,
|
||||
'&user_id=', mar.userId, '&done=true') mobileUrl
|
||||
FROM member_apply_record mar
|
||||
LEFT JOIN `user` u ON u.id=mar.userId
|
||||
JOIN (SELECT 1 nodeId, '部门工会审核' nodeName
|
||||
UNION ALL SELECT 2, '校工会审核') nodes ON 1=1
|
||||
JOIN audit a ON a.id=CASE nodes.nodeId WHEN 1 THEN mar.unionAuditId ELSE mar.schoolAuditId END
|
||||
WHERE a.loginname=@loginname AND a.auditTime>=@startTime AND a.auditTime<@endTime
|
||||
AND ((nodes.nodeId=1 AND @unionAllowed=1 AND (@admin=1 OR mar.unionId=@unionId))
|
||||
OR (nodes.nodeId=2 AND @schoolAllowed=1))
|
||||
ORDER BY a.auditTime DESC, mar.id, nodes.nodeId
|
||||
""");
|
||||
sql.setParam("loginname", loginname);
|
||||
sql.setParam("startTime", year + "-01-01");
|
||||
sql.setParam("endTime", (year + 1) + "-01-01");
|
||||
sql.setParam("unionAllowed", union ? 1 : 0);
|
||||
sql.setParam("schoolAllowed", school ? 1 : 0);
|
||||
sql.setParam("admin", admin ? 1 : 0);
|
||||
sql.setParam("unionId", Strings.sNull(Vi.getUnionId()));
|
||||
return listMap(sql);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,112 +1,47 @@
|
||||
package io.v.nutz.mobile.member;
|
||||
|
||||
import cn.wizzer.framework.base.service.BaseService;
|
||||
import io.v.nutz.annontation.ViReturn;
|
||||
import io.v.nutz.base.utils.Vi;
|
||||
import io.v.nutz.dao.CndPlus;
|
||||
import io.v.nutz.member.constant.MemberApplyState;
|
||||
import io.v.nutz.util.ShiroUtil;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import io.v.nutz.member.service.MemberService;
|
||||
import org.apache.shiro.authz.annotation.RequiresAuthentication;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.apache.shiro.authz.annotation.Logical;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Lang;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
|
||||
/**
|
||||
* @author zhf
|
||||
* @date 2021/9/26 9:24
|
||||
* @description
|
||||
*/
|
||||
/** 手机端会员审核统一入口,与 PC 端共享两级审核权限。 */
|
||||
@IocBean
|
||||
@At("/mobile/member/audit")
|
||||
@Ok("json:full")
|
||||
@RequiresAuthentication
|
||||
@RequiresPermissions(value = {"member.apply.audit.union", "member.apply.audit.school"}, logical = Logical.OR)
|
||||
public class MemberAuditUnionController {
|
||||
@Inject
|
||||
private MemberService memberService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/mobile/member/audit_list.html")
|
||||
public void indext() {
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@Inject
|
||||
private BaseService baseService;
|
||||
|
||||
|
||||
/**
|
||||
* pageNumber/pageSize 为页码和每页条数,isAudit 区分已审/待审,year 为申请年份(可空)。
|
||||
* 返回分页对象,list 为申请记录,totalCount 为符合当前审核权限的数据总数。
|
||||
*/
|
||||
@At
|
||||
@ViReturn
|
||||
public Object pageData(int pageNumber, int pageSize, boolean isAudit, Integer year) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
mar.*,
|
||||
st.stateName,
|
||||
st.stateColor,
|
||||
u.unionname,
|
||||
u.username,
|
||||
u.loginname,
|
||||
u.personType
|
||||
FROM
|
||||
`member_apply_record` mar
|
||||
LEFT JOIN audit_state st ON st.stateId = mar.stateId
|
||||
LEFT JOIN `user` u ON u.id = mar.userId
|
||||
$condition
|
||||
""");
|
||||
|
||||
CndPlus cnd = CndPlus.create();
|
||||
cnd.and("mar.memberStates", "=", 1);
|
||||
|
||||
if (ShiroUtil.hasAnyRoles("sysadmin")) {
|
||||
cnd.and("mar.stateId", "in", isAudit ? Lang.array(MemberApplyState.UNION_FAIL, MemberApplyState.SCHOOL_UNION_FAIL, MemberApplyState.NORMAL_MEMBER) : Lang.array(MemberApplyState.UNION, MemberApplyState.SCHOOL_UNION));
|
||||
} else {
|
||||
if (ShiroUtil.hasAnyRoles("A06,wyh02") && ShiroUtil.hasAnyRoles("H04")) {
|
||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||
seg.or("mar.stateId", isAudit ? ">" : "=", MemberApplyState.SCHOOL_UNION);
|
||||
seg.or(CndPlus.exps("mar.unionId", "=", Vi.getUnionId()).and("mar.stateId", isAudit ? ">" : "=", MemberApplyState.UNION));
|
||||
cnd.and(seg);
|
||||
} else if (ShiroUtil.hasAnyRoles("A06,wyh02")) {
|
||||
cnd.and("mar.stateId", isAudit ? ">" : "=", MemberApplyState.SCHOOL_UNION);
|
||||
} else if (ShiroUtil.hasAnyRoles("H04")) {
|
||||
cnd.and("mar.unionId", "=", Vi.getUnionId());
|
||||
cnd.and("mar.stateId", isAudit ? ">" : "=", MemberApplyState.UNION);
|
||||
}
|
||||
|
||||
|
||||
/*if (ShiroUtil.hasAnyRoles("A06,wyh02")) {
|
||||
cnd.and("mar.stateId", isAudit ? ">" : "=", MemberApplyState.SCHOOL_UNION);
|
||||
} else if (ShiroUtil.hasAnyRoles("H04")) {
|
||||
cnd.and("mar.unionId", "=", Vi.getUnionId());
|
||||
cnd.and("mar.stateId", isAudit ? ">" : "=", MemberApplyState.UNION);
|
||||
}*/
|
||||
}
|
||||
|
||||
/* if (!ShiroUtil.hasAnyRoles("sysadmin")) {
|
||||
if (ShiroUtil.hasAnyRoles("A06,wyh02")) {
|
||||
cnd.and("mar.stateId", isAudit ? ">" : "=", MemberApplyState.SCHOOL_UNION);
|
||||
}
|
||||
}*/
|
||||
|
||||
cnd.andExcludeEmpty("YEAR(mar.applyTime)", "=", year);
|
||||
|
||||
cnd.asc("mar.stateId");
|
||||
cnd.desc("mar.applyTime");
|
||||
sql.setCondition(cnd);
|
||||
return baseService.listPageMap(pageNumber, pageSize, sql);
|
||||
return memberService.mobileApplyAuditPage(pageNumber, pageSize, isAudit, year);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* record_id 为申请记录 ID,user_id 为申请人 ID,done 表示从已办入口只读查看。
|
||||
* 返回 Beetl 页面视图;实际审核阶段和访问范围均由数据库记录决定。
|
||||
*/
|
||||
@At("/findOne")
|
||||
@Ok("re")
|
||||
public String findOne(Integer stateId) {
|
||||
if (stateId == MemberApplyState.UNION && ShiroUtil.hasAnyRoles("H04,A06,sysadmin")) {
|
||||
return "beetl:/mobile/member/union_Audit.html";
|
||||
} else if (stateId == MemberApplyState.SCHOOL_UNION && ShiroUtil.hasAnyRoles("A06,sysadmin")) {
|
||||
return "beetl:/mobile/member/school_Audit.html";
|
||||
} /*else if (stateId == MemberApplyState.NORMAL_MEMBER || stateId == MemberApplyState.UNION_FAIL || stateId == MemberApplyState.SCHOOL_UNION_FAIL) {
|
||||
return "beetl:/mobile/member/detail.html";
|
||||
}*/
|
||||
return "beetl:/mobile/member/detail.html";
|
||||
public String findOne(String record_id, String user_id, boolean done) {
|
||||
return memberService.mobileApplyAuditView(record_id, user_id, done);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -12,13 +12,11 @@ import io.v.nutz.sys.models.Sys_menu;
|
||||
import io.v.nutz.sys.models.Sys_user;
|
||||
import io.v.nutz.util.ShiroUtil;
|
||||
import io.v.nutz.zgfw.service.CondolenceService;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Strings;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.apache.shiro.authz.annotation.RequiresAuthentication;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
|
||||
@@ -53,71 +51,24 @@ public class CondolenceAgentController {
|
||||
|
||||
List<NutMap> result = new ArrayList<>();
|
||||
|
||||
result.add(new NutMap().setv("title", title).setv("url", UCR).setv("iconClass", vi.getIconByPath(UCR)).setv("label", "待部门工会审核").setv("number", getUcrCount()));
|
||||
result.add(new NutMap().setv("title", title).setv("url", FR).setv("iconClass", vi.getIconByPath(FR)).setv("label", "待二级党组织审核").setv("number", getFrCount()));
|
||||
result.add(new NutMap().setv("title", title).setv("url", VCR).setv("iconClass", vi.getIconByPath(VCR)).setv("label", "待校工会审核").setv("number", getVcrCount()));
|
||||
result.add(new NutMap().setv("title", title).setv("url", ECR).setv("iconClass", vi.getIconByPath(ECR)).setv("label", "待工会常务副主席审核").setv("number", getEcrCount()));
|
||||
result.add(new NutMap().setv("title", title).setv("url", UCR).setv("iconClass", vi.getIconByPath(UCR)).setv("label", "待部门工会审核").setv("number", condolenceService.countCurrentYearAgenda(2000)));
|
||||
result.add(new NutMap().setv("title", title).setv("url", FR).setv("iconClass", vi.getIconByPath(FR)).setv("label", "待二级党组织审核").setv("number", condolenceService.countCurrentYearAgenda(2012)));
|
||||
result.add(new NutMap().setv("title", title).setv("url", VCR).setv("iconClass", vi.getIconByPath(VCR)).setv("label", "待校工会审核").setv("number", condolenceService.countCurrentYearAgenda(2020)));
|
||||
result.add(new NutMap().setv("title", title).setv("url", ECR).setv("iconClass", vi.getIconByPath(ECR)).setv("label", "待工会常务副主席审核").setv("number", condolenceService.countCurrentYearAgenda(2050)));
|
||||
Sys_user user = (Sys_user) ShiroUtil.getPrincipal();
|
||||
List<Sys_menu> menus = Optional.ofNullable(user).orElse(new Sys_user()).getMenus();
|
||||
return result.stream().filter(v -> Strings.isNotBlank(v.getString("url")) && menus.stream().anyMatch(x -> Strings.isNotBlank(x.getHref()) && v.getString("url").equals(x.getHref()))).distinct().collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 待工会主席审核
|
||||
*
|
||||
* @return
|
||||
* 无需传参,身份取自登录会话,返回今年本人办理的慰问记录列表。
|
||||
* 每项包含 moduleName(业务名称)、auditState(办理节点)、auditTime(审核日期)、mobileUrl(详情链接)。
|
||||
*/
|
||||
private Integer getUcrCount() {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT COUNT(1) FROM condolence con LEFT JOIN `user` us ON con.be_user=us.id $condition
|
||||
""");
|
||||
cnd.and("con.state_id", "=", 2000);
|
||||
if (!ShiroUtil.hasAnyRoles("sysadmin,A06")) {
|
||||
cnd.and("us.unionid", "=", vi.getUnionId());
|
||||
}
|
||||
sql.setCondition(cnd);
|
||||
return condolenceService.count(sql);
|
||||
@At
|
||||
@ViReturn
|
||||
@RequiresAuthentication
|
||||
public Object getCompletes() {
|
||||
return condolenceService.getCurrentYearCompletes();
|
||||
}
|
||||
|
||||
/**
|
||||
* 待工会会计审核
|
||||
* 暂时没用
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private Integer getFrCount() {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT COUNT(1) FROM condolence con LEFT JOIN `user` us ON con.be_user=us.id $condition
|
||||
""");
|
||||
cnd.and("con.state_id", "=", 2012);
|
||||
if (!ShiroUtil.hasAnyRoles("sysadmin,A06")) {
|
||||
cnd.and("us.unionid", "=", vi.getUnionId());
|
||||
}
|
||||
sql.setCondition(cnd);
|
||||
return condolenceService.count(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* 待校工会主席审核
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private Integer getVcrCount() {
|
||||
return condolenceService.count(Cnd.where("state_id", "=", 2020));
|
||||
}
|
||||
|
||||
/**
|
||||
* 待工会常务副主席审核
|
||||
* 暂时没用
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private Integer getEcrCount() {
|
||||
return condolenceService.count(Cnd.where("state_id", "=", 2050));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import io.v.nutz.service.ViService;
|
||||
import io.v.nutz.zgfw.model.condolence.Condolence;
|
||||
import org.nutz.dao.entity.Record;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
@@ -19,6 +20,20 @@ public interface CondolenceService extends ViService<Condolence> {
|
||||
*/
|
||||
NutMap findOne(String id);
|
||||
|
||||
/**
|
||||
* 无参数;按当前会话工号及本自然年审核日期查询本人慰问已办。
|
||||
* @return 列表项包含 id、reviewId、moduleName、auditState、auditTime、mobileUrl;按审核日期倒序
|
||||
*/
|
||||
List<NutMap> getCurrentYearCompletes();
|
||||
|
||||
/**
|
||||
* 统计当前登录用户可见范围内、申请时间属于当前自然年的慰问待办数量。
|
||||
*
|
||||
* @param stateId 审核状态:2000 部门工会、2012 二级党组织、2020 校工会、2050 历史常务副主席待办
|
||||
* @return 待办数量(Integer);不支持的状态返回 0,权限菜单过滤仍由待办接口保留
|
||||
*/
|
||||
Integer countCurrentYearAgenda(int stateId);
|
||||
|
||||
/**
|
||||
* 判断被慰问人在当前自然年是否已有住院慰问申请。
|
||||
*
|
||||
|
||||
@@ -3,6 +3,8 @@ package io.v.nutz.zgfw.service.impl;
|
||||
|
||||
import cn.wizzer.framework.base.service.BaseService;
|
||||
import io.v.nutz.base.utils.DateUtil;
|
||||
import io.v.nutz.base.utils.Vi;
|
||||
import io.v.nutz.util.ShiroUtil;
|
||||
import io.v.nutz.modules.services.ReviewService;
|
||||
import io.v.nutz.service.impl.ViServiceImpl;
|
||||
import io.v.nutz.zgfw.model.condolence.Condolence;
|
||||
@@ -19,6 +21,8 @@ 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 java.util.List;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* @author 1V
|
||||
@@ -37,6 +41,78 @@ public class CondolenceServiceImpl extends ViServiceImpl<Condolence> implements
|
||||
this.condolenceDao = dao;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按审核状态统计本自然年申请,保留原待办对部门工会、二级党组织节点的工会范围限制。
|
||||
*
|
||||
* @param stateId 2000、2012、2020 或 2050;其他值不属于本接口的待办节点
|
||||
* @return 当前节点的待办条数,不包含往年或下一年度申请
|
||||
*/
|
||||
/**
|
||||
* 按审核记录的办理人工号及办理年份筛选,不将申请当前状态误作个人审核结果。
|
||||
* @return 本人今年的已办列表;未获得登录工号时返回空列表,禁止扩大到全员记录
|
||||
*/
|
||||
@Override
|
||||
public List<NutMap> getCurrentYearCompletes() {
|
||||
Object principalLoginname = ShiroUtil.getPrincipalProperty("loginname");
|
||||
String loginname = principalLoginname == null ? "" : principalLoginname.toString();
|
||||
if (Strings.isBlank(loginname)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
int year = DateUtil.getYear();
|
||||
// 只读取申请当前关联的审核记录;再次审核覆盖的旧关联无法在此恢复。
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT con.id, r.id reviewId,
|
||||
CONCAT('【职工慰问】', COALESCE(con.be_user_username, '')) moduleName,
|
||||
nodes.nodeName auditState, r.time auditTime,
|
||||
CONCAT('/mobile/condolence/apply/info?id=', con.id) mobileUrl
|
||||
FROM condolence con
|
||||
JOIN (
|
||||
SELECT 1 nodeId, '部门工会审核' nodeName
|
||||
UNION ALL SELECT 2, '二级党组织审核'
|
||||
UNION ALL SELECT 3, '校工会审核'
|
||||
UNION ALL SELECT 4, '工会常务副主席审核'
|
||||
) nodes ON 1=1
|
||||
JOIN review r ON r.id = CASE nodes.nodeId
|
||||
WHEN 1 THEN con.union_chairman_review
|
||||
WHEN 2 THEN con.finance_review
|
||||
WHEN 3 THEN con.vice_chairman_review
|
||||
WHEN 4 THEN con.executive_chairman_review END
|
||||
WHERE r.loginname = @loginname AND r.time >= @startTime AND r.time < @endTime
|
||||
ORDER BY r.time DESC, con.id, nodes.nodeId
|
||||
""");
|
||||
sql.setParam("loginname", loginname);
|
||||
sql.setParam("startTime", year + "-01-01");
|
||||
sql.setParam("endTime", (year + 1) + "-01-01");
|
||||
return listMap(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer countCurrentYearAgenda(int stateId) {
|
||||
if (stateId != 2000 && stateId != 2012 && stateId != 2020 && stateId != 2050) {
|
||||
return 0;
|
||||
}
|
||||
// 年份只读取一次;左闭右开范围包含年初当天及年末全部时间,跨年后自动切换。
|
||||
int year = DateUtil.getYear();
|
||||
if (stateId == 2000 || stateId == 2012) {
|
||||
Cnd cnd = Cnd.where("con.state_id", "=", stateId)
|
||||
.and("con.apply_time", ">=", year + "-01-01")
|
||||
.and("con.apply_time", "<", (year + 1) + "-01-01");
|
||||
// 沿用原待办的角色判断:系统管理员和校工会管理员不限制所属工会。
|
||||
if (!ShiroUtil.hasAnyRoles("sysadmin,A06")) {
|
||||
cnd.and("us.unionid", "=", Vi.getUnionId());
|
||||
}
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT COUNT(1) FROM condolence con LEFT JOIN `user` us ON con.be_user=us.id $condition
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
return count(sql);
|
||||
}
|
||||
// 校级节点保留原有全校统计范围,仅追加申请年份条件。
|
||||
return count(Cnd.where("state_id", "=", stateId)
|
||||
.and("apply_time", ">=", year + "-01-01")
|
||||
.and("apply_time", "<", (year + 1) + "-01-01"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasHospitalCondolenceInCurrentYear(Condolence application) {
|
||||
CondolenceType type = condolenceDao.fetch(CondolenceType.class, application.getType());
|
||||
@@ -110,6 +186,14 @@ public class CondolenceServiceImpl extends ViServiceImpl<Condolence> implements
|
||||
if (Strings.isNotBlank(record.getString("union_chairman_review"))) {
|
||||
record.put("ucr", reviewService.fetch(record.getString("union_chairman_review")));
|
||||
}
|
||||
// 二级党组织审核沿用 finance_review 字段,详情以 fr 返回审核人、时间、意见和签字。
|
||||
if (Strings.isNotBlank(record.getString("finance_review"))) {
|
||||
record.put("fr", reviewService.fetch(record.getString("finance_review")));
|
||||
}
|
||||
// 历史常务副主席审核记录仅用于展示,不改变当前审批流转。
|
||||
if (Strings.isNotBlank(record.getString("executive_chairman_review"))) {
|
||||
record.put("ecr", reviewService.fetch(record.getString("executive_chairman_review")));
|
||||
}
|
||||
//校工会
|
||||
if (Strings.isNotBlank(record.getString("vice_chairman_review"))) {
|
||||
record.put("vcr", reviewService.fetch(record.getString("vice_chairman_review")));
|
||||
|
||||
Reference in New Issue
Block a user