From 33859d3be09c6972dd03e84709e3d4a1c2c2fbfc Mon Sep 17 00:00:00 2001 From: = <=> Date: Wed, 17 Jun 2026 09:58:15 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9C=BA=E5=9C=B0=E9=A2=84=E7=BA=A6=E6=95=B4?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/sys/controller/SysHomeController.java | 44 +-- .../app/sys/services/SysHomeNewsService.java | 15 + .../services/impl/SysHomeNewsServiceImpl.java | 70 ++++ .../controller/SiteCugApplyController.java | 49 ++- .../SiteCugBranchUnionAuditController.java | 66 ++++ .../SiteCugDeputySchoolUnionController.java | 66 ++++ .../controller/SiteCugManageController.java | 64 ++- .../SiteCugSchoolUnionAuditController.java | 189 +-------- .../siteCug/model/SiteCugApply.java | 5 + .../siteCug/service/SiteCugApplyService.java | 13 + .../service/impl/SiteCugApplyServiceImpl.java | 260 ++++++++++++- .../views/layouts/v4/home/index.html | 8 +- .../resources/views/layouts/v4/home/jcdt.js | 335 ++++++++-------- .../zhgh/dayofficework/siteCug/apply/apply.js | 89 ++++- .../siteCug/branchUnionAudit/index.html | 368 ++++++++++++++++++ .../dayofficework/siteCug/common/applyInfo.js | 3 +- .../siteCug/deputySchoolUnion/index.html | 368 ++++++++++++++++++ .../dayofficework/siteCug/manage/basicForm.js | 368 ++++++++++++++---- .../zhgh/dayofficework/siteCug/manage/info.js | 27 +- .../siteCug/schoolUnionAudit/index.html | 6 +- .../dayofficework/siteCug/apply/form/apply.js | 69 +++- .../siteCug/apply/form/index.html | 26 +- .../siteCug/branchUnionAudit/index.html | 335 ++++++++++++++++ .../dayofficework/siteCug/common/applyInfo.js | 2 + .../dayofficework/siteCug/common/siteInfo.js | 27 +- .../siteCug/deputySchoolUnion/index.html | 335 ++++++++++++++++ .../siteCug/schoolUnionAudit/index.html | 2 +- 27 files changed, 2686 insertions(+), 523 deletions(-) create mode 100644 src/main/java/com/budwk/app/sys/services/SysHomeNewsService.java create mode 100644 src/main/java/com/budwk/app/sys/services/impl/SysHomeNewsServiceImpl.java create mode 100644 src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/controller/SiteCugBranchUnionAuditController.java create mode 100644 src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/controller/SiteCugDeputySchoolUnionController.java create mode 100644 src/main/resources/views/platform/zhgh/dayofficework/siteCug/branchUnionAudit/index.html create mode 100644 src/main/resources/views/platform/zhgh/dayofficework/siteCug/deputySchoolUnion/index.html create mode 100644 src/main/resources/views/platform/zhghh5/dayofficework/siteCug/branchUnionAudit/index.html create mode 100644 src/main/resources/views/platform/zhghh5/dayofficework/siteCug/deputySchoolUnion/index.html diff --git a/src/main/java/com/budwk/app/sys/controller/SysHomeController.java b/src/main/java/com/budwk/app/sys/controller/SysHomeController.java index cb32dd5..42db156 100644 --- a/src/main/java/com/budwk/app/sys/controller/SysHomeController.java +++ b/src/main/java/com/budwk/app/sys/controller/SysHomeController.java @@ -5,32 +5,26 @@ import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.http.useragent.UserAgent; import cn.hutool.http.useragent.UserAgentUtil; -import cn.hutool.json.JSONObject; import com.budwk.app.base.constant.RoleConstant; import com.budwk.app.base.result.Result; import com.budwk.app.sys.models.Sys_home_activity; import com.budwk.app.sys.models.Sys_home_template; import com.budwk.app.sys.models.Sys_menu; +import com.budwk.app.sys.services.SysHomeNewsService; import com.budwk.app.sys.services.SysMenuService; import com.budwk.app.sys.services.SysUserService; import com.budwk.app.web.commons.auth.utils.AuthUtil; import com.budwk.app.web.commons.auth.utils.SecurityUtil; import com.budwk.app.zhgh.activity.basic.service.ActivityBasicScopeService; import io.swagger.annotations.ApiOperation; -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.select.Elements; import org.nutz.dao.Cnd; import org.nutz.dao.Dao; import org.nutz.dao.FieldFilter; import org.nutz.dao.Sqls; import org.nutz.dao.sql.Sql; import org.nutz.dao.util.Daos; -import org.nutz.integration.jedis.RedisService; import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.IocBean; -import org.nutz.json.Json; import org.nutz.lang.Lang; import org.nutz.lang.Strings; import org.nutz.lang.util.NutMap; @@ -42,9 +36,7 @@ import org.nutz.mvc.annotation.Param; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; -import java.io.IOException; import java.util.*; -import java.util.stream.Collectors; @IocBean @@ -58,7 +50,7 @@ public class SysHomeController { @Inject private SysUserService sysUserService; @Inject - private RedisService redisService; + private SysHomeNewsService sysHomeNewsService; @Inject private ActivityBasicScopeService activityBasicScopeService; @@ -285,31 +277,11 @@ public class SysHomeController { // @CacheDefaults(cacheName = RedisConstant.PLATFORM_REDIS_WKCACHE_PREFIX + "web_news", isHash = true) // @CacheResult(cacheKey = "news", ignoreNull = true, cacheLiveTime = 60 * 60 * 24) public Result getNews() { - try { - String url = "https://xgh.cug.edu.cn/"; - Document document = Jsoup.connect(url).get(); - Elements homeElements = document.select(".gh,.jc,.fc,.jg"); - - List> news = homeElements.stream().map(homeElement -> { - //获取板块名称 - String name = homeElement.selectFirst(".title").text(); - Elements liElements = homeElement.select("li"); - List ele = liElements.stream().map(liElement -> { - NutMap row = NutMap.NEW(); - String href = liElement.selectFirst("a").attr("href"); - String time = liElement.selectFirst("span").text(); - String title = liElement.selectFirst("a").attr("title"); - row.put("href", href); - row.put("time", time); - row.put("text", title); - return row; - }).toList(); - return Map.of("label", name, "value", ele); - }).collect(Collectors.toList()); - redisService.setex("gonghui_news", 60 * 60 * 24, Json.toJson(news)); - return Result.success(news); - } catch (IOException e) { - throw new RuntimeException(e); - } + try { + return Result.success(sysHomeNewsService.getUnionNoticeNews()); + } catch (Exception e) { + log.error(e); + return Result.success(); + } } } diff --git a/src/main/java/com/budwk/app/sys/services/SysHomeNewsService.java b/src/main/java/com/budwk/app/sys/services/SysHomeNewsService.java new file mode 100644 index 0000000..c4b7273 --- /dev/null +++ b/src/main/java/com/budwk/app/sys/services/SysHomeNewsService.java @@ -0,0 +1,15 @@ +package com.budwk.app.sys.services; + +import cn.hutool.json.JSONObject; + +import java.io.IOException; + +public interface SysHomeNewsService { + + /** + * 获取江苏农牧科技职业学院工会网站通知公告,并保持首页新闻组件需要的数据结构。 + * + * @return 首页网站新闻数据,当前使用 grassroots 字段兼容前端组件 + */ + JSONObject getUnionNoticeNews() throws IOException; +} diff --git a/src/main/java/com/budwk/app/sys/services/impl/SysHomeNewsServiceImpl.java b/src/main/java/com/budwk/app/sys/services/impl/SysHomeNewsServiceImpl.java new file mode 100644 index 0000000..3272a24 --- /dev/null +++ b/src/main/java/com/budwk/app/sys/services/impl/SysHomeNewsServiceImpl.java @@ -0,0 +1,70 @@ +package com.budwk.app.sys.services.impl; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONObject; +import com.budwk.app.sys.services.SysHomeNewsService; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; +import org.nutz.ioc.loader.annotation.IocBean; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +@IocBean +public class SysHomeNewsServiceImpl implements SysHomeNewsService { + + private static final String UNION_HOME_URL = "https://www.jsahvc.edu.cn/gh/main.htm"; + + @Override + public JSONObject getUnionNoticeNews() throws IOException { + JSONObject root = new JSONObject(); + List noticeList = new ArrayList<>(); + + Document doc = Jsoup.connect(UNION_HOME_URL) + // 学校官网会过滤部分非浏览器请求,这里补充常规浏览器请求头提高抓取稳定性。 + .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36") + .referrer("https://www.jsahvc.edu.cn/") + .timeout(10000) + .get(); + + Elements noticeItems = getNoticeItems(doc); + for (Element item : noticeItems) { + Element titleLink = item.selectFirst(".news_title a, a[title], a"); + if (titleLink == null) { + continue; + } + + String title = StrUtil.blankToDefault(titleLink.attr("title"), titleLink.text()).trim(); + String url = titleLink.absUrl("href").trim(); + Element meta = item.selectFirst(".news_meta, .date, .news_date, .time"); + + JSONObject node = new JSONObject(); + node.set("title", title); + node.set("date", meta == null ? "" : meta.text().trim()); + node.set("url", url); + noticeList.add(node); + } + + root.set("grassroots", noticeList); + return root; + } + + /** + * 优先按栏目标题查找通知公告列表,找不到时再使用学校官网历史模板中的栏目位兜底。 + * + * @param doc 工会网站首页文档 + * @return 通知公告列表节点 + */ + private Elements getNoticeItems(Document doc) { + for (Element post : doc.select(".post")) { + Element title = post.selectFirst(".tt .title, .tit .title, h3, h2"); + if (title != null && title.text().contains("通知公告")) { + return post.select(".news_list li, .wp_article_list li"); + } + } + return doc.select(".post-18 .news_list li, .post-18 .wp_article_list li"); + } +} diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/controller/SiteCugApplyController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/controller/SiteCugApplyController.java index f95e3ee..b11f657 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/controller/SiteCugApplyController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/controller/SiteCugApplyController.java @@ -284,19 +284,52 @@ public class SiteCugApplyController { private List buildDisabledRanges(NutMap site, String today) { List disabledList = toNutMapList(site.get("notApplyTimeList")); List result = new ArrayList<>(); + int targetWeekDay = toWeekDay(DateUtil.parseDate(today)); for (NutMap item : disabledList) { - if (item == null || !StrUtil.equals(today, item.getString("date"))) { + if (item == null || StrUtil.hasBlank(item.getString("startTime"), item.getString("endTime"))) { continue; } - Integer start = parseTimeToMinutes(item.getString("startTime")); - Integer end = parseTimeToMinutes(item.getString("endTime")); - if (start != null && end != null && end > start) { - result.add(new int[]{start, end}); + // 禁用时间兼容旧的按日期配置,同时支持新增的按星期配置。 + if (isDateDisabledRange(item, today) || isWeekDisabledRange(item, targetWeekDay)) { + addDisabledRange(result, item); } } return result; } + private boolean isDateDisabledRange(NutMap item, String today) { + String type = item.getString("type"); + return (StrUtil.isBlank(type) || StrUtil.equals("date", type)) + && StrUtil.equals(today, item.getString("date")); + } + + private boolean isWeekDisabledRange(NutMap item, int targetWeekDay) { + Integer weekDay = parseWeekDay(item.get("weekDay")); + return StrUtil.equals("week", item.getString("type")) + && weekDay != null + && weekDay == targetWeekDay; + } + + private void addDisabledRange(List result, NutMap item) { + Integer start = parseTimeToMinutes(item.getString("startTime")); + Integer end = parseTimeToMinutes(item.getString("endTime")); + if (start != null && end != null && end > start) { + result.add(new int[]{start, end}); + } + } + + private Integer parseWeekDay(Object value) { + if (value == null) { + return null; + } + try { + int weekDay = Integer.parseInt(String.valueOf(value)); + return weekDay >= 1 && weekDay <= 7 ? weekDay : null; + } catch (NumberFormatException e) { + return null; + } + } + private List buildReservedRanges(List applyList, String today) { List result = new ArrayList<>(); String dayStart = today + " 00:00:00"; @@ -404,6 +437,11 @@ public class SiteCugApplyController { return week == 0 || week == 6; } + private int toWeekDay(DateTime date) { + int week = date.dayOfWeek() - 1; + return week == 0 ? 7 : week; + } + private List buildAvailabilityBlocks(SiteCugInfo siteInfo, String day, List applyList, Set holidaySet) { if (siteInfo.getReserveTimeType() != null && siteInfo.getReserveTimeType() == 2) { return buildFullDayAvailabilityBlocks(siteInfo, day, applyList, holidaySet); @@ -802,6 +840,7 @@ public class SiteCugApplyController { .setReserveStartTime(apply.getReserveStartTime()) .setReserveEndTime(apply.getReserveEndTime()) .setJoinCount(apply.getJoinCount()) + .setCoffeeNeeded(apply.getCoffeeNeeded()) .setApplyCause(apply.getApplyCause()) .setBackOption(apply.getBackOption()) .setYearlyReserveEndDate(apply.getYearlyReserveEndDate()); diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/controller/SiteCugBranchUnionAuditController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/controller/SiteCugBranchUnionAuditController.java new file mode 100644 index 0000000..fa953ab --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/controller/SiteCugBranchUnionAuditController.java @@ -0,0 +1,66 @@ +package com.budwk.app.zhgh.dayofficework.siteCug.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaMode; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.base.result.Result; +import com.budwk.app.zhgh.dayofficework.siteCug.service.SiteCugApplyService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +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; +import org.nutz.mvc.annotation.Ok; +import org.nutz.mvc.annotation.Param; + +@IocBean +@At("/platform/siteCug/branchUnionAudit") +@Api("场馆分工会审核") +@Ok("json:full") +public class SiteCugBranchUnionAuditController { + + private static final String AUDIT_TASK_NAME = "c4493b93-75c0-4980-b604-19df2be2c42c"; + + @Inject + private SiteCugApplyService applyService; + + @At("/") + @Ok("beetl:/platform/zhgh/dayofficework/siteCug/branchUnionAudit/index.html") + @SaCheckPermission("siteCug.branchUnionAudit") + public void index() { + } + + @At("/h5") + @Ok("beetl:/platform/zhghh5/dayofficework/siteCug/branchUnionAudit/index.html") + @SaCheckPermission("h5.siteCug.branchUnionAudit") + public void h5Index() { + } + + @At + @ApiOperation("分页查询") + @SaCheckPermission(value = {"siteCug.branchUnionAudit", "h5.siteCug.branchUnionAudit"}, mode = SaMode.OR) + public Result pageData(PageForm pageForm, + @Param("siteType") String siteType, + @Param("siteId") String siteId, + @Param("approval") Boolean approval) { + return Result.success(applyService.listAuditPage(pageForm, siteType, siteId, approval, AUDIT_TASK_NAME)); + } + + @At("/executeTask") + @ApiOperation("执行审核任务") + @Aop(TransAop.READ_COMMITTED) + @SaCheckPermission(value = {"siteCug.branchUnionAudit", "h5.siteCug.branchUnionAudit"}, mode = SaMode.OR) + public Result executeTask(@Param("data") String data) { + return applyService.executeAuditTask(data); + } + + @At("/revokeTask") + @ApiOperation("撤回审核任务") + @Aop(TransAop.READ_COMMITTED) + @SaCheckPermission(value = {"siteCug.branchUnionAudit", "h5.siteCug.branchUnionAudit"}, mode = SaMode.OR) + public Result revokeTask(@Param("taskId") Long taskId, @Param("applyId") String applyId) { + return applyService.revokeAuditTask(taskId, applyId); + } +} diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/controller/SiteCugDeputySchoolUnionController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/controller/SiteCugDeputySchoolUnionController.java new file mode 100644 index 0000000..9e22772 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/controller/SiteCugDeputySchoolUnionController.java @@ -0,0 +1,66 @@ +package com.budwk.app.zhgh.dayofficework.siteCug.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaMode; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.base.result.Result; +import com.budwk.app.zhgh.dayofficework.siteCug.service.SiteCugApplyService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +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; +import org.nutz.mvc.annotation.Ok; +import org.nutz.mvc.annotation.Param; + +@IocBean +@At("/platform/siteCug/deputySchoolUnion") +@Api("场馆校工会副主席审核") +@Ok("json:full") +public class SiteCugDeputySchoolUnionController { + + private static final String AUDIT_TASK_NAME = "de7044e4-187b-43c8-ab47-87eb0998302a"; + + @Inject + private SiteCugApplyService applyService; + + @At("/") + @Ok("beetl:/platform/zhgh/dayofficework/siteCug/deputySchoolUnion/index.html") + @SaCheckPermission("siteCug.deputySchoolUnion") + public void index() { + } + + @At("/h5") + @Ok("beetl:/platform/zhghh5/dayofficework/siteCug/deputySchoolUnion/index.html") + @SaCheckPermission("h5.siteCug.deputySchoolUnion") + public void h5Index() { + } + + @At + @ApiOperation("分页查询") + @SaCheckPermission(value = {"siteCug.deputySchoolUnion", "h5.siteCug.deputySchoolUnion"}, mode = SaMode.OR) + public Result pageData(PageForm pageForm, + @Param("siteType") String siteType, + @Param("siteId") String siteId, + @Param("approval") Boolean approval) { + return Result.success(applyService.listAuditPage(pageForm, siteType, siteId, approval, AUDIT_TASK_NAME)); + } + + @At("/executeTask") + @ApiOperation("执行审核任务") + @Aop(TransAop.READ_COMMITTED) + @SaCheckPermission(value = {"siteCug.deputySchoolUnion", "h5.siteCug.deputySchoolUnion"}, mode = SaMode.OR) + public Result executeTask(@Param("data") String data) { + return applyService.executeAuditTask(data); + } + + @At("/revokeTask") + @ApiOperation("撤回审核任务") + @Aop(TransAop.READ_COMMITTED) + @SaCheckPermission(value = {"siteCug.deputySchoolUnion", "h5.siteCug.deputySchoolUnion"}, mode = SaMode.OR) + public Result revokeTask(@Param("taskId") Long taskId, @Param("applyId") String applyId) { + return applyService.revokeAuditTask(taskId, applyId); + } +} diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/controller/SiteCugManageController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/controller/SiteCugManageController.java index d95de00..f90d392 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/controller/SiteCugManageController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/controller/SiteCugManageController.java @@ -83,15 +83,11 @@ public class SiteCugManageController { public Object submit(@Param("data") SiteCugInfo info) { List notApplyTimeList = info.getNotApplyTimeList(); if (notApplyTimeList != null) { - boolean invalid = notApplyTimeList.stream().anyMatch(item -> - item == null - || StrUtil.isBlank(item.getString("date")) - || StrUtil.isBlank(item.getString("startTime")) - || StrUtil.isBlank(item.getString("endTime")) - || item.getString("startTime").compareTo(item.getString("endTime")) >= 0); + boolean invalid = notApplyTimeList.stream().anyMatch(this::isInvalidDisabledTime); if (invalid) { return Result.error("Invalid disabled time settings"); } + notApplyTimeList.forEach(this::normalizeDisabledTime); } if (info.getReserveTimeType() == null) { @@ -196,6 +192,62 @@ public class SiteCugManageController { } } + private boolean isInvalidDisabledTime(NutMap item) { + if (item == null + || StrUtil.isBlank(item.getString("startTime")) + || StrUtil.isBlank(item.getString("endTime")) + || item.getString("startTime").compareTo(item.getString("endTime")) >= 0) { + return true; + } + String type = item.getString("type"); + if (StrUtil.isBlank(type) || StrUtil.equals(type, "date")) { + return StrUtil.isBlank(item.getString("date")); + } + if (StrUtil.equals(type, "week")) { + return !isWeekDay(item.get("weekDay")); + } + return true; + } + + private void normalizeDisabledTime(NutMap item) { + if (item == null) { + return; + } + if (StrUtil.isBlank(item.getString("type"))) { + item.put("type", "date"); + } + if (StrUtil.equals(item.getString("type"), "week")) { + int weekDay = Integer.parseInt(String.valueOf(item.get("weekDay"))); + item.put("weekDay", weekDay); + item.put("weekName", getWeekName(weekDay)); + } + } + + private boolean isWeekDay(Object value) { + if (value == null) { + return false; + } + try { + int weekDay = Integer.parseInt(String.valueOf(value)); + return weekDay >= 1 && weekDay <= 7; + } catch (Exception e) { + return false; + } + } + + private String getWeekName(int weekDay) { + return switch (weekDay) { + case 1 -> "星期一"; + case 2 -> "星期二"; + case 3 -> "星期三"; + case 4 -> "星期四"; + case 5 -> "星期五"; + case 6 -> "星期六"; + case 7 -> "星期日"; + default -> ""; + }; + } + private NutMap normalizeOpenHourTimeUnit(NutMap item) { if (item == null) { return null; diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/controller/SiteCugSchoolUnionAuditController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/controller/SiteCugSchoolUnionAuditController.java index b14d135..a6ad993 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/controller/SiteCugSchoolUnionAuditController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/controller/SiteCugSchoolUnionAuditController.java @@ -2,55 +2,29 @@ package com.budwk.app.zhgh.dayofficework.siteCug.controller; import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaMode; -import cn.dev33.satoken.stp.StpUtil; -import cn.hutool.core.lang.Dict; -import cn.hutool.core.util.StrUtil; -import com.budwk.app.base.constant.RoleConstant; -import com.budwk.app.base.page.Pagination; import com.budwk.app.base.param.PageForm; import com.budwk.app.base.result.Result; -import com.budwk.app.base.utils.PageUtil; -import com.budwk.app.flow.constant.FlowConst; -import com.budwk.app.flow.entity.ProcessTask; -import com.budwk.app.flow.enums.ProcessTaskStateEnum; -import com.budwk.app.flow.service.FlowCommonService; -import com.budwk.app.flow.service.ProcessTaskService; -import com.budwk.app.web.commons.auth.utils.SecurityUtil; -import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugApply; import com.budwk.app.zhgh.dayofficework.siteCug.service.SiteCugApplyService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.nutz.aop.interceptor.ioc.TransAop; -import org.nutz.dao.Cnd; -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.Inject; import org.nutz.ioc.loader.annotation.IocBean; -import org.nutz.lang.util.NutMap; -import org.nutz.json.Json; import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Param; -import java.util.ArrayList; -import java.util.List; - @IocBean @At("/platform/siteCug/schoolUnionAudit") -@Api("场馆校工会审核") +@Api("场馆校工会主席审核") @Ok("json:full") public class SiteCugSchoolUnionAuditController { - private static final String YEARLY_BATCH_PREFIX = "YEARLY_BATCH:"; + private static final String AUDIT_TASK_NAME = "c8c03407-cf26-4e0b-82f1-b2afc9c79996"; @Inject private SiteCugApplyService applyService; - @Inject - private ProcessTaskService processTaskService; - @Inject - private FlowCommonService flowCommonService; @At("/") @Ok("beetl:/platform/zhgh/dayofficework/siteCug/schoolUnionAudit/index.html") @@ -71,102 +45,7 @@ public class SiteCugSchoolUnionAuditController { @Param("siteType") String siteType, @Param("siteId") String siteId, @Param("approval") Boolean approval) { - Sql sql = Sqls.create(""" - SELECT - info.*, - si.name as siteName, - CASE WHEN info.reserveType = 'club' THEN info.clubName ELSE info.applyUnionName END AS reserveTargetName, - ins.id AS instanceId, - ins.businessNo, - ins.state instanceState, - ins.variable instanceVariable, - ins.processDefineId instanceProcessDefineId, - t.id taskId, - t.taskName AS taskKey, - t.displayName taskName, - t.taskType, - t.performType taskPerformType, - t.taskState, - t.finishTime, - t.taskParentId, - t.variable taskVariable, - IFNULL(GROUP_CONCAT(DISTINCT nt.displayName),'结束') curTaskName, - CASE WHEN EXISTS ( - SELECT 1 FROM wf_process_task rt - WHERE rt.processInstanceId = ins.id AND rt.taskParentId = t.id - ) THEN 1 ELSE 0 END AS canRevoke, - CASE WHEN info.backOption LIKE 'YEARLY_BATCH:%' THEN 1 ELSE 0 END AS yearlyBatch, - CASE WHEN info.backOption LIKE 'YEARLY_BATCH:%' THEN ( - SELECT COUNT(1) FROM site_cug_apply batch_info WHERE batch_info.backOption = info.backOption AND batch_info.createdBy = info.createdBy - ) ELSE 1 END AS batchAuditCount - FROM - wf_process_task t - LEFT JOIN wf_process_instance ins ON ins.id = t.processInstanceId - LEFT JOIN site_cug_apply info ON info.id = ins.businessNo - LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = t.id - LEFT JOIN site_cug_info si ON info.siteId = si.id - LEFT JOIN wf_process_task nt ON nt.processInstanceId = ins.id AND nt.taskState = 10 - LEFT JOIN wf_process_task rt ON rt.processInstanceId = ins.id AND rt.taskParentId = t.id - $condition - """); - Cnd cnd = Cnd.NEW(); - if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) { - SqlExpressionGroup seg = new SqlExpressionGroup(); - seg.or(SiteCugApply::getApplyUserName, "like", "%" + pageForm.getSearchKeyword() + "%"); - seg.or(SiteCugApply::getApplyLoginName, "like", "%" + pageForm.getSearchKeyword() + "%"); - cnd.and(seg); - } - cnd.andEX("si.typeId", "=", siteType); - cnd.andEX("info.siteId", "=", siteId); - cnd.and("t.taskName", "=", "c8c03407-cf26-4e0b-82f1-b2afc9c79996"); - if (!StpUtil.hasRole(RoleConstant.SYSADMIN.name())) { - cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId())); - } - if (Boolean.TRUE.equals(approval)) { - cnd.and("t.taskState", "in", List.of(ProcessTaskStateEnum.FINISHED.getCode(), ProcessTaskStateEnum.INTERRUPT.getCode())); - } else { - cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode()); - } - - if (StrUtil.isNotBlank(pageForm.getPageOrderName()) && StrUtil.isNotBlank(pageForm.getPageOrderBy())) { - cnd.orderBy(resolveOrderColumn(pageForm.getPageOrderName()), PageUtil.getOrder(pageForm.getPageOrderBy())); - } else { - cnd.desc("info.createdAt"); - } - cnd.groupBy("t.id"); - sql.setCondition(cnd); - Pagination pageVO = applyService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); - return Result.success(pageVO); - } - - private String resolveOrderColumn(String pageOrderName) { - if (StrUtil.isBlank(pageOrderName)) { - return "info.createdAt"; - } - switch (pageOrderName) { - case "siteName": - return "si.name"; - case "applyUserName": - return "info.applyUserName"; - case "applyLoginName": - return "info.applyLoginName"; - case "yearlyBatch": - return "yearlyBatch"; - case "reserveTargetName": - return "reserveTargetName"; - case "reserveStartTime": - return "info.reserveStartTime"; - case "reserveEndTime": - return "info.reserveEndTime"; - case "applyMobile": - return "info.applyMobile"; - case "curTaskName": - return "curTaskName"; - case "instanceState": - return "ins.state"; - default: - return "info.createdAt"; - } + return Result.success(applyService.listAuditPage(pageForm, siteType, siteId, approval, AUDIT_TASK_NAME)); } @At("/executeTask") @@ -174,72 +53,14 @@ public class SiteCugSchoolUnionAuditController { @Aop(TransAop.READ_COMMITTED) @SaCheckPermission(value = {"siteCug.schoolUnionAudit", "h5.siteCug.schoolUnionAudit"}, mode = SaMode.OR) public Result executeTask(@Param("data") String data) { - Dict args = Json.fromJson(Dict.class, data); - Long processTaskId = args.getLong(FlowConst.PROCESS_TASK_ID_KEY); - ProcessTask currentTask = processTaskService.getById(processTaskId); - if (currentTask == null) { - return Result.error("审核任务不存在"); - } - - SiteCugApply apply = applyService.fetch(args.getStr("applyId")); - if (apply == null) { - return Result.error("预约记录不存在"); - } - - List taskList = new ArrayList<>(); - if (StrUtil.isNotBlank(apply.getBackOption()) && apply.getBackOption().startsWith(YEARLY_BATCH_PREFIX)) { - List batchList = applyService.query(Cnd.where("backOption", "=", apply.getBackOption()).and("createdBy", "=", apply.getCreatedBy())); - List bizIds = batchList.stream().map(SiteCugApply::getId).toList(); - taskList = processTaskService.getDoingTaskByBizIdTaskName(bizIds, currentTask.getTaskName()); - } - if (taskList.isEmpty()) { - taskList.add(currentTask); - } - - for (ProcessTask task : taskList) { - Dict cloneArgs = args.clone(); - cloneArgs.put(FlowConst.PROCESS_TASK_ID_KEY, task.getId()); - flowCommonService.executeTask(cloneArgs); - } - if (taskList.size() > 1) { - return Result.success("已完成该全年预约批次的审核"); - } - return Result.success("提交成功"); + return applyService.executeAuditTask(data); } - @At("/revokeTask") @ApiOperation("撤回审核任务") @Aop(TransAop.READ_COMMITTED) @SaCheckPermission(value = {"siteCug.schoolUnionAudit", "h5.siteCug.schoolUnionAudit"}, mode = SaMode.OR) public Result revokeTask(@Param("taskId") Long taskId, @Param("applyId") String applyId) { - ProcessTask currentTask = processTaskService.getById(taskId); - if (currentTask == null) { - return Result.error("撤回任务不存在"); - } - - SiteCugApply apply = applyService.fetch(applyId); - if (apply == null) { - return Result.error("预约记录不存在"); - } - - List taskList = new ArrayList<>(); - if (StrUtil.isNotBlank(apply.getBackOption()) && apply.getBackOption().startsWith(YEARLY_BATCH_PREFIX)) { - List batchList = applyService.query(Cnd.where("backOption", "=", apply.getBackOption()).and("createdBy", "=", apply.getCreatedBy())); - List bizIds = batchList.stream().map(SiteCugApply::getId).toList(); - taskList = processTaskService.getDoneTaskByBizIdTaskName(bizIds, currentTask.getTaskName()); - } - if (taskList.isEmpty()) { - taskList.add(currentTask); - } - - for (ProcessTask task : taskList) { - flowCommonService.revokeTask(task.getId()); - } - if (taskList.size() > 1) { - return Result.success("已撤回该全年预约批次的审核任务"); - } - return Result.success("撤回成功"); + return applyService.revokeAuditTask(taskId, applyId); } - } diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/model/SiteCugApply.java b/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/model/SiteCugApply.java index 4857fa3..1ec759e 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/model/SiteCugApply.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/model/SiteCugApply.java @@ -100,6 +100,11 @@ public class SiteCugApply extends BaseModel { @ColDefine(type = ColType.INT) private Integer joinCount; + @Column + @Comment("是否需要咖啡") + @ColDefine(type = ColType.INT) + private Integer coffeeNeeded; + @Column @Comment("预约事由") @ColDefine(type = ColType.VARCHAR, width = 1000) diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/service/SiteCugApplyService.java b/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/service/SiteCugApplyService.java index 1be3c7a..b323769 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/service/SiteCugApplyService.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/service/SiteCugApplyService.java @@ -1,10 +1,14 @@ package com.budwk.app.zhgh.dayofficework.siteCug.service; +import com.budwk.app.base.page.Pagination; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.base.result.Result; import com.budwk.app.base.service.BaseService; import com.budwk.app.zhgh.dayofficework.siteCug.model.SiteCugApply; import com.budwk.app.zhgh.dayofficework.siteCug.param.SiteCugRecordPageForm; import org.nutz.dao.Cnd; import org.nutz.dao.sql.Sql; +import org.nutz.lang.util.NutMap; import javax.servlet.http.HttpServletResponse; import java.util.Map; @@ -21,4 +25,13 @@ public interface SiteCugApplyService extends BaseService { // 场馆预约查询页的导出逻辑统一放在 service,controller 只负责接收请求 void exportRecord(SiteCugRecordPageForm pageForm, HttpServletResponse response); + + // 场馆预约审核页共用列表查询,按流程节点 taskName 区分不同审核页面 + Pagination listAuditPage(PageForm pageForm, String siteType, String siteId, Boolean approval, String auditTaskName); + + // 场馆预约审核提交共用同一套任务执行逻辑,兼容全年预约批次一起审核 + Result executeAuditTask(String data); + + // 场馆预约审核撤回共用同一套任务撤回逻辑,兼容全年预约批次一起撤回 + Result revokeAuditTask(Long taskId, String applyId); } diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/service/impl/SiteCugApplyServiceImpl.java b/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/service/impl/SiteCugApplyServiceImpl.java index dba66f6..f754e37 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/service/impl/SiteCugApplyServiceImpl.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/siteCug/service/impl/SiteCugApplyServiceImpl.java @@ -4,14 +4,25 @@ 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.dev33.satoken.stp.StpUtil; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; +import cn.hutool.core.lang.Dict; import cn.hutool.core.util.StrUtil; +import com.budwk.app.base.constant.RoleConstant; +import com.budwk.app.base.page.Pagination; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.base.result.Result; import com.budwk.app.base.service.impl.BaseServiceImpl; import com.budwk.app.base.utils.CommonDownloadUtil; import com.budwk.app.base.utils.PageUtil; +import com.budwk.app.flow.constant.FlowConst; import com.budwk.app.flow.entity.ProcessInstance; +import com.budwk.app.flow.entity.ProcessTask; import com.budwk.app.flow.enums.ProcessInstanceStateEnum; +import com.budwk.app.flow.enums.ProcessTaskStateEnum; +import com.budwk.app.flow.service.FlowCommonService; +import com.budwk.app.flow.service.ProcessTaskService; import com.budwk.app.sys.models.SysHoliday; import com.budwk.app.sys.models.Sys_union; import com.budwk.app.web.commons.auth.utils.SecurityUtil; @@ -30,6 +41,7 @@ import org.nutz.dao.sql.Sql; import org.nutz.dao.util.cri.SqlExpressionGroup; import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.json.Json; import org.nutz.lang.util.NutMap; import javax.servlet.http.HttpServletResponse; @@ -44,8 +56,14 @@ import java.util.stream.Collectors; @IocBean(args = {"refer:dao"}) public class SiteCugApplyServiceImpl extends BaseServiceImpl implements SiteCugApplyService { + private static final String YEARLY_BATCH_PREFIX = "YEARLY_BATCH:"; + @Inject private SysClubService sysClubService; + @Inject + private ProcessTaskService processTaskService; + @Inject + private FlowCommonService flowCommonService; public SiteCugApplyServiceImpl(Dao dao) { super(dao); @@ -64,6 +82,11 @@ public class SiteCugApplyServiceImpl extends BaseServiceImpl imple if (StrUtil.isBlank(apply.getReserveStartTime()) || StrUtil.isBlank(apply.getReserveEndTime())) { return Map.of(false, "预约时间不能为空"); } + if (apply.getCoffeeNeeded() == null) { + apply.setCoffeeNeeded(0); + } else if (apply.getCoffeeNeeded() != 0 && apply.getCoffeeNeeded() != 1) { + return Map.of(false, "是否需要咖啡仅支持是/否"); + } if (!DateUtil.parseDateTime(apply.getReserveEndTime()).isAfter(DateUtil.parseDateTime(apply.getReserveStartTime()))) { return Map.of(false, "结束时间必须晚于开始时间"); } @@ -204,6 +227,123 @@ public class SiteCugApplyServiceImpl extends BaseServiceImpl imple CommonDownloadUtil.download("场馆预约查询.xlsx", workbook, response); } + @Override + public Pagination listAuditPage(PageForm pageForm, String siteType, String siteId, Boolean approval, String auditTaskName) { + Sql sql = Sqls.create(""" + SELECT + info.*, + si.name as siteName, + CASE WHEN info.reserveType = 'club' THEN info.clubName ELSE info.applyUnionName END AS reserveTargetName, + ins.id AS instanceId, + ins.businessNo, + ins.state instanceState, + ins.variable instanceVariable, + ins.processDefineId instanceProcessDefineId, + t.id taskId, + t.taskName AS taskKey, + t.displayName taskName, + t.taskType, + t.performType taskPerformType, + t.taskState, + t.finishTime, + t.taskParentId, + t.variable taskVariable, + IFNULL(GROUP_CONCAT(DISTINCT nt.displayName),'结束') curTaskName, + CASE WHEN EXISTS ( + SELECT 1 FROM wf_process_task rt + WHERE rt.processInstanceId = ins.id AND rt.taskParentId = t.id + ) THEN 1 ELSE 0 END AS canRevoke, + CASE WHEN info.backOption LIKE 'YEARLY_BATCH:%' THEN 1 ELSE 0 END AS yearlyBatch, + CASE WHEN info.backOption LIKE 'YEARLY_BATCH:%' THEN ( + SELECT COUNT(1) FROM site_cug_apply batch_info WHERE batch_info.backOption = info.backOption AND batch_info.createdBy = info.createdBy + ) ELSE 1 END AS batchAuditCount + FROM + wf_process_task t + LEFT JOIN wf_process_instance ins ON ins.id = t.processInstanceId + LEFT JOIN site_cug_apply info ON info.id = ins.businessNo + LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = t.id + LEFT JOIN site_cug_info si ON info.siteId = si.id + LEFT JOIN wf_process_task nt ON nt.processInstanceId = ins.id AND nt.taskState = 10 + LEFT JOIN wf_process_task rt ON rt.processInstanceId = ins.id AND rt.taskParentId = t.id + $condition + """); + Cnd cnd = Cnd.NEW(); + if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) { + SqlExpressionGroup seg = new SqlExpressionGroup(); + seg.or(SiteCugApply::getApplyUserName, "like", "%" + pageForm.getSearchKeyword() + "%"); + seg.or(SiteCugApply::getApplyLoginName, "like", "%" + pageForm.getSearchKeyword() + "%"); + cnd.and(seg); + } + cnd.andEX("si.typeId", "=", siteType); + cnd.andEX("info.siteId", "=", siteId); + cnd.and("t.taskName", "=", auditTaskName); + if (!StpUtil.hasRole(RoleConstant.SYSADMIN.name())) { + cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId())); + } + if (Boolean.TRUE.equals(approval)) { + cnd.and("t.taskState", "in", List.of(ProcessTaskStateEnum.FINISHED.getCode(), ProcessTaskStateEnum.INTERRUPT.getCode())); + } else { + cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode()); + } + + if (StrUtil.isNotBlank(pageForm.getPageOrderName()) && StrUtil.isNotBlank(pageForm.getPageOrderBy())) { + cnd.orderBy(resolveAuditOrderColumn(pageForm.getPageOrderName()), PageUtil.getOrder(pageForm.getPageOrderBy())); + } else { + cnd.desc("info.createdAt"); + } + cnd.groupBy("t.id"); + sql.setCondition(cnd); + return listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); + } + + @Override + public Result executeAuditTask(String data) { + Dict args = Json.fromJson(Dict.class, data); + Long processTaskId = args.getLong(FlowConst.PROCESS_TASK_ID_KEY); + ProcessTask currentTask = processTaskService.getById(processTaskId); + if (currentTask == null) { + return Result.error("审核任务不存在"); + } + + SiteCugApply apply = fetch(args.getStr("applyId")); + if (apply == null) { + return Result.error("预约记录不存在"); + } + + List taskList = getBatchDoingTaskList(apply, currentTask); + for (ProcessTask task : taskList) { + Dict cloneArgs = args.clone(); + cloneArgs.put(FlowConst.PROCESS_TASK_ID_KEY, task.getId()); + flowCommonService.executeTask(cloneArgs); + } + if (taskList.size() > 1) { + return Result.success("已完成该全年预约批次的审核"); + } + return Result.success("提交成功"); + } + + @Override + public Result revokeAuditTask(Long taskId, String applyId) { + ProcessTask currentTask = processTaskService.getById(taskId); + if (currentTask == null) { + return Result.error("撤回任务不存在"); + } + + SiteCugApply apply = fetch(applyId); + if (apply == null) { + return Result.error("预约记录不存在"); + } + + List taskList = getBatchDoneTaskList(apply, currentTask); + for (ProcessTask task : taskList) { + flowCommonService.revokeTask(task.getId()); + } + if (taskList.size() > 1) { + return Result.success("已撤回该全年预约批次的审核任务"); + } + return Result.success("撤回成功"); + } + // 场馆预约查询导出字段统一在 service 中定义,并与当前列表展示字段保持一致 private List buildRecordExportEntities() { List exportEntities = new ArrayList<>(); @@ -218,6 +358,66 @@ public class SiteCugApplyServiceImpl extends BaseServiceImpl imple return exportEntities; } + private String resolveAuditOrderColumn(String pageOrderName) { + if (StrUtil.isBlank(pageOrderName)) { + return "info.createdAt"; + } + switch (pageOrderName) { + case "siteName": + return "si.name"; + case "applyUserName": + return "info.applyUserName"; + case "applyLoginName": + return "info.applyLoginName"; + case "yearlyBatch": + return "yearlyBatch"; + case "reserveTargetName": + return "reserveTargetName"; + case "reserveStartTime": + return "info.reserveStartTime"; + case "reserveEndTime": + return "info.reserveEndTime"; + case "applyMobile": + return "info.applyMobile"; + case "curTaskName": + return "curTaskName"; + case "instanceState": + return "ins.state"; + default: + return "info.createdAt"; + } + } + + private List getBatchDoingTaskList(SiteCugApply apply, ProcessTask currentTask) { + List taskList = new ArrayList<>(); + if (isYearlyBatchApply(apply)) { + List batchList = query(Cnd.where("backOption", "=", apply.getBackOption()).and("createdBy", "=", apply.getCreatedBy())); + List bizIds = batchList.stream().map(SiteCugApply::getId).toList(); + taskList = processTaskService.getDoingTaskByBizIdTaskName(bizIds, currentTask.getTaskName()); + } + if (taskList.isEmpty()) { + taskList.add(currentTask); + } + return taskList; + } + + private List getBatchDoneTaskList(SiteCugApply apply, ProcessTask currentTask) { + List taskList = new ArrayList<>(); + if (isYearlyBatchApply(apply)) { + List batchList = query(Cnd.where("backOption", "=", apply.getBackOption()).and("createdBy", "=", apply.getCreatedBy())); + List bizIds = batchList.stream().map(SiteCugApply::getId).toList(); + taskList = processTaskService.getDoneTaskByBizIdTaskName(bizIds, currentTask.getTaskName()); + } + if (taskList.isEmpty()) { + taskList.add(currentTask); + } + return taskList; + } + + private boolean isYearlyBatchApply(SiteCugApply apply) { + return StrUtil.isNotBlank(apply.getBackOption()) && apply.getBackOption().startsWith(YEARLY_BATCH_PREFIX); + } + // 预约时间范围内只要包含周六或周日,就视为不可预约 private boolean containsWeekend(String reserveStartTime, String reserveEndTime) { Date start = DateUtil.beginOfDay(DateUtil.parseDateTime(reserveStartTime)); @@ -261,19 +461,69 @@ public class SiteCugApplyServiceImpl extends BaseServiceImpl imple DateTime reserveStart = DateUtil.parseDateTime(reserveStartTime); DateTime reserveEnd = DateUtil.parseDateTime(reserveEndTime); for (NutMap range : timeRanges) { - if (range == null || StrUtil.hasBlank(range.getString("date"), range.getString("startTime"), range.getString("endTime"))) { + if (range == null || StrUtil.hasBlank(range.getString("startTime"), range.getString("endTime"))) { continue; } - DateTime disabledStart = DateUtil.parseDateTime(range.getString("date") + " " + range.getString("startTime") + ":00"); - DateTime disabledEnd = DateUtil.parseDateTime(range.getString("date") + " " + range.getString("endTime") + ":00"); - boolean overlap = reserveStart.isBefore(disabledEnd) && reserveEnd.isAfter(disabledStart); - if (overlap) { + if (isDateDisabledTime(range) && intersectsDateDisabledTime(range, reserveStart, reserveEnd)) { + return true; + } + if (isWeekDisabledTime(range) && intersectsWeekDisabledTime(range, reserveStart, reserveEnd)) { return true; } } return false; } + private boolean isDateDisabledTime(NutMap range) { + String type = range.getString("type"); + return (StrUtil.isBlank(type) || StrUtil.equals(type, "date")) && StrUtil.isNotBlank(range.getString("date")); + } + + private boolean isWeekDisabledTime(NutMap range) { + return StrUtil.equals(range.getString("type"), "week") && range.get("weekDay") != null; + } + + private boolean intersectsDateDisabledTime(NutMap range, DateTime reserveStart, DateTime reserveEnd) { + DateTime disabledStart = DateUtil.parseDateTime(range.getString("date") + " " + range.getString("startTime") + ":00"); + DateTime disabledEnd = DateUtil.parseDateTime(range.getString("date") + " " + range.getString("endTime") + ":00"); + return reserveStart.isBefore(disabledEnd) && reserveEnd.isAfter(disabledStart); + } + + private boolean intersectsWeekDisabledTime(NutMap range, DateTime reserveStart, DateTime reserveEnd) { + int disabledWeekDay = parseWeekDay(range.get("weekDay")); + if (disabledWeekDay == 0) { + return false; + } + Date current = DateUtil.beginOfDay(reserveStart); + Date end = DateUtil.beginOfDay(reserveEnd); + while (current.compareTo(end) <= 0) { + DateTime currentDay = DateUtil.date(current); + if (toWeekDay(currentDay) == disabledWeekDay) { + DateTime disabledStart = DateUtil.parseDateTime(DateUtil.formatDate(currentDay) + " " + range.getString("startTime") + ":00"); + DateTime disabledEnd = DateUtil.parseDateTime(DateUtil.formatDate(currentDay) + " " + range.getString("endTime") + ":00"); + if (reserveStart.isBefore(disabledEnd) && reserveEnd.isAfter(disabledStart)) { + return true; + } + } + current = DateUtil.offsetDay(current, 1); + } + return false; + } + + private int parseWeekDay(Object value) { + try { + int weekDay = Integer.parseInt(String.valueOf(value)); + return weekDay >= 1 && weekDay <= 7 ? weekDay : 0; + } catch (Exception e) { + return 0; + } + } + + private int toWeekDay(DateTime currentDay) { + int weekDay = currentDay.dayOfWeek() - 1; + return weekDay == 0 ? 7 : weekDay; + } + // 按预约类型补齐最终落库数据,避免前端传错或被绕过 private Map fillReserveTypeData(SiteCugApply apply) { if (StrUtil.isBlank(apply.getReserveType())) { diff --git a/src/main/resources/views/layouts/v4/home/index.html b/src/main/resources/views/layouts/v4/home/index.html index a2f9f0f..4783ac7 100644 --- a/src/main/resources/views/layouts/v4/home/index.html +++ b/src/main/resources/views/layouts/v4/home/index.html @@ -130,7 +130,7 @@ layout("/layouts/v4/baseLayout.html"){ - + @@ -148,7 +148,9 @@ layout("/layouts/v4/baseLayout.html"){ el: '#v4-home-app', data(){ return{ - websiteNews: [], + websiteNews: { + grassroots: [] + }, homeBannerList: "${config.AppHomeImg!}".split(",").map(item => item.trim()).filter(item => item) } }, @@ -167,7 +169,7 @@ layout("/layouts/v4/baseLayout.html"){ getWebSiteNews(){ this.$axios.post('/platform/home/getNews').then(res => { if (res.code === 0) { - this.websiteNews = res.data + this.$set(this, 'websiteNews', res.data || {grassroots: []}) } }) } diff --git a/src/main/resources/views/layouts/v4/home/jcdt.js b/src/main/resources/views/layouts/v4/home/jcdt.js index dbeefbc..b3e03f4 100644 --- a/src/main/resources/views/layouts/v4/home/jcdt.js +++ b/src/main/resources/views/layouts/v4/home/jcdt.js @@ -1,33 +1,29 @@ const jcdt = { - template: /*language=HTML*/ ` -
-
- - -
- {{ item.label }} -
-
-
-
-
- - {{o.time}} -
-
-
- -
-
{{o.text}}
-
-
-
-
-
-
-
-
- `, + template: [ + '
', + '
', + '
', + ' 通知公告', + '
', + '
', + '
', + '
', + '
', + ' ', + ' {{item.date}}', + '
', + '
', + '
', + ' ', + '
', + '
{{item.title}}
', + '
', + '
', + '
', + '
', + '
', + '
' + ].join(''), data() { return {} }, @@ -39,144 +35,149 @@ const jcdt = { }, methods: { onLink(item) { - const url = this.isHttpOrHttps(item.href) ? item.href : "https://xgh.cug.edu.cn/" + item.href - window.open(url) - }, - isHttpOrHttps(url) { - return /^(http:\/\/|https:\/\/)/i.test(url) + if (!item.url) { + return + } + window.open(item.url) } }, - style: /*language=CSS*/ ` - .jcdt-wrapper { - width: 100%; - background-size: cover; - background-position: center; - background-repeat: no-repeat; - } - - .jcdt-container { - width: 80%; - max-width: 80%; - margin: 0 auto 10px; - background-color: #FFFFFF; - border-radius: 12px; - padding: 20px; - box-shadow: 0 6px 20px rgba(0, 0, 0, 0.06); - } - - /deep/ .jcdt-title{ - font-size: 30px; - color: #000000; - display: block; - font-weight: bold; - position: relative; - text-align: center; - padding: 20px 0; - } - - /deep/ .jcdt-container .jcdt-title span::before { - content: ''; - width: 24px; - height: 11px; - background: url(https://www.ncu.edu.cn/images/titl.svg) no-repeat center; - background-size: 24px 11px; - display: inline-block; - margin-right: 0; - vertical-align: middle; - } - - /deep/ .jcdt-container .jcdt-title span::after { - content: ''; - width: 24px; - height: 11px; - background: url(https://www.ncu.edu.cn/images/titr.svg) no-repeat center; - background-size: 24px 11px; - display: inline-block; - margin-left: 0; - vertical-align: middle; - } - - /deep/ .jcdt-list { - display: grid; - grid-template-columns: repeat(4, 1fr); - gap: 20px; - } - - /deep/ .jcdt-item { - display: flex; - flex-direction: column; - padding: 16px; - border: none; - border-bottom: 3px solid transparent; - transition: all 0.3s ease; - cursor: pointer; - height: auto; - border-radius: 12px; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); - border-bottom-color: var(--color-primary); - background: #ffffff; - } - - /deep/ .jcdt-item:hover{ - transform: translateY(-4px); - } - - /deep/ .jcdt-item .date { - font-size: 20px; - font-weight: bold; - white-space: nowrap; - text-align: left; - margin-bottom: 8px; - transition: opacity 0.3s ease; - } - - /deep/ .jcdt-item .title { - font-size: 16px; - font-weight: 600; - /*margin-bottom: 12px;*/ - line-height: 1.4; - display: -webkit-box; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - overflow: hidden; - /*height: 45px;*/ - } - - /deep/ .jcdt-item .image { - width: 100%; - height: 180px; - margin: 0 0 16px 0; - border-radius: 8px; - overflow: hidden; - background: #f5f5f5; - display: flex; - align-items: center; - justify-content: center; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); - transition: transform 0.3s ease; - } - - /deep/ .jcdt-item .image img { - width: 100%; - height: 100%; - object-fit: cover; - transition: transform 0.3s ease; - } - - /deep/ .jcdt-item .summary { - font-size: 14px; - color: #666; - line-height: 1.6; - display: -webkit-box; - -webkit-line-clamp: 3; - -webkit-box-orient: vertical; - overflow: hidden; - text-align: justify; - margin-bottom: 12px; - } - - /deep/ .jcdt-item i { - color: #007aff; - } - ` + style: [ + '.jcdt-wrapper {', + ' width: 100%;', + ' background-size: cover;', + ' background-position: center;', + ' background-repeat: no-repeat;', + '}', + '', + '.jcdt-container {', + ' width: 80%;', + ' max-width: 80%;', + ' margin: 0 auto 10px;', + ' background-color: #FFFFFF;', + ' border-radius: 12px;', + ' padding: 20px;', + ' box-shadow: 0 6px 20px rgba(0, 0, 0, 0.06);', + '}', + '', + '/deep/ .jcdt-title{', + ' font-size: 30px;', + ' color: #000000;', + ' display: block;', + ' font-weight: bold;', + ' position: relative;', + ' text-align: center;', + ' padding: 20px 0;', + '}', + '', + '/deep/ .jcdt-container .jcdt-title span::before {', + " content: '';", + ' width: 24px;', + ' height: 11px;', + ' background: url(https://www.ncu.edu.cn/images/titl.svg) no-repeat center;', + ' background-size: 24px 11px;', + ' display: inline-block;', + ' margin-right: 0;', + ' vertical-align: middle;', + '}', + '', + '/deep/ .jcdt-container .jcdt-title span::after {', + " content: '';", + ' width: 24px;', + ' height: 11px;', + ' background: url(https://www.ncu.edu.cn/images/titr.svg) no-repeat center;', + ' background-size: 24px 11px;', + ' display: inline-block;', + ' margin-left: 0;', + ' vertical-align: middle;', + '}', + '', + '/deep/ .jcdt-list {', + ' display: grid;', + ' grid-template-columns: repeat(4, 1fr);', + ' gap: 20px;', + '}', + '', + '/deep/ .jcdt-item {', + ' display: flex;', + ' flex-direction: column;', + ' padding: 16px;', + ' border: none;', + ' border-bottom: 3px solid transparent;', + ' transition: all 0.3s ease;', + ' cursor: pointer;', + ' height: auto;', + ' border-radius: 12px;', + ' box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);', + ' border-bottom-color: var(--color-primary);', + ' background: #ffffff;', + '}', + '', + '/deep/ .jcdt-item:hover{', + ' transform: translateY(-4px);', + '}', + '', + '/deep/ .jcdt-item .date {', + ' font-size: 20px;', + ' font-weight: bold;', + ' white-space: nowrap;', + ' text-align: left;', + ' margin-bottom: 8px;', + ' transition: opacity 0.3s ease;', + '}', + '', + '/deep/ .jcdt-item .title {', + ' font-size: 16px;', + ' font-weight: 600;', + ' /*margin-bottom: 12px;*/', + ' line-height: 1.4;', + ' display: -webkit-box;', + ' -webkit-line-clamp: 2;', + ' -webkit-box-orient: vertical;', + ' overflow: hidden;', + ' /*height: 45px;*/', + '}', + '', + '/deep/ .jcdt-item-icon {', + ' color: #007aff;', + ' font-size: 22px;', + ' margin-right: 8px;', + '}', + '', + '/deep/ .jcdt-item .image {', + ' width: 100%;', + ' height: 180px;', + ' margin: 0 0 16px 0;', + ' border-radius: 8px;', + ' overflow: hidden;', + ' background: #f5f5f5;', + ' display: flex;', + ' align-items: center;', + ' justify-content: center;', + ' box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);', + ' transition: transform 0.3s ease;', + '}', + '', + '/deep/ .jcdt-item .image img {', + ' width: 100%;', + ' height: 100%;', + ' object-fit: cover;', + ' transition: transform 0.3s ease;', + '}', + '', + '/deep/ .jcdt-item .summary {', + ' font-size: 14px;', + ' color: #666;', + ' line-height: 1.6;', + ' display: -webkit-box;', + ' -webkit-line-clamp: 3;', + ' -webkit-box-orient: vertical;', + ' overflow: hidden;', + ' text-align: justify;', + ' margin-bottom: 12px;', + '}', + '', + '/deep/ .jcdt-item i {', + ' color: #007aff;', + '}' + ].join('') }; diff --git a/src/main/resources/views/platform/zhgh/dayofficework/siteCug/apply/apply.js b/src/main/resources/views/platform/zhgh/dayofficework/siteCug/apply/apply.js index ecd499b..2ec2796 100644 --- a/src/main/resources/views/platform/zhgh/dayofficework/siteCug/apply/apply.js +++ b/src/main/resources/views/platform/zhgh/dayofficework/siteCug/apply/apply.js @@ -144,7 +144,7 @@ const apply = { - + + + + + 否 + 是 + + + + + + + + +
@@ -239,6 +257,7 @@ const apply = { reserveStartTime: '', reserveEndTime: '', yearlyReserveEndDate: '', + coffeeNeeded: 0, joinCount: 1, applyCause: '', }, @@ -251,7 +270,26 @@ const apply = { applyMobile: [{required: true, message: '必填', trigger: ['blur', 'change']}], reserveStartTime: [{required: true, message: '必填', trigger: ['blur', 'change']}], reserveEndTime: [{required: true, message: '必填', trigger: ['blur', 'change']}], - joinCount: [{required: true, message: '必填', trigger: ['blur', 'change']}], + coffeeNeeded: [{ + validator: (rule, value, callback) => { + if (value !== 0 && value !== 1) { + callback(new Error('请选择是否需要咖啡')) + return + } + callback() + }, + trigger: ['blur', 'change'], + }], + joinCount: [{ + validator: (rule, value, callback) => { + if (!Number.isInteger(Number(value)) || Number(value) <= 0) { + callback(new Error('预约人数必须为大于0的整数')) + return + } + callback() + }, + trigger: ['blur', 'change'], + }], applyCause: [{required: true, message: '必填', trigger: ['blur', 'change']}], clubId: [{ validator: (rule, value, callback) => { @@ -451,6 +489,7 @@ const apply = { reserveStartTime: '', reserveEndTime: '', yearlyReserveEndDate: '', + coffeeNeeded: 0, joinCount: 1, applyCause: '', } @@ -679,10 +718,31 @@ const apply = { } return timeStr.length === 5 ? timeStr + ':00' : timeStr }, + getDayWeekDay(dayStr) { + const target = this.$moment(dayStr, 'YYYY-MM-DD') + if (!target.isValid()) { + return 0 + } + const weekDay = target.day() + return weekDay === 0 ? 7 : weekDay + }, + isDateDisabledTime(item, dayStr) { + if (!item || !item.date) { + return false + } + const type = item.type || 'date' + return type === 'date' && this.$moment(item.date).format('YYYY-MM-DD') === dayStr + }, + isWeekDisabledTime(item, dayStr) { + if (!item || item.type !== 'week') { + return false + } + return Number(item.weekDay) === this.getDayWeekDay(dayStr) + }, getDisabledRangesByDay(dayStr) { const list = Array.isArray(this.timeLimitConfig.notApplyTimeList) ? this.timeLimitConfig.notApplyTimeList : [] return list - .filter(item => item && item.date && this.$moment(item.date).format('YYYY-MM-DD') === dayStr) + .filter(item => item && item.startTime && item.endTime && (this.isDateDisabledTime(item, dayStr) || this.isWeekDisabledTime(item, dayStr))) .sort((a, b) => this.normalizeTime(a.startTime).localeCompare(this.normalizeTime(b.startTime))) }, buildSelectableRange(dateTimeValue) { @@ -742,15 +802,22 @@ const apply = { return false }, overlapsDisabledRange(start, end) { - const list = Array.isArray(this.timeLimitConfig.notApplyTimeList) ? this.timeLimitConfig.notApplyTimeList : [] - return list.some(item => { - if (!item || !item.date || !item.startTime || !item.endTime) { - return false + const current = start.clone().startOf('day') + const endDay = end.clone().startOf('day') + while (current.isSameOrBefore(endDay)) { + const dayStr = current.format('YYYY-MM-DD') + const disabledRanges = this.getDisabledRangesByDay(dayStr) + const matched = disabledRanges.some(item => { + const rangeStart = this.$moment(dayStr + ' ' + this.normalizeTime(item.startTime)) + const rangeEnd = this.$moment(dayStr + ' ' + this.normalizeTime(item.endTime)) + return start.isBefore(rangeEnd) && end.isAfter(rangeStart) + }) + if (matched) { + return true } - const rangeStart = this.$moment(this.$moment(item.date).format('YYYY-MM-DD') + ' ' + this.normalizeTime(item.startTime)) - const rangeEnd = this.$moment(this.$moment(item.date).format('YYYY-MM-DD') + ' ' + this.normalizeTime(item.endTime)) - return start.isBefore(rangeEnd) && end.isAfter(rangeStart) - }) + current.add(1, 'day') + } + return false }, validateTimeLimit(showMessage = true, startTime = this.formData.reserveStartTime, endTime = this.formData.reserveEndTime) { if (!startTime || !endTime) { diff --git a/src/main/resources/views/platform/zhgh/dayofficework/siteCug/branchUnionAudit/index.html b/src/main/resources/views/platform/zhgh/dayofficework/siteCug/branchUnionAudit/index.html new file mode 100644 index 0000000..4381090 --- /dev/null +++ b/src/main/resources/views/platform/zhgh/dayofficework/siteCug/branchUnionAudit/index.html @@ -0,0 +1,368 @@ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + 已审核 + 未审核 + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + diff --git a/src/main/resources/views/platform/zhgh/dayofficework/siteCug/common/applyInfo.js b/src/main/resources/views/platform/zhgh/dayofficework/siteCug/common/applyInfo.js index c549a4f..6c054c7 100644 --- a/src/main/resources/views/platform/zhgh/dayofficework/siteCug/common/applyInfo.js +++ b/src/main/resources/views/platform/zhgh/dayofficework/siteCug/common/applyInfo.js @@ -14,8 +14,9 @@ const siteCugApplyInfo = { {{ reserveTargetName }} {{ viewData.reserveStartTime }} {{ viewData.reserveEndTime }} + {{ viewData.coffeeNeeded === 1 ? '是' : '否' }} + {{ viewData.joinCount || '-' }} {{ viewData.applyMobile }} - {{ viewData.joinCount }} {{ viewData.applyCause }}