Author SHA1 Message Date
c-chenxs1 ac3e08fe5d feat: 优化品牌活动报名失败 2026-11-05 21:07:04 +08:00
c-chenxs1 f4bbb379c3 feat: 清除.idea 2026-11-05 20:42:31 +08:00
c-chenxs1 a01ebd7d3e feat: 清除target 2026-11-05 20:40:25 +08:00
26 changed files with 335 additions and 699 deletions
+27 -4
View File
@@ -1,5 +1,28 @@
# Maven build output is generated locally and must not be versioned. # Maven build output
/target/ target/
*.class
# IDEA workspace settings belong to the local developer environment. # IDE settings
/.idea/workspace.xml .idea/
*.iml
*.ipr
*.iws
.vscode/
.classpath
.project
.settings/
target
# Logs and temporary files
*.log
/logs/
/temp/
/tmp/
*.tmp
*.swp
*.swo
*~
# Operating system files
.DS_Store
Thumbs.db
Desktop.ini
-14
View File
@@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile default="true" name="Default" enabled="true" />
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="mini" />
</profile>
</annotationProcessing>
</component>
</project>
-7
View File
@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>
-30
View File
@@ -1,30 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="nutz-snapshots" />
<option name="name" value="nutz-snapshots" />
<option name="url" value="https://maven.aliyun.com/repository/public" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://maven.aliyun.com/repository/public" />
</remote-repository>
<remote-repository>
<option name="id" value="nutz" />
<option name="name" value="nutz" />
<option name="url" value="https://maven.aliyun.com/repository/public" />
</remote-repository>
</component>
</project>
-25
View File
@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_15" default="true" project-jdk-name="15" project-jdk-type="JavaSDK" />
<component name="SvnBranchConfigurationManager">
<option name="myConfigurationMap">
<map>
<entry key="$PROJECT_DIR$">
<value>
<SvnBranchConfiguration>
<option name="trunkUrl" value="http://28bq156916.qicp.vip/svn/UNION_NJUST" />
</SvnBranchConfiguration>
</value>
</entry>
</map>
</option>
</component>
</project>
-10
View File
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="com.android.tools.idea.compose.preview.runconfiguration.ComposePreviewRunConfigurationProducer" />
</set>
</option>
</component>
</project>
Generated
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
@@ -49,9 +49,7 @@ public class MemberAgendaController {
final String title = "【会员系统】"; final String title = "【会员系统】";
List<NutMap> list = new ArrayList<>(); 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; return list;
} }
boolean anyRoles = ShiroUtil.hasAnyRoles("sysadmin,A06,H03"); boolean anyRoles = ShiroUtil.hasAnyRoles("sysadmin,A06,H03");
@@ -69,26 +67,20 @@ public class MemberAgendaController {
int marUnionNum = 0; int marUnionNum = 0;
Cnd marUnionCnd = Cnd.where("mar.stateId", "=", MemberApplyState.UNION); Cnd marUnionCnd = Cnd.where("mar.stateId", "=", MemberApplyState.UNION);
// 入会审核范围与 PC 部门审核列表一致,校级角色不能自动越过部门权限。 if (!anyRoles) {
if (!ShiroUtil.hasAnyRoles("sysadmin")) { marUnionCnd.and("u.unionid", "=", Vi.getUnionId());
marUnionCnd.and("mar.unionId", "=", Vi.getUnionId());
} }
marSql.setCondition(marUnionCnd); marSql.setCondition(marUnionCnd);
marUnionNum = memberService.count(marSql); marUnionNum = memberService.count(marSql);
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"));
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; int marSchoolNum = 0;
Cnd marSchoolCnd = Cnd.where("mar.stateId", "=", MemberApplyState.SCHOOL_UNION); Cnd marSchoolCnd = Cnd.where("mar.stateId", "=", MemberApplyState.SCHOOL_UNION);
marSql.setCondition(marSchoolCnd); marSql.setCondition(marSchoolCnd);
marSchoolNum = memberService.count(marSql); marSchoolNum = memberService.count(marSql);
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"));
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(""" Sql mcrSql = Sqls.create("""
SELECT SELECT
@@ -119,24 +111,4 @@ public class MemberAgendaController {
List<Sys_menu> menus = Optional.ofNullable(user).orElse(new Sys_user()).getMenus(); 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()); 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,8 +15,6 @@ import io.v.nutz.util.ShiroUtil;
import org.apache.shiro.authz.annotation.RequiresAuthentication; import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.nutz.dao.Sqls; 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.dao.sql.Sql;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
@@ -132,7 +130,6 @@ public class MemberApplyAuditController {
@At @At
@ViReturn @ViReturn
@Aop(TransAop.READ_COMMITTED)
public Object doAudit(@ViRequired String recordId, Audit audit) { public Object doAudit(@ViRequired String recordId, Audit audit) {
MemberApplyRecord record = memberApplyRecordViService.fetch(recordId); MemberApplyRecord record = memberApplyRecordViService.fetch(recordId);
MemberApplyAuditHandle applyHandle = Enum.instance(MemberApplyAuditHandle.class, record.getStateId()); MemberApplyAuditHandle applyHandle = Enum.instance(MemberApplyAuditHandle.class, record.getStateId());
@@ -7,7 +7,6 @@ import io.v.nutz.diseaseaid.constant.AidFundMemberAuditState;
import io.v.nutz.diseaseaid.mode.AidFundMemberMode; import io.v.nutz.diseaseaid.mode.AidFundMemberMode;
import io.v.nutz.diseaseaid.model.AidFundMemberAuditRecord; import io.v.nutz.diseaseaid.model.AidFundMemberAuditRecord;
import io.v.nutz.member.UserMode; 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.MemberApplyState;
import io.v.nutz.member.constant.MemberOrigin; import io.v.nutz.member.constant.MemberOrigin;
import io.v.nutz.member.model.MemberApplyRecord; import io.v.nutz.member.model.MemberApplyRecord;
@@ -26,8 +25,6 @@ import io.v.nutz.util.ShiroUtil;
import io.v.nutz.util.ViResource; import io.v.nutz.util.ViResource;
import io.v.nutz.web.commons.base.Globals; import io.v.nutz.web.commons.base.Globals;
import lombok.Getter; 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.Chain;
import org.nutz.dao.Cnd; import org.nutz.dao.Cnd;
import org.nutz.dao.Dao; import org.nutz.dao.Dao;
@@ -58,7 +55,6 @@ public enum MemberApplyAuditHandle {
*/ */
CREATE(null) { CREATE(null) {
@Override @Override
@Aop(TransAop.READ_COMMITTED)
public MemberApplyRecord next(MemberApplyRecord record, Audit audit) { public MemberApplyRecord next(MemberApplyRecord record, Audit audit) {
record.setUserId(ShiroUtil.getPrincipalProperty("id").toString()); record.setUserId(ShiroUtil.getPrincipalProperty("id").toString());
record.setStateId(MemberApplyState.UNION); record.setStateId(MemberApplyState.UNION);
@@ -68,8 +64,22 @@ public enum MemberApplyAuditHandle {
Sys_user user = sysUserService.fetch(record.getUserId()); Sys_user user = sysUserService.fetch(record.getUserId());
// 接收人由 PC 部门审核权限关联的角色确定,并限定申请所属工会。 Sql sql = Sqls.create("""
List<NutMap> mapList = memberService.applyAuditRecipients(false, record.getUnionId()); 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);
if (Lang.isNotEmpty(mapList)) { if (Lang.isNotEmpty(mapList)) {
List<TodoTask.Processor> processors = new ArrayList<>(); List<TodoTask.Processor> processors = new ArrayList<>();
@@ -92,8 +102,6 @@ public enum MemberApplyAuditHandle {
todoTask.setInitiatorId(user.getLoginname()); todoTask.setInitiatorId(user.getLoginname());
todoTask.setPcViewUrl(Globals.AppDomain + "/platform/member/apply/audit/union"); todoTask.setPcViewUrl(Globals.AppDomain + "/platform/member/apply/audit/union");
todoTask.setH5ViewUrl(Globals.AppDomain + "/mobile/member/audit"); 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.setBizId(insert.getId());
todoTask.setBizType("申请入会部门工会审核"); todoTask.setBizType("申请入会部门工会审核");
todoTask.setStatus(TodoTaskEnum.TaskStatus.ACTIVE.name()); todoTask.setStatus(TodoTaskEnum.TaskStatus.ACTIVE.name());
@@ -113,7 +121,6 @@ public enum MemberApplyAuditHandle {
*/ */
AUDIT_UNION(MemberApplyState.UNION) { AUDIT_UNION(MemberApplyState.UNION) {
@Override @Override
@Aop(TransAop.READ_COMMITTED)
public MemberApplyRecord next(MemberApplyRecord record, Audit audit) { public MemberApplyRecord next(MemberApplyRecord record, Audit audit) {
record.setStateId(audit.getAuditPass() ? MemberApplyState.SCHOOL_UNION : MemberApplyState.UNION_FAIL); record.setStateId(audit.getAuditPass() ? MemberApplyState.SCHOOL_UNION : MemberApplyState.UNION_FAIL);
@@ -123,8 +130,18 @@ public enum MemberApplyAuditHandle {
if (audit.getAuditPass()) { if (audit.getAuditPass()) {
// 部门通过后仅向具有 PC 校工会审核权限的角色成员派发下一阶段待办。 Sql sql = Sqls.create("""
List<NutMap> mapList = memberService.applyAuditRecipients(true, record.getUnionId()); 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);
if (Lang.isNotEmpty(mapList)) { if (Lang.isNotEmpty(mapList)) {
List<TodoTask.Processor> processors = new ArrayList<>(); List<TodoTask.Processor> processors = new ArrayList<>();
@@ -146,8 +163,6 @@ public enum MemberApplyAuditHandle {
todoTask.setInitiatorId(user.getLoginname()); todoTask.setInitiatorId(user.getLoginname());
todoTask.setPcViewUrl(Globals.AppDomain + "/platform/member/apply/audit/school"); todoTask.setPcViewUrl(Globals.AppDomain + "/platform/member/apply/audit/school");
todoTask.setH5ViewUrl(Globals.AppDomain + "/mobile/member/audit"); 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.setBizId(record.getId());
todoTask.setBizType("申请入会校工会审核"); todoTask.setBizType("申请入会校工会审核");
todoTask.setStatus(TodoTaskEnum.TaskStatus.ACTIVE.name()); todoTask.setStatus(TodoTaskEnum.TaskStatus.ACTIVE.name());
@@ -163,7 +178,14 @@ public enum MemberApplyAuditHandle {
List.of(Map.of("tool", MsgApi.sendTool.wechat_enterprise.name()))); List.of(Map.of("tool", MsgApi.sendTool.wechat_enterprise.name())));
} }
memberService.completeApplyAuditTasks(record.getId(), false); //部门工会的待办设置为完成
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);
}
return record; return record;
} }
}, },
@@ -172,7 +194,6 @@ public enum MemberApplyAuditHandle {
*/ */
AUDIT_SCHOOL(MemberApplyState.SCHOOL_UNION) { AUDIT_SCHOOL(MemberApplyState.SCHOOL_UNION) {
@Override @Override
@Aop(TransAop.READ_COMMITTED)
public MemberApplyRecord next(MemberApplyRecord record, Audit audit) { public MemberApplyRecord next(MemberApplyRecord record, Audit audit) {
memberApplyRecordViService.transactional(() -> { memberApplyRecordViService.transactional(() -> {
@@ -221,7 +242,14 @@ public enum MemberApplyAuditHandle {
List.of(Map.of("tool", MsgApi.sendTool.wechat_enterprise.name()))); List.of(Map.of("tool", MsgApi.sendTool.wechat_enterprise.name())));
} }
memberService.completeApplyAuditTasks(record.getId(), true); //校工会的待办设置为完成
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);
}
}); });
sysUserService.deleteCache(record.getUserId()); sysUserService.deleteCache(record.getUserId());
@@ -242,7 +270,6 @@ public enum MemberApplyAuditHandle {
public TodoTaskInterface todoTaskInterface = ViResource.ioc.getByType(TodoTaskInterface.class); public TodoTaskInterface todoTaskInterface = ViResource.ioc.getByType(TodoTaskInterface.class);
public MsgApi msgApi = ViResource.ioc.getByType(MsgApi.class); public MsgApi msgApi = ViResource.ioc.getByType(MsgApi.class);
public Dao dao = ViResource.dao; public Dao dao = ViResource.dao;
public MemberService memberService = ViResource.ioc.getByType(MemberService.class);
public abstract MemberApplyRecord next(MemberApplyRecord record, Audit audit); public abstract MemberApplyRecord next(MemberApplyRecord record, Audit audit);
@@ -34,21 +34,4 @@ public interface MemberService extends ViService<Sys_user> {
* @return * @return
*/ */
Pagination memberChangeRecords(PageForm pageForm, CndPlus cnd); 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,21 +15,6 @@ import org.nutz.lang.util.NutMap;
import org.nutz.plugins.wkcache.annotation.CacheDefaults; import org.nutz.plugins.wkcache.annotation.CacheDefaults;
import java.util.List; 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;
/** /**
@@ -85,151 +70,4 @@ public class MemberServiceImpl extends ViServiceImpl<Sys_user> implements Member
Sql sql = Sqls.create(MEMBER_CHANGE_RECORDS).setCondition(cnd); Sql sql = Sqls.create(MEMBER_CHANGE_RECORDS).setCondition(cnd);
return list(pageForm, sql); 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,47 +1,112 @@
package io.v.nutz.mobile.member; package io.v.nutz.mobile.member;
import cn.wizzer.framework.base.service.BaseService;
import io.v.nutz.annontation.ViReturn; import io.v.nutz.annontation.ViReturn;
import io.v.nutz.member.service.MemberService; import io.v.nutz.base.utils.Vi;
import org.apache.shiro.authz.annotation.RequiresAuthentication; import io.v.nutz.dao.CndPlus;
import org.apache.shiro.authz.annotation.RequiresPermissions; import io.v.nutz.member.constant.MemberApplyState;
import org.apache.shiro.authz.annotation.Logical; 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 org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Ok;
/** 手机端会员审核统一入口,与 PC 端共享两级审核权限。 */ /**
* @author zhf
* @date 2021/9/26 9:24
* @description
*/
@IocBean @IocBean
@At("/mobile/member/audit") @At("/mobile/member/audit")
@Ok("json:full") @Ok("json:full")
@RequiresAuthentication
@RequiresPermissions(value = {"member.apply.audit.union", "member.apply.audit.school"}, logical = Logical.OR)
public class MemberAuditUnionController { public class MemberAuditUnionController {
@Inject
private MemberService memberService;
@At("") @At("")
@Ok("beetl:/mobile/member/audit_list.html") @Ok("beetl:/mobile/member/audit_list.html")
public void index() { public void indext() {
} }
/** @Inject
* pageNumber/pageSize 为页码和每页条数,isAudit 区分已审/待审,year 为申请年份(可空)。 private BaseService baseService;
* 返回分页对象,list 为申请记录,totalCount 为符合当前审核权限的数据总数。
*/
@At @At
@ViReturn @ViReturn
public Object pageData(int pageNumber, int pageSize, boolean isAudit, Integer year) { public Object pageData(int pageNumber, int pageSize, boolean isAudit, Integer year) {
return memberService.mobileApplyAuditPage(pageNumber, pageSize, isAudit, 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);
} }
/**
* record_id 为申请记录 ID,user_id 为申请人 ID,done 表示从已办入口只读查看。
* 返回 Beetl 页面视图;实际审核阶段和访问范围均由数据库记录决定。
*/
@At("/findOne") @At("/findOne")
@Ok("re") @Ok("re")
public String findOne(String record_id, String user_id, boolean done) { public String findOne(Integer stateId) {
return memberService.mobileApplyAuditView(record_id, user_id, done); 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";
} }
} }
@@ -277,7 +277,7 @@ public class MTrainSignUpActivityController {
if(signFullByUnionId) { if(signFullByUnionId) {
return Result.error("该活动您所在的分工会名额已报满"); return Result.error("该活动您所在的分工会名额已报满");
} }
if(course.getReserveMode() == 2 && currentFamilyNumber == null) { if(Integer.valueOf(2).equals(course.getReserveMode()) && currentFamilyNumber == null) {
//课程已报人数 //课程已报人数
List<TrainSignUpUser> signUpUsers = dao.query(TrainSignUpUser.class, Cnd.where("courseId", "=", courseId)); List<TrainSignUpUser> signUpUsers = dao.query(TrainSignUpUser.class, Cnd.where("courseId", "=", courseId));
int hasRegisterNum = signUpUsers.size() + 1;//+1是算自己 int hasRegisterNum = signUpUsers.size() + 1;//+1是算自己
@@ -336,7 +336,7 @@ public class TrainSignUpActivityServiceImpl extends ViServiceImpl<TrainSignUpAct
TrainSignUpActivity activity = dao().fetch(TrainSignUpActivity.class, Cnd.where("id", "=", course.getActivityId())); TrainSignUpActivity activity = dao().fetch(TrainSignUpActivity.class, Cnd.where("id", "=", course.getActivityId()));
//如果这个课程的预留名额方式为报名人数不变 //如果这个课程的预留名额方式为报名人数不变
if (course.getReserveMode() == 2) { if (Integer.valueOf(2).equals(course.getReserveMode())) {
//如果当前报名+已报小于这个课程限制人数 //如果当前报名+已报小于这个课程限制人数
//课程已报人数 //课程已报人数
List<TrainSignUpUser> signUpUsers = dao().query(TrainSignUpUser.class, Cnd.where("courseId", "=", trainSignUpUser.getCourseId())); List<TrainSignUpUser> signUpUsers = dao().query(TrainSignUpUser.class, Cnd.where("courseId", "=", trainSignUpUser.getCourseId()));
@@ -487,7 +487,7 @@ public class TrainSignUpActivityServiceImpl extends ViServiceImpl<TrainSignUpAct
hasFamilyNum = num.get() + (currentFamilyNumber != null ? currentFamilyNumber : 0);//currentFamilyNumber是当前报名时填的家属人数 hasFamilyNum = num.get() + (currentFamilyNumber != null ? currentFamilyNumber : 0);//currentFamilyNumber是当前报名时填的家属人数
} }
//如果预留名额模式是报名人数减少 //如果预留名额模式是报名人数减少
if (course.getReserveMode() == 1) { if (course.getReserveMode() == null || course.getReserveMode() == 1) {
//如果已报人数+预留人数+当前报名(自己)+家属 > 总人数 //如果已报人数+预留人数+当前报名(自己)+家属 > 总人数
return (hasRegisterNum + course.getCourseReservedNumber() + hasFamilyNum) > coursePeopleNumber; return (hasRegisterNum + course.getCourseReservedNumber() + hasFamilyNum) > coursePeopleNumber;
} else {//如果预留名额模式是报名人数不变 } else {//如果预留名额模式是报名人数不变
@@ -12,11 +12,13 @@ import io.v.nutz.sys.models.Sys_menu;
import io.v.nutz.sys.models.Sys_user; import io.v.nutz.sys.models.Sys_user;
import io.v.nutz.util.ShiroUtil; import io.v.nutz.util.ShiroUtil;
import io.v.nutz.zgfw.service.CondolenceService; 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.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings; import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap; import org.nutz.lang.util.NutMap;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Ok;
@@ -51,24 +53,71 @@ public class CondolenceAgentController {
List<NutMap> result = new ArrayList<>(); List<NutMap> result = new ArrayList<>();
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", 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", condolenceService.countCurrentYearAgenda(2012))); 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", condolenceService.countCurrentYearAgenda(2020))); 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", condolenceService.countCurrentYearAgenda(2050))); result.add(new NutMap().setv("title", title).setv("url", ECR).setv("iconClass", vi.getIconByPath(ECR)).setv("label", "待工会常务副主席审核").setv("number", getEcrCount()));
Sys_user user = (Sys_user) ShiroUtil.getPrincipal(); Sys_user user = (Sys_user) ShiroUtil.getPrincipal();
List<Sys_menu> menus = Optional.ofNullable(user).orElse(new Sys_user()).getMenus(); 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 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());
} }
/** /**
* 无需传参,身份取自登录会话,返回今年本人办理的慰问记录列表。 * 待工会主席审核
* 每项包含 moduleName(业务名称)、auditState(办理节点)、auditTime(审核日期)、mobileUrl(详情链接)。 *
* @return
*/ */
@At private Integer getUcrCount() {
@ViReturn Cnd cnd = Cnd.NEW();
@RequiresAuthentication Sql sql = Sqls.create("""
public Object getCompletes() { SELECT COUNT(1) FROM condolence con LEFT JOIN `user` us ON con.be_user=us.id $condition
return condolenceService.getCurrentYearCompletes(); """);
cnd.and("con.state_id", "=", 2000);
if (!ShiroUtil.hasAnyRoles("sysadmin,A06")) {
cnd.and("us.unionid", "=", vi.getUnionId());
}
sql.setCondition(cnd);
return condolenceService.count(sql);
} }
/**
* 待工会会计审核
* 暂时没用
*
* @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,7 +5,6 @@ import io.v.nutz.service.ViService;
import io.v.nutz.zgfw.model.condolence.Condolence; import io.v.nutz.zgfw.model.condolence.Condolence;
import org.nutz.dao.entity.Record; import org.nutz.dao.entity.Record;
import org.nutz.lang.util.NutMap; import org.nutz.lang.util.NutMap;
import java.util.List;
/** /**
@@ -20,20 +19,6 @@ public interface CondolenceService extends ViService<Condolence> {
*/ */
NutMap findOne(String id); 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,8 +3,6 @@ package io.v.nutz.zgfw.service.impl;
import cn.wizzer.framework.base.service.BaseService; import cn.wizzer.framework.base.service.BaseService;
import io.v.nutz.base.utils.DateUtil; 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.modules.services.ReviewService;
import io.v.nutz.service.impl.ViServiceImpl; import io.v.nutz.service.impl.ViServiceImpl;
import io.v.nutz.zgfw.model.condolence.Condolence; import io.v.nutz.zgfw.model.condolence.Condolence;
@@ -21,8 +19,6 @@ import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings; import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap; import org.nutz.lang.util.NutMap;
import java.util.List;
import java.util.Collections;
/** /**
* @author 1V * @author 1V
@@ -41,78 +37,6 @@ public class CondolenceServiceImpl extends ViServiceImpl<Condolence> implements
this.condolenceDao = dao; 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 @Override
public boolean hasHospitalCondolenceInCurrentYear(Condolence application) { public boolean hasHospitalCondolenceInCurrentYear(Condolence application) {
CondolenceType type = condolenceDao.fetch(CondolenceType.class, application.getType()); CondolenceType type = condolenceDao.fetch(CondolenceType.class, application.getType());
@@ -186,14 +110,6 @@ public class CondolenceServiceImpl extends ViServiceImpl<Condolence> implements
if (Strings.isNotBlank(record.getString("union_chairman_review"))) { if (Strings.isNotBlank(record.getString("union_chairman_review"))) {
record.put("ucr", reviewService.fetch(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"))) { if (Strings.isNotBlank(record.getString("vice_chairman_review"))) {
record.put("vcr", reviewService.fetch(record.getString("vice_chairman_review"))); record.put("vcr", reviewService.fetch(record.getString("vice_chairman_review")));
@@ -0,0 +1,4 @@
update sys_app_menu set moduleId = '282ea934ff624b7b9e279eab85a8ce39'
where moduleId = '956eeb9432424dbab7f1cd46950f228d';
delete from sys_app_module where moduleId = '956eeb9432424dbab7f1cd46950f228d';
@@ -235,36 +235,6 @@
</el-form> </el-form>
</el-tab-pane> </el-tab-pane>
<el-tab-pane v-if="hasPane(6)&&viewData.ecr" label="工会常务副主席审核信息" name="6">
<el-form label-width="130px" label-suffix=":" style="padding: 20px 0">
<vi-title title="审核信息"></vi-title>
<el-row gutter="20">
<el-col :span="12">
<el-form-item label="审核人员">
{{ viewData.ecr.username }}
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="审核时间">
{{ viewData.ecr.time }}
</el-form-item>
</el-col>
</el-row>
<el-form-item label="审核意见">
<div class="textarea-div">{{ viewData.ecr.opinion ? viewData.ecr.opinion : '暂无' }}</div>
</el-form-item>
<el-form-item label="签&emsp;&emsp;字">
<el-image v-if="viewData.ecr.sign"
style="width: 300px; height: 100px"
:src="viewData.ecr.sign"
fit="contain"></el-image>
<span v-else>暂无</span>
</el-form-item>
</el-form>
</el-tab-pane>
<el-tab-pane v-if="handle" :label="label" name="999"> <el-tab-pane v-if="handle" :label="label" name="999">
<slot name="handle"></slot> <slot name="handle"></slot>
</el-tab-pane> </el-tab-pane>
@@ -287,7 +257,7 @@ module.exports = {
}, },
panes: { panes: {
type: Array, type: Array,
default: () => [] default: []
}, },
}, },
filters: { filters: {
@@ -308,32 +278,27 @@ module.exports = {
watch: {}, watch: {},
methods: { methods: {
hasPane(name) { hasPane(name) {
// 未指定页签范围时展示所有已有审核记录;显式传入范围时保持原有限制。 if (!this.handle) {
if (!this.handle || this.panes.length === 0) {
return true return true
} }
return this.panes.includes(name) return this.panes.includes(name)
}, },
/** async getInfo(id) {
* id 为慰问申请 ID;接口 data 为申请详情,ucr/fr/vcr/ecr 为各节点审核记录对象。 this.loading = true
* 无记录时对应页签隐藏;请求结束后统一解除加载状态。 const {data, code, msg} = await $.get("/platform/fw/condolence/findOne", {id})
*/ this.loading = false
getInfo(id) { if (data) {
this.$set(this, 'loading', true) this.activeName = this.handle ? "999" : "1"
this.$set(this, 'viewData', {}) condolence.toFormData(data)
return $.post('/platform/fw/condolence/findOne', {id}) this.viewData = data
.then((res) => {
if (res.code === 0 && res.data) { } else {
condolence.toFormData(res.data) this.viewData = {}
this.$set(this, 'activeName', this.handle ? '999' : '1') this.$message({
this.$set(this, 'viewData', res.data) message: "获取信息失败",
} else { type: 'error'
this.$message.error('获取信息失败') });
} }
})
.always(() => {
this.$set(this, 'loading', false)
})
}, },
}, },
created() { created() {
+19 -115
View File
@@ -223,12 +223,9 @@ layout("/mobile/platform.html"){
roles: [], roles: [],
active: 1, active: 1,
needCount: 0, needCount: 0,
needRequestId: 0,
needItems: [], needItems: [],
activeName: '0', activeName: '0',
completedItems: [], completedItems: [],
completedLoading: false,
completedRequestId: 0,
} }
}, },
methods: { methods: {
@@ -247,8 +244,7 @@ layout("/mobile/platform.html"){
location.href = o.mobileHref location.href = o.mobileHref
}, },
toHref(o) { toHref(o) {
// 详情链接已携带申请 ID,保留查询参数。 location.href = o.mobileUrl + '?audit=1';
location.href = o.mobileUrl;
}, },
/** /**
* 入学登记待办 * 入学登记待办
@@ -260,111 +256,20 @@ layout("/mobile/platform.html"){
this.needItems = this.needItems.concat(data.filter(v => v.number > 0)) this.needItems = this.needItems.concat(data.filter(v => v.number > 0))
} }
},*/ },*/
/** async getNeedItems() {
* requestId 为本轮刷新序号,忽略旧请求,避免返回页面或切换页签时覆盖新数据。 const {data, code} = await $.get('/platform/needItems/getNeedItems')
* 通用接口 data 为待办数组,使用 count 和 mobileHref;完成后继续加载慰问待办。 if (code === 0) {
*/ const obj = data.filter(v => {
getNeedItems(requestId) { return v.mobileHref != null && v.count > 0
return $.post('/platform/needItems/getNeedItems')
.then((res) => {
if (requestId === this.needRequestId && res.code === 0) {
this.$set(this, 'needItems', (res.data || []).filter(v => v.mobileHref && v.count > 0
&& v.mobileHref.split('?')[0] !== '/mobile/member/audit'
&& !['/platform/member/apply/audit/union', '/platform/member/apply/audit/school'].includes((v.href || '').split('?')[0])))
}
})
.always(() => {
if (requestId === this.needRequestId) {
this.getCondolenceAgenda(requestId)
}
}) })
this.needItems = obj
}
}, },
/** async getCompletes() {
* 复用 PC 慰问待办的菜单权限和统计口径,将 label/number 转为手机模板的 name/count。 const {data, code} = await $.get('/platform/sys/completed/getCompletes')
* 仅映射手机端已有审核页面的三个节点,历史常务副主席节点不提供手机办理入口。 if (code === 0) {
*/ this.completedItems = data;
getCondolenceAgenda(requestId) { }
const auditUrls = [
'/platform/fw/condolence/ucr/union',
'/platform/fw/condolence/fr',
'/platform/fw/condolence/vcr/school'
]
return $.post('/platform/condolence/agent/getAgenda')
.then((res) => {
if (requestId !== this.needRequestId || res.code !== 0) {
return
}
const items = (res.data || []).filter(v => auditUrls.includes(v.url) && v.number > 0)
.map(v => ({
title: v.title,
name: v.label,
count: v.number,
mobileHref: '/mobile/condolence/audit'
}))
this.$set(this, 'needItems', this.needItems.concat(items))
})
.always(() => {
if (requestId === this.needRequestId) {
this.getMemberApplyAgenda(requestId)
}
})
},
/**
* 无需业务参数;后端按会话权限返回今年会员入会节点,字段与首页待办卡片一致。
* 专用数据替代通用配置中的同业务卡片,避免双计数;失败不影响已加载的慰问待办。
*/
getMemberApplyAgenda(requestId) {
return $.post('/platform/member/agenda/getMobileAgenda')
.then((res) => {
if (requestId !== this.needRequestId) return
if (res.code === 0) {
const items = (res.data || []).filter(v => v.count > 0 && v.mobileHref)
this.$set(this, 'needItems', this.needItems.concat(items))
} else {
vant.Toast.fail('会员入会待办加载失败,请重试')
}
}, () => {
if (requestId === this.needRequestId) vant.Toast.fail('会员入会待办加载失败,请重试')
})
.always(() => {
if (requestId === this.needRequestId) this.$set(this, 'needCount', this.needItems.length)
})
},
/**
* 两个接口均无需传办理人,按当前会话返回本人今年已办。
* 各业务独立合并;全部请求结束后关闭 loading,旧刷新结果不得覆盖当前列表。
*/
getCompletes() {
const requestId = this.completedRequestId + 1
this.$set(this, 'completedRequestId', requestId)
this.$set(this, 'completedItems', [])
this.$set(this, 'completedLoading', true)
const sources = [
{url: '/platform/condolence/agent/getCompletes', label: '慰问'},
{url: '/platform/member/agenda/getCompletes', label: '会员入会'}
]
let remaining = sources.length
const requests = sources.map(source => $.post(source.url)
.then((res) => {
if (requestId !== this.completedRequestId) return
if (res.code === 0) {
const items = this.completedItems.concat(res.data || [])
// 现有日期字段统一交给 moment 解析,兼容日期字符串和时间戳。
items.sort((a, b) => (moment(b.auditTime).valueOf() || 0) - (moment(a.auditTime).valueOf() || 0))
this.$set(this, 'completedItems', items)
} else {
vant.Toast.fail(source.label + '已办加载失败,请重试')
}
}, () => {
if (requestId === this.completedRequestId) vant.Toast.fail(source.label + '已办加载失败,请重试')
})
.always(() => {
remaining--
if (requestId === this.completedRequestId && remaining === 0) {
this.$set(this, 'completedLoading', false)
}
}))
return $.when.apply($, requests)
}, },
/** /**
* 会员个人核对待办 * 会员个人核对待办
@@ -386,13 +291,12 @@ layout("/mobile/platform.html"){
this.needItems = this.needItems.concat(data.filter(v => v.count > 0)) this.needItems = this.needItems.concat(data.filter(v => v.count > 0))
} }
}, },
initData() { async initData() {
this.getCompletes() await this.getNeedItems();
// 每轮重新合并通用、慰问和会员入会待办,防止重复追加;刷新序号隔离尚未完成的旧请求。 // await this.getMemberCheckSelfAgenda()
this.$set(this, 'needRequestId', this.needRequestId + 1) // await this.getWelfareCheckSelfAgenda()
this.$set(this, 'needItems', []) // await this.getCompletes();
this.$set(this, 'needCount', 0) this.needCount = this.needItems.length
return this.getNeedItems(this.needRequestId)
}, },
async setNeedItems() { async setNeedItems() {
const {data, code} = await $.get('/platform/needItems/getNeedItems') const {data, code} = await $.get('/platform/needItems/getNeedItems')
@@ -59,10 +59,9 @@ layout("/mobile/platform.html"){
{text: '已审核', value: true}, {text: '已审核', value: true},
], ],
handle: true, handle: true,
queryVersion: 0,
pageForm: { pageForm: {
year: GetQueryString("isAudit") === "true" ? null : new Date().getFullYear(), year: new Date().getFullYear(),
isAudit: GetQueryString("isAudit") === "true", isAudit: false,
}, },
} }
}, },
@@ -71,7 +70,6 @@ layout("/mobile/platform.html"){
}, },
methods: { methods: {
yearChange() { yearChange() {
this.queryVersion++
this.pageForm.pageNumber = 1 this.pageForm.pageNumber = 1
this.tableData = [] this.tableData = []
this.finished = false this.finished = false
@@ -79,32 +77,40 @@ layout("/mobile/platform.html"){
}, },
onLoad() { onLoad() {
this.loading = true this.loading = true
// 捕获本次筛选条件,筛选切换后忽略旧请求,避免串页。 $.post(loc() + '/pageData', this.pageForm).then(res => {
const requestKey = this.queryVersion || 0
$.post('/mobile/member/audit/pageData', Object.assign({}, this.pageForm)).then(res => {
if (requestKey !== (this.queryVersion || 0)) return
if (res.code === 0) { if (res.code === 0) {
this.tableData = this.tableData.concat(res.data.list) this.tableData = this.tableData.concat(res.data.list)
this.finished = this.tableData.length >= res.data.totalCount || res.data.list.length === 0 if (this.tableData.length === res.data.totalCount) {
if (!this.finished) this.pageForm.pageNumber++ this.finished = true
} else { } else {
this.finished = true this.pageForm.pageNumber++
this.$toast.fail(res.msg || '加载失败') }
} }
}).fail(() => { this.loading = false
if (requestKey !== (this.queryVersion || 0)) return
this.finished = true
this.$toast.fail('加载失败,请重新筛选后重试')
}).always(() => {
if (requestKey === (this.queryVersion || 0)) this.loading = false
}) })
}, },
/* pageData() {
this.mLoading = true
setTimeout(async () => {
$.get(loc() + '/pageData', this.pageForm, (res) => {
if (res.code === 0) {
this.tableData = this.tableData.concat(res.data.list)
if (this.tableData.length === res.data.totalCount) {
this.finished = true
} else {
this.pageForm.pageNumber++
}
}
})
this.mLoading = false
}, 600)
},*/
openView(o) { openView(o) {
window.location.href = '/mobile/member/audit/findOne?stateId=' + o.stateId + '&record_id=' + o.id + '&user_id=' + o.userId + '&done=' + this.pageForm.isAudit window.location.href = '/mobile/member/audit/findOne?stateId=' + o.stateId + '&record_id=' + o.id + '&user_id=' + o.userId
}, },
}, },
created() { async created() {
this.yearList = [{text: '全部年份', value: null}]
let nowYear = new Date().getFullYear() let nowYear = new Date().getFullYear()
for (let i = nowYear; i >= nowYear - 9; i--) { for (let i = nowYear; i >= nowYear - 9; i--) {
this.yearList.push({text: i, value: i}) this.yearList.push({text: i, value: i})
@@ -26,6 +26,7 @@ layout("/mobile/platform.html"){
<van-field v-model="formData.auditTime" label="审核时间" readonly></van-field> <van-field v-model="formData.auditTime" label="审核时间" readonly></van-field>
<van-field <van-field
required
v-model="formData.auditOpinion" v-model="formData.auditOpinion"
rows="1" rows="1"
autosize autosize
@@ -45,12 +46,12 @@ layout("/mobile/platform.html"){
<van-row gutter="20" style="margin-top: 30px;padding: 0 25px"> <van-row gutter="20" style="margin-top: 30px;padding: 0 25px">
<van-col span="12"> <van-col span="12">
<van-button :color="themeColor" plain block :loading="formLoading" :disabled="formLoading" @click="doAudit(false)">拒 绝 <van-button :color="themeColor" plain block @click="doAudit(false)">拒 绝
</van-button> </van-button>
</van-col> </van-col>
<van-col span="12"> <van-col span="12">
<van-button :color="themeColor" block :loading="formLoading" :disabled="formLoading" @click="doAudit(true)">通 过 <van-button :color="themeColor" block @click="doAudit(true)">通 过
</van-button> </van-button>
</van-col> </van-col>
</van-row> </van-row>
@@ -71,7 +72,6 @@ layout("/mobile/platform.html"){
data() { data() {
return { return {
handle: true, handle: true,
formLoading: false,
id: "", id: "",
formData: {}, formData: {},
} }
@@ -81,27 +81,25 @@ layout("/mobile/platform.html"){
'mobile-sign': httpVueLoader('/components/sign/mobileSign.vue'), 'mobile-sign': httpVueLoader('/components/sign/mobileSign.vue'),
}, },
methods: { methods: {
doAudit(pass) { async doAudit(pass) {
if (this.formLoading) return if (!this.formData.auditOpinion) {
// 与 PC 共用审核参数;提交前读取手写签名,避免仅提交历史签名。 this.$toast.fail('请填写审核意见');
this.$refs.signature.submitSign() return
this.$set(this.formData, 'auditPass', pass) }
this.formLoading = true this.formData.auditPass = pass
$.post('/platform/member/apply/audit/doAudit', this.formData).then(resp => { const resp = await $.post("/platform/member/apply/audit/doAudit", this.formData)
requestLaterFun(resp, () => { requestLaterFun(resp, (data) => {
this.$toast.success('审核成功') this.$toast.success('审核成功');
location.replace('/mobile/member/audit') setTimeout(() => {
}, () => { location.href = '/mobile/member/audit'
this.$toast.fail('审核失败') }, 1000)
}, () => {}) }, () => {
}).fail(() => { this.$toast.fail('审核失败');
this.$toast.fail('审核失败,请稍后重试') }, () => {
}).always(() => {
this.formLoading = false
}) })
}, },
}, },
created() { async created() {
const record_id = GetQueryString("record_id") const record_id = GetQueryString("record_id")
const user_id = GetQueryString("user_id") const user_id = GetQueryString("user_id")
setTimeout(() => { setTimeout(() => {
@@ -26,7 +26,7 @@ layout("/mobile/platform.html"){
<van-field v-model="formData.auditTime" label="审核时间" readonly></van-field> <van-field v-model="formData.auditTime" label="审核时间" readonly></van-field>
<van-field <van-field required
v-model="formData.auditOpinion" v-model="formData.auditOpinion"
rows="1" rows="1"
autosize autosize
@@ -45,12 +45,12 @@ layout("/mobile/platform.html"){
<van-row gutter="20" style="margin-top: 30px;padding: 0 25px"> <van-row gutter="20" style="margin-top: 30px;padding: 0 25px">
<van-col span="12"> <van-col span="12">
<van-button :color="themeColor" plain block :loading="formLoading" :disabled="formLoading" @click="doAudit(false)">拒 绝 <van-button :color="themeColor" plain block @click="doAudit(false)">拒 绝
</van-button> </van-button>
</van-col> </van-col>
<van-col span="12"> <van-col span="12">
<van-button :color="themeColor" block :loading="formLoading" :disabled="formLoading" @click="doAudit(true)">通 过 <van-button :color="themeColor" block @click="doAudit(true)">通 过
</van-button> </van-button>
</van-col> </van-col>
</van-row> </van-row>
@@ -70,7 +70,6 @@ layout("/mobile/platform.html"){
data() { data() {
return { return {
handle: true, handle: true,
formLoading: false,
id: "", id: "",
formData: {}, formData: {},
} }
@@ -81,27 +80,25 @@ layout("/mobile/platform.html"){
}, },
methods: { methods: {
doAudit(pass) { async doAudit(pass) {
if (this.formLoading) return if (!this.formData.auditOpinion) {
// 与 PC 共用审核参数;提交前读取手写签名,避免仅提交历史签名。 this.$toast.fail('请填写审核意见');
this.$refs.signature.submitSign() return
this.$set(this.formData, 'auditPass', pass) }
this.formLoading = true this.formData.auditPass = pass
$.post('/platform/member/apply/audit/doAudit', this.formData).then(resp => { const resp = await $.post("/platform/member/apply/audit/doAudit", this.formData)
requestLaterFun(resp, () => { requestLaterFun(resp, (data) => {
this.$toast.success('审核成功') this.$toast.success('审核成功');
location.replace('/mobile/member/audit') setTimeout(() => {
}, () => { location.href = '/mobile/member/audit'
this.$toast.fail('审核失败') }, 1000)
}, () => {}) }, () => {
}).fail(() => { this.$toast.fail('审核失败');
this.$toast.fail('审核失败,请稍后重试') }, () => {
}).always(() => {
this.formLoading = false
}) })
}, },
}, },
created() { async created() {
const record_id = GetQueryString("record_id") const record_id = GetQueryString("record_id")
const user_id = GetQueryString("user_id") const user_id = GetQueryString("user_id")
setTimeout(() => { setTimeout(() => {
@@ -106,7 +106,7 @@ layout("/mobile/platform.html"){
@click-left="location.replace('/platform/mobile/trainSignUpActivity/trainList')"></van-nav-bar> @click-left="location.replace('/platform/mobile/trainSignUpActivity/trainList')"></van-nav-bar>
</van-sticky> </van-sticky>
<van-image height="186" :src="CREATE_PREVIEW_URL(activity?.cover[0].id)"></van-image> <van-image height="186" :src="activity.cover && activity.cover[0] ? CREATE_PREVIEW_URL(activity.cover[0].id) : ''"></van-image>
<div class="title">{{activity.activityName}}</div> <div class="title">{{activity.activityName}}</div>
<van-tabs v-model:active="tabActive" shrink> <van-tabs v-model:active="tabActive" shrink>
@@ -288,8 +288,7 @@
pageForm: { pageForm: {
source: source, source: source,
searchName: "u.username", searchName: "u.username",
// 已办入口默认显示本阶段已审核记录。 audit: 2
audit: new URLSearchParams(window.location.search).get("audit") === "1" ? 1 : 2
}, },
unions: [], unions: [],
tableColumns: [ tableColumns: [