体育报名外援优化;体育服装管理整改,关联选择活动;比赛名称录入可选工会补全;沿用保存活动bug修复
This commit is contained in:
@@ -89,7 +89,11 @@ public class ActivityApplyController {
|
||||
LEFT JOIN activity_school acts ON acts.id=apply.activityId
|
||||
LEFT JOIN activity_event ev ON ev.id = apply.eventId $condition
|
||||
""");
|
||||
cnd.and("apply.activityUnionId", "=", getUnionId());
|
||||
// 其他工会出战的外援仍由原报名人维护,重新打开项目时必须回显。
|
||||
SqlExpressionGroup ownerOrUnion = new SqlExpressionGroup();
|
||||
ownerOrUnion.or("apply.activityUnionId", "=", getUnionId());
|
||||
ownerOrUnion.or("apply.applyUser", "=", ShiroUtil.getUserId());
|
||||
cnd.and(ownerOrUnion);
|
||||
/* if (!ShiroUtil.hasAnyRoles("A06,sysadmin")) {
|
||||
SqlExpressionGroup group = new SqlExpressionGroup();
|
||||
if (ShiroUtil.hasAnyRoles("H01")) {
|
||||
@@ -239,12 +243,13 @@ public class ActivityApplyController {
|
||||
WHERE
|
||||
asa.eventId = @eventId
|
||||
AND asa.activityId=@activityId
|
||||
AND asa.activityUnionId = @unionid
|
||||
AND (asa.activityUnionId = @unionid OR asa.applyUser = @applyUser)
|
||||
AND asa.`status` != 3
|
||||
ORDER BY
|
||||
asa.identity DESC,
|
||||
asa.sex
|
||||
""").setParam("eventId", eventId).setParam("unionid", union_id).setParam("activityId", activityId);
|
||||
""").setParam("eventId", eventId).setParam("unionid", union_id)
|
||||
.setParam("applyUser", ShiroUtil.getUserId()).setParam("activityId", activityId);
|
||||
List<ActivitySchoolApply> list = activitySchoolApplyService.listEntity(applySql);
|
||||
//团体人数
|
||||
List<ActivitySchoolApply> awardsModeT = list.stream().filter(v -> v.getAwardsMode().equals("2")).collect(Collectors.toList());
|
||||
@@ -387,20 +392,26 @@ public class ActivityApplyController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建报名专用外援,工号由服务端生成,页面不能指定。
|
||||
* 创建报名专用人员;工号留空时由服务端生成,手动填写时服务端负责查重。
|
||||
* @param username 外援姓名
|
||||
* @param sex 性别,男或女
|
||||
* @param birthday 出生日期,yyyy-MM-dd
|
||||
* @param loginname 可为空;留空时自动生成,手动填写时不能与现有账号重复
|
||||
* @param idcard 18位身份证号,出生日期由服务端从身份证号读取
|
||||
* @param mobile 手机号码
|
||||
* @return Sys_user,id 为报名人员 ID,loginname 为 wy 年份流水工号,其他字段用于页面回显
|
||||
* @param fitForCompetition 身体条件是否适合参赛,只有 true 可创建
|
||||
* @return Sys_user,id 为报名人员 ID,loginname 为最终工号,其他字段用于页面回显
|
||||
*/
|
||||
@At
|
||||
@ViReturn
|
||||
@RequiresPermissions("activity.apply")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Object addExternalUser(String username, String sex, String birthday, String mobile) {
|
||||
public Object addExternalUser(String username, String loginname, String sex, String idcard, String mobile,
|
||||
Boolean fitForCompetition) {
|
||||
if (!Boolean.TRUE.equals(fitForCompetition)) {
|
||||
throw new IllegalArgumentException("身体条件不适合参赛,不能添加外援");
|
||||
}
|
||||
Sys_user operator = (Sys_user) ShiroUtil.getPrincipal();
|
||||
return activitySchoolApplyService.createExternalUser(username, sex, birthday, mobile, operator.getUnitid());
|
||||
return activitySchoolApplyService.createExternalUser(username, loginname, sex, idcard, mobile, operator.getUnitid());
|
||||
}
|
||||
|
||||
/** @return String,当前年份的下一个外援工号预览,实际编号以创建接口返回值为准。 */
|
||||
@@ -765,25 +776,18 @@ public class ActivityApplyController {
|
||||
return insert.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询添加外援时可复用的系统人员。
|
||||
* @param queryString 姓名或工号片段;空值不查询
|
||||
* @param userId 不参与返回的用户 ID 列表,可为空
|
||||
* @return List<NutMap>,每项包含 id、username、loginname、sex、idcard、birthday、mobile、unitid、unitname
|
||||
*/
|
||||
@At
|
||||
@ViReturn
|
||||
@RequiresPermissions("activity.apply")
|
||||
@Ok("json:{ignoreNull:true}")
|
||||
public Object getSysUser(String queryString, String[] userId) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.andEX("id", "not in", userId);
|
||||
if (StrUtil.isNotBlank(queryString)) {
|
||||
SqlExpressionGroup group = new SqlExpressionGroup();
|
||||
group.andLike("username", queryString).orLike("loginname", queryString);
|
||||
cnd.and(group);
|
||||
}
|
||||
// cnd.and("unionid", "=", Vi.getUnionId());
|
||||
Sql sql = Sqls.create("select id,loginname,username,sex,mobile,unitid,birthday from `user` $condition LIMIT 30");
|
||||
sql.setCondition(cnd);
|
||||
sql.setCallback(Sqls.callback.entities());
|
||||
sql.setEntity(sysUserService.getEntity());
|
||||
List<Sys_user> list = sysUserService.execute(sql).getList(Sys_user.class);
|
||||
return list;
|
||||
return activitySchoolApplyService.searchSystemUsers(queryString, userId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -280,7 +280,7 @@ public class ActivityCommonController {
|
||||
app.activityUnionName,
|
||||
app.sex,
|
||||
COALESCE(NULLIF(app.mobile, ''), u.mobile) mobile,
|
||||
u.idCard idcard,
|
||||
COALESCE(NULLIF(app.idCard, ''), u.idCard) idcard,
|
||||
COALESCE(unit.unitcode, u.unitcode) unitcode,
|
||||
CASE WHEN u.member = 1 THEN '是' ELSE '否' END isMember,
|
||||
CASE
|
||||
|
||||
@@ -179,8 +179,8 @@ public class ActivityGradesController {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
us.unitname,
|
||||
apply.*
|
||||
apply.*,
|
||||
COALESCE(NULLIF(apply.unitname, ''), us.unitname) unitname
|
||||
FROM
|
||||
activity_school_apply apply
|
||||
LEFT JOIN `user` us ON apply.userId = us.id $condition
|
||||
|
||||
@@ -138,6 +138,10 @@ public class ActivityInfoManageController {
|
||||
} else if ("four".equals(query)) {
|
||||
cnd.and(new Static("now() > school.endTime"));
|
||||
}
|
||||
// 时间状态快捷查询只展示已提交活动;历史记录的 isSave 可能为空。
|
||||
if ("one".equals(query) || "two".equals(query) || "three".equals(query) || "four".equals(query)) {
|
||||
cnd.and(new Static("(school.isSave IS NULL OR school.isSave <> 1)"));
|
||||
}
|
||||
if (!ShiroUtil.hasAnyRoles("sysadmin,A06")) {
|
||||
if (ActivityRoleUtil.isUnionManager()) {
|
||||
cnd.and("school.belongUnionId", "in", ActivityRoleUtil.getManageUnionStr(ShiroUtil.getUserId()));
|
||||
|
||||
@@ -112,42 +112,21 @@ public class ActivityReadingController {
|
||||
ActivityBasicUnit basicUnit = activitySchoolService.dao().fetch(ActivityBasicUnit.class, Cnd.where("id", "=", unitId));
|
||||
ActivityBasicUnion basicUnion = activitySchoolService.dao().fetch(ActivityBasicUnion.class, Cnd.where("id", "=", basicUnit.getUnionid()));
|
||||
ActivitySchool activitySchool = activitySchoolService.fetch(id);
|
||||
Cnd cnd = Cnd.NEW();
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
app.*,
|
||||
school.`name` activityName,
|
||||
school.applyType applyType,
|
||||
school.belongUnionId belongUnionId,
|
||||
school.belongClubId belongClubId,
|
||||
team.`name` team,
|
||||
COALESCE(NULLIF(app.unitname, ''), unit.`name`) unitname,
|
||||
ev.allName,
|
||||
ev.id evid,
|
||||
ev.projectType
|
||||
FROM
|
||||
activity_school_apply app
|
||||
LEFT JOIN activity_school school ON school.id = app.activityId
|
||||
LEFT JOIN activity_school_team team ON app.teamId = team.id
|
||||
LEFT JOIN activity_event ev ON ev.id = app.eventId
|
||||
LEFT JOIN sys_unit unit ON app.unitId = unit.id
|
||||
$condition
|
||||
""");
|
||||
|
||||
cnd.and("app.activityId", "=", id);
|
||||
// cnd.and("YEAR(app.applyDate)", "=", year);
|
||||
sql.setCondition(cnd);
|
||||
List<NutMap> applies = activitySchoolApplyService.listRepresentedApplies(id);
|
||||
if (!ShiroUtil.hasAnyRoles("sysadmin,A06")) {
|
||||
if ((ActivityRoleUtil.isUnionManager() || ShiroUtil.hasRole("gh08")) && activityLevel.equals("40002")) {
|
||||
cnd.and("app.activityUnionId", "=", basicUnit.getUnionid());
|
||||
cnd.and("school.belongUnionId", "=", basicUnit.getUnionid());
|
||||
// 权限仍按活动所属工会限制;报名分组按外援选中的单位工会计算。
|
||||
applies = basicUnit.getUnionid().equals(activitySchool.getBelongUnionId())
|
||||
? applies.stream().filter(v -> basicUnit.getUnionid().equals(v.getString("representedActivityUnionId")))
|
||||
.collect(Collectors.toList()) : List.of();
|
||||
}
|
||||
if (ShiroUtil.hasRole("H02") && activityLevel.equals("40003")) {
|
||||
cnd.and("school.belongClubId", "in", vi.getMangeClubStr());
|
||||
if (activitySchoolService.count(Cnd.where("id", "=", id)
|
||||
.and("belongClubId", "in", vi.getMangeClubStr())) == 0) {
|
||||
applies = List.of();
|
||||
}
|
||||
}
|
||||
}
|
||||
cnd.desc("ev.allName").asc("ev.projectType").asc("team.`name`");
|
||||
List<NutMap> applies = activitySchoolApplyService.listMap(sql);
|
||||
|
||||
List<NutMap> apply = new ArrayList();
|
||||
|
||||
@@ -157,10 +136,6 @@ public class ActivityReadingController {
|
||||
unionCnd.and("id", "=", basicUnit.getUnionid());
|
||||
}
|
||||
}
|
||||
if (activityLevel.equals("40002")) {
|
||||
unionCnd.and("id", "=", activitySchool.getBelongUnionId());
|
||||
}
|
||||
unionCnd.and("isEnable", "=", true);
|
||||
unionCnd.asc("unioncode");
|
||||
|
||||
if (!activityLevel.equals("40003")) {
|
||||
@@ -168,10 +143,20 @@ public class ActivityReadingController {
|
||||
|
||||
for (ActivityBasicUnion union : unions) {
|
||||
String unionId = union.getId();
|
||||
boolean hasApplies = applies.stream()
|
||||
.anyMatch(v -> unionId.equals(v.getString("representedActivityUnionId")));
|
||||
if (!union.isEnable() && !hasApplies) {
|
||||
continue;
|
||||
}
|
||||
// 院级活动保留主办工会,同时展示由所选单位代表其他工会出战的报名。
|
||||
if (activityLevel.equals("40002") && !unionId.equals(activitySchool.getBelongUnionId())
|
||||
&& !hasApplies) {
|
||||
continue;
|
||||
}
|
||||
NutMap map = new NutMap();
|
||||
|
||||
List<NutMap> applyList = applies.stream().filter(v -> {
|
||||
return v.getString("activityUnionId").equals(unionId);
|
||||
return unionId.equals(v.getString("representedActivityUnionId"));
|
||||
}).collect(Collectors.toList());
|
||||
map.setv("id", unionId);
|
||||
map.setv("unionname", union.getUnionname());
|
||||
@@ -183,7 +168,7 @@ public class ActivityReadingController {
|
||||
}
|
||||
} else {
|
||||
NutMap map = new NutMap();
|
||||
Sys_club sysClub = sysClubService.fetch(cnd.where("id", "=", activitySchool.getBelongClubId()));
|
||||
Sys_club sysClub = sysClubService.fetch(Cnd.where("id", "=", activitySchool.getBelongClubId()));
|
||||
map.setv("id", sysClub.getId());
|
||||
map.setv("unionname", sysClub.getName());
|
||||
map.setv("unioncode", sysClub.getCode());
|
||||
@@ -246,12 +231,16 @@ public class ActivityReadingController {
|
||||
FROM
|
||||
`activity_school_apply` apply
|
||||
LEFT JOIN activity_event `event` ON `event`.id = apply.eventId
|
||||
LEFT JOIN sys_unit selectedUnit ON selectedUnit.id = apply.unitId
|
||||
LEFT JOIN activity_basic_unit activityUnit ON activityUnit.id = apply.unitId
|
||||
LEFT JOIN activity_basic_settings groupSetting ON groupSetting.id = `event`.competitionCategory
|
||||
LEFT JOIN activity_basic_settings projectNameSetting ON projectNameSetting.id = `event`.sports
|
||||
LEFT JOIN activity_basic_settings distanceSetting ON distanceSetting.id = `event`.distance
|
||||
WHERE
|
||||
apply.activityId = @id
|
||||
AND apply.unionId = @unionId
|
||||
AND (CASE WHEN apply.unitname = selectedUnit.name AND selectedUnit.unionid IS NOT NULL
|
||||
AND activityUnit.unionid IS NOT NULL THEN selectedUnit.unionid
|
||||
ELSE apply.unionId END) = @unionId
|
||||
AND JSON_CONTAINS(apply.identity,JSON_Array( '1' ))
|
||||
ORDER BY
|
||||
FIELD( apply.sex, '男', '女 ' ),
|
||||
|
||||
@@ -23,10 +23,12 @@ import org.nutz.dao.util.cri.Static;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Strings;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -139,20 +141,21 @@ public class ActivityRemindController {
|
||||
WHERE
|
||||
sur.unionid = un.id
|
||||
AND sr.id IN (@h04RoleId, @activityRoleId)
|
||||
) unionleader,
|
||||
( SELECT COUNT( 1 ) FROM activity_school_apply asp WHERE asp.unionId = un.id AND asp.activityId = @activityId ) num
|
||||
) unionleader
|
||||
FROM
|
||||
`sys_union` un
|
||||
ORDER BY
|
||||
un.unioncode
|
||||
""").setParam("h04RoleId", Roles.UNION_MANGER)
|
||||
.setParam("activityRoleId", Roles.SPORTS_ACTIVITY_UNION_ADMIN)
|
||||
.setParam("activityId", activityId);
|
||||
.setParam("activityRoleId", Roles.SPORTS_ACTIVITY_UNION_ADMIN);
|
||||
|
||||
List<Record> unions = sysUnionService.list(sql);
|
||||
Map<String, List<NutMap>> appliesByUnion = activitySchoolApplyService.groupRepresentedAppliesByUnion(activityId);
|
||||
|
||||
unions.forEach(v -> {
|
||||
v.set("users", activitySchoolApplyService.query(Cnd.where("unionId", "=", v.getString("id")).and("activityId", "=", activityId).desc("identity")));
|
||||
List<NutMap> users = appliesByUnion.getOrDefault(v.getString("id"), List.of());
|
||||
v.set("users", users);
|
||||
v.set("num", users.size());
|
||||
});
|
||||
|
||||
return unions;
|
||||
@@ -185,20 +188,20 @@ public class ActivityRemindController {
|
||||
WHERE
|
||||
sur.unionid = un.id
|
||||
AND sr.id IN (@h04RoleId, @activityRoleId)
|
||||
) telephone,
|
||||
( SELECT COUNT( 1 ) FROM activity_school_apply asp WHERE asp.unionId = un.id AND asp.activityId = @activityId ) num
|
||||
) telephone
|
||||
FROM
|
||||
`sys_union` un
|
||||
ORDER BY
|
||||
un.unioncode
|
||||
""").setParam("h04RoleId", Roles.UNION_MANGER)
|
||||
.setParam("activityRoleId", Roles.SPORTS_ACTIVITY_UNION_ADMIN)
|
||||
.setParam("activityId", activityId);
|
||||
.setParam("activityRoleId", Roles.SPORTS_ACTIVITY_UNION_ADMIN);
|
||||
|
||||
List<Record> unions = sysUnionService.list(sql);
|
||||
Map<String, List<NutMap>> appliesByUnion = activitySchoolApplyService.groupRepresentedAppliesByUnion(activityId);
|
||||
|
||||
List<Record> collect = unions.stream().filter(v -> {
|
||||
return v.getInt("num") <= 0 && v.getString("telephone") != null;
|
||||
return appliesByUnion.getOrDefault(v.getString("id"), List.of()).isEmpty()
|
||||
&& v.getString("telephone") != null;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
collect.forEach(v -> {
|
||||
|
||||
@@ -5,6 +5,7 @@ import io.v.nutz.activity.models.ActivityBasicUnion;
|
||||
import io.v.nutz.activity.models.ActivityBasicUnit;
|
||||
import io.v.nutz.activity.models.ActivityResults;
|
||||
import io.v.nutz.activity.models.ActivitySchoolApply;
|
||||
import io.v.nutz.activity.services.ActivitySchoolApplyService;
|
||||
import io.v.nutz.annontation.ViReturn;
|
||||
import io.v.nutz.base.utils.DateUtil;
|
||||
import io.v.nutz.base.utils.Vi;
|
||||
@@ -47,6 +48,9 @@ public class ActivityResultsController {
|
||||
@Inject("ActivitySchoolApply")
|
||||
private ViService<ActivitySchoolApply> activitySchoolApplyViService;
|
||||
|
||||
@Inject
|
||||
private ActivitySchoolApplyService activitySchoolApplyService;
|
||||
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:platform/activity/school/ActivityResults.html")
|
||||
@@ -195,32 +199,14 @@ public class ActivityResultsController {
|
||||
|
||||
|
||||
/**
|
||||
* 查询团体参赛部门工会
|
||||
*
|
||||
* @param activityId
|
||||
* @param eventId
|
||||
* @return
|
||||
* activityId、eventId 为页面当前活动和项目ID,仅保留接口参数兼容原调用。
|
||||
* 返回全部系统工会列表,每项包含 id 和 unionname,供团体成绩录入选择。
|
||||
*/
|
||||
|
||||
@At
|
||||
@ViReturn
|
||||
public Object getUnionList(String activityId, String eventId) {
|
||||
Sql sql = Sqls.create("""
|
||||
|
||||
SELECT
|
||||
un.id,
|
||||
un.unionname
|
||||
FROM
|
||||
activity_school_apply asa
|
||||
LEFT JOIN sys_union un ON un.id = asa.unionId
|
||||
WHERE
|
||||
asa.activityId = @activityId
|
||||
AND asa.eventId = @eventId
|
||||
|
||||
GROUP BY
|
||||
un.unionname
|
||||
""").setParam("activityId", activityId).setParam("eventId", eventId);
|
||||
return activitySchoolApplyViService.list(sql);
|
||||
return activitySchoolApplyService.getResultUnionOptions();
|
||||
}
|
||||
|
||||
@Inject("Sys_user")
|
||||
|
||||
@@ -168,6 +168,9 @@ public class ActivitySchoolApply implements Serializable {
|
||||
private String mobile;
|
||||
|
||||
|
||||
@Column
|
||||
@Comment("报名时使用的身份证号,系统资料为空时保存本次手动补充值")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
@Excel(name = "身份证号", width = 20)
|
||||
private String idCard;
|
||||
|
||||
|
||||
@@ -13,19 +13,49 @@ import java.util.Map;
|
||||
*/
|
||||
public interface ActivitySchoolApplyService extends ViService<ActivitySchoolApply> {
|
||||
|
||||
/**
|
||||
* 获取团体成绩录入可选的全部系统工会,不受活动项目报名情况或启用状态限制。
|
||||
* @return 工会列表,每项包含 id(成绩记录使用的工会ID)和 unionname(下拉显示名称)
|
||||
*/
|
||||
List<NutMap> getResultUnionOptions();
|
||||
|
||||
/** @return 当前年份预计分配的外援工号;实际工号以创建接口返回值为准。 */
|
||||
String previewExternalLoginname();
|
||||
|
||||
/**
|
||||
* 创建仅用于报名的外援用户,按年份生成 wy+年份+流水号的工号。
|
||||
* 按姓名或工号查找可复用的系统人员。
|
||||
* @param queryString 搜索内容,空值返回空列表
|
||||
* @param excludedUserIds 当前页面需要排除的用户 ID
|
||||
* @return 人员列表,每项包含 id、姓名、工号、性别、身份证号、出生日期、电话和系统单位
|
||||
*/
|
||||
List<NutMap> searchSystemUsers(String queryString, String[] excludedUserIds);
|
||||
|
||||
/**
|
||||
* 查询活动报名及其代表出战的工会;历史报名仅在所存单位 ID 与单位名称一致时按该单位归属。
|
||||
* @param activityId 活动 ID
|
||||
* @return 报名列表,representedUnionId 是系统工会 ID,representedActivityUnionId 是活动工会 ID,
|
||||
* 其余字段为报名、活动、项目和队伍的展示字段
|
||||
*/
|
||||
List<NutMap> listRepresentedApplies(String activityId);
|
||||
|
||||
/**
|
||||
* 按代表出战的系统工会归集活动报名,供工会提醒名单和报名人数共用。
|
||||
* @param activityId 活动 ID
|
||||
* @return 以系统工会 ID 为键、该工会报名记录列表为值的 Map
|
||||
*/
|
||||
Map<String, List<NutMap>> groupRepresentedAppliesByUnion(String activityId);
|
||||
|
||||
/**
|
||||
* 创建仅用于报名的用户;工号可采用 wy 年份流水号,也可手动填写。
|
||||
* @param username 外援姓名
|
||||
* @param sex 性别,男或女
|
||||
* @param birthday 出生日期,yyyy-MM-dd
|
||||
* @param loginname 留空时自动生成的工号;手动填写时不能与系统现有工号重复
|
||||
* @param idcard 身份证号,出生日期从中读取
|
||||
* @param mobile 手机号码
|
||||
* @param unitId 报名人所在单位 ID,用于归属当前报名工会
|
||||
* @return 已创建的系统用户,包含用户 ID 和自动生成的工号
|
||||
* @return 已创建的系统用户,包含用户 ID、最终工号和系统资料
|
||||
*/
|
||||
Sys_user createExternalUser(String username, String sex, String birthday, String mobile, String unitId);
|
||||
Sys_user createExternalUser(String username, String loginname, String sex, String idcard, String mobile, String unitId);
|
||||
|
||||
void doApplies(List<ActivitySchoolApply> applies);
|
||||
|
||||
|
||||
+134
-17
@@ -1,6 +1,7 @@
|
||||
package io.v.nutz.activity.services.impl;
|
||||
|
||||
|
||||
import cn.hutool.core.util.IdcardUtil;
|
||||
import io.v.nutz.activity.models.ActivityBasicUnion;
|
||||
import io.v.nutz.activity.models.ActivityBasicUnit;
|
||||
import io.v.nutz.activity.models.ActivitySchoolApply;
|
||||
@@ -8,11 +9,13 @@ import io.v.nutz.activity.services.ActivitySchoolApplyService;
|
||||
import io.v.nutz.base.utils.DateUtil;
|
||||
import io.v.nutz.service.impl.ViServiceImpl;
|
||||
import io.v.nutz.sys.models.Sys_user;
|
||||
import io.v.nutz.sys.models.Sys_unit;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Lang;
|
||||
@@ -30,6 +33,7 @@ import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
@IocBean(args = {"refer:dao"})
|
||||
@@ -41,44 +45,122 @@ public class ActivitySchoolApplyServiceImpl extends ViServiceImpl<ActivitySchool
|
||||
super(dao);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NutMap> getResultUnionOptions() {
|
||||
// 团体成绩可以选择未报名该项目的工会,因此从系统工会表完整读取。
|
||||
return listMap(Sqls.create("SELECT id, unionname FROM sys_union ORDER BY unioncode"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String previewExternalLoginname() {
|
||||
String prefix = "wy" + Year.now().getValue();
|
||||
Sql next = Sqls.create("SELECT COALESCE(MAX(CAST(SUBSTRING(loginname, 7) AS UNSIGNED)), 0) "
|
||||
+ "FROM sys_user WHERE loginname REGEXP @pattern");
|
||||
next.setParam("pattern", "^" + prefix + "[0-9]+$");
|
||||
next.setCallback(Sqls.callback.integer());
|
||||
dao().execute(next);
|
||||
int number = ((Number) next.getResult()).intValue() + 1;
|
||||
return prefix + String.format("%02d", number);
|
||||
Sql sql = Sqls.create("SELECT loginname FROM sys_user WHERE loginname LIKE @prefix");
|
||||
sql.setParam("prefix", prefix + "%");
|
||||
long number = 0;
|
||||
for (NutMap row : listMap(sql)) {
|
||||
String loginname = row.getString("loginname");
|
||||
if (Strings.isBlank(loginname) || !loginname.matches("^" + prefix + "[0-9]+$")) continue;
|
||||
try {
|
||||
number = Math.max(number, Long.parseLong(loginname.substring(prefix.length())));
|
||||
} catch (NumberFormatException ignored) {
|
||||
// 非法超长工号不参与流水号计算,保留其他有效工号的最大值。
|
||||
}
|
||||
}
|
||||
return prefix + String.format("%02d", number + 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NutMap> searchSystemUsers(String queryString, String[] excludedUserIds) {
|
||||
String query = Strings.sNull(queryString).trim();
|
||||
if (query.isEmpty()) return List.of();
|
||||
Sql sql = Sqls.create("SELECT u.id,u.loginname,u.username,u.sex,u.idcard,u.birthday,u.mobile,"
|
||||
+ "u.unitid,un.name unitname FROM sys_user u "
|
||||
+ "LEFT JOIN sys_unit un ON un.id=u.unitid $condition LIMIT 30");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.andEX("u.id", "not in", excludedUserIds);
|
||||
SqlExpressionGroup names = new SqlExpressionGroup();
|
||||
names.orLike("u.username", query).orLike("u.loginname", query);
|
||||
cnd.and(names);
|
||||
sql.setCondition(cnd);
|
||||
return listMap(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NutMap> listRepresentedApplies(String activityId) {
|
||||
// 兼容提交时曾写入操作人工会的外援记录;只有保存的单位 ID 和名称一致才采用所选单位的工会。
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT app.*, school.name activityName, school.applyType, school.belongUnionId,
|
||||
school.belongClubId, team.name team,
|
||||
COALESCE(NULLIF(app.unitname, ''), unit.name) unitname,
|
||||
ev.allName, ev.id evid, ev.projectType,
|
||||
CASE WHEN app.unitname = unit.name AND unit.unionid IS NOT NULL
|
||||
AND basicUnit.unionid IS NOT NULL THEN unit.unionid
|
||||
ELSE app.unionId END representedUnionId,
|
||||
CASE WHEN app.unitname = unit.name AND unit.unionid IS NOT NULL
|
||||
AND basicUnit.unionid IS NOT NULL THEN basicUnit.unionid
|
||||
ELSE app.activityUnionId END representedActivityUnionId
|
||||
FROM activity_school_apply app
|
||||
LEFT JOIN activity_school school ON school.id = app.activityId
|
||||
LEFT JOIN activity_school_team team ON team.id = app.teamId
|
||||
LEFT JOIN activity_event ev ON ev.id = app.eventId
|
||||
LEFT JOIN sys_unit unit ON unit.id = app.unitId
|
||||
LEFT JOIN activity_basic_unit basicUnit ON basicUnit.id = app.unitId
|
||||
WHERE app.activityId = @activityId
|
||||
ORDER BY ev.allName DESC, ev.projectType ASC, team.name ASC
|
||||
""").setParam("activityId", activityId);
|
||||
return listMap(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<NutMap>> groupRepresentedAppliesByUnion(String activityId) {
|
||||
return listRepresentedApplies(activityId).stream()
|
||||
.filter(row -> Strings.isNotBlank(row.getString("representedUnionId")))
|
||||
.collect(Collectors.groupingBy(row -> row.getString("representedUnionId")));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Sys_user createExternalUser(String username, String sex, String birthday, String mobile, String unitId) {
|
||||
public Sys_user createExternalUser(String username, String loginname, String sex, String idcard, String mobile, String unitId) {
|
||||
String name = Strings.sNull(username).trim();
|
||||
String account = Strings.sNull(loginname).trim();
|
||||
String card = Strings.sNull(idcard).trim().toUpperCase();
|
||||
String phone = Strings.sNull(mobile).trim();
|
||||
if (name.isEmpty() || name.length() > 50 || !("男".equals(sex) || "女".equals(sex))
|
||||
|| !phone.matches("^1[3456789]\\d{9}$")) {
|
||||
throw new IllegalArgumentException("请填写外援姓名、性别及正确的手机号码");
|
||||
}
|
||||
if (account.length() > 50) {
|
||||
throw new IllegalArgumentException("工号不能超过50位");
|
||||
}
|
||||
if (!card.matches("^[0-9]{17}[0-9X]$") || !IdcardUtil.isValidCard(card)) {
|
||||
throw new IllegalArgumentException("请填写正确的18位身份证号");
|
||||
}
|
||||
String birthday = card.substring(6, 10) + "-" + card.substring(10, 12) + "-" + card.substring(12, 14);
|
||||
try {
|
||||
LocalDate.parse(birthday);
|
||||
} catch (DateTimeParseException | NullPointerException e) {
|
||||
throw new IllegalArgumentException("请选择正确的出生年月");
|
||||
throw new IllegalArgumentException("身份证号中的出生日期不正确");
|
||||
}
|
||||
ActivityBasicUnit unit = dao().fetch(ActivityBasicUnit.class, unitId);
|
||||
if (unit == null || Strings.isBlank(unit.getUnionid())) {
|
||||
throw new IllegalArgumentException("当前报名单位未配置活动工会");
|
||||
}
|
||||
// 工号在服务端分配,避免多个浏览器按相同的前端预览号建人。
|
||||
// 自动工号与手填工号都在同一锁内查重,避免并发创建出相同账号。
|
||||
synchronized (EXTERNAL_NUMBER_LOCK) {
|
||||
if (account.isEmpty()) account = previewExternalLoginname();
|
||||
if (dao().count(Sys_user.class, Cnd.where("loginname", "=", account)) > 0) {
|
||||
throw new IllegalArgumentException("工号已存在,请更换工号");
|
||||
}
|
||||
if (dao().count(Sys_user.class, Cnd.where("idcard", "=", card)) > 0) {
|
||||
throw new IllegalArgumentException("身份证号已存在,请搜索并选择系统人员");
|
||||
}
|
||||
Sys_user user = new Sys_user();
|
||||
user.setId(R.UU32());
|
||||
user.setLoginname(previewExternalLoginname());
|
||||
user.setLoginname(account);
|
||||
user.setUsername(name);
|
||||
user.setSex(sex);
|
||||
user.setBirthday(birthday);
|
||||
user.setIdcard(card);
|
||||
user.setMobile(phone);
|
||||
user.setUnitid(unitId);
|
||||
user.setUnionid(unit.getUnionid());
|
||||
@@ -102,17 +184,52 @@ public class ActivitySchoolApplyServiceImpl extends ViServiceImpl<ActivitySchool
|
||||
public void doApplies(String activity, String union_id, String eventId,List<ActivitySchoolApply> applies) {
|
||||
for (ActivitySchoolApply apply : applies) {
|
||||
Sys_user user = Strings.isBlank(apply.getUserId()) ? null : dao().fetch(Sys_user.class, apply.getUserId());
|
||||
if (Strings.isNotBlank(apply.getIdCard())) {
|
||||
String card = apply.getIdCard().trim().toUpperCase();
|
||||
if (!IdcardUtil.isValidCard(card)) {
|
||||
throw new IllegalArgumentException("报名人员身份证号不正确");
|
||||
}
|
||||
apply.setIdCard(card);
|
||||
}
|
||||
if (user != null && user.isDisabled() && Strings.isNotBlank(user.getLoginname())
|
||||
&& user.getLoginname().matches("wy[0-9]{6,}")) {
|
||||
// 外援资料以创建时保存的用户记录为准,不接受浏览器修改工号或单位名称。
|
||||
// 工号和姓名保持系统身份;身份证、出生日期和电话保留本次报名的纠错值。
|
||||
apply.setLoginname(user.getLoginname());
|
||||
apply.setUsername(user.getUsername());
|
||||
apply.setSex(user.getSex());
|
||||
apply.setBirthday(user.getBirthday());
|
||||
apply.setMobile(user.getMobile());
|
||||
apply.setUnitId(user.getUnitid());
|
||||
apply.setUnitname("外援");
|
||||
if (Strings.isNotBlank(user.getSex())) apply.setSex(user.getSex());
|
||||
if (Strings.isBlank(apply.getIdCard())) apply.setIdCard(user.getIdcard());
|
||||
if (Strings.isBlank(apply.getBirthday())) apply.setBirthday(user.getBirthday());
|
||||
if (Strings.isBlank(apply.getMobile())) apply.setMobile(user.getMobile());
|
||||
if (Strings.isBlank(apply.getUnitId())) {
|
||||
apply.setUnitId(user.getUnitid());
|
||||
}
|
||||
if (Strings.isBlank(apply.getUnitname())) {
|
||||
throw new IllegalArgumentException("请填写外援报名单位");
|
||||
}
|
||||
}
|
||||
if (Strings.isNotBlank(apply.getUnitId()) && Strings.isNotBlank(apply.getUnitname())) {
|
||||
Sys_unit selectedUnit = dao().fetch(Sys_unit.class, apply.getUnitId());
|
||||
// 单位来自系统下拉时,所属工会就是本次代表出战的工会;手填单位保留报名人工会。
|
||||
if (selectedUnit != null && apply.getUnitname().trim().equals(selectedUnit.getName())) {
|
||||
ActivityBasicUnit activityUnit = dao().fetch(ActivityBasicUnit.class, apply.getUnitId());
|
||||
if (Strings.isBlank(selectedUnit.getUnionid()) || activityUnit == null
|
||||
|| Strings.isBlank(activityUnit.getUnionid())) {
|
||||
throw new IllegalArgumentException("所选单位未配置活动工会,不能确定代表出战的工会");
|
||||
}
|
||||
ActivityBasicUnion activityUnion = dao().fetch(ActivityBasicUnion.class, activityUnit.getUnionid());
|
||||
if (activityUnion == null) {
|
||||
throw new IllegalArgumentException("所选单位对应的活动工会不存在");
|
||||
}
|
||||
apply.setUnionId(selectedUnit.getUnionid());
|
||||
apply.setActivityUnionId(activityUnion.getId());
|
||||
apply.setActivityUnionName(activityUnion.getUnionname());
|
||||
}
|
||||
}
|
||||
}
|
||||
// 重存时清理本操作人以前代表其他工会报名的记录,避免换单位后留下重复报名。
|
||||
if (!applies.isEmpty()) {
|
||||
clear(Cnd.where("activityId", "=", activity).and("eventId", "=", eventId)
|
||||
.and("applyUser", "=", applies.get(0).getApplyUser()).and("activityUnionId", "!=", union_id));
|
||||
}
|
||||
clear(Cnd.where("activityId", "=", activity).and("activityUnionId", "=", union_id).and("eventId","=",eventId));
|
||||
doApplies(applies);
|
||||
|
||||
@@ -97,7 +97,11 @@ public class ActivitySchoolServiceImpl extends ViServiceImpl<ActivitySchool> imp
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public String doReuseAdd(String sourceId, ActivitySchool school, ActivitySchoolEvent[] events) {
|
||||
findReuseActivity(sourceId);
|
||||
if (school.getEventsIds() == null || school.getEventsIds().isEmpty()) {
|
||||
if (school.getEventsIds() == null) {
|
||||
school.setEventsIds(new java.util.ArrayList<>());
|
||||
}
|
||||
boolean isDraft = Integer.valueOf(1).equals(school.getIsSave());
|
||||
if (!isDraft && school.getEventsIds().isEmpty()) {
|
||||
throw new IllegalArgumentException("请选择活动项目");
|
||||
}
|
||||
ActivitySchoolEvent[] cleanEvents = Arrays.stream(events == null ? new ActivitySchoolEvent[0] : events)
|
||||
@@ -108,19 +112,22 @@ public class ActivitySchoolServiceImpl extends ViServiceImpl<ActivitySchool> imp
|
||||
event.setId(null);
|
||||
event.setActivityId(null);
|
||||
}).toArray(ActivitySchoolEvent[]::new);
|
||||
for (String eventId : school.getEventsIds()) {
|
||||
ActivityEvent event = dao().fetch(ActivityEvent.class, Cnd.where("id", "=", eventId).and("whetherEnable", "=", 1));
|
||||
if (event == null) {
|
||||
throw new IllegalArgumentException("所选项目已停用或不存在,请重新选择");
|
||||
}
|
||||
if (Arrays.stream(cleanEvents).noneMatch(config -> eventId.equals(config.getEventId()))) {
|
||||
throw new IllegalArgumentException("项目配置不完整,请进入下一步完善项目信息");
|
||||
// 草稿允许暂不选择或配置项目;正式提交仍需验证项目可用且配置齐全。
|
||||
if (!isDraft) {
|
||||
for (String eventId : school.getEventsIds()) {
|
||||
ActivityEvent event = dao().fetch(ActivityEvent.class, Cnd.where("id", "=", eventId).and("whetherEnable", "=", 1));
|
||||
if (event == null) {
|
||||
throw new IllegalArgumentException("所选项目已停用或不存在,请重新选择");
|
||||
}
|
||||
if (Arrays.stream(cleanEvents).noneMatch(config -> eventId.equals(config.getEventId()))) {
|
||||
throw new IllegalArgumentException("项目配置不完整,请进入下一步完善项目信息");
|
||||
}
|
||||
}
|
||||
}
|
||||
school.setId(null);
|
||||
school.setClose(false);
|
||||
school.setFoundDate(DateUtil.getDate());
|
||||
if (school.getActivityLevel() == 40002) {
|
||||
if (Integer.valueOf(40002).equals(school.getActivityLevel())) {
|
||||
school.setBelongUnionId(ActivityRoleUtil.getCurrentUnionId(dao()));
|
||||
} else {
|
||||
school.setBelongUnionId(null);
|
||||
@@ -166,7 +173,7 @@ public class ActivitySchoolServiceImpl extends ViServiceImpl<ActivitySchool> imp
|
||||
public String doAdd(ActivitySchool activitySchool, ActivitySchoolEvent[] events) {
|
||||
activitySchool.setClose(false);
|
||||
ActivitySchool school = insert(activitySchool);
|
||||
addTeam(school.getId(), events);
|
||||
addTeam(school.getId(), events == null ? new ActivitySchoolEvent[0] : events);
|
||||
return school.getId();
|
||||
|
||||
}
|
||||
@@ -174,7 +181,12 @@ public class ActivitySchoolServiceImpl extends ViServiceImpl<ActivitySchool> imp
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void doEdit(ActivitySchool activitySchool, ActivitySchoolEvent[] events, String applyEndTime) {
|
||||
long time = DateUtil.formatDate(applyEndTime);
|
||||
// 未填写报名结束时间的草稿也可再次保存;没有项目时按空配置处理。
|
||||
long time = Strings.isBlank(applyEndTime) ? 0 : DateUtil.formatDate(applyEndTime);
|
||||
if (activitySchool.getEventsIds() == null) {
|
||||
activitySchool.setEventsIds(new java.util.ArrayList<>());
|
||||
}
|
||||
ActivitySchoolEvent[] safeEvents = events == null ? new ActivitySchoolEvent[0] : events;
|
||||
long l = System.currentTimeMillis();
|
||||
|
||||
if (l < time) {
|
||||
@@ -191,7 +203,7 @@ public class ActivitySchoolServiceImpl extends ViServiceImpl<ActivitySchool> imp
|
||||
return !activitySchool.getEventsIds().contains(v.getEventId());
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
List<ActivitySchoolEvent> collect1 = Lang.array2list(events).stream().filter(v -> {
|
||||
List<ActivitySchoolEvent> collect1 = Lang.array2list(safeEvents).stream().filter(v -> {
|
||||
return !query.stream().map(x -> x.getEventId()).collect(Collectors.toList()).contains(v.getEventId()) && (v.getId() == null || !v.getId().equals("allItems"));
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
@@ -206,7 +218,7 @@ public class ActivitySchoolServiceImpl extends ViServiceImpl<ActivitySchool> imp
|
||||
if (collect1.size() > 0) {
|
||||
addTeam(activitySchool.getId(), collect1.toArray(new ActivitySchoolEvent[collect1.size()]));
|
||||
}
|
||||
for (ActivitySchoolEvent event : events) {
|
||||
for (ActivitySchoolEvent event : safeEvents) {
|
||||
update(event);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.entity.Record;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
@@ -67,16 +69,17 @@ public class ClothingRecordController {
|
||||
|
||||
@At
|
||||
@RequiresAuthentication
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Object doDelete(String projectId, String year, String userId) {
|
||||
|
||||
if(StrUtil.isBlank(projectId)) {
|
||||
Result.error("项目不能为空!");
|
||||
return Result.error("项目不能为空!");
|
||||
}
|
||||
if(StrUtil.isBlank(year)) {
|
||||
Result.error("年份不能为空!");
|
||||
return Result.error("年份不能为空!");
|
||||
}
|
||||
if(StrUtil.isBlank(userId)) {
|
||||
Result.error("登记人不能为空!");
|
||||
return Result.error("登记人不能为空!");
|
||||
}
|
||||
boolean b = clothingRegisterService.doDelete(projectId, year, userId);
|
||||
return b ? Result.success(): Result.error();
|
||||
@@ -104,6 +107,10 @@ public class ClothingRecordController {
|
||||
return b ? Result.success(): Result.error();
|
||||
}
|
||||
|
||||
/**
|
||||
* year 为活动报名年度,projectId 为活动ID,userId 为登记人ID;旧项目记录按登记年度筛选。
|
||||
* request 和 response 为当前 HTTP 请求及下载响应;返回值为 void,内容写入响应流。
|
||||
*/
|
||||
@At
|
||||
@Ok("void")
|
||||
public void doExport(String year, String projectId, String userId, HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
@@ -135,11 +142,13 @@ public class ClothingRecordController {
|
||||
FROM
|
||||
clothing_register c
|
||||
LEFT JOIN `user` u ON u.id = c.buyUserId
|
||||
LEFT JOIN activity_school s ON s.id = c.projectId
|
||||
$condition
|
||||
""");
|
||||
cnd.and("year(ctime)", "=", year);
|
||||
cnd.and("projectId", "=", projectId);
|
||||
cnd.and("userId", "=", userId);
|
||||
// 导出与台账采用同一业务年度,旧项目记录回退到登记年度。
|
||||
cnd.and("COALESCE(YEAR(s.applyStartTime), YEAR(c.ctime))", "=", year);
|
||||
cnd.and("c.projectId", "=", projectId);
|
||||
cnd.and("c.userId", "=", userId);
|
||||
sql.setCondition(cnd);
|
||||
List<Record> buyUserList = clothingRegisterService.list(sql);
|
||||
for (int i = 0; i < buyUserList.size(); i++) {
|
||||
|
||||
@@ -13,6 +13,8 @@ import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.entity.Record;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
@@ -41,30 +43,43 @@ public class ClothingRegisterController {
|
||||
@RequiresPermissions("clothing.register")
|
||||
public void index() {}
|
||||
|
||||
/** pageForm 为分页和姓名工号条件;projectId 为活动ID;isBuy 为购买状态;sex、unionId 为可选筛选,返回人员分页数据。 */
|
||||
@At
|
||||
@ViReturn
|
||||
public Object pageData(PageForm pageForm, Integer year, String projectId, Boolean isBuy, String sex, String unionId) {
|
||||
public Object pageData(PageForm pageForm, String projectId, Boolean isBuy, String sex, String unionId) {
|
||||
|
||||
return clothingRegisterService.getRegisterUser(pageForm, year, projectId, isBuy, sex, unionId);
|
||||
return clothingRegisterService.getRegisterUser(pageForm, projectId, isBuy, sex, unionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* ids 为所选人员ID;projectId 为活动ID,购买限制以该活动的报名年度和已选项目为准;
|
||||
* isBuy 为购买状态,true 时仅移除当前活动记录,false 时登记;
|
||||
* 成功返回 null 由 ViReturn 包装,业务校验失败返回含错误说明的 Result。
|
||||
*/
|
||||
@At
|
||||
@ViReturn
|
||||
public Object doHandler(String[] ids, String projectId, Integer year, Boolean isBuy) {
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Object doHandler(String[] ids, String projectId, Boolean isBuy) {
|
||||
|
||||
if(!isBuy) {
|
||||
clothingRegisterService.add(ids, projectId);
|
||||
} else {
|
||||
clothingRegisterService.removeBuyUser(ids, projectId, year);
|
||||
try {
|
||||
if(!Boolean.TRUE.equals(isBuy)) {
|
||||
clothingRegisterService.add(ids, projectId);
|
||||
} else {
|
||||
clothingRegisterService.removeBuyUser(ids, projectId);
|
||||
}
|
||||
} catch (IllegalArgumentException exception) {
|
||||
// 重复购衣等业务校验错误直接返回给页面,供提交按钮显示明确原因。
|
||||
return Result.error(exception.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** year 为空时返回全部已提交活动,否则按报名开始时间所属年度筛选;data 数组的每项包含活动 id 和 name。 */
|
||||
@At
|
||||
@ViReturn
|
||||
public Object getBuyClothesProject() {
|
||||
public Object getBuyClothesProject(Integer year) {
|
||||
|
||||
return clothingRegisterService.getBuyClothesProject();
|
||||
return clothingRegisterService.getBuyClothesProject(year);
|
||||
}
|
||||
|
||||
@At
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package io.v.nutz.clothing.services;
|
||||
|
||||
import cn.wizzer.framework.page.Pagination;
|
||||
import io.v.nutz.activity.models.ActivityBasicSettings;
|
||||
import io.v.nutz.clothing.models.ClothingRegister;
|
||||
import io.v.nutz.modules.models.PageForm;
|
||||
import io.v.nutz.service.ViService;
|
||||
@@ -20,29 +19,31 @@ public interface ClothingRegisterService extends ViService<ClothingRegister> {
|
||||
/**
|
||||
* 列表查询
|
||||
*
|
||||
* @param pageForm: 表单
|
||||
* @param projectId: 项目id
|
||||
* @param year: 年份
|
||||
* @return io.v.nutz.base.page.Pagination
|
||||
* @param pageForm: 分页及查询表单
|
||||
* @param projectId: 活动ID,可为空
|
||||
* @param year: 活动报名年度;旧项目记录按登记年度筛选
|
||||
* @param unionId: 工会ID,可为空
|
||||
* @return Pagination,list 为按活动、登记人和年度分组的台账,totalCount 为分组总数
|
||||
* @author JyuHsin
|
||||
* @date 2022/12/5
|
||||
*/
|
||||
Pagination pageData(PageForm pageForm, String projectId, String year, String unionId);
|
||||
|
||||
/**
|
||||
* 获取所有买服装的项目
|
||||
* @author JyuHsin
|
||||
* @date 2022/12/5
|
||||
* @return java.util.List<io.v.nutz.activity.models.ActivityBasicSettings>
|
||||
* 获取已提交的校级活动,供服装登记、记录和台账选择项目。
|
||||
* year 为空时返回全部年度,否则按活动报名开始时间所属年度筛选。
|
||||
* 返回的每项包含活动 id(作为 projectId 保存和筛选)及 name(下拉显示名称)。
|
||||
*/
|
||||
List<ActivityBasicSettings> getBuyClothesProject();
|
||||
List<NutMap> getBuyClothesProject(Integer year);
|
||||
|
||||
/**
|
||||
* 获取项目人员名单
|
||||
* @author JyuHsin
|
||||
* @date 2022/12/5
|
||||
* @param projectId: 项目id
|
||||
* @return java.util.List<org.nutz.lang.util.NutMap>
|
||||
* @param projectId: 活动ID
|
||||
* @param userId: 登记人ID
|
||||
* @param year: 活动报名年度,可为空;旧项目记录按登记年度筛选
|
||||
* @return 人员列表,每项包含购买人资料及登记记录
|
||||
*/
|
||||
List<NutMap> findBuyClothesUser(String projectId, String userId, String year);
|
||||
|
||||
@@ -50,28 +51,25 @@ public interface ClothingRegisterService extends ViService<ClothingRegister> {
|
||||
* 删除
|
||||
* @author JyuHsin
|
||||
* @date 2022/12/5
|
||||
* @param projectId: 项目id
|
||||
* @param year: 年份
|
||||
* @param userId: 登记人
|
||||
* @return void
|
||||
* @param projectId: 活动ID
|
||||
* @param year: 活动报名年度;旧项目记录按登记年度删除
|
||||
* @param userId: 登记人ID
|
||||
* @return 是否完成指定活动、年度和登记人的删除
|
||||
*/
|
||||
boolean doDelete(String projectId, String year, String userId);
|
||||
|
||||
/**
|
||||
* 服装登记菜单查询用户
|
||||
* @author JyuHsin
|
||||
* @date 2022/12/5
|
||||
* @param pageForm:
|
||||
* @param year:
|
||||
* @param projectId:
|
||||
* @param isBuy:
|
||||
* @return cn.wizzer.framework.page.Pagination
|
||||
* 查询服装登记人员。pageForm 包含页码、页大小和姓名或工号查询条件;projectId 为当前活动ID;
|
||||
* isBuy 为购买状态,true 返回与活动年度相差不超过一年且同类项目已购买的人员,false 返回未购买人员;
|
||||
* sex 为可选性别,unionId 为可选工会ID。返回 Pagination,list 为人员及可移除状态,totalCount 为总人数。
|
||||
*/
|
||||
Pagination getRegisterUser(PageForm pageForm, Integer year, String projectId, Boolean isBuy, String sex, String unionId);
|
||||
Pagination getRegisterUser(PageForm pageForm, String projectId, Boolean isBuy, String sex, String unionId);
|
||||
|
||||
/** ids 为本次登记的人员ID,projectId 为活动ID;两年内同类项目已有购买记录时拒绝提交。 */
|
||||
Object add(String[] ids, String projectId);
|
||||
|
||||
boolean removeBuyUser(String[] ids, String projectId, Integer year);
|
||||
/** ids 为人员ID,projectId 为当前活动ID;仅移除当前活动的登记记录,不删除其他同类活动的历史记录。 */
|
||||
boolean removeBuyUser(String[] ids, String projectId);
|
||||
|
||||
boolean deleteBuyUser(String id);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package io.v.nutz.clothing.services.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.wizzer.framework.page.Pagination;
|
||||
import io.v.nutz.activity.models.ActivityBasicSettings;
|
||||
import io.v.nutz.activity.models.ActivitySchool;
|
||||
import io.v.nutz.base.utils.DateUtil;
|
||||
import io.v.nutz.base.utils.Vi;
|
||||
import io.v.nutz.clothing.models.ClothingRegister;
|
||||
@@ -20,13 +20,18 @@ import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.Static;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Strings;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.trans.Trans;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @Author JyuHsin
|
||||
@@ -48,14 +53,15 @@ public class ClothingRegisterServiceImpl extends ViServiceImpl<ClothingRegister>
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
c.*,
|
||||
YEAR ( c.ctime ) AS `year`,
|
||||
COALESCE(YEAR(s.applyStartTime), YEAR(c.ctime)) AS `year`,
|
||||
u.username,
|
||||
u.unionname,
|
||||
a.name AS projectName,
|
||||
COALESCE(s.name, a.name) AS projectName,
|
||||
count(c.buyUserId) AS buyCount
|
||||
FROM
|
||||
clothing_register c
|
||||
LEFT JOIN `user` u ON u.id = c.userId
|
||||
LEFT JOIN activity_school s ON s.id = c.projectId
|
||||
LEFT JOIN activity_basic_settings a ON a.CODE = c.projectId
|
||||
$condition
|
||||
""");
|
||||
@@ -65,8 +71,9 @@ public class ClothingRegisterServiceImpl extends ViServiceImpl<ClothingRegister>
|
||||
}
|
||||
cnd.andExcludeEmpty("u.unionId", "=", unionId);
|
||||
cnd.andExcludeEmpty("c.projectId", "=", projectId);
|
||||
cnd.andExcludeEmpty("year(c.ctime)", "=", year);
|
||||
cnd.groupBy("c.userId");
|
||||
// 活动记录按报名年度归档;无法关联活动的旧记录仍按实际登记年度展示。
|
||||
cnd.andExcludeEmpty("COALESCE(YEAR(s.applyStartTime), YEAR(c.ctime))", "=", year);
|
||||
cnd.groupBy("c.projectId", "c.userId", "COALESCE(YEAR(s.applyStartTime), YEAR(c.ctime))");
|
||||
cnd.desc("year").asc("projectId");
|
||||
sql.setCondition(cnd);
|
||||
|
||||
@@ -74,8 +81,17 @@ public class ClothingRegisterServiceImpl extends ViServiceImpl<ClothingRegister>
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ActivityBasicSettings> getBuyClothesProject() {
|
||||
return dao().query(ActivityBasicSettings.class, Cnd.where("clothing", "is not", null));
|
||||
public List<NutMap> getBuyClothesProject(Integer year) {
|
||||
// isSave=1 是草稿;历史已提交活动可能为 NULL,需与活动管理页的判定保持一致。
|
||||
CndPlus cnd = CndPlus.create();
|
||||
cnd.and(new Static("(isSave IS NULL OR isSave <> 1)"));
|
||||
cnd.andExcludeEmpty("YEAR(applyStartTime)", "=", year);
|
||||
cnd.desc("startTime").desc("foundDate");
|
||||
return listMap(Sqls.create("""
|
||||
SELECT id, name
|
||||
FROM activity_school
|
||||
$condition
|
||||
""").setCondition(cnd));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -94,26 +110,38 @@ public class ClothingRegisterServiceImpl extends ViServiceImpl<ClothingRegister>
|
||||
FROM
|
||||
clothing_register c
|
||||
LEFT JOIN `user` u ON u.id = c.buyUserId
|
||||
LEFT JOIN activity_school s ON s.id = c.projectId
|
||||
$condition
|
||||
""");
|
||||
cnd.andExcludeEmpty("c.projectId", "=", projectId);
|
||||
cnd.andExcludeEmpty("c.userId", "=", userId);
|
||||
cnd.andExcludeEmpty("year(c.ctime)", "=", year);
|
||||
cnd.andExcludeEmpty("COALESCE(YEAR(s.applyStartTime), YEAR(c.ctime))", "=", year);
|
||||
|
||||
sql.setCondition(cnd);
|
||||
return listMap(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public boolean doDelete(String projectId, String year, String userId) {
|
||||
|
||||
int clearCount = dao().clear(ClothingRegister.class, Cnd.where("projectId", "=", projectId)
|
||||
.and("year(ctime)", "=", year).and("userId", "=", userId));
|
||||
Cnd cnd = Cnd.where("projectId", "=", projectId).and("userId", "=", userId);
|
||||
ActivitySchool school = dao().fetch(ActivitySchool.class, projectId);
|
||||
String applyStartTime = school == null ? null : school.getApplyStartTime();
|
||||
// 新活动以报名年度定位整组登记;旧项目没有活动年度时沿用登记时间筛选。
|
||||
if (Strings.isNotBlank(applyStartTime) && applyStartTime.length() >= 4) {
|
||||
if (!year.equals(applyStartTime.substring(0, 4))) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
cnd.and("year(ctime)", "=", year);
|
||||
}
|
||||
int clearCount = dao().clear(ClothingRegister.class, cnd);
|
||||
return clearCount >= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pagination getRegisterUser(PageForm pageForm, Integer year, String projectId, Boolean isBuy, String sex, String unionId) {
|
||||
public Pagination getRegisterUser(PageForm pageForm, String projectId, Boolean isBuy, String sex, String unionId) {
|
||||
|
||||
CndPlus cnd = CndPlus.create();
|
||||
Sql sql = Sqls.create("""
|
||||
@@ -129,20 +157,105 @@ public class ClothingRegisterServiceImpl extends ViServiceImpl<ClothingRegister>
|
||||
if (Strings.isNotBlank(pageForm.getSearchName()) && Strings.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
cnd.where().andLike(pageForm.getSearchName(), pageForm.getSearchKeyword());
|
||||
}
|
||||
if(year != null) {
|
||||
int lastYear = year - 1;
|
||||
cnd.and(new Static("id %s (select buyUserId from clothing_register where projectId = '%s' and (year(ctime) = '%s' or year(ctime) = '%s'))"
|
||||
.formatted(isBuy ? "in" : "not in", projectId, year, lastYear)));
|
||||
if (Strings.isBlank(projectId)) {
|
||||
// 没有活动时不能把全部会员误显示为该活动的“未购买”人员。
|
||||
cnd.and(new Static("1 = 0"));
|
||||
} else {
|
||||
// 活动名称和ID每年可能变化,购买状态按活动选中项目的运动项目及活动年度判断。
|
||||
Set<String> purchasedIds = findPurchasedUserIds(projectId);
|
||||
if (purchasedIds.isEmpty()) {
|
||||
if (Boolean.TRUE.equals(isBuy)) cnd.and(new Static("1 = 0"));
|
||||
} else {
|
||||
cnd.and("u.id", Boolean.TRUE.equals(isBuy) ? "in" : "not in", purchasedIds.toArray(new String[0]));
|
||||
}
|
||||
}
|
||||
sql.setCondition(cnd);
|
||||
return listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
Pagination result = listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
if (Boolean.TRUE.equals(isBuy) && Strings.isNotBlank(projectId)) {
|
||||
// 历史活动中已购买的人员可查看,但只能移除当前活动自身的登记记录。
|
||||
Set<String> currentIds = listMap(Sqls.create("SELECT DISTINCT buyUserId AS buy_user_id FROM clothing_register WHERE projectId = @projectId")
|
||||
.setParam("projectId", projectId)).stream()
|
||||
.map(row -> row.getString("buy_user_id")).collect(Collectors.toSet());
|
||||
List<NutMap> users = result.getList();
|
||||
users.forEach(user -> user.setv("canRemove", currentIds.contains(user.getString("id"))));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* projectId 为当前活动ID;返回该活动选择的运动项目标识。项目未配置 sports 时以项目ID兜底,
|
||||
* 避免把不同项目误判为同类;已选项目为空时拒绝登记,防止绕过重复购买限制。
|
||||
*/
|
||||
private List<String> getSelectedSportKeys(String projectId) {
|
||||
List<NutMap> events = listMap(Sqls.create("""
|
||||
SELECT DISTINCT COALESCE(NULLIF(ae.sports, ''), ae.id) AS sport_key
|
||||
FROM activity_school_event ase
|
||||
JOIN activity_event ae ON ae.id = ase.eventId
|
||||
WHERE ase.activityId = @projectId
|
||||
""").setParam("projectId", projectId));
|
||||
List<String> keys = events.stream().map(event -> event.getString("sport_key"))
|
||||
.filter(Strings::isNotBlank).distinct().collect(Collectors.toList());
|
||||
if (keys.isEmpty()) throw new IllegalArgumentException("当前活动未配置可识别的活动项目,无法登记服装");
|
||||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* projectId 为当前活动ID;返回与活动年度相差不超过一年、购买过任一相同运动项目服装的人员ID。
|
||||
* 年度取活动报名开始时间,避免跨年补登记时因 clothing_register.ctime 不同而漏判。
|
||||
*/
|
||||
private Set<String> findPurchasedUserIds(String projectId) {
|
||||
ActivitySchool school = dao().fetch(ActivitySchool.class, projectId);
|
||||
if (school == null || Integer.valueOf(1).equals(school.getIsSave())) {
|
||||
throw new IllegalArgumentException("活动不存在或尚未提交");
|
||||
}
|
||||
String applyStartTime = school.getApplyStartTime();
|
||||
if (Strings.isBlank(applyStartTime) || applyStartTime.length() < 4) {
|
||||
throw new IllegalArgumentException("当前活动未设置报名开始时间,无法判断两年购买范围");
|
||||
}
|
||||
int activityYear;
|
||||
try {
|
||||
activityYear = Integer.parseInt(applyStartTime.substring(0, 4));
|
||||
} catch (NumberFormatException exception) {
|
||||
throw new IllegalArgumentException("当前活动报名开始时间格式不正确", exception);
|
||||
}
|
||||
List<String> sportKeys = getSelectedSportKeys(projectId);
|
||||
CndPlus cnd = CndPlus.create();
|
||||
// 补录历史活动时也要检查后一年的购买记录,避免登记顺序改变查重结果。
|
||||
cnd.and("YEAR(s.applyStartTime)", "in", new Integer[]{activityYear - 1, activityYear, activityYear + 1});
|
||||
cnd.and("COALESCE(NULLIF(ae.sports, ''), ae.id)", "in", sportKeys.toArray(new String[0]));
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT DISTINCT c.buyUserId AS buy_user_id
|
||||
FROM clothing_register c
|
||||
JOIN activity_school s ON s.id = c.projectId
|
||||
JOIN activity_school_event ase ON ase.activityId = s.id
|
||||
JOIN activity_event ae ON ae.id = ase.eventId
|
||||
$condition
|
||||
""").setCondition(cnd);
|
||||
return listMap(sql).stream().map(row -> row.getString("buy_user_id"))
|
||||
.filter(Strings::isNotBlank).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Object add(String[] ids, String projectId) {
|
||||
|
||||
if (ids == null || ids.length == 0 || Strings.isBlank(projectId)) {
|
||||
throw new IllegalArgumentException("请选择活动和登记人员");
|
||||
}
|
||||
List<String> userIds = Arrays.stream(ids).filter(Strings::isNotBlank).distinct().sorted().collect(Collectors.toList());
|
||||
if (userIds.isEmpty()) throw new IllegalArgumentException("请选择登记人员");
|
||||
// 锁定人员行后再查重,防止并发提交同时通过两年内同项目的校验。
|
||||
for (String id : userIds) {
|
||||
if (listMap(Sqls.create("SELECT id FROM `user` WHERE id = @id FOR UPDATE").setParam("id", id)).isEmpty()) {
|
||||
throw new IllegalArgumentException("所选人员不存在,请刷新名单");
|
||||
}
|
||||
}
|
||||
Set<String> purchasedIds = findPurchasedUserIds(projectId);
|
||||
if (userIds.stream().anyMatch(purchasedIds::contains)) {
|
||||
throw new IllegalArgumentException("所选人员在近两年内已购买同类项目服装,不能重复提交,请刷新名单");
|
||||
}
|
||||
List<ClothingRegister> clothingRegisterList = new ArrayList<>();
|
||||
for (String id : ids) {
|
||||
for (String id : userIds) {
|
||||
ClothingRegister clothingRegister = new ClothingRegister();
|
||||
clothingRegister.setProjectId(projectId);
|
||||
clothingRegister.setUserId(ShiroUtil.getPrincipalProperty("id").toString());
|
||||
@@ -154,12 +267,17 @@ public class ClothingRegisterServiceImpl extends ViServiceImpl<ClothingRegister>
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeBuyUser(String[] ids, String projectId, Integer year) {
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public boolean removeBuyUser(String[] ids, String projectId) {
|
||||
|
||||
if (ids == null || ids.length == 0 || Strings.isBlank(projectId)) {
|
||||
throw new IllegalArgumentException("请选择当前活动中需要移除的人员");
|
||||
}
|
||||
Trans.exec(() -> {
|
||||
for (String id : ids) {
|
||||
dao().clear(ClothingRegister.class, Cnd.where("projectId", "=", projectId)
|
||||
.and("year(ctime)", "=", year).and("buyUserId", "=", id));
|
||||
Cnd cnd = Cnd.where("projectId", "=", projectId).and("buyUserId", "=", id);
|
||||
// 同类历史活动的购买记录仍保留,仅删除当前活动中选中的登记。
|
||||
dao().clear(ClothingRegister.class, cnd);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -14,4 +14,9 @@ public interface SysConfigService extends BaseService<Sys_config> {
|
||||
* @return
|
||||
*/
|
||||
List<Sys_config> getAllList();
|
||||
|
||||
/**
|
||||
* 确保系统配置中存在学校待办开关;首次创建时默认关闭。
|
||||
*/
|
||||
void ensureTodoTaskConfig();
|
||||
}
|
||||
|
||||
@@ -3,8 +3,10 @@ package io.v.nutz.sys.services.impl;
|
||||
import io.v.nutz.base.service.impl.BaseServiceImpl;
|
||||
import io.v.nutz.sys.models.Sys_config;
|
||||
import io.v.nutz.sys.services.SysConfigService;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
import java.util.List;
|
||||
@@ -21,4 +23,16 @@ public class SysConfigServiceImpl extends BaseServiceImpl<Sys_config> implements
|
||||
public List<Sys_config> getAllList() {
|
||||
return this.query(Cnd.where("delFlag", "=", false));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void ensureTodoTaskConfig() {
|
||||
if (fetch("TodoTaskEnabled") == null) {
|
||||
Sys_config config = new Sys_config();
|
||||
config.setConfigKey("TodoTaskEnabled");
|
||||
config.setConfigValue("false");
|
||||
config.setNote("启用学校统一待办推送、更新和删除;关闭时不调用学校待办网关");
|
||||
insert(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import io.v.nutz.sys.models.Sys_config;
|
||||
import io.v.nutz.sys.services.SysConfigService;
|
||||
import io.v.nutz.web.commons.utils.ShiroUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.dao.Dao;
|
||||
@@ -26,6 +28,17 @@ import java.util.Map;
|
||||
@Slf4j
|
||||
public class TodoTaskInterfaceImpl implements TodoTaskInterface {
|
||||
|
||||
/**
|
||||
* 只有系统配置明确开启时,才调用学校统一待办网关。
|
||||
*/
|
||||
private boolean isTodoTaskEnabled() {
|
||||
Sys_config config = sysConfigService.fetch("TodoTaskEnabled");
|
||||
return config != null && "true".equals(config.getConfigValue());
|
||||
}
|
||||
|
||||
@Inject
|
||||
private SysConfigService sysConfigService;
|
||||
|
||||
@Inject
|
||||
private RedisService redisService;
|
||||
|
||||
@@ -52,6 +65,9 @@ public class TodoTaskInterfaceImpl implements TodoTaskInterface {
|
||||
|
||||
@Override
|
||||
public void pushTask(TodoTask todoTask) {
|
||||
if (!isTodoTaskEnabled()) {
|
||||
return;
|
||||
}
|
||||
log.info("【推送待办入参】:" + Json.toJson(todoTask));
|
||||
String accessToken = getAccessToken();
|
||||
HttpRequest httpRequest = HttpUtil.createPost(TodoTaskConstants.PUSH_TASK_URL);
|
||||
@@ -69,6 +85,9 @@ public class TodoTaskInterfaceImpl implements TodoTaskInterface {
|
||||
|
||||
@Override
|
||||
public void updateTask(TodoTask todoTask) {
|
||||
if (!isTodoTaskEnabled()) {
|
||||
return;
|
||||
}
|
||||
log.info("【更新待办入参】:" + Json.toJson(todoTask));
|
||||
String accessToken = getAccessToken();
|
||||
HttpRequest httpRequest = HttpUtil.createPost(TodoTaskConstants.UPDATE_TASK_URL);
|
||||
@@ -86,6 +105,9 @@ public class TodoTaskInterfaceImpl implements TodoTaskInterface {
|
||||
|
||||
@Override
|
||||
public void deleteTask(TodoTask todoTask) {
|
||||
if (!isTodoTaskEnabled()) {
|
||||
return;
|
||||
}
|
||||
log.info("【删除待办入参】:" + Json.toJson(todoTask));
|
||||
String accessToken = getAccessToken();
|
||||
HttpRequest httpRequest = HttpUtil.createPost(TodoTaskConstants.DELETE_TASK_URL);
|
||||
|
||||
@@ -34,7 +34,7 @@ public class SysConfController {
|
||||
@Ok("beetl:/platform/sys/conf/index.html")
|
||||
@RequiresPermissions("sys.manager.conf")
|
||||
public void index() {
|
||||
|
||||
sysConfigService.ensureTodoTaskConfig();
|
||||
}
|
||||
|
||||
@At
|
||||
|
||||
@@ -27,6 +27,8 @@ import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Lang;
|
||||
@@ -98,7 +100,12 @@ public class CondolenceApplyCon {
|
||||
|
||||
@At
|
||||
@ViReturn
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Object doAdd(@Param("data") Condolence condolence, String sign) {
|
||||
if (condolenceService.hasHospitalCondolenceInCurrentYear(condolence)) {
|
||||
return Result.error().addMsg("住院慰问每年只能申请一次,请于下一年度再申请");
|
||||
}
|
||||
|
||||
List<Sys_file> files = condolence.getFiles();
|
||||
if (Lang.isEmpty(files)) {
|
||||
condolence.setFiles_num("0");
|
||||
|
||||
@@ -19,6 +19,14 @@ public interface CondolenceService extends ViService<Condolence> {
|
||||
*/
|
||||
NutMap findOne(String id);
|
||||
|
||||
/**
|
||||
* 判断被慰问人在当前自然年是否已有住院慰问申请。
|
||||
*
|
||||
* @param application 本次申请,包含慰问类型、被慰问人和编辑时的申请 ID
|
||||
* @return 已有其他同年住院慰问申请时返回 true,否则返回 false
|
||||
*/
|
||||
boolean hasHospitalCondolenceInCurrentYear(Condolence application);
|
||||
|
||||
/**
|
||||
* 添加
|
||||
*
|
||||
|
||||
@@ -2,9 +2,11 @@ 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.modules.services.ReviewService;
|
||||
import io.v.nutz.service.impl.ViServiceImpl;
|
||||
import io.v.nutz.zgfw.model.condolence.Condolence;
|
||||
import io.v.nutz.zgfw.model.condolence.CondolenceType;
|
||||
import io.v.nutz.zgfw.service.CondolenceService;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Cnd;
|
||||
@@ -28,9 +30,30 @@ public class CondolenceServiceImpl extends ViServiceImpl<Condolence> implements
|
||||
private ReviewService reviewService;
|
||||
@Inject
|
||||
private BaseService baseService;
|
||||
private final Dao condolenceDao;
|
||||
|
||||
public CondolenceServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
this.condolenceDao = dao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasHospitalCondolenceInCurrentYear(Condolence application) {
|
||||
CondolenceType type = condolenceDao.fetch(CondolenceType.class, application.getType());
|
||||
if (type == null || !"C".equals(type.getCode())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 按被慰问人和申请年份限制次数;编辑时排除当前申请,已退回的其他申请仍计入次数。
|
||||
String year = String.valueOf(DateUtil.getYear());
|
||||
Cnd cnd = Cnd.where("be_user", "=", application.getBe_user())
|
||||
.and("type", "=", application.getType())
|
||||
.and("apply_time", ">=", year + "-01-01")
|
||||
.and("apply_time", "<", (DateUtil.getYear() + 1) + "-01-01");
|
||||
if (Strings.isNotBlank(application.getId())) {
|
||||
cnd.and("id", "!=", application.getId());
|
||||
}
|
||||
return count(cnd) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -38,10 +38,14 @@ window.activity = {
|
||||
2: '部门工会报名',
|
||||
3: '小程序报名'
|
||||
},
|
||||
getStatus(close, applyStartTime, applyEndTime, startTime, endTime) {
|
||||
getStatus(close, applyStartTime, applyEndTime, startTime, endTime, isSave) {
|
||||
if (close) {
|
||||
return `<span class="text-danger">活动已关闭</span>`
|
||||
}
|
||||
// 管理列表传入 isSave;已保存但未提交的活动尚未开放报名。
|
||||
if (isSave === true || isSave === 1 || isSave === '1') {
|
||||
return `<span class="text-info">未提交</span>`
|
||||
}
|
||||
const now = moment().valueOf()
|
||||
const dateNow = moment(moment(moment().format('YYYY-MM-DD')).valueOf()).valueOf()
|
||||
|
||||
@@ -67,4 +71,4 @@ window.activity = {
|
||||
return false
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -649,7 +649,6 @@ module.exports = {
|
||||
applyTime: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
unitSponsor: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
// unitJointly: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
time: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
activityGroupId: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
gameStyle: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
applyWay: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
@@ -777,7 +776,8 @@ module.exports = {
|
||||
},
|
||||
// 合并当前所选项目与已沿用配置;新增选择使用原有默认值,已移除项目不再提交。
|
||||
buildReuseEvents() {
|
||||
return this.events.filter((event) => this.form.eventsIds.includes(event.id)).map((event) => {
|
||||
const selectedIds = this.form.eventsIds || []
|
||||
return this.events.filter((event) => selectedIds.includes(event.id)).map((event) => {
|
||||
const existing = this.checkedEventInfo.find((config) => config.eventId === event.id)
|
||||
const config = existing ? clone(existing) : {
|
||||
eventId: event.id, projectType: event.projectType, leanderNum: 0, coachNum: 0,
|
||||
@@ -792,7 +792,7 @@ module.exports = {
|
||||
return config
|
||||
})
|
||||
},
|
||||
// isSave 区分保存和提交;新接口返回新活动ID,保存成功后转入该新活动的编辑状态。
|
||||
// isSave 区分保存草稿和提交;草稿跳过字段校验,提交仍校验报名、活动及项目配置。
|
||||
doReuseAdd(isSave) {
|
||||
if (this.formLoading || this.reuseLoading) return
|
||||
if (!this.reuseReady) {
|
||||
@@ -801,70 +801,66 @@ module.exports = {
|
||||
}
|
||||
const save = () => {
|
||||
const form = clone(this.form)
|
||||
if (!form.applyTime || form.applyTime.length !== 2 || !form.time || form.time.length !== 2) {
|
||||
this.$message.warning('请重新填写报名日期和活动时间')
|
||||
return
|
||||
}
|
||||
if (moment(form.time[0]).valueOf() <= moment(form.applyTime[0]).valueOf()) {
|
||||
this.$message.error('活动时间必须晚于报名时间')
|
||||
return
|
||||
}
|
||||
if (!form.eventsIds.length) {
|
||||
this.$message.warning('请选择活动项目')
|
||||
return
|
||||
}
|
||||
if (this.getArrDifference(form.unitJointly, form.unitSponsor).length === 0) {
|
||||
this.$message.error('协办单位里存在主办单位')
|
||||
return
|
||||
if (!isSave) {
|
||||
if (!form.applyTime || form.applyTime.length !== 2 || !form.applyTime[0] || !form.applyTime[1]) {
|
||||
this.$message.warning('请填写报名日期')
|
||||
return
|
||||
}
|
||||
if (!form.time || form.time.length !== 2 || !form.time[0] || !form.time[1]) {
|
||||
this.$message.warning('请填写活动时间')
|
||||
return
|
||||
}
|
||||
if (moment(form.time[0]).valueOf() <= moment(form.applyTime[0]).valueOf()) {
|
||||
this.$message.error('活动时间必须晚于报名时间')
|
||||
return
|
||||
}
|
||||
if (!form.eventsIds || !form.eventsIds.length) {
|
||||
this.$message.warning('请选择活动项目')
|
||||
return
|
||||
}
|
||||
if (this.getArrDifference(form.unitJointly || [], form.unitSponsor || []).length === 0) {
|
||||
this.$message.error('协办单位里存在主办单位')
|
||||
return
|
||||
}
|
||||
}
|
||||
this.$set(form, 'id', null)
|
||||
this.$set(form, 'isSave', isSave)
|
||||
this.$set(form, 'applyStartTime', form.applyTime[0])
|
||||
this.$set(form, 'applyEndTime', form.applyTime[1])
|
||||
this.$set(form, 'startTime', form.time[0])
|
||||
this.$set(form, 'endTime', form.time[1])
|
||||
this.$set(form, 'isSave', isSave ? 1 : 0)
|
||||
// 草稿可没有报名和活动时间,缺失时明确传 null,避免复制旧活动日期。
|
||||
this.$set(form, 'applyStartTime', form.applyTime && form.applyTime[0] && form.applyTime[1] ? form.applyTime[0] : null)
|
||||
this.$set(form, 'applyEndTime', form.applyTime && form.applyTime[0] && form.applyTime[1] ? form.applyTime[1] : null)
|
||||
this.$set(form, 'startTime', form.time && form.time[0] && form.time[1] ? form.time[0] : null)
|
||||
this.$set(form, 'endTime', form.time && form.time[0] && form.time[1] ? form.time[1] : null)
|
||||
this.$set(this, 'formLoading', true)
|
||||
const loading = this.$loading({lock: true, text: '正在提交...', background: COVER_LAYER_COLOR})
|
||||
return $.post('/platform/activity/school/info/mange/doReuseAdd', {
|
||||
const loading = this.$loading({lock: true, text: isSave ? '正在保存...' : '正在提交...', background: COVER_LAYER_COLOR})
|
||||
const request = $.post('/platform/activity/school/info/mange/doReuseAdd', {
|
||||
sourceId: this.reuseActivityId, data: JSON.stringify(form), events: JSON.stringify(this.buildReuseEvents())
|
||||
}).then((resp) => {
|
||||
})
|
||||
// jQuery 1.x 的 then 回调抛错后可能中断后续回调;直接监听请求结束以关闭遮罩。
|
||||
request.always(() => {
|
||||
this.$set(this, 'formLoading', false)
|
||||
loading.close()
|
||||
})
|
||||
return request.then((resp) => {
|
||||
if (resp.code !== 0) {
|
||||
this.$message.error(resp.msg)
|
||||
return
|
||||
}
|
||||
if (isSave) {
|
||||
this.$message.success('保存成功')
|
||||
window.location.href = '/platform/activity/school/info/mange'
|
||||
return
|
||||
}
|
||||
this.$set(this.form, 'id', resp.data)
|
||||
this.$set(this, 'reuseActivityId', null)
|
||||
if (isSave) {
|
||||
this.$emit('flush')
|
||||
this.$message.success('保存成功')
|
||||
// 保存后读取新项目主键,后续编辑必须更新新活动的项目,不能继续使用空主键。
|
||||
return $.post('/platform/activity/school/info/mange/findOne', {id: resp.data}).then((saved) => {
|
||||
if (saved.code !== 0) {
|
||||
this.$message.error('活动已保存,回显失败,请从活动列表重新打开')
|
||||
return
|
||||
}
|
||||
const configs = (saved.data.schoolEvents || []).map((event) => {
|
||||
this.$set(event, 'unionLimit', this.reuseArray(event.unionLimit))
|
||||
this.$set(event, 'ageDate', event.startAgeDate ? [event.startAgeDate, event.endAgeDate] : [])
|
||||
return event
|
||||
})
|
||||
this.$set(this, 'checkedEventInfo', configs)
|
||||
this.$set(this, 'checkedEventInfo2', clone(configs))
|
||||
this.$set(this, 'eventsIds', clone(this.form.eventsIds))
|
||||
const selected = configs.find((event) => event.eventId === this.eventForm.checkedEventId)
|
||||
if (selected) {
|
||||
this.$set(this, 'eventForm', Object.assign({}, selected, {checkedEventId: selected.eventId}))
|
||||
}
|
||||
})
|
||||
}
|
||||
this.$emit('flip')
|
||||
}).fail(() => {
|
||||
}, () => {
|
||||
this.$message.error('请求失败,请检查活动列表后重试')
|
||||
}).always(() => {
|
||||
this.$set(this, 'formLoading', false)
|
||||
loading.close()
|
||||
})
|
||||
}
|
||||
if (isSave) {
|
||||
if (this.$refs.activityForm) this.$refs.activityForm.clearValidate()
|
||||
return save()
|
||||
}
|
||||
if (this.$refs.activityForm) {
|
||||
this.$refs.activityForm.validate((valid) => {
|
||||
if (valid) save()
|
||||
@@ -1110,7 +1106,8 @@ module.exports = {
|
||||
return
|
||||
}
|
||||
|
||||
if (moment(this.form.time[0]).valueOf() <= moment(this.form.applyTime[0]).valueOf()) {
|
||||
// 活动时间可在保存草稿后补填;已填写时仍需晚于报名开始时间。
|
||||
if (this.form.time && this.form.time[0] && this.form.time[1] && moment(this.form.time[0]).valueOf() <= moment(this.form.applyTime[0]).valueOf()) {
|
||||
this.$notify.error({title: '错误', message: '活动时间必须晚于报名时间'});
|
||||
return
|
||||
}
|
||||
@@ -1247,7 +1244,7 @@ module.exports = {
|
||||
this.clubOptions = await getClubsByRole()
|
||||
this.eventsIds = clone(JSON.parse(v.eventsIds))
|
||||
v.applyTime = [v.applyStartTime, v.applyEndTime]
|
||||
v.time = [v.startTime, v.endTime]
|
||||
this.$set(v, 'time', v.startTime && v.endTime ? [v.startTime, v.endTime] : null)
|
||||
v.eventsIds = JSON.parse(v.eventsIds)
|
||||
v.applyWay = JSON.parse(v.applyWay)
|
||||
v.unitSponsor = JSON.parse(v.unitSponsor)
|
||||
@@ -1323,6 +1320,12 @@ module.exports = {
|
||||
if (this.reuseLoading || this.formLoading) return
|
||||
if (this.reuseActivityId && !this.form.id) return this.doReuseAdd(false)
|
||||
|
||||
// 提交会开放活动,必须先补齐活动时间;仅保存草稿允许留空。
|
||||
if (!this.form.time || this.form.time.length !== 2 || !this.form.time[0] || !this.form.time[1]) {
|
||||
this.$message.warning('请填写活动时间后再提交')
|
||||
return
|
||||
}
|
||||
|
||||
const deleteEventIds = this.eventsIds.filter(v => !this.form.eventsIds.includes(v))
|
||||
const {data} = await $.get(loc() + "/getEventApply", {
|
||||
activityId: this.form.id,
|
||||
@@ -1340,8 +1343,10 @@ module.exports = {
|
||||
await this.doOperate()
|
||||
}
|
||||
},
|
||||
async doSave() {
|
||||
doSave() {
|
||||
if (this.reuseLoading || this.formLoading) return
|
||||
// 保存草稿不触发表单必填校验;下一步和提交仍按各自规则处理。
|
||||
if (this.$refs.activityForm) this.$refs.activityForm.clearValidate()
|
||||
if (this.reuseActivityId && !this.form.id) return this.doReuseAdd(true)
|
||||
let url = this.form.id ? "/doEdit" : "/doAdd"
|
||||
|
||||
@@ -1364,25 +1369,32 @@ module.exports = {
|
||||
const form = clone(this.form)
|
||||
form.restrictMaxNum = form.leanderNum + form.coachNum + form.athletesMaxNum + form.substituteNum
|
||||
form.restrictMinNum = form.athletesMaxNum
|
||||
form.isSave = true
|
||||
form.isSave = 1
|
||||
|
||||
const {time, applyTime} = form
|
||||
if (applyTime && applyTime.length) {
|
||||
if (applyTime && applyTime.length === 2 && applyTime[0] && applyTime[1]) {
|
||||
form.applyStartTime = applyTime[0]
|
||||
form.applyEndTime = applyTime[1]
|
||||
form.applyTime = undefined
|
||||
} else {
|
||||
form.applyStartTime = null
|
||||
form.applyEndTime = null
|
||||
}
|
||||
|
||||
if (time && time.length) {
|
||||
if (time && time.length === 2 && time[0] && time[1]) {
|
||||
form.startTime = time[0]
|
||||
form.endTime = time[1]
|
||||
form.time = undefined
|
||||
} else {
|
||||
// 清空已有活动时间时显式传 null,避免编辑草稿时沿用旧值。
|
||||
form.startTime = null
|
||||
form.endTime = null
|
||||
}
|
||||
|
||||
if (this.eventForm.checkedEventId == "allItems") {
|
||||
events = events.filter(v => v.projectType == 1 && v.id != "allItems")
|
||||
|
||||
} else {
|
||||
} else if (this.eventForm.checkedEventId) {
|
||||
this.$set(this.eventForm, "activityId", this.form.id)
|
||||
this.$set(this.eventForm, "eventId", this.eventForm.checkedEventId)
|
||||
if (this.eventForm.ageDate && this.eventForm.ageDate.length > 0) {
|
||||
@@ -1391,26 +1403,29 @@ module.exports = {
|
||||
}
|
||||
events = this.eventForm
|
||||
}
|
||||
this.$set(this, 'formLoading', true)
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
text: '正在提交...',
|
||||
text: '正在保存...',
|
||||
spinner: 'el-icon-loading',
|
||||
background: COVER_LAYER_COLOR
|
||||
});
|
||||
|
||||
const resp = await $.post("/platform/activity/school/info/mange" + url, {
|
||||
return $.post("/platform/activity/school/info/mange" + url, {
|
||||
data: JSON.stringify(form),
|
||||
events: JSON.stringify(events)
|
||||
})
|
||||
|
||||
closeLoadingFunc(loading, resp, async (data) => {
|
||||
|
||||
this.$emit('flush')
|
||||
if (!this.form.id) form.id = data
|
||||
await this.openEdit(form, false)
|
||||
|
||||
}, (data, msg) => {
|
||||
this.$message.error(msg);
|
||||
}).then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.$message.success('保存成功')
|
||||
window.location.href = '/platform/activity/school/info/mange'
|
||||
} else {
|
||||
this.$message.error(resp.msg)
|
||||
}
|
||||
}, () => {
|
||||
this.$message.error('保存失败,请检查活动列表后重试')
|
||||
}).always(() => {
|
||||
this.$set(this, 'formLoading', false)
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
examineTrans(form) {
|
||||
|
||||
@@ -906,39 +906,58 @@ layout("/layouts/platform.html"){
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item prop="username" label="姓  名">
|
||||
<el-input maxlength="50" placeholder="请填写外援姓名" v-model="formData.username"></el-input>
|
||||
<el-autocomplete style="width: 100%" maxlength="50" :trigger-on-focus="false"
|
||||
placeholder="输入姓名或工号搜索,未匹配时直接填写姓名"
|
||||
:fetch-suggestions="searchExternalUser" v-model="formData.username"
|
||||
@input="changeExternalName" @select="selectExternalUser">
|
||||
<template slot-scope="{ item }">{{item.username}}({{item.loginname}})</template>
|
||||
</el-autocomplete>
|
||||
</el-form-item>
|
||||
<el-form-item prop="loginname" label="工  号">
|
||||
<el-input disabled maxlength="50" placeholder="正在生成工号" v-model="formData.loginname"
|
||||
<el-input :disabled="!!formData.matchedUserId" maxlength="50" placeholder="留空自动生成,也可手动填写" v-model="formData.loginname"
|
||||
type="text"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="性  别" prop="sex">
|
||||
<el-radio-group v-model="formData.sex">
|
||||
<el-radio-group v-model="formData.sex" :disabled="!!formData.matchedUserId && !!selectedExternalUser && !!selectedExternalUser.sex">
|
||||
<el-radio :label="'男'" border>男</el-radio>
|
||||
<el-radio :label="'女'" border>女</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="身份证号" prop="idcard">
|
||||
<el-input maxlength="18" placeholder="请填写身份证号"
|
||||
v-model="formData.idcard" @input="updateExternalBirthday"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="出生年月" prop="birthday">
|
||||
<el-date-picker
|
||||
placeholder="选择出生年月"
|
||||
style="width: 100%"
|
||||
type="date"
|
||||
v-model="formData.birthday"
|
||||
value-format="yyyy-MM-dd">
|
||||
</el-date-picker>
|
||||
<el-date-picker style="width: 100%" type="date" value-format="yyyy-MM-dd"
|
||||
placeholder="从身份证号读取,也可手动选择" v-model="formData.birthday"></el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="电  话" prop="mobile">
|
||||
<el-input maxlength="11" placeholder="请填写电话" type="text"
|
||||
v-model="formData.mobile"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="unitId" label="所在单位">
|
||||
<el-input disabled v-model="formData.unitname"></el-input>
|
||||
<el-form-item prop="unitname" label="所在单位">
|
||||
<el-select v-if="formData.matchedUserId" filterable style="width: 100%"
|
||||
placeholder="请选择报名使用的单位" v-model="formData.unitId" @change="changeExternalUnit">
|
||||
<el-option v-for="item in unitOptions" :key="item.id" :label="item.name"
|
||||
:value="item.id"></el-option>
|
||||
</el-select>
|
||||
<el-autocomplete v-else style="width: 100%" maxlength="100"
|
||||
placeholder="搜索选择单位,或直接输入其他单位"
|
||||
:fetch-suggestions="searchExternalUnit" v-model="formData.unitname"
|
||||
@input="changeExternalUnitInput" @select="selectExternalUnit"></el-autocomplete>
|
||||
</el-form-item>
|
||||
<el-form-item label="身体条件" prop="fitForCompetition">
|
||||
<el-radio-group v-model="formData.fitForCompetition">
|
||||
<el-radio :label="true" border>适合参赛</el-radio>
|
||||
<el-radio :label="false" border>不适合参赛</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" :loading="formLoading" @click="doAddUser(false)">确 定</el-button>
|
||||
<el-button type="primary" :loading="formLoading" :disabled="formData.fitForCompetition !== true"
|
||||
@click="doAddUser(false)">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
|
||||
@@ -949,35 +968,58 @@ layout("/layouts/platform.html"){
|
||||
>
|
||||
<el-form :model="formData" ref="singleExternalForm" :rules="lsryRules" label-width="100px">
|
||||
<el-form-item prop="username" label="姓  名">
|
||||
<el-input maxlength="50" placeholder="请填写姓名" v-model="formData.username"
|
||||
type="text"></el-input>
|
||||
<el-autocomplete style="width: 100%" maxlength="50" :trigger-on-focus="false"
|
||||
placeholder="输入姓名或工号搜索,未匹配时直接填写姓名"
|
||||
:fetch-suggestions="searchExternalUser" v-model="formData.username"
|
||||
@input="changeExternalName" @select="selectExternalUser">
|
||||
<template slot-scope="{ item }">{{item.username}}({{item.loginname}})</template>
|
||||
</el-autocomplete>
|
||||
</el-form-item>
|
||||
<el-form-item prop="loginname" label="工  号">
|
||||
<el-input disabled maxlength="50" placeholder="正在生成工号" v-model="formData.loginname"
|
||||
<el-input :disabled="!!formData.matchedUserId" maxlength="50" placeholder="留空自动生成,也可手动填写" v-model="formData.loginname"
|
||||
type="text"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="性  别" prop="sex">
|
||||
<el-radio-group v-model="formData.sex">
|
||||
<el-radio-group v-model="formData.sex" :disabled="!!formData.matchedUserId && !!selectedExternalUser && !!selectedExternalUser.sex">
|
||||
<el-radio :label="'男'" border>男</el-radio>
|
||||
<el-radio :label="'女'" border>女</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="身份证号" prop="idcard">
|
||||
<el-input maxlength="18" placeholder="请填写身份证号"
|
||||
v-model="formData.idcard" @input="updateExternalBirthday"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="出生年月" prop="birthday">
|
||||
<el-date-picker placeholder="选择出生年月" style="width: 100%" type="date"
|
||||
v-model="formData.birthday" value-format="yyyy-MM-dd"></el-date-picker>
|
||||
<el-date-picker style="width: 100%" type="date" value-format="yyyy-MM-dd"
|
||||
placeholder="从身份证号读取,也可手动选择" v-model="formData.birthday"></el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item prop="mobile" label="电  话">
|
||||
<el-input maxlength="11" placeholder="请填写电话" v-model="formData.mobile"
|
||||
type="text"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="unitId" label="所在单位">
|
||||
<el-input disabled v-model="formData.unitname"></el-input>
|
||||
<el-form-item prop="unitname" label="所在单位">
|
||||
<el-select v-if="formData.matchedUserId" filterable style="width: 100%"
|
||||
placeholder="请选择报名使用的单位" v-model="formData.unitId" @change="changeExternalUnit">
|
||||
<el-option v-for="item in unitOptions" :key="item.id" :label="item.name"
|
||||
:value="item.id"></el-option>
|
||||
</el-select>
|
||||
<el-autocomplete v-else style="width: 100%" maxlength="100"
|
||||
placeholder="搜索选择单位,或直接输入其他单位"
|
||||
:fetch-suggestions="searchExternalUnit" v-model="formData.unitname"
|
||||
@input="changeExternalUnitInput" @select="selectExternalUnit"></el-autocomplete>
|
||||
</el-form-item>
|
||||
<el-form-item label="身体条件" prop="fitForCompetition">
|
||||
<el-radio-group v-model="formData.fitForCompetition">
|
||||
<el-radio :label="true" border>适合参赛</el-radio>
|
||||
<el-radio :label="false" border>不适合参赛</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogVisible2 = false">取 消</el-button>
|
||||
<el-button type="primary" :loading="formLoading" @click="doAddUser(true)">确 定</el-button>
|
||||
<el-button type="primary" :loading="formLoading" :disabled="formData.fitForCompetition !== true"
|
||||
@click="doAddUser(true)">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
|
||||
@@ -1041,6 +1083,10 @@ layout("/layouts/platform.html"){
|
||||
},
|
||||
activeName: '',
|
||||
userOptions: [],
|
||||
selectedExternalUser: null,
|
||||
selectedExternalUnit: null,
|
||||
externalSearchLoading: false,
|
||||
externalSearchQuery: '',
|
||||
applyUsers: [],
|
||||
applyValue: [],
|
||||
applyData: [],
|
||||
@@ -1093,13 +1139,29 @@ layout("/layouts/platform.html"){
|
||||
},
|
||||
lsryRules: {
|
||||
username: [{required: true, message: '请填写姓名', trigger: 'blur'}],
|
||||
loginname: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
loginname: [{validator: (rule, value, callback) => {
|
||||
if (this.formData.matchedUserId && !value) {
|
||||
callback(new Error('所选系统人员没有工号'))
|
||||
return
|
||||
}
|
||||
callback()
|
||||
}, trigger: ['blur', 'change']}],
|
||||
sex: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
idcard: [{validator: (rule, value, callback) => {
|
||||
const card = (value || '').toUpperCase()
|
||||
const date = card.substring(6, 14)
|
||||
if (!/^[0-9]{17}[0-9X]$/.test(card) || !moment(date, 'YYYYMMDD', true).isValid()) {
|
||||
callback(new Error('请填写正确的18位身份证号'))
|
||||
return
|
||||
}
|
||||
callback()
|
||||
}, trigger: ['blur', 'change']}],
|
||||
birthday: [{required: true, message: '请选择出生年月', trigger: 'change'}],
|
||||
mobile: [
|
||||
{required: true, message: '手机号码', trigger: ['blur', 'change']},
|
||||
{pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码'}],
|
||||
unitId: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
unitname: [{required: true, message: '请选择或填写单位', trigger: ['blur', 'change']}],
|
||||
fitForCompetition: [{required: true, message: '请选择身体条件', trigger: 'change'}],
|
||||
},
|
||||
submitLoading: false,
|
||||
selection: [],
|
||||
@@ -1686,89 +1748,200 @@ layout("/layouts/platform.html"){
|
||||
this.leaderOptions = [];
|
||||
}
|
||||
},
|
||||
doAddUser(single) {
|
||||
this.$refs[single ? 'singleExternalForm' : 'form'].validate((valid) => {
|
||||
if (valid) {
|
||||
this.formLoading = true
|
||||
$.post(loc() + "/addExternalUser", {
|
||||
username: this.formData.username,
|
||||
sex: this.formData.sex,
|
||||
birthday: this.formData.birthday,
|
||||
mobile: this.formData.mobile
|
||||
}).then((res) => {
|
||||
if (res.code !== 0) {
|
||||
this.notifyError(res.msg || '外援创建失败')
|
||||
return
|
||||
}
|
||||
const user = res.data
|
||||
const data = {
|
||||
...this.formData,
|
||||
userId: user.id,
|
||||
loginname: user.loginname,
|
||||
username: user.username,
|
||||
sex: user.sex,
|
||||
birthday: user.birthday,
|
||||
mobile: user.mobile,
|
||||
unitId: user.unitid,
|
||||
unitname: '外援',
|
||||
age: moment().diff(moment(user.birthday), 'years'),
|
||||
eventId: this.eventData.eventId,
|
||||
activityId: this.activityData.id,
|
||||
team: single ? null : this.teams.find(x => x.id === this.formData.teamId).name,
|
||||
isAddUser: true
|
||||
}
|
||||
if (single) {
|
||||
this.appliedData3.push(data)
|
||||
} else {
|
||||
this.appliedData.push(data)
|
||||
}
|
||||
this.sortApplyed()
|
||||
this.flushApplyed(this.appliedData)
|
||||
this.notifySuccess('已添加外援')
|
||||
this.dialogVisible = false
|
||||
this.dialogVisible2 = false
|
||||
}).fail(() => {
|
||||
this.notifyError('外援创建失败,请重试')
|
||||
}).always(() => {
|
||||
this.formLoading = false
|
||||
})
|
||||
} else {
|
||||
this.$notify.error({title: '错误', message: '存在未填写的的必填项'});
|
||||
searchExternalUser(query, callback) {
|
||||
// 姓名输入框既可搜索系统人员,也可直接填写新人员姓名。
|
||||
this.externalSearchQuery = query
|
||||
if (!query || !query.trim()) {
|
||||
this.externalSearchLoading = false
|
||||
callback([])
|
||||
return
|
||||
}
|
||||
this.externalSearchLoading = true
|
||||
$.post(loc() + "/getSysUser", {queryString: query}).then((res) => {
|
||||
if (this.externalSearchQuery !== query) {
|
||||
callback([])
|
||||
return
|
||||
}
|
||||
const users = res.code === 0 ? (res.data || []) : []
|
||||
callback(users.map(user => ({...user, value: user.username})))
|
||||
}).fail(() => {
|
||||
callback([])
|
||||
}).always(() => {
|
||||
if (this.externalSearchQuery === query) this.externalSearchLoading = false
|
||||
})
|
||||
},
|
||||
changeExternalName(value) {
|
||||
if (!this.selectedExternalUser || value === this.selectedExternalUser.username) return
|
||||
// 修改已选姓名即退出匹配,清除旧人的资料,避免作为新人员误提交。
|
||||
this.selectedExternalUser = null
|
||||
this.$set(this.formData, 'matchedUserId', '')
|
||||
const fields = ['loginname', 'sex', 'idcard', 'birthday', 'mobile', 'unitname']
|
||||
fields.forEach(key => {
|
||||
this.$set(this.formData, key, '')
|
||||
})
|
||||
this.$set(this.formData, 'unitId', "${@shiro.getPrincipalProperty('unit').getId()}")
|
||||
this.selectedExternalUnit = null
|
||||
},
|
||||
selectExternalUser(user) {
|
||||
// 选中候选人后复用其账号,系统字段为空的部分可在下方补填。
|
||||
this.selectedExternalUser = user
|
||||
this.$set(this.formData, 'matchedUserId', user.id)
|
||||
const fields = ['username', 'loginname', 'sex', 'idcard', 'birthday', 'mobile']
|
||||
fields.forEach(key => {
|
||||
this.$set(this.formData, key, user[key] || '')
|
||||
})
|
||||
const card = (user.idcard || '').toUpperCase()
|
||||
const date = card.substring(6, 14)
|
||||
if (!user.birthday && /^[0-9]{17}[0-9X]$/.test(card) && moment(date, 'YYYYMMDD', true).isValid()) {
|
||||
this.$set(this.formData, 'birthday', moment(date, 'YYYYMMDD').format('YYYY-MM-DD'))
|
||||
}
|
||||
const unit = this.unitOptions.find(item => item.id === user.unitid)
|
||||
this.$set(this.formData, 'unitId', unit ? unit.id : '')
|
||||
this.$set(this.formData, 'unitname', unit ? unit.name : '')
|
||||
},
|
||||
changeExternalUnit(id) {
|
||||
const unit = this.unitOptions.find(item => item.id === id)
|
||||
this.$set(this.formData, 'unitname', unit ? unit.name : '')
|
||||
},
|
||||
searchExternalUnit(query, callback) {
|
||||
const units = this.unitOptions.filter(item => !query || item.name.indexOf(query) > -1)
|
||||
callback(units.slice(0, 30).map(item => ({...item, value: item.name})))
|
||||
},
|
||||
changeExternalUnitInput(value) {
|
||||
// 手动改写单位名称后解除已选单位 ID,报名归属仍沿用操作人的单位。
|
||||
if (this.selectedExternalUnit && value !== this.selectedExternalUnit.name) {
|
||||
this.selectedExternalUnit = null
|
||||
this.$set(this.formData, 'unitId', "${@shiro.getPrincipalProperty('unit').getId()}")
|
||||
}
|
||||
},
|
||||
selectExternalUnit(unit) {
|
||||
this.selectedExternalUnit = unit
|
||||
this.$set(this.formData, 'unitId', unit.id)
|
||||
this.$set(this.formData, 'unitname', unit.name)
|
||||
},
|
||||
updateExternalBirthday(value) {
|
||||
// 身份证号变化时重新计算出生年月,避免沿用系统中可能错误的日期。
|
||||
const card = (value || '').toUpperCase()
|
||||
const date = card.substring(6, 14)
|
||||
const birthday = /^[0-9]{17}[0-9X]$/.test(card) && moment(date, 'YYYYMMDD', true).isValid()
|
||||
? moment(date, 'YYYYMMDD').format('YYYY-MM-DD') : ''
|
||||
this.$set(this.formData, 'birthday', birthday)
|
||||
},
|
||||
addExternalToApply(user, single) {
|
||||
const data = {
|
||||
...this.formData,
|
||||
userId: user.id,
|
||||
loginname: user.loginname,
|
||||
username: user.username,
|
||||
sex: this.formData.sex,
|
||||
idcard: this.formData.idcard,
|
||||
idCard: this.formData.idcard,
|
||||
birthday: this.formData.birthday,
|
||||
mobile: this.formData.mobile,
|
||||
unitId: this.formData.unitId,
|
||||
unitname: this.formData.unitname.trim(),
|
||||
age: this.formData.birthday ? moment().diff(moment(this.formData.birthday), 'years') : null,
|
||||
eventId: this.eventData.eventId,
|
||||
activityId: this.activityData.id,
|
||||
team: single ? null : this.teams.find(item => item.id === this.formData.teamId).name,
|
||||
isAddUser: true
|
||||
}
|
||||
if (single) {
|
||||
this.appliedData3.push(data)
|
||||
} else {
|
||||
this.appliedData.push(data)
|
||||
}
|
||||
// 系统人员可能仍在左侧可报名单中,移除该选项以免同一项目重复加入。
|
||||
this.applyData = this.applyData.filter(item => item.id !== user.id)
|
||||
this.applyValue = this.applyValue.filter(id => id !== user.id)
|
||||
this.rightChecked = this.rightChecked.filter(id => id !== user.id)
|
||||
this.sortApplyed()
|
||||
this.flushApplyed(this.appliedData)
|
||||
this.notifySuccess('已添加报名人员')
|
||||
this.dialogVisible = false
|
||||
this.dialogVisible2 = false
|
||||
},
|
||||
doAddUser(single) {
|
||||
// 匹配人员直接加入报名;未匹配人员先创建账号,再加入本次报名。
|
||||
if (this.formData.fitForCompetition !== true) return
|
||||
this.$refs[single ? 'singleExternalForm' : 'form'].validate((valid) => {
|
||||
if (!valid) {
|
||||
this.$notify.error({title: '错误', message: '存在未填写或不正确的必填项'})
|
||||
return
|
||||
}
|
||||
if (!this.formData.unitname || !this.formData.unitname.trim()) {
|
||||
this.notifyError('请选择或填写单位')
|
||||
return
|
||||
}
|
||||
if (this.appliedData.concat(this.appliedData3).some(item => item.userId === this.formData.matchedUserId)) {
|
||||
this.notifyError('该人员已在当前项目报名列表中')
|
||||
return
|
||||
}
|
||||
if (this.formData.matchedUserId) {
|
||||
if (this.selectedExternalUser && this.selectedExternalUser.id === this.formData.matchedUserId) {
|
||||
this.addExternalToApply(this.selectedExternalUser, single)
|
||||
}
|
||||
return
|
||||
}
|
||||
this.formLoading = true
|
||||
$.post(loc() + "/addExternalUser", {
|
||||
username: this.formData.username,
|
||||
loginname: this.formData.loginname,
|
||||
sex: this.formData.sex,
|
||||
idcard: this.formData.idcard,
|
||||
mobile: this.formData.mobile,
|
||||
fitForCompetition: this.formData.fitForCompetition
|
||||
}).then((res) => {
|
||||
if (res.code !== 0) {
|
||||
this.notifyError(res.msg || '外援创建失败')
|
||||
return
|
||||
}
|
||||
this.addExternalToApply(res.data, single)
|
||||
}).fail(() => {
|
||||
this.notifyError('外援创建失败,请重试')
|
||||
}).always(() => {
|
||||
this.formLoading = false
|
||||
})
|
||||
})
|
||||
},
|
||||
openAddUser() {
|
||||
this.formData = {
|
||||
teamId: this.team,
|
||||
identity: ['1'],
|
||||
username: '',
|
||||
loginname: '',
|
||||
sex: '',
|
||||
idcard: '',
|
||||
birthday: '',
|
||||
mobile: '',
|
||||
unitId: "${@shiro.getPrincipalProperty('unit').getId()}",
|
||||
unitname: '外援'
|
||||
unitname: '',
|
||||
matchedUserId: '',
|
||||
fitForCompetition: null
|
||||
}
|
||||
this.selectedExternalUser = null
|
||||
this.selectedExternalUnit = null
|
||||
this.externalSearchQuery = ''
|
||||
this.dialogVisible = true
|
||||
this.previewExternalNumber()
|
||||
},
|
||||
previewExternalNumber() {
|
||||
this.formLoading = true
|
||||
$.post(loc() + "/previewExternalLoginname", {}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$set(this.formData, 'loginname', res.data)
|
||||
} else {
|
||||
this.notifyError(res.msg || '工号生成失败')
|
||||
}
|
||||
}).fail(() => {
|
||||
this.notifyError('工号生成失败,请重试')
|
||||
}).always(() => {
|
||||
this.formLoading = false
|
||||
})
|
||||
},
|
||||
openAddUserD() {
|
||||
this.formData = {
|
||||
identity: ['1'],
|
||||
username: '',
|
||||
loginname: '',
|
||||
sex: '',
|
||||
idcard: '',
|
||||
birthday: '',
|
||||
mobile: '',
|
||||
unitId: "${@shiro.getPrincipalProperty('unit').getId()}",
|
||||
unitname: '外援'
|
||||
unitname: '',
|
||||
matchedUserId: '',
|
||||
fitForCompetition: null
|
||||
}
|
||||
this.selectedExternalUser = null
|
||||
this.selectedExternalUnit = null
|
||||
this.externalSearchQuery = ''
|
||||
this.dialogVisible2 = true
|
||||
this.previewExternalNumber()
|
||||
},
|
||||
async doApplied(flag1) {
|
||||
|
||||
|
||||
@@ -121,8 +121,11 @@ layout("/layouts/platform.html"){
|
||||
</template>
|
||||
|
||||
<template v-else-if="column.prop=='startTime'" scope="{row}">
|
||||
{{moment(row.startTime).format('YYYY-MM-DD')}} -
|
||||
{{moment(row.endTime).format('YYYY-MM-DD')}}
|
||||
<span v-if="row.startTime && row.endTime">
|
||||
{{moment(row.startTime).format('YYYY-MM-DD')}} -
|
||||
{{moment(row.endTime).format('YYYY-MM-DD')}}
|
||||
</span>
|
||||
<span v-else>未设置</span>
|
||||
</template>
|
||||
|
||||
<template v-else-if="column.prop=='state'"
|
||||
|
||||
@@ -17,8 +17,8 @@ layout("/layouts/platform.html"){
|
||||
<div class="search-item-option">
|
||||
<el-date-picker
|
||||
style="width: 100%"
|
||||
placeholder="选择年度"
|
||||
type="year"
|
||||
placeholder="全部年度"
|
||||
type="year" clearable @change="handleYearChange"
|
||||
v-model="pageForm.year"
|
||||
value-format="yyyy">
|
||||
</el-date-picker>
|
||||
@@ -27,13 +27,13 @@ layout("/layouts/platform.html"){
|
||||
<div class="search-item">
|
||||
<div class="search-item-label">项目名称:</div>
|
||||
<div class="search-item-option">
|
||||
<el-select v-model="pageForm.projectId" placeholder="请选择项目名称" filterable clearable
|
||||
<el-select v-model="pageForm.projectId" placeholder="请选择项目名称" filterable clearable :loading="projectLoading"
|
||||
style="width: 100%" @change="doSearch">
|
||||
<el-option
|
||||
v-for="item in projectList"
|
||||
:key="item.code"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.code">
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
@@ -113,6 +113,7 @@ layout("/layouts/platform.html"){
|
||||
],
|
||||
buyClothesUserData: [],
|
||||
projectList: [],
|
||||
projectLoading: false,
|
||||
unionList: [],
|
||||
}
|
||||
},
|
||||
@@ -128,15 +129,43 @@ layout("/layouts/platform.html"){
|
||||
this.$refs['guava'].view()
|
||||
}
|
||||
},
|
||||
//获取所有买服装的项目
|
||||
async getBuyClothesProject() {
|
||||
const {data} = await $.post('/platform/clothing/register/getBuyClothesProject')
|
||||
return data
|
||||
// 年度筛选与活动管理页一致,按活动报名开始时间所属年度获取活动。
|
||||
getBuyClothesProject(year) {
|
||||
this.$set(this, 'projectLoading', true)
|
||||
return $.post('/platform/clothing/register/getBuyClothesProject', {year: year})
|
||||
.then((resp) => {
|
||||
if (resp.code === 0) return resp.data || []
|
||||
this.notifyWarning(resp.msg)
|
||||
return []
|
||||
}, () => {
|
||||
this.notifyWarning('活动列表加载失败')
|
||||
return []
|
||||
})
|
||||
.always(() => {
|
||||
this.$set(this, 'projectLoading', false)
|
||||
})
|
||||
},
|
||||
// 年度变化后清空不属于新年度的项目选择,再按当前条件查询台账。
|
||||
handleYearChange() {
|
||||
const year = this.pageForm.year
|
||||
this.$set(this.pageForm, 'projectId', null)
|
||||
this.$set(this, 'projectList', [])
|
||||
this.getBuyClothesProject(year).then((projects) => {
|
||||
if (this.pageForm.year !== year) return
|
||||
this.$set(this, 'projectList', projects)
|
||||
this.doSearch()
|
||||
})
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
this.projectList = await this.getBuyClothesProject()
|
||||
this.unionList = await getUnion()
|
||||
created() {
|
||||
const year = this.pageForm.year
|
||||
this.getBuyClothesProject(year).then((projects) => {
|
||||
if (this.pageForm.year !== year) return
|
||||
this.$set(this, 'projectList', projects)
|
||||
})
|
||||
getUnion().then((unions) => {
|
||||
this.$set(this, 'unionList', unions)
|
||||
})
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
@@ -144,4 +173,4 @@ layout("/layouts/platform.html"){
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
#-->
|
||||
|
||||
@@ -17,8 +17,8 @@ layout("/layouts/platform.html"){
|
||||
<div class="search-item-option">
|
||||
<el-date-picker
|
||||
style="width: 100%"
|
||||
placeholder="选择年度"
|
||||
type="year"
|
||||
placeholder="全部年度"
|
||||
type="year" clearable @change="handleYearChange"
|
||||
v-model="pageForm.year"
|
||||
value-format="yyyy">
|
||||
</el-date-picker>
|
||||
@@ -27,13 +27,13 @@ layout("/layouts/platform.html"){
|
||||
<div class="search-item">
|
||||
<div class="search-item-label">项目名称:</div>
|
||||
<div class="search-item-option">
|
||||
<el-select v-model="pageForm.projectId" placeholder="请选择项目名称" filterable clearable
|
||||
<el-select v-model="pageForm.projectId" placeholder="请选择项目名称" filterable clearable :loading="projectLoading"
|
||||
style="width: 100%" @change="doSearch">
|
||||
<el-option
|
||||
v-for="item in projectList"
|
||||
:key="item.code"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.code">
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
@@ -111,6 +111,7 @@ layout("/layouts/platform.html"){
|
||||
],
|
||||
buyClothesUserData: [],
|
||||
projectList: [],
|
||||
projectLoading: false,
|
||||
note: '',
|
||||
clickRow: {},
|
||||
}
|
||||
@@ -177,10 +178,32 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
}
|
||||
},
|
||||
//获取所有买服装的项目
|
||||
async getBuyClothesProject() {
|
||||
const {data} = await $.post('/platform/clothing/register/getBuyClothesProject')
|
||||
return data
|
||||
// 年度筛选与活动管理页一致,按活动报名开始时间所属年度获取活动。
|
||||
getBuyClothesProject(year) {
|
||||
this.$set(this, 'projectLoading', true)
|
||||
return $.post('/platform/clothing/register/getBuyClothesProject', {year: year})
|
||||
.then((resp) => {
|
||||
if (resp.code === 0) return resp.data || []
|
||||
this.notifyWarning(resp.msg)
|
||||
return []
|
||||
}, () => {
|
||||
this.notifyWarning('活动列表加载失败')
|
||||
return []
|
||||
})
|
||||
.always(() => {
|
||||
this.$set(this, 'projectLoading', false)
|
||||
})
|
||||
},
|
||||
// 年度变化后清空不属于新年度的项目选择,再按当前条件查询登记记录。
|
||||
handleYearChange() {
|
||||
const year = this.pageForm.year
|
||||
this.$set(this.pageForm, 'projectId', null)
|
||||
this.$set(this, 'projectList', [])
|
||||
this.getBuyClothesProject(year).then((projects) => {
|
||||
if (this.pageForm.year !== year) return
|
||||
this.$set(this, 'projectList', projects)
|
||||
this.doSearch()
|
||||
})
|
||||
},
|
||||
doExport(row) {
|
||||
const loading = this.$loading({
|
||||
@@ -221,8 +244,12 @@ layout("/layouts/platform.html"){
|
||||
}).catch((err) => {})
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
this.projectList = await this.getBuyClothesProject()
|
||||
created() {
|
||||
const year = this.pageForm.year
|
||||
this.getBuyClothesProject(year).then((projects) => {
|
||||
if (this.pageForm.year !== year) return
|
||||
this.$set(this, 'projectList', projects)
|
||||
})
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
@@ -230,4 +257,4 @@ layout("/layouts/platform.html"){
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
#-->
|
||||
|
||||
@@ -27,8 +27,8 @@ layout("/layouts/platform.html"){
|
||||
<div class="search-item-option">
|
||||
<el-date-picker
|
||||
style="width: 100%"
|
||||
placeholder="选择年度"
|
||||
type="year" disabled
|
||||
placeholder="全部年度"
|
||||
type="year" clearable @change="handleYearChange"
|
||||
v-model="pageForm.year"
|
||||
value-format="yyyy">
|
||||
</el-date-picker>
|
||||
@@ -37,19 +37,24 @@ layout("/layouts/platform.html"){
|
||||
<div class="search-item">
|
||||
<div class="search-item-label">项目名称:</div>
|
||||
<div class="search-item-option">
|
||||
<el-select v-model="pageForm.projectId" placeholder="请选择项目名称" filterable
|
||||
<el-select v-model="pageForm.projectId" placeholder="请选择项目名称" filterable :loading="projectLoading"
|
||||
@change="doSearch" style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in projectList"
|
||||
:key="item.code"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.code">
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="search-item">
|
||||
<div class="search-item-label">近两年内:</div>
|
||||
<div class="search-item-label" style="white-space: nowrap;">
|
||||
近两年内:
|
||||
<el-tooltip content="按所选活动的报名年度,检查相邻年度活动中相同运动项目的购衣记录;补录往年活动也会查重" placement="top">
|
||||
<i class="el-icon-question" style="cursor: help;"></i>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div class="search-item-option">
|
||||
<el-radio-group @change="(val) => doSearch()" v-model="pageForm.isBuy">
|
||||
<el-radio-button :label="true">已购买</el-radio-button>
|
||||
@@ -112,22 +117,25 @@ layout("/layouts/platform.html"){
|
||||
</template>
|
||||
</vi-title2>
|
||||
</div>
|
||||
<el-table ref="multipleTable" @selection-change="handleSelectionChange" :data="userData" max-height="600"
|
||||
<el-table ref="multipleTable" v-loading="tableLoading" @selection-change="handleSelectionChange" :data="userData" max-height="600"
|
||||
:row-key="(val) => val.id">
|
||||
<el-table-column :reserve-selection="true" type="selection" width="55"></el-table-column>
|
||||
<el-table-column :reserve-selection="true" :selectable="canSelectUser" type="selection" width="55"></el-table-column>
|
||||
<el-table-column label="姓名" prop="username" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="工号" prop="loginname" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="性别" prop="sex" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="单位" prop="unitname" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="所属工会" prop="unionname" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="联系方式" prop="mobile" align="center" header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column v-if="pageForm.isBuy" label="购买来源" align="center" header-align="center">
|
||||
<template slot-scope="scope">{{scope.row.canRemove ? '当前活动' : '两年内同类活动'}}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div style="display: flex; justify-content: space-between; margin-top: 6px">
|
||||
<div> <!--#include("/layouts/pagination.html"){}#--></div>
|
||||
<div>
|
||||
<el-row justify="end" type="flex">
|
||||
<el-button v-if="!pageForm.isBuy" @click="doHandler" type="primary">提交</el-button>
|
||||
<el-button v-else @click="doHandler" type="danger">移除</el-button>
|
||||
<el-button v-if="!pageForm.isBuy" @click="doHandler" :loading="formLoading" type="primary">提交</el-button>
|
||||
<el-button v-else @click="doHandler" :loading="formLoading" type="danger">移除</el-button>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
@@ -154,11 +162,12 @@ layout("/layouts/platform.html"){
|
||||
data() {
|
||||
return {
|
||||
pageForm: {
|
||||
year: moment().format('YYYY'),
|
||||
year: null,
|
||||
isBuy: false,
|
||||
searchName: 'u.username'
|
||||
},
|
||||
projectList: [],
|
||||
projectLoading: false,
|
||||
userData: [],
|
||||
userValue: [],
|
||||
treeUnionList: [],
|
||||
@@ -172,7 +181,11 @@ layout("/layouts/platform.html"){
|
||||
},
|
||||
methods: {
|
||||
handleSelectionChange(val) {
|
||||
this.userValue = val.length > 0 ? val.map(o => o.id) : []
|
||||
this.$set(this, 'userValue', val.length > 0 ? val.map(o => o.id) : [])
|
||||
},
|
||||
// 其他同类活动的历史购买只能查看;移除操作仅处理当前活动的登记。
|
||||
canSelectUser(row) {
|
||||
return !this.pageForm.isBuy || row.canRemove
|
||||
},
|
||||
filterNode(value, data, node) {
|
||||
if (!value || node.level === 1) return true;
|
||||
@@ -187,7 +200,7 @@ layout("/layouts/platform.html"){
|
||||
this.pageData()
|
||||
}
|
||||
},
|
||||
async doHandler() {
|
||||
doHandler() {
|
||||
if(!this.pageForm.projectId) {
|
||||
this.notifyWarning('请选择项目!')
|
||||
return
|
||||
@@ -196,50 +209,104 @@ layout("/layouts/platform.html"){
|
||||
this.notifyWarning('请选择人员!')
|
||||
return
|
||||
}
|
||||
const confirm = await this.$confirm('您选择了' + this.userValue.length + '人, 是否继续?', '提示', {
|
||||
this.$confirm('您选择了' + this.userValue.length + '人, 是否继续?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
if (confirm === "confirm") {
|
||||
const resp = await $.post('/platform/clothing/register/doHandler', {
|
||||
}).then(() => {
|
||||
this.$set(this, 'formLoading', true)
|
||||
return $.post('/platform/clothing/register/doHandler', {
|
||||
ids: JSON.stringify(this.userValue),
|
||||
projectId: this.pageForm.projectId,
|
||||
year: this.pageForm.year,
|
||||
isBuy: this.pageForm.isBuy,
|
||||
})
|
||||
if(resp.code === 0) {
|
||||
this.doSearch()
|
||||
this.notifySuccess(resp.msg)
|
||||
} else {
|
||||
this.notifyWarning(resp.msg)
|
||||
}
|
||||
}
|
||||
.then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.doSearch()
|
||||
this.notifySuccess(resp.msg)
|
||||
} else {
|
||||
this.notifyWarning(resp.msg)
|
||||
}
|
||||
}, () => {
|
||||
this.notifyWarning('提交失败,请刷新名单后重试')
|
||||
})
|
||||
.always(() => {
|
||||
this.$set(this, 'formLoading', false)
|
||||
})
|
||||
}).catch(() => {})
|
||||
},
|
||||
doSearch() {
|
||||
this.$refs.multipleTable.clearSelection()
|
||||
this.pageData()
|
||||
},
|
||||
//查询人员名单
|
||||
async pageData() {
|
||||
const resp = await $.post('/platform/clothing/register/pageData', this.pageForm)
|
||||
if (resp.code === 0) {
|
||||
this.userData = resp.data.list
|
||||
this.pageForm.totalCount = resp.data.totalCount
|
||||
} else {
|
||||
this.$message.error(resp.msg)
|
||||
}
|
||||
// 查询与所选活动报名年度相差不超过一年、同类运动项目的购买状态。
|
||||
pageData() {
|
||||
const projectId = this.pageForm.projectId
|
||||
const isBuy = this.pageForm.isBuy
|
||||
this.$set(this, 'tableLoading', true)
|
||||
return $.post('/platform/clothing/register/pageData', this.pageForm)
|
||||
.then((resp) => {
|
||||
if (this.pageForm.projectId !== projectId || this.pageForm.isBuy !== isBuy) return
|
||||
if (resp.code === 0) {
|
||||
this.$set(this, 'userData', resp.data.list)
|
||||
this.$set(this.pageForm, 'totalCount', resp.data.totalCount)
|
||||
} else {
|
||||
this.$set(this, 'userData', [])
|
||||
this.$set(this.pageForm, 'totalCount', 0)
|
||||
this.$message.error(resp.msg)
|
||||
}
|
||||
}, () => {
|
||||
if (this.pageForm.projectId !== projectId || this.pageForm.isBuy !== isBuy) return
|
||||
this.$set(this, 'userData', [])
|
||||
this.$set(this.pageForm, 'totalCount', 0)
|
||||
this.$message.error('人员名单加载失败')
|
||||
})
|
||||
.always(() => {
|
||||
this.$set(this, 'tableLoading', false)
|
||||
})
|
||||
},
|
||||
//获取所有买服装的项目
|
||||
async getBuyClothesProject() {
|
||||
const {data} = await $.post('/platform/clothing/register/getBuyClothesProject')
|
||||
return data
|
||||
// 年度为空时获取全部已提交活动;指定年度时按活动报名开始时间筛选。
|
||||
getBuyClothesProject(year) {
|
||||
this.$set(this, 'projectLoading', true)
|
||||
return $.post('/platform/clothing/register/getBuyClothesProject', {year: year})
|
||||
.then((resp) => {
|
||||
if (resp.code === 0) return resp.data || []
|
||||
this.notifyWarning(resp.msg)
|
||||
return []
|
||||
}, () => {
|
||||
this.notifyWarning('活动列表加载失败')
|
||||
return []
|
||||
})
|
||||
.always(() => {
|
||||
this.$set(this, 'projectLoading', false)
|
||||
})
|
||||
},
|
||||
async unionTree() {
|
||||
const resp = await $.post('/platform/clothing/register/getTreeUnionList')
|
||||
if(resp.code === 0) {
|
||||
this.sysadmin = resp.data.sysadmin
|
||||
this.treeUnionList = [resp.data]
|
||||
// 切换年度时清除原项目,避免用上一年度的活动ID继续查询或登记。
|
||||
refreshProjects() {
|
||||
const year = this.pageForm.year
|
||||
this.$set(this.pageForm, 'projectId', null)
|
||||
this.$set(this, 'projectList', [])
|
||||
this.$set(this, 'userData', [])
|
||||
this.$set(this, 'userValue', [])
|
||||
return this.getBuyClothesProject(year).then((projects) => {
|
||||
if (this.pageForm.year !== year) return
|
||||
this.$set(this, 'projectList', projects)
|
||||
if (projects.length > 0) {
|
||||
this.$set(this.pageForm, 'projectId', projects[0].id)
|
||||
}
|
||||
})
|
||||
},
|
||||
handleYearChange() {
|
||||
const year = this.pageForm.year
|
||||
this.refreshProjects().then(() => {
|
||||
if (this.pageForm.year === year) this.doSearch()
|
||||
})
|
||||
},
|
||||
unionTree() {
|
||||
return $.post('/platform/clothing/register/getTreeUnionList').then((resp) => {
|
||||
if (resp.code !== 0) return
|
||||
this.$set(this, 'sysadmin', resp.data.sysadmin)
|
||||
this.$set(this, 'treeUnionList', [resp.data])
|
||||
if (this.sysadmin) {
|
||||
this.handleNodeClick({unioncode: ''}, {level: 1})
|
||||
} else {
|
||||
@@ -257,20 +324,19 @@ layout("/layouts/platform.html"){
|
||||
level: 2, data: data
|
||||
})
|
||||
}
|
||||
}
|
||||
}, () => {
|
||||
this.notifyWarning('工会列表加载失败')
|
||||
}).always(() => {})
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
this.projectList = await this.getBuyClothesProject()
|
||||
if (this.projectList && this.projectList.length > 0) {
|
||||
this.pageForm.projectId = this.projectList[0].code
|
||||
}
|
||||
await this.unionTree()
|
||||
this.pageData()
|
||||
created() {
|
||||
this.refreshProjects().then(() => {
|
||||
this.unionTree()
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
#-->
|
||||
|
||||
Reference in New Issue
Block a user