From b16443e1b744d0f749705f9e7a654ed125aa87ad Mon Sep 17 00:00:00 2001 From: hongqiwei <1143662660@qq.com> Date: Tue, 15 Sep 2026 17:42:21 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E7=9A=84=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E6=AE=B5=E6=94=B9=E6=88=90=E4=B8=A4=E4=B8=AA=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=EF=BC=9B=E4=BC=9A=E5=91=98=E6=95=B0=E6=8D=AE=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E5=A2=9E=E5=8A=A0=E5=AF=BC=E5=87=BA=EF=BC=9B?= =?UTF-8?q?=E5=9C=BA=E5=9C=B0=E9=A2=84=E7=BA=A6=E5=A2=9E=E5=8A=A0=E5=8D=95?= =?UTF-8?q?=E4=BD=8D=E9=A2=84=E7=BA=A6=E5=92=8C=E5=AE=A1=E6=A0=B8=E6=B5=81?= =?UTF-8?q?=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../activity/models/ActivitySiteReserve.java | 7 +- .../services/impl/SiteBookingService.java | 45 ++++--- .../site/SiteInfoMobileController.java | 4 +- .../SourceChangeManageController.java | 84 +++---------- .../service/SourceChangeManageService.java | 19 ++- .../impl/SourceChangeManageServiceImpl.java | 114 ++++++++++++++++++ .../components/activity/site/ReserveInfo.vue | 2 +- .../views/mobile/activity/site/audit.html | 4 +- .../views/mobile/activity/site/common/info.js | 2 +- .../views/mobile/activity/site/reserve.html | 14 ++- .../platform/activity/site/ReviewEntries.html | 1 + .../platform/activity/site/SiteReserve.html | 13 +- .../platform/activity/site/SiteReview.html | 4 +- .../platform/activity/site/common/info.js | 2 +- .../platform/fitnessWalk/stepStatistics.html | 62 ++++++---- .../platform/meeting/statistics/basic.html | 62 ++++++++-- .../platform/msgNotify/msgNotifyTitle.html | 49 +++++--- .../views/platform/msgNotify/sendList.html | 70 ++++++++--- .../views/platform/reimbursement/Summary.html | 56 ++++++--- .../sourcechange/manage/commonQuery.js | 79 ++++-------- .../platform/sourcechange/manage/index.html | 28 +++-- .../birthday/manage/commonQuery.js | 62 +++------- .../resources/views/platform/zcgl/zczhcx.html | 72 ++++++----- .../platform/zgfw/difficulty/reading.html | 45 ++++--- 24 files changed, 564 insertions(+), 336 deletions(-) diff --git a/src/main/java/io/v/nutz/zhgh/activity/models/ActivitySiteReserve.java b/src/main/java/io/v/nutz/zhgh/activity/models/ActivitySiteReserve.java index d45c56b..fdb35f2 100644 --- a/src/main/java/io/v/nutz/zhgh/activity/models/ActivitySiteReserve.java +++ b/src/main/java/io/v/nutz/zhgh/activity/models/ActivitySiteReserve.java @@ -56,6 +56,11 @@ public class ActivitySiteReserve extends BaseModel { @ColDefine(type = ColType.VARCHAR, width = 50) private String reserve_person_unit; + @Column + @Comment("申请时所属单位ID,单位预约审核按此快照匹配负责人") + @ColDefine(type = ColType.VARCHAR, width = 32) + private String reserveUnitId; + @Column @Comment("预约人联系方式") @ColDefine(type = ColType.VARCHAR, width = 20) @@ -137,7 +142,7 @@ public class ActivitySiteReserve extends BaseModel { private String joinUser; @Column - @Comment("预约类型(1.个人预约,2.分工会预约,3.协会预约)") + @Comment("预约类型(1.个人预约,2.分工会预约,3.协会预约,4.单位预约)") @ColDefine(type = ColType.INT, width = 10) private Integer reserve_type; } diff --git a/src/main/java/io/v/nutz/zhgh/activity/services/impl/SiteBookingService.java b/src/main/java/io/v/nutz/zhgh/activity/services/impl/SiteBookingService.java index b0929e3..3f88341 100644 --- a/src/main/java/io/v/nutz/zhgh/activity/services/impl/SiteBookingService.java +++ b/src/main/java/io/v/nutz/zhgh/activity/services/impl/SiteBookingService.java @@ -29,7 +29,7 @@ import java.util.stream.Collectors; */ @IocBean(args = {"refer:dao"}) public class SiteBookingService extends BaseServiceImpl { - public static final int UNION = 4000, CLUB = 4010, SCHOOL = 4020, PASS = 4030, REJECT = 4040, CANCEL = 4050; + public static final int UNION = 4000, CLUB = 4010, SCHOOL = 4020, PASS = 4030, REJECT = 4040, CANCEL = 4050, UNIT = 4060; /** 校工会节点统一按专属场地管理员角色分配待办和校验审核资格。 */ private static final String SCHOOL_REVIEW_ROLE = "SchoolUnionActivityVenueAdmin"; /** 兼容现有日历组件的状态字段;名称统一读取 state,不再读取 audit_state。 */ @@ -52,24 +52,25 @@ public class SiteBookingService extends BaseServiceImpl { + "order by c.name").setParam("uid", uid())); } - /** 无入参,返回当前申请人的id/name所属分工会;采用与提交相同的user视图组织来源,未配置时返回空字符串。 */ + /** 无入参,返回当前申请人的id/name所属分工会及unitId/unitName所属单位;采用与提交相同的user视图组织来源,未配置时返回空字符串。 */ public NutMap myBookingUnion() { - List rows=listMap(Sqls.create("select u.unionid id,un.unionname name from `user` u left join sys_union un on un.id=u.unionid where u.id=@id") + List rows=listMap(Sqls.create("select u.unionid id,un.unionname name,u.unitid unitId,u.unitname unitName from `user` u left join sys_union un on un.id=u.unionid where u.id=@id") .setParam("id",uid())); - return rows.isEmpty() ? NutMap.NEW().setv("id","").setv("name","") : rows.get(0); + return rows.isEmpty() ? NutMap.NEW().setv("id","").setv("name","").setv("unitId","").setv("unitName","") : rows.get(0); } - /** 预约类型 1 历史个人、2 分工会、3 协会,返回应进入的首个状态 ID。 */ + /** 预约类型 1 历史个人、2 分工会、3 协会、4 单位,返回应进入的首个状态 ID。 */ public int firstState(Integer type) { if (Integer.valueOf(1).equals(type)) return UNION; if (Integer.valueOf(2).equals(type)) return UNION; if (Integer.valueOf(3).equals(type)) return CLUB; + if (Integer.valueOf(4).equals(type)) return UNIT; throw new IllegalArgumentException("请选择有效的预约类型"); } /** 按节点角色及组织范围查实际审核人;不允许空组织退化为全校范围。 */ private List reviewers(int node, ActivitySiteReserve booking) { - String role = node == UNION ? "gh01" : node == CLUB ? "club01" : SCHOOL_REVIEW_ROLE; + String role = node == UNION ? "gh01" : node == CLUB ? "club01" : node == UNIT ? "unit_manger" : SCHOOL_REVIEW_ROLE; String filter = ""; if (node == UNION) { if (Strings.isBlank(booking.getReserve_person_unionid())) throw new IllegalArgumentException("申请人未关联分工会,请先完善所属分工会"); @@ -77,11 +78,15 @@ public class SiteBookingService extends BaseServiceImpl { } else if (node == CLUB) { if (Strings.isBlank(booking.getClubId())) throw new IllegalArgumentException("请选择所属协会"); filter = " and ur.stid=@org"; + } else if (node == UNIT) { + // 负责人必须绑定申请时的单位,不能使用其任职单位或仅凭角色放行。 + if (Strings.isBlank(booking.getReserveUnitId())) throw new IllegalArgumentException("申请人未关联单位,请先完善所属单位"); + filter = " and ur.unitid=@org and coalesce(r.disabled,0)=0"; } else if (node != SCHOOL) throw new IllegalArgumentException("当前节点不允许审核"); return listMap(Sqls.create("select distinct u.id,u.loginname from sys_user_role ur join sys_role r on r.id=ur.roleId " + "join sys_user u on u.id=ur.userId where r.code=@role and coalesce(u.disabled,0)=0 " + "and coalesce(u.delFlag,0)=0" + filter).setParam("role", role) - .setParam("org", node == UNION ? booking.getReserve_person_unionid() : booking.getClubId())); + .setParam("org", node == UNION ? booking.getReserve_person_unionid() : node == UNIT ? booking.getReserveUnitId() : booking.getClubId())); } /** 返回非空审核人工号名单,缺少节点负责人时中止事务并提示具体节点。 */ @@ -89,20 +94,21 @@ public class SiteBookingService extends BaseServiceImpl { List names = reviewers(node, booking).stream().map(v -> v.getString("loginname")) .filter(Strings::isNotBlank).distinct().collect(Collectors.toList()); if (names.isEmpty()) throw new IllegalArgumentException(node == UNION ? "所属分工会未配置可用的分工会主席" - : node == CLUB ? "所选协会未配置可用的协会会长" : "未配置可用的校工会场地管理员"); + : node == CLUB ? "所选协会未配置可用的协会会长" : node == UNIT ? "所属单位未配置可用的二级单位负责人" : "未配置可用的校工会场地管理员"); return names; } - /** stages 是后端固定入口 union/club/school,返回节点 ID,禁止任意传入状态码。 */ + /** stages 是后端固定入口 union/club/unit/school,返回节点 ID,禁止任意传入状态码。 */ public int node(String stage) { if ("union".equals(stage)) return UNION; if ("club".equals(stage)) return CLUB; if ("school".equals(stage)) return SCHOOL; + if ("unit".equals(stage)) return UNIT; throw new IllegalArgumentException("无效的审核入口"); } - private String stage(int node) { return node == UNION ? "union" : node == CLUB ? "club" : "school"; } - private String title(int node) { return node == UNION ? "分工会审核" : node == CLUB ? "协会审核" : "校工会审核"; } + private String stage(int node) { return node == UNION ? "union" : node == CLUB ? "club" : node == UNIT ? "unit" : "school"; } + private String title(int node) { return node == UNION ? "分工会审核" : node == CLUB ? "协会审核" : node == UNIT ? "单位审核" : "校工会审核"; } private String process(ActivitySiteReserve b) { return "activity_site@" + b.getSqid(); } /** @@ -128,9 +134,11 @@ public class SiteBookingService extends BaseServiceImpl { form.setReserve_person_phone(user.getMobile()); // user 视图按特殊人员工会关系、所属单位计算有效分工会;原表 unionid 可能为空或为历史值。 // 提交时保存有效组织快照,后续待办和审核范围均使用该快照匹配主席角色。 - List profile=listMap(Sqls.create("select unionid,unitname from `user` where id=@id").setParam("id",uid())); + List profile=listMap(Sqls.create("select unionid,unitid,unitname from `user` where id=@id").setParam("id",uid())); form.setReserve_person_unionid(profile.isEmpty() ? null : profile.get(0).getString("unionid")); form.setReserve_person_unit(profile.isEmpty() ? "" : profile.get(0).getString("unitname")); + // 所属单位由登录人资料生成,不接受客户端指定其他单位。 + form.setReserveUnitId(profile.isEmpty() ? null : profile.get(0).getString("unitid")); if (first == CLUB && myClubs().stream().noneMatch(v -> v.getString("id").equals(form.getClubId()))) throw new IllegalArgumentException("您不是所选协会的有效成员,请重新选择所属协会"); if (first != CLUB) form.setClubId(null); @@ -164,9 +172,9 @@ public class SiteBookingService extends BaseServiceImpl { List existing = query(Cnd.where("site_id", "=", site.getId()).and("reserve_day", "=", day) .and("start_time", "<", end).and("end_time", ">", start).and("reserve_state", "not in", Arrays.asList(REJECT, CANCEL))); if (existing.stream().anyMatch(v -> uid().equals(v.getReserve_person_id()))) throw new IllegalArgumentException("您已预约该时间段"); - if (!personal && !existing.isEmpty()) throw new IllegalArgumentException("该时段已有预约,协会或分工会预约需要空闲时段"); + if (!personal && !existing.isEmpty()) throw new IllegalArgumentException("该时段已有预约,分工会、协会或单位预约需要空闲时段"); if (personal && (existing.stream().anyMatch(v -> !Integer.valueOf(1).equals(v.getReserve_type())) - || site.getLimitNum() == null || siteInfoService.occupiedCount(existing,start,end) >= site.getLimitNum())) throw new IllegalArgumentException("该时段预约人数已满或已被分工会/协会预约"); + || site.getLimitNum() == null || siteInfoService.occupiedCount(existing,start,end) >= site.getLimitNum())) throw new IllegalArgumentException("该时段预约人数已满或已被分工会、协会、单位预约"); } String sqid = UUID.randomUUID().toString().replace("-", ""); for (NutMap slot : slots) { @@ -174,7 +182,7 @@ public class SiteBookingService extends BaseServiceImpl { row.setSqid(sqid); row.setSite_id(site.getId()); row.setReserve_type(form.getReserve_type()); row.setClubId(form.getClubId()); row.setReserve_person_unionid(form.getReserve_person_unionid()); row.setReserve_person_id(uid()); row.setReserve_person(user.getUsername()); - row.setReserve_person_phone(user.getMobile()); row.setReserve_person_unit(form.getReserve_person_unit()); + row.setReserve_person_phone(user.getMobile()); row.setReserve_person_unit(form.getReserve_person_unit()); row.setReserveUnitId(form.getReserveUnitId()); row.setReserve_cause(form.getReserve_cause()); row.setReserve_state(first); row.setReserve_day(slot.getString("day")); row.setStart_time(slot.getString("start_time")); row.setEnd_time(slot.getString("end_time")); dao().insert(row); @@ -240,8 +248,9 @@ public class SiteBookingService extends BaseServiceImpl { } } - /** 返回指定审核入口的数据范围,分工会/协会使用角色关系上的组织字段。 */ + /** 返回指定审核入口的数据范围,分工会、协会和单位均匹配角色关系上的对应组织字段。 */ private String scope(int node) { + if (node == UNIT) return "exists(select 1 from sys_user_role ur join sys_role r on r.id=ur.roleId where ur.userId=@uid and r.code='unit_manger' and coalesce(r.disabled,0)=0 and ur.unitid=b.reserveUnitId)"; if (node == SCHOOL) return "exists(select 1 from sys_user_role ur join sys_role r on r.id=ur.roleId where ur.userId=@uid and r.code='" + SCHOOL_REVIEW_ROLE + "')"; return "exists(select 1 from sys_user_role ur join sys_role r on r.id=ur.roleId where ur.userId=@uid and r.code='" + (node == UNION ? "gh01" : "club01") + "' and " @@ -362,7 +371,7 @@ public class SiteBookingService extends BaseServiceImpl { if (b == null) throw new IllegalArgumentException("预约不存在"); boolean allowed = uid().equals(b.getReserve_person_id()); for (int node : new java.util.LinkedHashSet<>(Arrays.asList(firstState(b.getReserve_type()), SCHOOL))) { - if (node == UNION && Strings.isBlank(b.getReserve_person_unionid()) || node == CLUB && Strings.isBlank(b.getClubId())) continue; + if (node == UNION && Strings.isBlank(b.getReserve_person_unionid()) || node == CLUB && Strings.isBlank(b.getClubId()) || node == UNIT && Strings.isBlank(b.getReserveUnitId())) continue; allowed |= reviewers(node,b).stream().anyMatch(v -> uid().equals(v.getString("id"))); } List history = b.getAuditList() == null ? new ArrayList<>() : b.getAuditList(); @@ -398,7 +407,7 @@ public class SiteBookingService extends BaseServiceImpl { listMap(Sqls.create("select id from activity_site_reserve where sqid=@sqid order by id for update").setParam("sqid",b.getSqid())); b = fetch(id); if (!Integer.valueOf(node).equals(b.getReserve_state())) throw new IllegalArgumentException("申请已处理或不属于当前审核节点,请刷新列表"); - if (reviewers(node,b).stream().noneMatch(v -> uid().equals(v.getString("id")))) throw new IllegalArgumentException("无权审核该分工会或协会的申请"); + if (reviewers(node,b).stream().noneMatch(v -> uid().equals(v.getString("id")))) throw new IllegalArgumentException("无权审核该组织的申请"); int next = !pass ? REJECT : node == SCHOOL ? PASS : SCHOOL; if (next == SCHOOL) assignments(SCHOOL,b); Audit audit = new Audit(); diff --git a/src/main/java/io/v/nutz/zhgh/mobile/activity/site/SiteInfoMobileController.java b/src/main/java/io/v/nutz/zhgh/mobile/activity/site/SiteInfoMobileController.java index 7400f26..9167e70 100644 --- a/src/main/java/io/v/nutz/zhgh/mobile/activity/site/SiteInfoMobileController.java +++ b/src/main/java/io/v/nutz/zhgh/mobile/activity/site/SiteInfoMobileController.java @@ -207,7 +207,7 @@ public class SiteInfoMobileController { @At("/getReserve") @Ok("json:full") @ViReturn - /** siteId为场地,day为日期,reserveType为1个人/2单位/3协会;返回带code/msg的可预约场次数组。 */ + /** siteId为场地,day为日期,reserveType为1历史个人/2分工会/3协会/4单位;返回带code/msg的可预约场次数组。 */ public Object getReserve(String siteId, String day, Integer reserveType) { return siteInfoService.availableSlots(siteId,day,reserveType); } @@ -215,7 +215,7 @@ public class SiteInfoMobileController { @At("/reserveDo") @Ok("json:full") @ViReturn - /** siteId 为场地;times 为 day/start_time/end_time 数组 JSON;message 为事由;reserve_type 为1/2/3,clubId 为协会预约所属协会;返回 sqid。 */ + /** siteId 为场地;times 为 day/start_time/end_time 数组 JSON;message 为事由;reserve_type 为1历史个人/2分工会/3协会/4单位,clubId 为协会预约所属协会;返回 sqid。 */ @Aop(TransAop.READ_COMMITTED) public Object reserveDo(String siteId, String times, String message, Integer reserve_type, String clubId) { ActivitySiteReserve form=new ActivitySiteReserve(); diff --git a/src/main/java/io/v/nutz/zhgh/staffmanage/sourcechange/controller/SourceChangeManageController.java b/src/main/java/io/v/nutz/zhgh/staffmanage/sourcechange/controller/SourceChangeManageController.java index e00c6ab..441d820 100644 --- a/src/main/java/io/v/nutz/zhgh/staffmanage/sourcechange/controller/SourceChangeManageController.java +++ b/src/main/java/io/v/nutz/zhgh/staffmanage/sourcechange/controller/SourceChangeManageController.java @@ -1,14 +1,9 @@ package io.v.nutz.zhgh.staffmanage.sourcechange.controller; -import cn.hutool.core.date.DateUtil; -import cn.hutool.core.util.StrUtil; import cn.wizzer.framework.base.Result; import io.v.nutz.base.annontation.ViReturn; -import io.v.nutz.base.utils.PageUtil; import io.v.nutz.sys.models.User; import io.v.nutz.web.commons.slog.annotation.SLog; -import io.v.nutz.zhgh.staffmanage.member.constant.MemberChangeType; -import io.v.nutz.zhgh.staffmanage.member.service.MemberCommonService; import io.v.nutz.zhgh.staffmanage.sourcechange.model.SourceChangeMiddleTable; import io.v.nutz.zhgh.staffmanage.sourcechange.param.pageform.SourceChangePageForm; import io.v.nutz.zhgh.staffmanage.sourcechange.service.SourceChangeManageService; @@ -16,10 +11,6 @@ import lombok.extern.slf4j.Slf4j; import org.apache.shiro.authz.annotation.RequiresPermissions; 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.dao.util.cri.Static; import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.lang.Lang; @@ -29,7 +20,6 @@ import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Param; import java.util.*; -import java.util.stream.Collectors; /** * @version 1.0 @@ -47,8 +37,6 @@ public class SourceChangeManageController { @Inject private Dao dao; @Inject - private MemberCommonService commonService; - @Inject private SourceChangeManageService sourceChangeManageService; @@ -59,67 +47,29 @@ public class SourceChangeManageController { } + /** + * @param pageForm 列表筛选、排序及分页参数;日期字段为 yyyy-MM-dd,changeTypes 为类型编码集合 + * @return 分页对象,list 为变更记录,totalCount 为符合条件的记录总数 + */ @At @ViReturn @RequiresPermissions("sourcechange.manage") public Object pageData(SourceChangePageForm pageForm){ - Sql sql = Sqls.create(""" - SELECT - scmt.id, - scmt.loginname, - scmt.username, - u.sex, - u.unitName, - u.unionName, - scmt.userState, - scmt.personType, - scmt.preparedBy, - scmt.changeTime, - scmt.changeTypes, - scmt.changeOrigin, - scmt.isOperate, - scmt.changeInfosStr, - u.id AS userId - FROM - source_change_middle_table scmt - LEFT JOIN `user` u ON scmt.loginname = u.loginname - $condition - """); - Cnd cnd = Cnd.NEW(); - if(StrUtil.isNotBlank(pageForm.getSearchKeyword())) { - SqlExpressionGroup seg = new SqlExpressionGroup(); - seg.orLike("u.username",pageForm.getSearchKeyword()); - seg.orLike("u.loginname",pageForm.getSearchKeyword()); - cnd.and(seg); - } - if (StrUtil.isAllNotBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) { - cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy())); - } else { - cnd.desc("changeTime"); - } + return sourceChangeManageService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), + sourceChangeManageService.buildQuery(pageForm)); + } - if (Lang.isNotEmpty(pageForm.getChangeTypes())) { - SqlExpressionGroup seg = new SqlExpressionGroup(); - for (String type : pageForm.getChangeTypes()) { - seg.or(new Static("JSON_CONTAINS(scmt.changeTypes, JSON_QUOTE('%s'), '$')".formatted(type))); - } - cnd.and(seg); - } - cnd.andEX("u.unionId", "=", pageForm.getUnionId()); - cnd.andEX("u.unitId", "=", pageForm.getUnitId()); - cnd.andEX("u.sex", "=", pageForm.getSex()); - cnd.andEX("scmt.personType", "=", pageForm.getPersonType()); - cnd.andEX("scmt.preparedBy", "=", pageForm.getPreparedBy()); - cnd.andEX("scmt.userState", "=", pageForm.getUserState()); - cnd.andEX("scmt.isOperate", "=", pageForm.getIsOperate()); - if (StrUtil.isAllNotBlank(pageForm.getChangeDateBefore(), pageForm.getChangeDateEnd())) { - cnd.and(new Static(String.format("Date(changeTime) >= '%s' and Date(changeTime) <= '%s'", pageForm.getChangeDateBefore(), pageForm.getChangeDateEnd()))); - } else { - cnd.and("Date(changeTime)", "=", DateUtil.today()); - } - sql.setCondition(cnd); - return commonService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); + /** + * 按列表筛选条件导出全部变更记录,不受分页或勾选行限制。 + * @param pageForm 姓名工号、单位工会、人员属性、变更类型、起止日期和操作状态,与列表参数一致 + * @param response 输出人员变更记录.xlsx,列为列表展示字段,变更类型使用中文名称 + */ + @At + @Ok("void") + @RequiresPermissions("sourcechange.manage") + public void doExport(SourceChangePageForm pageForm, javax.servlet.http.HttpServletResponse response) { + sourceChangeManageService.exportXlsx(pageForm, response); } diff --git a/src/main/java/io/v/nutz/zhgh/staffmanage/sourcechange/service/SourceChangeManageService.java b/src/main/java/io/v/nutz/zhgh/staffmanage/sourcechange/service/SourceChangeManageService.java index 207dbce..8ff734d 100644 --- a/src/main/java/io/v/nutz/zhgh/staffmanage/sourcechange/service/SourceChangeManageService.java +++ b/src/main/java/io/v/nutz/zhgh/staffmanage/sourcechange/service/SourceChangeManageService.java @@ -5,7 +5,9 @@ import io.v.nutz.sys.models.User; import io.v.nutz.zhgh.data.model.UserHistory; import io.v.nutz.zhgh.staffmanage.sourcechange.model.SourceChangeMiddleTable; -import java.util.Date; +import io.v.nutz.zhgh.staffmanage.sourcechange.param.pageform.SourceChangePageForm; +import org.nutz.dao.sql.Sql; +import javax.servlet.http.HttpServletResponse; /** * @version 1.0 @@ -16,6 +18,21 @@ import java.util.Date; */ public interface SourceChangeManageService extends BaseService { + /** + * 生成列表及导出共用的查询,保留原有筛选及排序规则。 + * @param pageForm 人员、日期、类型、操作状态及排序条件;分页参数由列表调用方处理 + * @return 未设置分页的 SQL,结果包含人员信息、变更类型、明细及变更时间 + */ + Sql buildQuery(SourceChangePageForm pageForm); + + /** + * 导出当前条件下的全部变更记录。 + * @param pageForm 与列表相同的筛选条件,忽略 pageNumber 和 pageSize + * @param response 输出 xlsx 文件,列与列表一致,类型编码转换为中文 + */ + void exportXlsx(SourceChangePageForm pageForm, HttpServletResponse response); + + /** * 人工变更,做变更 * @param middleTable diff --git a/src/main/java/io/v/nutz/zhgh/staffmanage/sourcechange/service/impl/SourceChangeManageServiceImpl.java b/src/main/java/io/v/nutz/zhgh/staffmanage/sourcechange/service/impl/SourceChangeManageServiceImpl.java index 31321a3..52c4a89 100644 --- a/src/main/java/io/v/nutz/zhgh/staffmanage/sourcechange/service/impl/SourceChangeManageServiceImpl.java +++ b/src/main/java/io/v/nutz/zhgh/staffmanage/sourcechange/service/impl/SourceChangeManageServiceImpl.java @@ -1,6 +1,18 @@ package io.v.nutz.zhgh.staffmanage.sourcechange.service.impl; +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.bean.BeanUtil; +import io.v.nutz.base.utils.CommonDownloadUtil; +import io.v.nutz.base.utils.PageUtil; +import io.v.nutz.zhgh.staffmanage.sourcechange.param.pageform.SourceChangePageForm; +import org.apache.poi.ss.usermodel.Workbook; +import org.nutz.dao.util.cri.SqlExpressionGroup; +import org.nutz.dao.util.cri.Static; +import org.nutz.json.Json; +import javax.servlet.http.HttpServletResponse; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.ObjectUtil; @@ -68,6 +80,108 @@ public class SourceChangeManageServiceImpl extends BaseServiceImpl= '%s' and Date(changeTime) <= '%s'", pageForm.getChangeDateBefore(), pageForm.getChangeDateEnd()))); + } else { + cnd.and("Date(changeTime)", "=", DateUtil.today()); + } + sql.setCondition(cnd); + return sql; + } + + /** {@inheritDoc} */ + @Override + public void exportXlsx(SourceChangePageForm pageForm, HttpServletResponse response) { + List rows = listMap(buildQuery(pageForm)); + Map typeNames = Arrays.stream(MemberChangeType.values()) + .collect(Collectors.toMap(MemberChangeType::getType, MemberChangeType::getChangeTypeName)); + for (NutMap row : rows) { + // 空类型保持空白;历史未知编码保留原值,避免导出丢失已有信息。 + String rawTypes = row.getString("changeTypes"); + List types = StrUtil.isBlank(rawTypes) ? Collections.emptyList() + : Json.fromJsonAsList(String.class, rawTypes); + row.put("changeTypes", types == null ? "" : types.stream() + .map(type -> typeNames.getOrDefault(type, type)).collect(Collectors.joining(","))); + Object changeTime = row.get("changeTime"); + if (changeTime instanceof Date) { + row.put("changeTime", DateUtil.format((Date) changeTime, "yyyy-MM-dd HH:mm:ss")); + } + } + List columns = new ArrayList<>(); + columns.add(new ExcelExportEntity("工号", "loginname", 20)); + columns.add(new ExcelExportEntity("姓名", "username", 15)); + columns.add(new ExcelExportEntity("在职状态", "userState", 15)); + columns.add(new ExcelExportEntity("人员类型", "personType", 20)); + // JDBC 返回的列名为 unionname,与列表字段一致;Excel 按键名取值时区分大小写。 + columns.add(new ExcelExportEntity("所属工会", "unionname", 25)); + columns.add(new ExcelExportEntity("变更详细信息", "changeInfosStr", 80)); + columns.add(new ExcelExportEntity("变更类型", "changeTypes", 30)); + columns.add(new ExcelExportEntity("变更时间", "changeTime", 25)); + ExportParams exportParams = new ExportParams(); + exportParams.setType(ExcelType.XSSF); + // 即使没有匹配记录也生成包含表头的文件,保持下载行为一致。 + try (Workbook workbook = ExcelExportUtil.exportExcel(exportParams, columns, rows)) { + CommonDownloadUtil.download("人员变更记录.xlsx", workbook, response); + } catch (Exception e) { + log.error("导出人员变更记录失败", e); + throw new RuntimeException("导出人员变更记录失败", e); + } + } + @Override @Aop(TransAop.READ_COMMITTED) public void doSourceChange(SourceChangeMiddleTable middleTable) { diff --git a/src/main/resources/static/components/activity/site/ReserveInfo.vue b/src/main/resources/static/components/activity/site/ReserveInfo.vue index c2ba0a0..66b8fab 100644 --- a/src/main/resources/static/components/activity/site/ReserveInfo.vue +++ b/src/main/resources/static/components/activity/site/ReserveInfo.vue @@ -33,7 +33,7 @@ - {{ {1:'个人预约',2:'分工会预约',3:'协会预约'}[viewData.reserve_type] }} + {{ {1:'个人预约',2:'分工会预约',3:'协会预约',4:'单位预约'}[viewData.reserve_type] }} {{viewData.club_name || '—'}} {{ viewData.reserve_person }} {{ viewData.site_name }} diff --git a/src/main/resources/views/mobile/activity/site/audit.html b/src/main/resources/views/mobile/activity/site/audit.html index 0fa2fdc..57f536e 100644 --- a/src/main/resources/views/mobile/activity/site/audit.html +++ b/src/main/resources/views/mobile/activity/site/audit.html @@ -150,12 +150,12 @@ this.clearPopupHistory(() => pjaxReplace('/mobile/index')) } }, - typeName(type) { return {1:'个人预约',2:'分工会预约',3:'协会预约'}[type] || '—' }, + typeName(type) { return {1:'个人预约',2:'分工会预约',3:'协会预约',4:'单位预约'}[type] || '—' }, filterOpened() { this.$set(this, 'filterShow', true) }, filterClosed() { this.$set(this, 'filterShow', false) }, canReview(row) { const stage = this.reviewApi.substring(this.reviewApi.lastIndexOf('/') + 1) - return Number(row.reserve_state) === {union:4000,club:4010,school:4020}[stage] + return Number(row.reserve_state) === {union:4000,club:4010,unit:4060,school:4020}[stage] }, search() { // 筛选变更使旧响应失效,避免未审核和已审核数据混入同一列表。 diff --git a/src/main/resources/views/mobile/activity/site/common/info.js b/src/main/resources/views/mobile/activity/site/common/info.js index c756f34..3f92abb 100644 --- a/src/main/resources/views/mobile/activity/site/common/info.js +++ b/src/main/resources/views/mobile/activity/site/common/info.js @@ -46,7 +46,7 @@ const SITE_AUDIT_INFO = { props: {reviewApi: {type: String, required: true}}, data() { return {viewData: {}, activeName: 'basic', expanded: true, detailLoading: false, requestId: 0} }, methods: { - typeName(type) { return {1:'个人预约',2:'分工会预约',3:'协会预约'}[type] || '—' }, + typeName(type) { return {1:'个人预约',2:'分工会预约',3:'协会预约',4:'单位预约'}[type] || '—' }, toggleExpanded() { this.$set(this, 'expanded', !this.expanded) }, // id 为预约记录主键;返回预约字段及 auditListTable 历史,loaded 通知父页核验可审核状态。 onOpen(id) { diff --git a/src/main/resources/views/mobile/activity/site/reserve.html b/src/main/resources/views/mobile/activity/site/reserve.html index 0e174a0..8a739b9 100644 --- a/src/main/resources/views/mobile/activity/site/reserve.html +++ b/src/main/resources/views/mobile/activity/site/reserve.html @@ -270,8 +270,9 @@ layout("/mobile/platform.html"){ {{site.name}} - + + @@ -342,9 +343,9 @@ layout("/mobile/platform.html"){ return { historyPopupKeys: ['show','calendarVisible','optionsShow'], optionsShow: false, optionKind: 'type', - // 新申请仅开放分工会和协会,个人类型保留用于历史数据。 - reserveTypeOptions: [{text:'分工会预约',value:2},{text:'协会预约',value:3}], - bookingUnionName:'', unionLoading:false, + // 新申请开放分工会、协会和单位,个人类型保留用于历史数据。 + reserveTypeOptions: [{text:'分工会预约',value:2},{text:'协会预约',value:3},{text:'单位预约',value:4}], + bookingUnionName:'', bookingUnitName:'', unionLoading:false, myClubs: [], clubId: '', formLoading: false, // 新预约须主动选择类型,初始不选中任何选项。 reserve_type: null, @@ -492,7 +493,10 @@ layout("/mobile/platform.html"){ this.$set(this,'unionLoading',true) $.post('/platform/activity/site/reserve/myUnion').then(res=>{ if(this._isDestroyed || this._isBeingDestroyed)return - if(res && res.code===0)this.$set(this,'bookingUnionName',res.data && res.data.name || '') + if(res && res.code===0) { + this.$set(this,'bookingUnionName',res.data && res.data.name || '') + this.$set(this,'bookingUnitName',res.data && res.data.unitName || '') + } else vant.Toast(res && res.msg || '所属分工会加载失败') },()=>{if(!this._isDestroyed && !this._isBeingDestroyed)vant.Toast('所属分工会加载失败,请重新进入')}).always(()=>{ if(!this._isDestroyed && !this._isBeingDestroyed)this.$set(this,'unionLoading',false) diff --git a/src/main/resources/views/platform/activity/site/ReviewEntries.html b/src/main/resources/views/platform/activity/site/ReviewEntries.html index 0dc5531..e34f504 100644 --- a/src/main/resources/views/platform/activity/site/ReviewEntries.html +++ b/src/main/resources/views/platform/activity/site/ReviewEntries.html @@ -3,4 +3,5 @@

分工会审核 · 手机端

协会审核 · 手机端

校工会审核 · 手机端

+

单位审核 · 手机端

diff --git a/src/main/resources/views/platform/activity/site/SiteReserve.html b/src/main/resources/views/platform/activity/site/SiteReserve.html index b930679..896835f 100644 --- a/src/main/resources/views/platform/activity/site/SiteReserve.html +++ b/src/main/resources/views/platform/activity/site/SiteReserve.html @@ -498,12 +498,17 @@ layout("/layouts/platform.html"){ 分工会预约 协会预约 + 单位预约 + + + + @@ -546,7 +551,7 @@ layout("/layouts/platform.html"){ max: 24, min: 0, myClubs: [], - bookingUnionName:'', unionLoading:false, unionRequestVersion:0, + bookingUnionName:'', bookingUnitName:'', unionLoading:false, unionRequestVersion:0, bookingSlots:[], slotsLoading:false, slotsVersion:0, bookingTab:'time', bookingRangeStart:'', bookingRangeEnd:'', slotsLoadFailed:false, formLoading: false, @@ -718,10 +723,14 @@ layout("/layouts/platform.html"){ const version=this.unionRequestVersion+1 this.$set(this,'unionRequestVersion',version) this.$set(this,'bookingUnionName','') + this.$set(this,'bookingUnitName','') this.$set(this,'unionLoading',true) $.post('/platform/activity/site/reserve/myUnion').then(res=>{ if(version!==this.unionRequestVersion)return - if(res && res.code===0)this.$set(this,'bookingUnionName',res.data && res.data.name || '') + if(res && res.code===0) { + this.$set(this,'bookingUnionName',res.data && res.data.name || '') + this.$set(this,'bookingUnitName',res.data && res.data.unitName || '') + } else this.$message.error(res && res.msg || '所属分工会加载失败') },()=>{if(version===this.unionRequestVersion)this.$message.error('所属分工会加载失败,请重新打开表单')}).always(()=>{ if(version===this.unionRequestVersion)this.$set(this,'unionLoading',false) diff --git a/src/main/resources/views/platform/activity/site/SiteReview.html b/src/main/resources/views/platform/activity/site/SiteReview.html index e400682..f5dcd33 100644 --- a/src/main/resources/views/platform/activity/site/SiteReview.html +++ b/src/main/resources/views/platform/activity/site/SiteReview.html @@ -151,11 +151,11 @@ }) }).catch(() => {}) }, - typeName(type) { return {1:'个人预约',2:'分工会预约',3:'协会预约'}[type] || '—' }, + typeName(type) { return {1:'个人预约',2:'分工会预约',3:'协会预约',4:'单位预约'}[type] || '—' }, // 以申请实际节点决定审核入口,已流转的申请只允许查看。 canReview(row) { const stage = this.reviewApi.substring(this.reviewApi.lastIndexOf('/') + 1) - return Number(row.reserve_state) === {union:4000,club:4010,school:4020}[stage] + return Number(row.reserve_state) === {union:4000,club:4010,unit:4060,school:4020}[stage] }, openView(row) { this.$refs.guava.view() diff --git a/src/main/resources/views/platform/activity/site/common/info.js b/src/main/resources/views/platform/activity/site/common/info.js index 5065ffc..8b80132 100644 --- a/src/main/resources/views/platform/activity/site/common/info.js +++ b/src/main/resources/views/platform/activity/site/common/info.js @@ -45,7 +45,7 @@ const info = { return {viewData: {}, activeName: 'info', detailLoading: false, requestId: 0} }, methods: { - typeName(type) { return {1:'个人预约',2:'分工会预约',3:'协会预约'}[type] || '—' }, + typeName(type) { return {1:'个人预约',2:'分工会预约',3:'协会预约',4:'单位预约'}[type] || '—' }, // id 为预约记录主键,activeName 为申请信息或审核标签;结果含预约字段及 auditListTable 审核历史。 onOpen(id, activeName = 'info') { const requestId = this.requestId + 1 diff --git a/src/main/resources/views/platform/fitnessWalk/stepStatistics.html b/src/main/resources/views/platform/fitnessWalk/stepStatistics.html index bb802cb..8fd5277 100644 --- a/src/main/resources/views/platform/fitnessWalk/stepStatistics.html +++ b/src/main/resources/views/platform/fitnessWalk/stepStatistics.html @@ -32,18 +32,19 @@ layout("/layouts/platform.html"){
-
日期范围:
+
日期开始
- - + +
+
+
+
日期结束
+
+
@@ -128,6 +129,8 @@ layout("/layouts/platform.html"){ mixins: [initTableMixins], data() { return { + dateStart: "", + dateEnd: "", tableColumns: [ {label: '姓名', prop: 'username'}, {label: '工号', prop: 'loginname'}, @@ -157,7 +160,24 @@ layout("/layouts/platform.html"){ } }, methods: { + // 两个日期框合成为原接口的起止数组;两端清空表示不限定日期,单端或倒置时停止查询。 + syncDateRange() { + const start = this.dateStart + const end = this.dateEnd + if ((!start && end) || (start && !end)) { + this.$message.warning('请选择完整的日期开始和日期结束') + return false + } + if (start && end && start > end) { + this.$message.warning('日期开始不能晚于日期结束') + return false + } + this.$set(this.pageForm, 'activityDate', start && end ? [start, end] : []) + return true + }, + exportExcel() { + if (!this.syncDateRange()) return const {activityId, unionId, unitId, activityDate} = this.pageForm let activityDate1 = [] if (activityDate && activityDate.length > 0) { @@ -165,9 +185,6 @@ layout("/layouts/platform.html"){ } window.open(loc() + '/exportExcel?activityId=' + activityId + '&unionId=' + unionId + '&unitId=' + unitId + '&activityDate=' + activityDate1) }, - activityDateChange() { - // this.$set(this.pageForm, "activityDate", []) - }, async unionChange(val) { this.pageForm.unitId = null this.unitOptions = await getUnits(val) @@ -184,22 +201,25 @@ layout("/layouts/platform.html"){ } }, pageData() { + if (!this.syncDateRange()) return sublime.showLoadingbar(); - this.tableLoading = true + this.$set(this, "tableLoading", true) let pageForm = clone(this.pageForm) if (pageForm.activityDate && pageForm.activityDate.length > 0) { pageForm.activityDate = JSON.stringify(pageForm.activityDate) } - $.post(loc() + "/pageData", pageForm, (data) => { - sublime.closeLoadingbar(); - this.tableLoading = false + return $.post(loc() + "/pageData", pageForm).then((data) => { if (data.code === 0) { - this.tableData = data.data.list; - this.pageForm.totalCount = data.data.totalCount; + this.$set(this, "tableData", data.data.list); + this.$set(this.pageForm, "totalCount", data.data.totalCount); } else { this.$message.error(data.msg); } - }, "json"); + }).always(() => { + // 成功或失败均释放查询状态,避免日期筛选请求异常后界面一直等待。 + sublime.closeLoadingbar(); + this.$set(this, "tableLoading", false) + }); }, async getActivityById(){ diff --git a/src/main/resources/views/platform/meeting/statistics/basic.html b/src/main/resources/views/platform/meeting/statistics/basic.html index 6471c99..007e6fe 100644 --- a/src/main/resources/views/platform/meeting/statistics/basic.html +++ b/src/main/resources/views/platform/meeting/statistics/basic.html @@ -12,19 +12,18 @@ layout("/layouts/platform.html"){