From b2fc1979fe1fbbaa370b4048281efbddce284846 Mon Sep 17 00:00:00 2001
From: hongqiwei <1143662660@qq.com>
Date: Mon, 28 Sep 2026 17:43:46 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BD=93=E8=82=B2=E6=B4=BB=E5=8A=A8=E5=88=9B?=
=?UTF-8?q?=E5=BB=BA=E5=8F=AF=E4=BB=A5=E6=B2=BF=E7=94=A8=EF=BC=8C=E6=89=BF?=
=?UTF-8?q?=E5=8A=9E=E5=8D=95=E4=BD=8D=E9=80=89=E5=A1=AB=EF=BC=9B=E5=AF=BC?=
=?UTF-8?q?=E5=87=BA=E5=87=BA=E7=8E=B0=E9=87=8D=E5=A4=8D=E4=BA=BA=E5=91=98?=
=?UTF-8?q?=E4=BF=AE=E5=A4=8D=EF=BC=9B=E4=BC=98=E5=8C=96=E5=A2=9E=E5=8A=A0?=
=?UTF-8?q?=E5=A4=96=E6=8F=B4=E5=8A=9F=E8=83=BD=EF=BC=8C=E4=B9=9F=E5=8F=AF?=
=?UTF-8?q?=E4=BB=A5=E5=AF=BC=E5=87=BA=EF=BC=9B=E6=8A=A5=E5=90=8D=E7=95=8C?=
=?UTF-8?q?=E9=9D=A2=E7=9A=84=E8=AE=BE=E7=BD=AE=E9=A2=86=E5=AF=BC=E4=BB=A5?=
=?UTF-8?q?=E5=8F=8A=E6=95=99=E7=BB=83=E4=B8=8D=E8=83=BD=E5=88=A0=E9=99=A4?=
=?UTF-8?q?=E4=BF=AE=E5=A4=8D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.idea/vcs.xml | 2 +-
.idea/workspace.xml | 34 +-
.../school/ActivityApplyController.java | 156 ++---
.../school/ActivityCommonController.java | 23 +-
.../school/ActivityInfoManageController.java | 34 ++
.../school/ActivityReadingController.java | 9 +-
.../school/ActivityReviewController.java | 3 +
.../SchoolActivityApplyExportEntity.java | 8 +
.../services/ActivitySchoolApplyService.java | 48 ++
.../services/ActivitySchoolService.java | 11 +
.../impl/ActivitySchoolApplyServiceImpl.java | 237 ++++++++
.../impl/ActivitySchoolServiceImpl.java | 115 ++++
.../activity/school/AddActivity.vue | 257 ++++++++-
.../components/activity/school/DeleteInfo.vue | 2 +
.../components/activity/school/Info.vue | 4 +-
.../activity/school/ActivityApply.html | 543 +++++++++---------
.../activity/school/ActivityReading.html | 1 +
.../activity/school/ActivityReview.html | 5 +-
18 files changed, 1062 insertions(+), 430 deletions(-)
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 45cf85c..35eb1dd 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index dd2b65d..6204e3f 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -4,12 +4,7 @@
-
-
-
-
-
-
+
@@ -33,13 +28,15 @@
+
@@ -101,6 +98,11 @@
+
+
+
+
+
@@ -114,24 +116,6 @@
C:\Users\Administrator\AppData\Roaming\Subversion
125
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/java/io/v/nutz/activity/controller/school/ActivityApplyController.java b/src/main/java/io/v/nutz/activity/controller/school/ActivityApplyController.java
index 0a42e51..90bdea6 100644
--- a/src/main/java/io/v/nutz/activity/controller/school/ActivityApplyController.java
+++ b/src/main/java/io/v/nutz/activity/controller/school/ActivityApplyController.java
@@ -349,6 +349,7 @@ public class ActivityApplyController {
*/
@At
@ViReturn
+ @Aop(TransAop.READ_COMMITTED)
public Object doApply(@Param("data") ActivitySchoolApply[] applies, @Param("appliedData3") ActivitySchoolApply[] applies2, String eventId, boolean pass) {
Sys_user user = (Sys_user) ShiroUtil.getPrincipal();
Sys_unit unit = user.getUnit();
@@ -376,16 +377,40 @@ public class ActivityApplyController {
apply2.setActivityUnionId(basicUnit.getUnionid());
apply2.setActivityUnionName(basicUnion.getUnionname());
}
- if (applies.length > 0) {
- activitySchoolApplyService.doApplies(activityId, basicUnit.getUnionid(), eventId, Arrays.asList(applies));
- }
- if (applies2.length > 0) {
- activitySchoolApplyService.doApplies(activityId, basicUnit.getUnionid(), eventId, Arrays.asList(applies2));
+ if (applies.length > 0 || applies2.length > 0) {
+ List allApplies = new ArrayList<>(Arrays.asList(applies));
+ allApplies.addAll(Arrays.asList(applies2));
+ activitySchoolApplyService.doApplies(activityId, basicUnit.getUnionid(), eventId, allApplies);
}
return null;
}
+ /**
+ * 创建报名专用外援,工号由服务端生成,页面不能指定。
+ * @param username 外援姓名
+ * @param sex 性别,男或女
+ * @param birthday 出生日期,yyyy-MM-dd
+ * @param mobile 手机号码
+ * @return Sys_user,id 为报名人员 ID,loginname 为 wy 年份流水工号,其他字段用于页面回显
+ */
+ @At
+ @ViReturn
+ @RequiresPermissions("activity.apply")
+ @Aop(TransAop.READ_COMMITTED)
+ public Object addExternalUser(String username, String sex, String birthday, String mobile) {
+ Sys_user operator = (Sys_user) ShiroUtil.getPrincipal();
+ return activitySchoolApplyService.createExternalUser(username, sex, birthday, mobile, operator.getUnitid());
+ }
+
+ /** @return String,当前年份的下一个外援工号预览,实际编号以创建接口返回值为准。 */
+ @At
+ @ViReturn
+ @RequiresPermissions("activity.apply")
+ public Object previewExternalLoginname() {
+ return activitySchoolApplyService.previewExternalLoginname();
+ }
+
/**
* 个人报名
*
@@ -646,116 +671,39 @@ public class ActivityApplyController {
/**
- * 如果当前项目是综合类活动就添加工会总领队和教练
+ * 保存综合类活动的领队、教练及工作人员;取消选择的活动级身份会删除。
*
- * @param LeaderData
- * @param CoachData
- * @return
+ * @param activityId 当前活动ID
+ * @param staffData 工作人员报名信息,userId 为所选用户ID,空值表示取消
+ * @param LeaderData 领队报名信息,userId 为所选用户ID,空值表示取消
+ * @param CoachData 教练报名信息,userId 为所选用户ID,空值表示取消
+ * @param headData 团长报名信息,userId 为所选用户ID,空值表示取消
+ * @return null,由 @ViReturn 包装为操作结果
*/
@At
@ViReturn
- public Object doLeaderCoachHead(@Param("staffData") ActivitySchoolApply staffData, @Param("LeaderData") ActivitySchoolApply LeaderData, @Param("CoachData") ActivitySchoolApply CoachData, @Param("headData") ActivitySchoolApply headData) {
-
- if (staffData.getUserId() != null) {
- ActivityBasicUnit basicUnit = activitySchoolService.dao().fetch(ActivityBasicUnit.class, Cnd.where("id", "=", staffData.getUnitId()));
- ActivityBasicUnion basicUnion = activitySchoolService.dao().fetch(ActivityBasicUnion.class, Cnd.where("id", "=", basicUnit.getUnionid()));
- activitySchoolApplyService.clear(Cnd.where("activityId", "=", staffData.getActivityId()).and("unionStaff", "=", true).and("unionId", "=", getUnionId()));
- staffData.setApplyUser(ShiroUtil.getPrincipalProperty("id").toString());
- staffData.setApplyDate(DateUtil.getDate());
- staffData.setUnitname(basicUnit.getName());
- staffData.setActivityUnionId(basicUnion.getId());
- staffData.setActivityUnionName(basicUnion.getUnionname());
- activitySchoolApplyService.insert(staffData);
- }
- if (LeaderData.getUserId() != null) {
- ActivityBasicUnit basicUnit = activitySchoolService.dao().fetch(ActivityBasicUnit.class, Cnd.where("id", "=", LeaderData.getUnitId()));
- ActivityBasicUnion basicUnion = activitySchoolService.dao().fetch(ActivityBasicUnion.class, Cnd.where("id", "=", basicUnit.getUnionid()));
- activitySchoolApplyService.clear(Cnd.where("activityId", "=", LeaderData.getActivityId()).and("unionLeader", "=", true).and("unionId", "=", getUnionId()));
- LeaderData.setApplyUser(ShiroUtil.getPrincipalProperty("id").toString());
- LeaderData.setApplyDate(DateUtil.getDate());
- LeaderData.setUnitname(basicUnit.getName());
- LeaderData.setActivityUnionId(basicUnion.getId());
- LeaderData.setActivityUnionName(basicUnion.getUnionname());
- activitySchoolApplyService.insert(LeaderData);
- }
- if (CoachData.getUserId() != null) {
- ActivityBasicUnit basicUnit = activitySchoolService.dao().fetch(ActivityBasicUnit.class, Cnd.where("id", "=", CoachData.getUnitId()));
- ActivityBasicUnion basicUnion = activitySchoolService.dao().fetch(ActivityBasicUnion.class, Cnd.where("id", "=", basicUnit.getUnionid()));
- activitySchoolApplyService.clear(Cnd.where("activityId", "=", CoachData.getActivityId()).and("unionCoach", "=", true).and("unionId", "=", getUnionId()));
- CoachData.setApplyUser(ShiroUtil.getPrincipalProperty("id").toString());
- CoachData.setApplyDate(DateUtil.getDate());
- CoachData.setUnitname(basicUnit.getName());
- CoachData.setActivityUnionId(basicUnion.getId());
- CoachData.setActivityUnionName(basicUnion.getUnionname());
- activitySchoolApplyService.insert(CoachData);
- }
- if (headData.getUserId() != null) {
- ActivityBasicUnit basicUnit = activitySchoolService.dao().fetch(ActivityBasicUnit.class, Cnd.where("id", "=", headData.getUnitId()));
- ActivityBasicUnion basicUnion = activitySchoolService.dao().fetch(ActivityBasicUnion.class, Cnd.where("id", "=", basicUnit.getUnionid()));
- activitySchoolApplyService.clear(Cnd.where("activityId", "=", headData.getActivityId()).and("unionHead", "=", true).and("unionId", "=", getUnionId()));
- headData.setApplyUser(ShiroUtil.getPrincipalProperty("id").toString());
- headData.setApplyDate(DateUtil.getDate());
- headData.setUnitname(basicUnit.getName());
- headData.setActivityUnionId(basicUnion.getId());
- headData.setActivityUnionName(basicUnion.getUnionname());
- activitySchoolApplyService.insert(headData);
-
- }
-
-
+ @Aop(TransAop.READ_COMMITTED)
+ public Object doLeaderCoachHead(String activityId, @Param("staffData") ActivitySchoolApply staffData,
+ @Param("LeaderData") ActivitySchoolApply LeaderData,
+ @Param("CoachData") ActivitySchoolApply CoachData,
+ @Param("headData") ActivitySchoolApply headData) {
+ activitySchoolApplyService.saveUnionRoles(activityId, getUnionId(), ShiroUtil.getUserId(),
+ staffData, LeaderData, CoachData, headData);
return null;
}
+ /**
+ * 查询活动中当前工会的领队、教练和工作人员,并提供可回显的用户选项。
+ *
+ * @param activityId 当前活动ID
+ * @return Map,unionCoach、unionLeader、unionHead、unionStaff 为对应报名记录,
+ * userOptions 为有效用户列表;历史空 userId 仅在返回值中按唯一工号回显
+ */
@At
@ViReturn
public Object getUnionCoachLeaderHead(String activityId) {
- Map result = new HashMap();
- Sql sql = Sqls.create("""
- SELECT apply.*,us.unitname FROM activity_school_apply apply LEFT JOIN `user` us ON us.id=apply.userId WHERE apply.activityId=@activityId and apply.unionId=@unionId
- """);
- sql.setParam("unionId", getUnionId());
- sql.setParam("activityId", activityId);
- List list = activitySchoolApplyService.listMap(sql);
- NutMap unionCoach = list.stream().filter(v -> {
- return v.getBoolean("unionCoach");
- }).findFirst().orElse(null);
- NutMap unionLeader = list.stream().filter(v -> {
- return v.getBoolean("unionLeader");
- }).findFirst().orElse(null);
- NutMap unionHead = list.stream().filter(v -> {
- return v.getBoolean("unionHead");
- }).findFirst().orElse(null);
- NutMap unionStaff = list.stream().filter(v -> {
- return v.getBoolean("unionStaff");
- }).findFirst().orElse(null);
- result.put("unionCoach", unionCoach);
- result.put("unionLeader", unionLeader);
- result.put("unionHead", unionHead);
- result.put("unionStaff", unionStaff);
-
- List userOptions = List.of();
-
- ArrayList arrayList = new ArrayList<>(userOptions);
-
- if (unionCoach != null) {
- arrayList.add(sysUserService.fetch(unionCoach.getString("userId")));
- }
-
- if (unionLeader != null) {
- arrayList.add(sysUserService.fetch(unionLeader.getString("userId")));
- }
- if (unionHead != null) {
- arrayList.add(sysUserService.fetch(unionHead.getString("userId")));
- }
- if (unionStaff != null) {
- arrayList.add(sysUserService.fetch(unionStaff.getString("userId")));
- }
-
-
- result.put("userOptions", arrayList);
-
- return result;
+ return activitySchoolApplyService.getUnionRoleInfo(activityId, getUnionId());
}
@At
diff --git a/src/main/java/io/v/nutz/activity/controller/school/ActivityCommonController.java b/src/main/java/io/v/nutz/activity/controller/school/ActivityCommonController.java
index 9a5c4fe..624b95e 100644
--- a/src/main/java/io/v/nutz/activity/controller/school/ActivityCommonController.java
+++ b/src/main/java/io/v/nutz/activity/controller/school/ActivityCommonController.java
@@ -2,6 +2,7 @@ package io.v.nutz.activity.controller.school;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
+import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.hutool.core.util.StrUtil;
import com.deepoove.poi.XWPFTemplate;
@@ -206,7 +207,7 @@ public class ActivityCommonController {
SELECT
app.*,
team.`name` team,
- unit.`name` unitname
+ COALESCE(NULLIF(app.unitname, ''), unit.`name`) unitname
FROM
activity_school_apply app
LEFT JOIN activity_school_team team ON app.teamId = team.id
@@ -266,7 +267,14 @@ public class ActivityCommonController {
public void exportXlsx(String id, String unionId, HttpServletResponse response) throws IOException {
Sql sql = Sqls.create("""
SELECT
+ app.id,
+ app.activityId,
+ app.unionId,
+ app.userId,
+ app.eventId,
+ app.teamId,
app.username,
+ app.birthday,
COALESCE(NULLIF(app.loginname, ''), u.loginname) loginname,
app.identity,
app.activityUnionName,
@@ -316,7 +324,7 @@ public class ActivityCommonController {
if (Strings.isNotBlank(unionId)) {
sql.setVar("cnd", "and u.unionid='" + unionId + "'");
}
- List nutMaps = activitySchoolApplyService.listMap(sql);
+ List nutMaps = activitySchoolApplyService.mergeExportIdentities(activitySchoolApplyService.listMap(sql));
String activityName = nutMaps.get(0).getString("activityName");
List entityList = new ArrayList<>();
@@ -329,6 +337,7 @@ public class ActivityCommonController {
entityList.add(new ExcelExportEntity("工号", "loginname", 20));
entityList.add(new ExcelExportEntity("姓名", "username", 20));
entityList.add(new ExcelExportEntity("性别", "sex", 10));
+ entityList.add(new ExcelExportEntity("出生年月", "birthday", 20));
entityList.add(new ExcelExportEntity("身份证号", "idcard", 20));
entityList.add(new ExcelExportEntity("报名人电话号码", "mobile", 20));
entityList.add(new ExcelExportEntity("是否会员", "isMember", 15));
@@ -343,8 +352,10 @@ public class ActivityCommonController {
z.put("sf", sf.replace("[", "").replace("]", ""));
});
response.setContentType("application/octet-stream");
- response.setHeader("Content-Disposition", "attachment;filename=" + new String((activityName + "报名表.xls").getBytes("utf-8"), "ISO8859-1"));
- Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), entityList, nutMaps);
+ response.setHeader("Content-Disposition", "attachment;filename=" + new String((activityName + "报名表.xlsx").getBytes("utf-8"), "ISO8859-1"));
+ ExportParams exportParams = new ExportParams();
+ exportParams.setType(ExcelType.XSSF);
+ Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entityList, nutMaps);
markMissingRequiredInfo(workbook);
workbook.write(response.getOutputStream());
}
@@ -454,7 +465,7 @@ public class ActivityCommonController {
ae.allName,
app.*,
team.`name` teamName,
- unit.`name` unitName,
+ COALESCE(NULLIF(app.unitname, ''), unit.`name`) unitName,
gh.unionname AS unionName
FROM
activity_school_apply app
@@ -640,7 +651,7 @@ public class ActivityCommonController {
SELECT
app.*,
team.`name` team,
- unit.`name` unitname
+ COALESCE(NULLIF(app.unitname, ''), unit.`name`) unitname
FROM
activity_school_apply app
LEFT JOIN activity_school_team team ON app.teamId = team.id
diff --git a/src/main/java/io/v/nutz/activity/controller/school/ActivityInfoManageController.java b/src/main/java/io/v/nutz/activity/controller/school/ActivityInfoManageController.java
index 93c98a6..9b129c2 100644
--- a/src/main/java/io/v/nutz/activity/controller/school/ActivityInfoManageController.java
+++ b/src/main/java/io/v/nutz/activity/controller/school/ActivityInfoManageController.java
@@ -16,6 +16,8 @@ import io.v.nutz.util.ShiroUtil;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.nutz.dao.Chain;
+import org.nutz.aop.interceptor.ioc.TransAop;
+import org.nutz.ioc.aop.Aop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
@@ -57,6 +59,38 @@ public class ActivityInfoManageController {
public void index() {
}
+ /** 无参数;返回 data 数组,每项包含可沿用活动的 id 和 name。 */
+ @At
+ @ViReturn
+ @RequiresPermissions("activity.school.info")
+ public Object getReuseActivityOptions() {
+ return activitySchoolService.getReuseActivityOptions();
+ }
+
+ /** id 为来源活动ID;返回 data 对象,包含活动字段和 schoolEvents 项目配置数组。 */
+ @At
+ @ViReturn
+ @RequiresPermissions("activity.school.info")
+ public Object findReuseActivity(String id) {
+ return activitySchoolService.findReuseActivity(id);
+ }
+
+ /**
+ * sourceId 为来源活动ID,data 为新活动表单,events 为项目配置数组。
+ * 返回 data 字符串(新活动ID),供保存后继续编辑使用。
+ */
+ @At
+ @ViReturn
+ @RequiresPermissions("activity.school.info")
+ @Aop(TransAop.READ_COMMITTED)
+ public Object doReuseAdd(String sourceId, @Param("data") ActivitySchool data,
+ @Param("events") ActivitySchoolEvent[] events) {
+ if (StrUtil.isBlank(sourceId) || data == null || data.getActivityLevel() == null) {
+ return Result.error("请选择沿用活动并填写活动信息");
+ }
+ return activitySchoolService.doReuseAdd(sourceId, data, events);
+ }
+
@At
@ViReturn
public Object pageData(PageForm page, Integer year, String name, String gameStyle, String query, String activityId, String activityLevel) {
diff --git a/src/main/java/io/v/nutz/activity/controller/school/ActivityReadingController.java b/src/main/java/io/v/nutz/activity/controller/school/ActivityReadingController.java
index 4e874c7..ee9b804 100644
--- a/src/main/java/io/v/nutz/activity/controller/school/ActivityReadingController.java
+++ b/src/main/java/io/v/nutz/activity/controller/school/ActivityReadingController.java
@@ -121,7 +121,7 @@ public class ActivityReadingController {
school.belongUnionId belongUnionId,
school.belongClubId belongClubId,
team.`name` team,
- unit.`name` unitname,
+ COALESCE(NULLIF(app.unitname, ''), unit.`name`) unitname,
ev.allName,
ev.id evid,
ev.projectType
@@ -230,6 +230,9 @@ public class ActivityReadingController {
Sql sql = Sqls.create("""
SELECT
apply.loginname,
+ apply.birthday,
+ apply.mobile,
+ apply.unitname,
apply.username,
apply.sex,
IF(apply.sex='男',1,2) AS sexOrder,
@@ -269,6 +272,10 @@ public class ActivityReadingController {
for (int i = 0; i < v.size(); i++) {
switch (i) {
case 0 -> {
+ entity.setLoginname(v.get(i).getString("loginname"));
+ entity.setBirthday(v.get(i).getString("birthday"));
+ entity.setMobile(v.get(i).getString("mobile"));
+ entity.setUnitname(v.get(i).getString("unitname"));
if (v.get(i).getInt("awardsMode") == 1) {
entity.setUserName(v.get(i).getString("username"));
entity.setSex(v.get(i).getString("sex"));
diff --git a/src/main/java/io/v/nutz/activity/controller/school/ActivityReviewController.java b/src/main/java/io/v/nutz/activity/controller/school/ActivityReviewController.java
index 8aae670..9641ff4 100644
--- a/src/main/java/io/v/nutz/activity/controller/school/ActivityReviewController.java
+++ b/src/main/java/io/v/nutz/activity/controller/school/ActivityReviewController.java
@@ -52,6 +52,9 @@ public class ActivityReviewController {
apply.loginname,
apply.username,
apply.mobile,
+ apply.sex,
+ apply.birthday,
+ apply.unitname,
apply.identity,
school.id schoolId,
school.eventsId,
diff --git a/src/main/java/io/v/nutz/activity/controller/school/constant/SchoolActivityApplyExportEntity.java b/src/main/java/io/v/nutz/activity/controller/school/constant/SchoolActivityApplyExportEntity.java
index d7b5366..68fcbe7 100644
--- a/src/main/java/io/v/nutz/activity/controller/school/constant/SchoolActivityApplyExportEntity.java
+++ b/src/main/java/io/v/nutz/activity/controller/school/constant/SchoolActivityApplyExportEntity.java
@@ -18,6 +18,14 @@ public class SchoolActivityApplyExportEntity {
private String number;
@Excel(name = "姓名", width = 20d)
private String userName;
+ @Excel(name = "工号", width = 20d)
+ private String loginname;
+ @Excel(name = "出生年月", width = 20d)
+ private String birthday;
+ @Excel(name = "电话", width = 20d)
+ private String mobile;
+ @Excel(name = "单位", width = 20d)
+ private String unitname;
@Excel(name = "性别", width = 20d)
private String sex;
diff --git a/src/main/java/io/v/nutz/activity/services/ActivitySchoolApplyService.java b/src/main/java/io/v/nutz/activity/services/ActivitySchoolApplyService.java
index d89dccd..d4e97b1 100644
--- a/src/main/java/io/v/nutz/activity/services/ActivitySchoolApplyService.java
+++ b/src/main/java/io/v/nutz/activity/services/ActivitySchoolApplyService.java
@@ -1,18 +1,66 @@
package io.v.nutz.activity.services;
import io.v.nutz.activity.models.ActivitySchoolApply;
+import io.v.nutz.sys.models.Sys_user;
import io.v.nutz.service.ViService;
+import org.nutz.lang.util.NutMap;
import java.util.List;
+import java.util.Map;
/**
* @author Aaron
*/
public interface ActivitySchoolApplyService extends ViService {
+ /** @return 当前年份预计分配的外援工号;实际工号以创建接口返回值为准。 */
+ String previewExternalLoginname();
+
+ /**
+ * 创建仅用于报名的外援用户,按年份生成 wy+年份+流水号的工号。
+ * @param username 外援姓名
+ * @param sex 性别,男或女
+ * @param birthday 出生日期,yyyy-MM-dd
+ * @param mobile 手机号码
+ * @param unitId 报名人所在单位 ID,用于归属当前报名工会
+ * @return 已创建的系统用户,包含用户 ID 和自动生成的工号
+ */
+ Sys_user createExternalUser(String username, String sex, String birthday, String mobile, String unitId);
+
void doApplies(List applies);
void doApplies(String activity, String union_id, String eventId,List applies);
void doApply(ActivitySchoolApply apply);
+
+ /**
+ * 保存活动级工会人员;空 userId 表示取消该身份,项目内的报名记录不受影响。
+ *
+ * @param activityId 活动ID
+ * @param unionId 当前工会ID
+ * @param operatorId 当前操作人的用户ID
+ * @param staffData 工作人员报名信息,空 userId 表示取消
+ * @param leaderData 领队报名信息,空 userId 表示取消
+ * @param coachData 教练报名信息,空 userId 表示取消
+ * @param headData 团长报名信息,空 userId 表示取消
+ */
+ void saveUnionRoles(String activityId, String unionId, String operatorId, ActivitySchoolApply staffData,
+ ActivitySchoolApply leaderData, ActivitySchoolApply coachData, ActivitySchoolApply headData);
+
+ /**
+ * 查询活动级工会人员及姓名下拉选项,历史空用户ID仅在返回数据中按唯一工号补齐。
+ *
+ * @param activityId 活动ID
+ * @param unionId 当前工会ID
+ * @return 包含 unionCoach、unionLeader、unionHead、unionStaff 报名记录及 userOptions 用户列表的 Map
+ */
+ Map getUnionRoleInfo(String activityId, String unionId);
+
+ /**
+ * 合并同一人员在活动级和同一项目队伍中的导出身份,保留不同项目和队伍。
+ *
+ * @param rows 导出查询的报名记录,需包含活动、工会、人员、项目、队伍ID及 identity
+ * @return 每个项目队伍一行的导出记录;没有项目报名的活动级人员仍保留一行
+ */
+ List mergeExportIdentities(List rows);
}
diff --git a/src/main/java/io/v/nutz/activity/services/ActivitySchoolService.java b/src/main/java/io/v/nutz/activity/services/ActivitySchoolService.java
index 8dc9380..5410f8a 100644
--- a/src/main/java/io/v/nutz/activity/services/ActivitySchoolService.java
+++ b/src/main/java/io/v/nutz/activity/services/ActivitySchoolService.java
@@ -4,12 +4,23 @@ package io.v.nutz.activity.services;
import io.v.nutz.activity.models.ActivitySchool;
import io.v.nutz.activity.models.ActivitySchoolEvent;
import io.v.nutz.service.ViService;
+import org.nutz.lang.util.NutMap;
+import java.util.List;
/**
* @author Aaron
*/
public interface ActivitySchoolService extends ViService {
+ /** 无参数;返回当前管理范围内可沿用活动的 id、name 列表,按创建时间倒序。 */
+ List getReuseActivityOptions();
+
+ /** id 为历史活动ID;返回活动字段及 schoolEvents 项目配置数组,不可访问时抛出异常。 */
+ NutMap findReuseActivity(String id);
+
+ /** sourceId 为来源活动ID,activitySchool 为新活动信息,events 为项目配置;返回新活动ID。 */
+ String doReuseAdd(String sourceId, ActivitySchool activitySchool, ActivitySchoolEvent[] events);
+
String doAdd(ActivitySchool activitySchool, ActivitySchoolEvent[] events);
void doEdit(ActivitySchool activitySchool, ActivitySchoolEvent[] events, String applyEndTime);
diff --git a/src/main/java/io/v/nutz/activity/services/impl/ActivitySchoolApplyServiceImpl.java b/src/main/java/io/v/nutz/activity/services/impl/ActivitySchoolApplyServiceImpl.java
index b4fba34..11fb145 100644
--- a/src/main/java/io/v/nutz/activity/services/impl/ActivitySchoolApplyServiceImpl.java
+++ b/src/main/java/io/v/nutz/activity/services/impl/ActivitySchoolApplyServiceImpl.java
@@ -1,25 +1,93 @@
package io.v.nutz.activity.services.impl;
+import io.v.nutz.activity.models.ActivityBasicUnion;
+import io.v.nutz.activity.models.ActivityBasicUnit;
import io.v.nutz.activity.models.ActivitySchoolApply;
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 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.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.IocBean;
+import org.nutz.lang.Lang;
+import org.nutz.lang.Strings;
+import org.nutz.lang.random.R;
+import org.nutz.lang.util.NutMap;
+import java.time.LocalDate;
+import java.time.Year;
+import java.time.format.DateTimeParseException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
@IocBean(args = {"refer:dao"})
public class ActivitySchoolApplyServiceImpl extends ViServiceImpl implements ActivitySchoolApplyService {
+ private static final Object EXTERNAL_NUMBER_LOCK = new Object();
+
public ActivitySchoolApplyServiceImpl(Dao dao) {
super(dao);
}
+ @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);
+ }
+
+ @Override
+ @Aop(TransAop.READ_COMMITTED)
+ public Sys_user createExternalUser(String username, String sex, String birthday, String mobile, String unitId) {
+ String name = Strings.sNull(username).trim();
+ 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("请填写外援姓名、性别及正确的手机号码");
+ }
+ try {
+ LocalDate.parse(birthday);
+ } catch (DateTimeParseException | NullPointerException e) {
+ throw new IllegalArgumentException("请选择正确的出生年月");
+ }
+ ActivityBasicUnit unit = dao().fetch(ActivityBasicUnit.class, unitId);
+ if (unit == null || Strings.isBlank(unit.getUnionid())) {
+ throw new IllegalArgumentException("当前报名单位未配置活动工会");
+ }
+ // 工号在服务端分配,避免多个浏览器按相同的前端预览号建人。
+ synchronized (EXTERNAL_NUMBER_LOCK) {
+ Sys_user user = new Sys_user();
+ user.setId(R.UU32());
+ user.setLoginname(previewExternalLoginname());
+ user.setUsername(name);
+ user.setSex(sex);
+ user.setBirthday(birthday);
+ user.setMobile(phone);
+ user.setUnitid(unitId);
+ user.setUnionid(unit.getUnionid());
+ user.setDisabled(true);
+ dao().insert(user);
+ return user;
+ }
+ }
+
@Aop(TransAop.READ_COMMITTED)
public void doApplies(List applies) {
@@ -32,6 +100,20 @@ public class ActivitySchoolApplyServiceImpl extends ViServiceImpl applies) {
+ for (ActivitySchoolApply apply : applies) {
+ Sys_user user = Strings.isBlank(apply.getUserId()) ? null : dao().fetch(Sys_user.class, apply.getUserId());
+ 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("外援");
+ }
+ }
clear(Cnd.where("activityId", "=", activity).and("activityUnionId", "=", union_id).and("eventId","=",eventId));
doApplies(applies);
}
@@ -41,4 +123,159 @@ public class ActivitySchoolApplyServiceImpl extends ViServiceImpl getUnionRoleInfo(String activityId, String unionId) {
+ Sql sql = Sqls.create("SELECT apply.*,us.unitname FROM activity_school_apply apply "
+ + "LEFT JOIN `user` us ON us.id=apply.userId "
+ + "WHERE apply.activityId=@activityId AND apply.unionId=@unionId AND apply.eventId IS NULL");
+ sql.setParam("activityId", activityId);
+ sql.setParam("unionId", unionId);
+ List rows = listMap(sql);
+ NutMap coach = rows.stream().filter(row -> Boolean.TRUE.equals(row.getBoolean("unionCoach"))).findFirst().orElse(null);
+ NutMap leader = rows.stream().filter(row -> Boolean.TRUE.equals(row.getBoolean("unionLeader"))).findFirst().orElse(null);
+ NutMap head = rows.stream().filter(row -> Boolean.TRUE.equals(row.getBoolean("unionHead"))).findFirst().orElse(null);
+ NutMap staff = rows.stream().filter(row -> Boolean.TRUE.equals(row.getBoolean("unionStaff"))).findFirst().orElse(null);
+ Map result = new LinkedHashMap<>();
+ result.put("unionCoach", coach);
+ result.put("unionLeader", leader);
+ result.put("unionHead", head);
+ result.put("unionStaff", staff);
+
+ Map options = new LinkedHashMap<>();
+ // 历史记录的 userId 可能为空;工号只在唯一匹配时用于回显,不在查询时改写数据库。
+ for (NutMap role : Arrays.asList(coach, leader, head, staff)) {
+ if (role == null) continue;
+ Sys_user user = Strings.isBlank(role.getString("userId")) ? null : dao().fetch(Sys_user.class, role.getString("userId"));
+ if (user == null && Strings.isNotBlank(role.getString("loginname"))) {
+ List matches = dao().query(Sys_user.class, Cnd.where("loginname", "=", role.getString("loginname")));
+ if (matches.size() == 1) user = matches.get(0);
+ }
+ if (user != null) {
+ role.put("userId", user.getId());
+ options.put(user.getId(), user);
+ }
+ }
+ result.put("userOptions", new ArrayList<>(options.values()));
+ return result;
+ }
+
+ @Override
+ public List mergeExportIdentities(List rows) {
+ Map> accountUsers = new LinkedHashMap<>();
+ for (NutMap row : rows) {
+ if (Strings.isNotBlank(row.getString("loginname")) && Strings.isNotBlank(row.getString("userId"))) {
+ accountUsers.computeIfAbsent(exportAccountKey(row), key -> new LinkedHashSet<>()).add(row.getString("userId"));
+ }
+ }
+ Map> activityRoles = new LinkedHashMap<>();
+ Map> projectRoles = new LinkedHashMap<>();
+ Map projectRows = new LinkedHashMap<>();
+ Set peopleWithProjects = new LinkedHashSet<>();
+ for (NutMap row : rows) {
+ String person = exportPersonKey(row, accountUsers);
+ List identity = Lang.map2Object(row, ActivitySchoolApply.class).getIdentity();
+ String project = exportProjectKey(row, person);
+ if (project == null) {
+ activityRoles.computeIfAbsent(person, key -> new LinkedHashSet<>()).addAll(identity == null ? List.of() : identity);
+ } else {
+ peopleWithProjects.add(person);
+ projectRows.putIfAbsent(project, row);
+ projectRoles.computeIfAbsent(project, key -> new LinkedHashSet<>()).addAll(identity == null ? List.of() : identity);
+ }
+ }
+
+ List result = new ArrayList<>();
+ Set emitted = new LinkedHashSet<>();
+ for (NutMap row : rows) {
+ String person = exportPersonKey(row, accountUsers);
+ String project = exportProjectKey(row, person);
+ if (project == null && peopleWithProjects.contains(person)) continue;
+ String outputKey = project == null ? "activity:" + person : "project:" + project;
+ if (!emitted.add(outputKey)) continue;
+ NutMap source = project == null ? row : projectRows.get(project);
+ NutMap merged = new NutMap();
+ merged.putAll(source);
+ Set identities = new LinkedHashSet<>();
+ if (project != null) identities.addAll(projectRoles.get(project));
+ identities.addAll(activityRoles.getOrDefault(person, Set.of()));
+ merged.put("identity", new ArrayList<>(identities));
+ result.add(merged);
+ }
+ return result;
+ }
+
+ /** 工号和姓名用于关联历史空 userId 记录;发现多个账号共用该组合时,保留各自记录。 */
+ private String exportPersonKey(NutMap row, Map> accountUsers) {
+ String union = Strings.sNull(row.getString("unionId"));
+ String loginname = row.getString("loginname");
+ String userId = row.getString("userId");
+ if (Strings.isNotBlank(loginname)) {
+ String account = exportAccountKey(row);
+ if (accountUsers.getOrDefault(account, Set.of()).size() > 1) {
+ return Strings.isNotBlank(userId) ? union + ":user:" + userId : union + ":row:" + row.getString("id");
+ }
+ return account;
+ }
+ if (Strings.isNotBlank(userId)) return union + ":user:" + userId;
+ return union + ":row:" + row.getString("id");
+ }
+
+ private String exportAccountKey(NutMap row) {
+ return Strings.sNull(row.getString("unionId")) + ":login:" + row.getString("loginname")
+ + ":name:" + Strings.sNull(row.getString("username"));
+ }
+
+ /** 同一项目中不同队伍仍是不同报名行;活动级身份没有项目和队伍。 */
+ private String exportProjectKey(NutMap row, String person) {
+ if (Strings.isBlank(row.getString("eventId"))) return null;
+ return person + ":event:" + row.getString("eventId") + ":team:" + Strings.sNull(row.getString("teamId"));
+ }
}
diff --git a/src/main/java/io/v/nutz/activity/services/impl/ActivitySchoolServiceImpl.java b/src/main/java/io/v/nutz/activity/services/impl/ActivitySchoolServiceImpl.java
index 3b5fb16..f2293fa 100644
--- a/src/main/java/io/v/nutz/activity/services/impl/ActivitySchoolServiceImpl.java
+++ b/src/main/java/io/v/nutz/activity/services/impl/ActivitySchoolServiceImpl.java
@@ -6,11 +6,18 @@ import io.v.nutz.activity.services.ActivitySchoolApplyService;
import io.v.nutz.activity.services.ActivitySchoolService;
import io.v.nutz.activity.services.ActivitySchoolTeamService;
import io.v.nutz.base.utils.DateUtil;
+import io.v.nutz.base.utils.Vi;
+import io.v.nutz.activity.utils.ActivityRoleUtil;
+import io.v.nutz.util.ShiroUtil;
import io.v.nutz.service.ViService;
import io.v.nutz.service.impl.ViServiceImpl;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
+import org.nutz.dao.Chain;
import org.nutz.dao.Dao;
+import org.nutz.dao.Sqls;
+import org.nutz.lang.Strings;
+import org.nutz.lang.util.NutMap;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
@@ -46,6 +53,114 @@ public class ActivitySchoolServiceImpl extends ViServiceImpl imp
@Inject("ActivitySchoolEvent")
private ViService activitySchoolEventViService;
+ @Inject
+ private Vi vi;
+
+ /** 沿用列表和详情共用现有活动管理的数据范围,防止通过历史活动ID跨范围读取。 */
+ private Cnd reuseActivityCnd() {
+ Cnd cnd = Cnd.NEW();
+ if (!ShiroUtil.hasAnyRoles("sysadmin,A06")) {
+ if (ActivityRoleUtil.isUnionManager()) {
+ cnd.and("belongUnionId", "in", ActivityRoleUtil.getManageUnionStr(ShiroUtil.getUserId()));
+ }
+ if (ShiroUtil.hasRole("H02")) {
+ cnd.and("belongClubId", "in", vi.getMangeClubStr());
+ }
+ }
+ return cnd;
+ }
+
+ /** 返回当前用户管理范围内的历史活动ID和名称,按创建时间倒序排列。 */
+ @Override
+ public List getReuseActivityOptions() {
+ return listMap(Sqls.create("SELECT id, name FROM activity_school $condition")
+ .setCondition(reuseActivityCnd().desc("foundDate")));
+ }
+
+ /** id 为历史活动ID;详情包含原活动字段和 schoolEvents 数组,供前端复制业务配置。 */
+ @Override
+ public NutMap findReuseActivity(String id) {
+ if (Strings.isBlank(id) || fetch(reuseActivityCnd().and("id", "=", id)) == null) {
+ throw new IllegalArgumentException("沿用活动不存在或无权访问");
+ }
+ NutMap result = fetch(Sqls.create("SELECT * FROM activity_school WHERE id = @id").setParam("id", id));
+ result.setv("schoolEvents", listMap(Sqls.create("SELECT ase.*, ae.projectType FROM activity_school_event ase "
+ + "LEFT JOIN activity_event ae ON ae.id = ase.eventId WHERE ase.activityId = @id").setParam("id", id)));
+ return result;
+ }
+
+ /**
+ * sourceId 为来源活动ID;只复制表单及项目配置,重新生成活动、配置、小队和组织记录。
+ * 返回新活动ID,所有写入使用同一事务,任何失败均回滚,不修改来源活动及报名记录。
+ */
+ @Override
+ @Aop(TransAop.READ_COMMITTED)
+ public String doReuseAdd(String sourceId, ActivitySchool school, ActivitySchoolEvent[] events) {
+ findReuseActivity(sourceId);
+ if (school.getEventsIds() == null || school.getEventsIds().isEmpty()) {
+ throw new IllegalArgumentException("请选择活动项目");
+ }
+ ActivitySchoolEvent[] cleanEvents = Arrays.stream(events == null ? new ActivitySchoolEvent[0] : events)
+ .filter(event -> event != null && school.getEventsIds().contains(event.getEventId())
+ && !"allItems".equals(event.getEventId()))
+ .peek(event -> {
+ // 配置主键和所属活动必须重新生成,不能信任前端传入的旧记录标识。
+ 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("项目配置不完整,请进入下一步完善项目信息");
+ }
+ }
+ school.setId(null);
+ school.setClose(false);
+ school.setFoundDate(DateUtil.getDate());
+ if (school.getActivityLevel() == 40002) {
+ school.setBelongUnionId(ActivityRoleUtil.getCurrentUnionId(dao()));
+ } else {
+ school.setBelongUnionId(null);
+ }
+ if (school.getUndertakeUnit() == null) {
+ school.setUndertakeUnit(new java.util.ArrayList<>());
+ }
+ insert(school);
+ addTeam(school.getId(), cleanEvents);
+ // 与普通创建保持一致,创建可报名工会和活动组织记录,保留后续报名入口所需关联。
+ for (ActivityBasicUnion unit : dao().query(ActivityBasicUnion.class, Cnd.where("isEnable", "=", true))) {
+ ActivityUnion union = new ActivityUnion();
+ union.setActivityId(school.getId());
+ union.setUnionname(unit.getUnionname());
+ dao().insert(union);
+ }
+ ActivityTissue tissue = new ActivityTissue();
+ tissue.setApplyTime(school.getFoundDate());
+ tissue.setType(school.getActivityLevel());
+ tissue.setProjectTypeCode("50004");
+ tissue.setActivityCode(school.getActivityCode());
+ tissue.setName(school.getName());
+ tissue.setUserId(ShiroUtil.getUserId());
+ tissue.setState(3);
+ tissue.setClubId(school.getBelongClubId());
+ tissue.setUnionId(school.getBelongUnionId());
+ tissue.setAddress(school.getAddress());
+ tissue.setApplyStartTime(school.getApplyStartTime());
+ tissue.setApplyEndTime(school.getApplyEndTime());
+ tissue.setStartTime(school.getStartTime());
+ tissue.setEndTime(school.getEndTime());
+ if (school.getImage() != null && !school.getImage().isEmpty()) {
+ tissue.setCover(school.getImage().get(0).getId());
+ }
+ dao().insert(tissue);
+ // 与原创建入口一致,在插入后统一组织ID,避免实体 @Prev 的主键生成策略影响关联。
+ dao().update(ActivityTissue.class, Chain.make("id", school.getId()), Cnd.where("id", "=", tissue.getId()));
+ return school.getId();
+ }
+
@Override
@Aop(TransAop.READ_COMMITTED)
public String doAdd(ActivitySchool activitySchool, ActivitySchoolEvent[] events) {
diff --git a/src/main/resources/static/components/activity/school/AddActivity.vue b/src/main/resources/static/components/activity/school/AddActivity.vue
index 55173b6..2d1ea86 100644
--- a/src/main/resources/static/components/activity/school/AddActivity.vue
+++ b/src/main/resources/static/components/activity/school/AddActivity.vue
@@ -11,6 +11,21 @@
label-suffix=":">
+
+
+
+
+
+
+
+
+
+
+
@@ -620,6 +635,12 @@ module.exports = {
planList: [],
events: [],
projectType: "",
+ reuseActivityId: null,
+ reuseActivityOptions: [],
+ reuseLoading: false,
+ reuseReady: false,
+ formLoading: false,
+ reuseRequestId: 0,
formRules: {
name: [{required: true, message: '必填', trigger: ['blur', 'change']}],
address: [{required: true, message: '必填', trigger: ['blur', 'change']}],
@@ -627,7 +648,6 @@ module.exports = {
eventsIds: [{required: true, message: '必填', trigger: ['blur', 'change']}],
applyTime: [{required: true, message: '必填', trigger: ['blur', 'change']}],
unitSponsor: [{required: true, message: '必填', trigger: ['blur', 'change']}],
- undertakeUnit: [{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']}],
@@ -652,6 +672,208 @@ module.exports = {
},
methods: {
+ // 下拉接口无参数;data 为当前管理范围内的 {id, name} 数组。
+ getReuseActivityOptions() {
+ return $.post('/platform/activity/school/info/mange/getReuseActivityOptions').then((resp) => {
+ if (resp.code === 0) {
+ this.$set(this, 'reuseActivityOptions', resp.data || [])
+ } else {
+ this.$message.error(resp.msg)
+ }
+ }).fail(() => {
+ this.$message.error('历史活动列表加载失败,请重新打开创建活动')
+ })
+ },
+ // JSON 列可能返回字符串、数组或空值,统一转成独立数组,避免修改来源数据。
+ reuseArray(value) {
+ let data = value
+ try {
+ data = typeof value === 'string' ? JSON.parse(value || '[]') : value
+ } catch (error) {
+ this.$message.warning('历史活动存在无法读取的配置,请检查并重新填写')
+ return []
+ }
+ return Array.isArray(data) ? clone(data) : []
+ },
+ // id 为来源活动ID;响应包含活动字段和 schoolEvents,不携带旧主键进入新增保存。
+ reuseActivityChange(id) {
+ const requestId = ++this.reuseRequestId
+ this.$set(this, 'reuseReady', false)
+ if (!id) {
+ this.$set(this, 'reuseLoading', false)
+ this.openAdd()
+ return
+ }
+ this.$set(this, 'reuseLoading', true)
+ return $.post('/platform/activity/school/info/mange/findReuseActivity', {id}).then((resp) => {
+ if (requestId !== this.reuseRequestId) return
+ if (resp.code !== 0) {
+ this.$message.error(resp.msg)
+ return
+ }
+ const form = clone(resp.data)
+ // 项目列表及编号按沿用活动的实际类型加载,旧日期要求重新填写。
+ return $.when(
+ $.post('/platform/activity/common/getEvents', {type: form.applyType}),
+ $.post('/platform/activity/apply/generateActivityCode', {activity_type: form.activityLevel}),
+ $.post('/platform/vi/common/getClubsByRole')
+ ).then((eventResponse, codeResponse, clubResponse) => {
+ if (requestId !== this.reuseRequestId) return
+ // 当前项目使用 jQuery 1.x;when 返回每个请求的 [data, status, xhr]。
+ const responses = [eventResponse[0], codeResponse[0], clubResponse[0]]
+ const failed = responses.find((response) => response.code !== 0)
+ if (failed) {
+ this.$message.error(failed.msg)
+ return
+ }
+ const events = responses[0].data || []
+ const selectedIds = this.reuseArray(form.eventsIds)
+ const availableIds = selectedIds.filter((eventId) => events.some((event) => event.id === eventId))
+ if (availableIds.length !== selectedIds.length) {
+ this.$message.warning('历史活动中已停用或不存在的项目未沿用,请检查活动项目')
+ }
+ ;['applyWay', 'unitSponsor', 'undertakeUnit', 'unitJointly', 'image'].forEach((key) => {
+ this.$set(form, key, this.reuseArray(form[key]))
+ })
+ const configs = (form.schoolEvents || []).filter((event) => availableIds.includes(event.eventId)).map((event) => {
+ const config = clone(event)
+ this.$set(config, 'id', null)
+ this.$set(config, 'activityId', null)
+ this.$set(config, 'unionLimit', this.reuseArray(config.unionLimit))
+ this.$set(config, 'ageDate', config.startAgeDate ? [config.startAgeDate, config.endAgeDate] : [])
+ return config
+ })
+ ;['id', 'foundDate', 'applyStartTime', 'applyEndTime', 'startTime', 'endTime'].forEach((key) => this.$set(form, key, null))
+ this.$set(form, 'schoolEvents', [])
+ this.$set(form, 'close', false)
+ this.$set(form, 'activityCode', responses[1].data)
+ this.$set(form, 'activityLevel', Number(form.activityLevel))
+ this.$set(form, 'activityGroupId', form.activityGroupId ? Number(form.activityGroupId) : null)
+ this.$set(form, 'applyTime', [])
+ this.$set(form, 'time', [])
+ this.$set(form, 'eventsIds', availableIds)
+ this.$set(this, 'events', events)
+ this.$set(this, 'clubOptions', responses[2].data || [])
+ this.$set(this, 'form', form)
+ this.$set(this, 'eventsIds', [])
+ this.$set(this, 'checkedEventInfo', configs)
+ this.$set(this, 'checkedEventInfo2', clone(configs))
+ this.$set(this, 'eventForm', {})
+ this.$set(this, 'checkedEvents', [])
+ this.$set(this, 'rightChecked', [])
+ this.$set(this, 'reuseReady', true)
+ this.$nextTick(() => {
+ this.initEditor()
+ if (this.$refs.activityForm) this.$refs.activityForm.clearValidate()
+ })
+ })
+ }).fail(() => {
+ if (requestId === this.reuseRequestId) {
+ this.$message.error('沿用活动加载失败,请重新选择活动')
+ }
+ }).always(() => {
+ if (requestId === this.reuseRequestId) this.$set(this, 'reuseLoading', false)
+ })
+ },
+ // 合并当前所选项目与已沿用配置;新增选择使用原有默认值,已移除项目不再提交。
+ buildReuseEvents() {
+ return this.events.filter((event) => this.form.eventsIds.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,
+ athletesMaxNum: event.projectType === '1' ? 3 : null,
+ restrictRegNumber: event.projectType === '1' ? 2 : null,
+ restrictTotalTeam: 1, substituteNum: 0, applyUserModel: 1
+ }
+ this.$set(config, 'id', null)
+ this.$set(config, 'activityId', null)
+ this.$set(config, 'startAgeDate', config.ageDate && config.ageDate.length ? config.ageDate[0] : null)
+ this.$set(config, 'endAgeDate', config.ageDate && config.ageDate.length ? config.ageDate[1] : null)
+ return config
+ })
+ },
+ // isSave 区分保存和提交;新接口返回新活动ID,保存成功后转入该新活动的编辑状态。
+ doReuseAdd(isSave) {
+ if (this.formLoading || this.reuseLoading) return
+ if (!this.reuseReady) {
+ this.$message.warning('请重新选择并加载沿用活动')
+ return
+ }
+ 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
+ }
+ 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(this, 'formLoading', true)
+ const loading = this.$loading({lock: true, text: '正在提交...', background: COVER_LAYER_COLOR})
+ return $.post('/platform/activity/school/info/mange/doReuseAdd', {
+ sourceId: this.reuseActivityId, data: JSON.stringify(form), events: JSON.stringify(this.buildReuseEvents())
+ }).then((resp) => {
+ if (resp.code !== 0) {
+ this.$message.error(resp.msg)
+ 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 (this.$refs.activityForm) {
+ this.$refs.activityForm.validate((valid) => {
+ if (valid) save()
+ })
+ } else {
+ return save()
+ }
+ },
+
async applyUserModelInput(val) {
if (val === 2) {
if (!this.eventForm.unionLimit || this.eventForm.unionLimit.length === 0) {
@@ -871,6 +1093,11 @@ module.exports = {
});
},
next() {
+ if (this.reuseLoading || this.formLoading) return
+ if (this.reuseActivityId && !this.reuseReady) {
+ this.$message.warning('请重新选择并加载沿用活动')
+ return
+ }
this.$refs["activityForm"].validate(async (valid) => {
const form = clone(this.form)
if (!valid) {
@@ -917,7 +1144,13 @@ module.exports = {
this.eventForm.checkedEventId = this.checkedEvents[0].id
this.projectType = this.checkedEvents[0].projectType
- if (!form.id || this.checkedEventInfo2.length <= 0) {
+ if (this.reuseActivityId && !form.id) {
+ // 新活动也保留沿用配置,不能因尚无活动ID而恢复为默认人数。
+ const allItems = this.checkedEventInfo.find((event) => event.eventId === 'allItems')
+ const configs = this.buildReuseEvents()
+ if (allItems) configs.unshift(clone(allItems))
+ this.$set(this, 'checkedEventInfo', configs)
+ } else if (!form.id || this.checkedEventInfo2.length <= 0) {
this.eventForm = {
checkedEventId: this.checkedEvents[0].id,
leanderNum: 0,
@@ -959,6 +1192,14 @@ module.exports = {
}
,
async openAdd() {
+ this.reuseRequestId++
+ this.$set(this, 'reuseLoading', false)
+ this.$set(this, 'reuseReady', false)
+ this.$set(this, 'reuseActivityId', null)
+ this.$set(this, 'checkedEventInfo', [])
+ this.$set(this, 'checkedEventInfo2', [])
+ this.$set(this, 'eventsIds', [])
+ this.getReuseActivityOptions()
this.events = await activity.getEvents(2)
this.planList = await activity.getSchoolActivityPlan(this.form.activityLevel)
await this.getActivityGroup()
@@ -977,6 +1218,7 @@ module.exports = {
applyWay: [2],
eventsIds: [],
unitJointly: [],
+ undertakeUnit: [],
applyType: 2,
activityCode: data,
activityLevel: 40001,
@@ -989,6 +1231,9 @@ module.exports = {
return data;
},
async openEdit(row, flag) {
+ this.reuseRequestId++
+ this.$set(this, 'reuseLoading', false)
+ this.$set(this, 'reuseActivityId', null)
this.active = flag ? 0 : this.active
await this.applyTypeChange(row.applyType)
this.planList = await activity.getSchoolActivityPlan(1)
@@ -1006,7 +1251,7 @@ module.exports = {
v.eventsIds = JSON.parse(v.eventsIds)
v.applyWay = JSON.parse(v.applyWay)
v.unitSponsor = JSON.parse(v.unitSponsor)
- v.undertakeUnit = JSON.parse(v.undertakeUnit)
+ v.undertakeUnit = this.reuseArray(v.undertakeUnit)
v.unitJointly = JSON.parse(v.unitJointly)
v.activityGroupId = parseInt(v.activityGroupId)
v.activityLevel = parseInt(v.activityLevel)
@@ -1075,6 +1320,8 @@ module.exports = {
}
,
async operate() {
+ if (this.reuseLoading || this.formLoading) return
+ if (this.reuseActivityId && !this.form.id) return this.doReuseAdd(false)
const deleteEventIds = this.eventsIds.filter(v => !this.form.eventsIds.includes(v))
const {data} = await $.get(loc() + "/getEventApply", {
@@ -1094,6 +1341,8 @@ module.exports = {
}
},
async doSave() {
+ if (this.reuseLoading || this.formLoading) return
+ if (this.reuseActivityId && !this.form.id) return this.doReuseAdd(true)
let url = this.form.id ? "/doEdit" : "/doAdd"
this.checkedEventInfo.forEach(v => {
@@ -1295,4 +1544,4 @@ module.exports = {
.restrictTotalTeam .el-form-item__label {
color: red;
}
-
\ No newline at end of file
+
diff --git a/src/main/resources/static/components/activity/school/DeleteInfo.vue b/src/main/resources/static/components/activity/school/DeleteInfo.vue
index 537a9d2..c3f7f55 100644
--- a/src/main/resources/static/components/activity/school/DeleteInfo.vue
+++ b/src/main/resources/static/components/activity/school/DeleteInfo.vue
@@ -111,6 +111,8 @@ module.exports = {
{prop: 'loginname', label: '工号'},
{prop: 'mobile', label: '电话'},
{prop: 'sex', label: '性别'},
+ {prop: 'birthday', label: '出生年月'},
+ {prop: 'unitname', label: '单位'},
{prop: 'identity', label: '身份', sortable: true},
// {prop: 'divisionLevelLeadership', label: '是否处级领导', sortable: true},
{prop: 'status', label: '状态', sortable: true},
diff --git a/src/main/resources/static/components/activity/school/Info.vue b/src/main/resources/static/components/activity/school/Info.vue
index e0c0c22..3b359a8 100644
--- a/src/main/resources/static/components/activity/school/Info.vue
+++ b/src/main/resources/static/components/activity/school/Info.vue
@@ -331,6 +331,8 @@
prop="mobile" header-align="center" align="center"
label="电话">
+
\ No newline at end of file
+
diff --git a/src/main/resources/views/platform/activity/school/ActivityApply.html b/src/main/resources/views/platform/activity/school/ActivityApply.html
index ceadd84..a6cadc9 100644
--- a/src/main/resources/views/platform/activity/school/ActivityApply.html
+++ b/src/main/resources/views/platform/activity/school/ActivityApply.html
@@ -450,6 +450,8 @@ layout("/layouts/platform.html"){
prop="mobile" header-align="center" align="center"
label="电话">
+
+
-
+
\ No newline at end of file
+#-->