diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/birthdayWishes/task/BirthdayWishesTask.java b/src/main/java/com/budwk/app/zhgh/dayofficework/birthdayWishes/task/BirthdayWishesTask.java index d342057..3fa8c9a 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/birthdayWishes/task/BirthdayWishesTask.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/birthdayWishes/task/BirthdayWishesTask.java @@ -1,13 +1,10 @@ package com.budwk.app.zhgh.dayofficework.birthdayWishes.task; -import cn.hutool.core.date.DateUtil; import com.budwk.app.zhgh.staffmanage.birthday.service.UserBirthdayService; import lombok.extern.slf4j.Slf4j; import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.IocBean; -import org.nutz.json.Json; import org.quartz.Job; -import org.quartz.JobDataMap; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; @@ -22,18 +19,8 @@ public class BirthdayWishesTask implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { log.info("=================================执行计划任务:{}", context.getJobDetail().getKey().getName()); - JobDataMap dataMap = context.getJobDetail().getJobDataMap(); - log.info("=================================参数:{}", Json.toJson(dataMap)); - - String planName = dataMap.getString("name"); - - String today = DateUtil.today(); - - String title = planName + today; - String content = dataMap.getString("template"); - // 统一由生日服务查询当天生日会员、生成移动端链接并记录系统推送日志。 - int receiverCount = userBirthdayService.sendTodayBirthdayMessages(title, content); + int receiverCount = userBirthdayService.sendTodayBirthdayMessages(); log.info("=================================当天生日通知进入发送队列人数:{}", receiverCount); } } diff --git a/src/main/java/com/budwk/app/zhgh/staffmanage/birthday/controller/UserBirthdayConfigController.java b/src/main/java/com/budwk/app/zhgh/staffmanage/birthday/controller/UserBirthdayConfigController.java new file mode 100644 index 0000000..fc4cb62 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffmanage/birthday/controller/UserBirthdayConfigController.java @@ -0,0 +1,71 @@ +package com.budwk.app.zhgh.staffmanage.birthday.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.util.StrUtil; +import com.budwk.app.base.result.Result; +import com.budwk.app.zhgh.staffmanage.birthday.models.UserBirthdayConfig; +import com.budwk.app.zhgh.staffmanage.birthday.service.UserBirthdayService; +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; + +/** + * 生日祝福配置管理。 + * 配置内容包含页面图片、默认查询天数、自动发送开关和发送文案。 + */ +@IocBean +@At("/platform/staffManage/birthday/config") +@Ok("json:full") +@Api(tags = "生日祝福配置") +public class UserBirthdayConfigController { + + @Inject + private UserBirthdayService userBirthdayService; + + @At("") + @Ok("beetl:/platform/zhgh/staffmanage/birthday/config/index.html") + @SaCheckPermission("staff.birthday.config") + public void index() { + } + + /** + * 获取当前生日祝福配置。 + * + * @return Result.data 为 UserBirthdayConfig,包含图片文件ID、查询天数、自动发送开关、标题和内容 + */ + @At + @ApiOperation("获取生日祝福配置") + @SaCheckPermission("staff.birthday.config") + public Result getConfig() { + return Result.success(userBirthdayService.getConfig()); + } + + /** + * 保存生日祝福配置。 + * config.picUrl、birthdayUrl 为图片文件ID;birthdayDays 为正整数; + * autoSendEnabled 为自动发送开关;sendTitle、sendContent 为默认发送文案。 + * + * @return Result.data 为保存后的 UserBirthdayConfig + */ + @At + @Aop(TransAop.READ_COMMITTED) + @ApiOperation("保存生日祝福配置") + @SaCheckPermission("staff.birthday.config") + public Result saveConfig(UserBirthdayConfig config) { + if (config == null || config.getBirthdayDays() == null || config.getBirthdayDays() <= 0) { + return Result.error("默认查询天数必须为正整数"); + } + if (StrUtil.isBlank(config.getSendTitle())) { + return Result.error("请输入发送标题"); + } + if (StrUtil.isBlank(config.getSendContent())) { + return Result.error("请输入发送内容"); + } + return Result.success("保存成功", userBirthdayService.saveConfig(config)); + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffmanage/birthday/models/UserBirthdayConfig.java b/src/main/java/com/budwk/app/zhgh/staffmanage/birthday/models/UserBirthdayConfig.java index 6bbdb6e..172c7aa 100644 --- a/src/main/java/com/budwk/app/zhgh/staffmanage/birthday/models/UserBirthdayConfig.java +++ b/src/main/java/com/budwk/app/zhgh/staffmanage/birthday/models/UserBirthdayConfig.java @@ -38,4 +38,24 @@ public class UserBirthdayConfig extends BaseModel { @Comment("生日福利贺卡图片文件ID") @ColDefine(type = ColType.VARCHAR, width = 100) private String birthdayUrl; + + @Column + @Comment("默认查询未来生日天数") + @ColDefine(type = ColType.INT) + private Integer birthdayDays; + + @Column + @Comment("是否自动发送生日祝福") + @ColDefine(type = ColType.BOOLEAN) + private Boolean autoSendEnabled; + + @Column + @Comment("默认发送标题") + @ColDefine(type = ColType.VARCHAR, width = 255) + private String sendTitle; + + @Column + @Comment("默认发送内容") + @ColDefine(type = ColType.TEXT) + private String sendContent; } diff --git a/src/main/java/com/budwk/app/zhgh/staffmanage/birthday/param/UserBirthdayPageForm.java b/src/main/java/com/budwk/app/zhgh/staffmanage/birthday/param/UserBirthdayPageForm.java index 0fc7779..978825d 100644 --- a/src/main/java/com/budwk/app/zhgh/staffmanage/birthday/param/UserBirthdayPageForm.java +++ b/src/main/java/com/budwk/app/zhgh/staffmanage/birthday/param/UserBirthdayPageForm.java @@ -27,16 +27,17 @@ public class UserBirthdayPageForm extends MemberInfoPageForm { /** * 将生日日期条件追加到已有人员查询条件。 - * 未传日期时默认查询今天起十五天内的生日,跨年时自动使用 OR 条件。 + * 未传日期时按配置天数查询,配置无效时默认十五天,跨年时自动使用 OR 条件。 * * @param cnd 已包含人员范围和会员状态的查询条件 */ - public void buildBirthdaySearch(Cnd cnd) { + public void buildBirthdaySearch(Cnd cnd, Integer birthdayDays) { String start = normalizeMonthDay(startDate); String end = normalizeMonthDay(endDate); if (StrUtil.isAllBlank(start, end)) { + int days = birthdayDays == null || birthdayDays <= 0 ? 15 : birthdayDays; start = DateUtil.format(DateUtil.date(), "MM-dd"); - end = DateUtil.format(DateUtil.offsetDay(DateUtil.date(), 15), "MM-dd"); + end = DateUtil.format(DateUtil.offsetDay(DateUtil.date(), days), "MM-dd"); } if (StrUtil.isAllNotBlank(start, end)) { diff --git a/src/main/java/com/budwk/app/zhgh/staffmanage/birthday/service/UserBirthdayService.java b/src/main/java/com/budwk/app/zhgh/staffmanage/birthday/service/UserBirthdayService.java index fe4306b..a407945 100644 --- a/src/main/java/com/budwk/app/zhgh/staffmanage/birthday/service/UserBirthdayService.java +++ b/src/main/java/com/budwk/app/zhgh/staffmanage/birthday/service/UserBirthdayService.java @@ -53,21 +53,19 @@ public interface UserBirthdayService extends BaseService { /** * 向当天生日的会员发送系统生日通知,供 Quartz 任务调用。 * - * @param title 消息标题 - * @param content 消息正文 * @return 实际进入发送队列的接收人数 */ - int sendTodayBirthdayMessages(String title, String content); + int sendTodayBirthdayMessages(); /** - * 获取最新生日页面配置;未配置时返回空配置对象。 + * 获取最新生日页面配置;未配置时返回默认配置。 */ UserBirthdayConfig getConfig(); /** * 新增或更新生日页面配置。 * - * @param config 背景图片和福利贺卡文件ID + * @param config 图片、查询天数、自动发送开关及默认消息内容 * @return 保存后的配置 */ UserBirthdayConfig saveConfig(UserBirthdayConfig config); diff --git a/src/main/java/com/budwk/app/zhgh/staffmanage/birthday/service/impl/UserBirthdayServiceImpl.java b/src/main/java/com/budwk/app/zhgh/staffmanage/birthday/service/impl/UserBirthdayServiceImpl.java index ac63ed0..ac091e3 100644 --- a/src/main/java/com/budwk/app/zhgh/staffmanage/birthday/service/impl/UserBirthdayServiceImpl.java +++ b/src/main/java/com/budwk/app/zhgh/staffmanage/birthday/service/impl/UserBirthdayServiceImpl.java @@ -25,12 +25,18 @@ import org.nutz.dao.Dao; import org.nutz.dao.Sqls; import org.nutz.dao.sql.Sql; import org.nutz.ioc.aop.Aop; +import org.nutz.ioc.impl.PropertiesProxy; import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.lang.Times; import org.nutz.lang.util.NutMap; +import org.nutz.mvc.Mvcs; +import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.net.URI; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; @@ -38,6 +44,13 @@ import java.util.List; @IocBean(args = {"refer:dao"}) public class UserBirthdayServiceImpl extends BaseServiceImpl implements UserBirthdayService { + private static final int DEFAULT_BIRTHDAY_DAYS = 15; + private static final String DEFAULT_SEND_TITLE = "请点击查收您的生日福利"; + private static final String DEFAULT_SEND_CONTENT = "校工会祝您:生日快乐!幸福安康"; + + @Inject + private PropertiesProxy conf; + @Inject private SysMsgService sysMsgService; @@ -106,7 +119,12 @@ public class UserBirthdayServiceImpl extends BaseServiceImpl implement @Override @Aop(TransAop.READ_COMMITTED) - public int sendTodayBirthdayMessages(String title, String content) { + public int sendTodayBirthdayMessages() { + UserBirthdayConfig config = getConfig(); + if (!Boolean.TRUE.equals(config.getAutoSendEnabled())) { + log.info("生日祝福自动发送已关闭"); + return 0; + } Sql sql = Sqls.create(""" SELECT loginname FROM vw_user @@ -118,18 +136,37 @@ public class UserBirthdayServiceImpl extends BaseServiceImpl implement sql.setCallback(Sqls.callback.strList()); dao().execute(sql); List loginNames = sql.getList(String.class); - return sendMessages(loginNames, title, content, "system", "系统推送", "系统推送"); + return sendMessages(loginNames, config.getSendTitle(), config.getSendContent(), + "system", "系统推送", "系统推送"); } @Override public UserBirthdayConfig getConfig() { UserBirthdayConfig config = dao().fetch(UserBirthdayConfig.class, Cnd.NEW().desc("updatedAt")); - return config == null ? new UserBirthdayConfig() : config; + return fillConfigDefaults(config == null ? new UserBirthdayConfig() : config); } @Override @Aop(TransAop.READ_COMMITTED) public UserBirthdayConfig saveConfig(UserBirthdayConfig config) { + UserBirthdayConfig current = dao().fetch(UserBirthdayConfig.class, Cnd.NEW().desc("updatedAt")); + if (current != null) { + config.setId(current.getId()); + // 兼容原图片配置入口,未提交的新配置字段保留已有值。 + if (config.getBirthdayDays() == null) { + config.setBirthdayDays(current.getBirthdayDays()); + } + if (config.getAutoSendEnabled() == null) { + config.setAutoSendEnabled(current.getAutoSendEnabled()); + } + if (config.getSendTitle() == null) { + config.setSendTitle(current.getSendTitle()); + } + if (config.getSendContent() == null) { + config.setSendContent(current.getSendContent()); + } + } + fillConfigDefaults(config); dao().insertOrUpdate(config); return config; } @@ -167,12 +204,51 @@ public class UserBirthdayServiceImpl extends BaseServiceImpl implement cnd.and("u.birthday", "is not", null); cnd.and("u.member", "=", 1); pageForm.buildSearch(cnd, "u."); - pageForm.buildBirthdaySearch(cnd); + pageForm.buildBirthdaySearch(cnd, getConfig().getBirthdayDays()); cnd.asc("daysUntilBirthday"); sql.setCondition(cnd); return sql; } + private UserBirthdayConfig fillConfigDefaults(UserBirthdayConfig config) { + if (config.getBirthdayDays() == null || config.getBirthdayDays() <= 0) { + config.setBirthdayDays(DEFAULT_BIRTHDAY_DAYS); + } + if (config.getAutoSendEnabled() == null) { + config.setAutoSendEnabled(true); + } + config.setSendTitle(StrUtil.blankToDefault(config.getSendTitle(), DEFAULT_SEND_TITLE)); + config.setSendContent(StrUtil.blankToDefault(config.getSendContent(), DEFAULT_SEND_CONTENT)); + return config; + } + + private String getBirthdayBaseUrl() { + HttpServletRequest request = Mvcs.getReq(); + if (request != null) { + String requestUrl = request.getRequestURL().toString(); + return requestUrl.substring(0, requestUrl.length() - request.getRequestURI().length()) + + request.getContextPath(); + } + + // 定时任务没有请求上下文;本机地址未配置端口时使用项目监听端口。 + String baseUrl = StrUtil.removeSuffix(Globals.AppDomain, "/"); + URI domain = URI.create(baseUrl); + if (domain.getPort() == -1 && StrUtil.equalsAnyIgnoreCase(domain.getHost(), + "localhost", "127.0.0.1", "[::1]", "::1")) { + int defaultPort = "https".equalsIgnoreCase(domain.getScheme()) ? 443 : 80; + int port = conf.getInt("server.port", defaultPort); + if (port != defaultPort) { + baseUrl = domain.getScheme() + "://" + domain.getRawAuthority() + ":" + port + + StrUtil.blankToDefault(domain.getRawPath(), ""); + } + } + String contextPath = StrUtil.removeSuffix(StrUtil.blankToDefault(Globals.AppBase, ""), "/"); + if (StrUtil.isNotBlank(contextPath) && !baseUrl.endsWith(contextPath)) { + baseUrl += contextPath; + } + return baseUrl; + } + /** * 将生日消息写入当前项目消息中心并生成发送记录。 * Sys_msg.url 用于站内消息点击,正文中的完整链接供外部短信/微信渠道访问。 @@ -190,9 +266,9 @@ public class UserBirthdayServiceImpl extends BaseServiceImpl implement UserBirthdayConfig config = getConfig(); String pagePath = "/platform/staffManage/birthday/manage/h5"; if (StrUtil.isNotBlank(config.getBirthdayUrl())) { - pagePath = pagePath + "?id=" + config.getBirthdayUrl(); + pagePath = pagePath + "?id=" + URLEncoder.encode(config.getBirthdayUrl(), StandardCharsets.UTF_8); } - String fullLink = Globals.AppDomain + pagePath; + String fullLink = getBirthdayBaseUrl() + pagePath; Sys_msg message = new Sys_msg(); message.setTitle(title); diff --git a/src/main/resources/db/user_birthday_config_add_settings.sql b/src/main/resources/db/user_birthday_config_add_settings.sql new file mode 100644 index 0000000..f16a16f --- /dev/null +++ b/src/main/resources/db/user_birthday_config_add_settings.sql @@ -0,0 +1,6 @@ +-- 已有生日配置表增加查询和发送配置字段。 +ALTER TABLE `user_birthday_config` + ADD COLUMN `birthdayDays` int DEFAULT 15 COMMENT '默认查询未来生日天数', + ADD COLUMN `autoSendEnabled` tinyint(1) DEFAULT 1 COMMENT '是否自动发送生日祝福', + ADD COLUMN `sendTitle` varchar(255) DEFAULT NULL COMMENT '默认发送标题', + ADD COLUMN `sendContent` text COMMENT '默认发送内容'; diff --git a/src/main/resources/db/user_birthday_create.sql b/src/main/resources/db/user_birthday_create.sql index fa5712b..ecd8e0f 100644 --- a/src/main/resources/db/user_birthday_create.sql +++ b/src/main/resources/db/user_birthday_create.sql @@ -2,6 +2,10 @@ CREATE TABLE IF NOT EXISTS `user_birthday_config` ( `id` varchar(32) NOT NULL COMMENT 'ID', `picUrl` varchar(100) DEFAULT NULL COMMENT '移动端背景图片文件ID', `birthdayUrl` varchar(100) DEFAULT NULL COMMENT '生日福利贺卡图片文件ID', + `birthdayDays` int DEFAULT 15 COMMENT '默认查询未来生日天数', + `autoSendEnabled` tinyint(1) DEFAULT 1 COMMENT '是否自动发送生日祝福', + `sendTitle` varchar(255) DEFAULT NULL COMMENT '默认发送标题', + `sendContent` text COMMENT '默认发送内容', `createdBy` varchar(32) DEFAULT NULL COMMENT '创建人', `createdAt` bigint DEFAULT NULL COMMENT '创建时间', `updatedBy` varchar(32) DEFAULT NULL COMMENT '修改人', diff --git a/src/main/resources/views/platform/zhgh/staffmanage/birthday/config/index.html b/src/main/resources/views/platform/zhgh/staffmanage/birthday/config/index.html new file mode 100644 index 0000000..3409354 --- /dev/null +++ b/src/main/resources/views/platform/zhgh/staffmanage/birthday/config/index.html @@ -0,0 +1,122 @@ + +
+ + +
+ 生日祝福配置 +
+ + + +
建议使用竖版生日主题图片。
+
+ + +
移动端点击“领取生日福利”后展示该图片。
+
+ + + 生日人员页未选择日期时,默认查询今天起未来N天。 + + + + + + + + + + 保存配置 + 预览生日页面 + +
+
+
+
+ + + diff --git a/src/main/resources/views/platform/zhgh/staffmanage/birthday/manage/index.html b/src/main/resources/views/platform/zhgh/staffmanage/birthday/manage/index.html index 213fffb..3b4cf16 100644 --- a/src/main/resources/views/platform/zhgh/staffmanage/birthday/manage/index.html +++ b/src/main/resources/views/platform/zhgh/staffmanage/birthday/manage/index.html @@ -38,7 +38,7 @@ layout("/layouts/platform.html"){ - 导出Excel 发送通知 @@ -172,6 +172,8 @@ layout("/layouts/platform.html"){ sendQueryForm: {title:"",content:""}, sendUserDialogVisible: false, sendUserForm: {userId:"",userInfo:"",title:"",content:""}, + birthdayDays: 15, + defaultMsgConfig: {title:"",content:""}, configDialogVisible: false, configForm: {id:"",picUrl:"",birthdayUrl:""} } @@ -231,7 +233,7 @@ layout("/layouts/platform.html"){ }) }, openSendByQuery() { - this.$set(this, "sendQueryForm", Object.assign(this.requestParams(), {title:"",content:""})) + this.$set(this, "sendQueryForm", Object.assign(this.requestParams(), {title:this.defaultMsgConfig.title,content:this.defaultMsgConfig.content})) this.$set(this, "sendQueryDialogVisible", true) }, closeSendByQuery() { @@ -259,7 +261,7 @@ layout("/layouts/platform.html"){ }) }, openSendByUser(row) { - this.$set(this, "sendUserForm", {userId:row.id,userInfo:row.username + "(" + row.loginname + ")",title:"",content:""}) + this.$set(this, "sendUserForm", {userId:row.id,userInfo:row.username + "(" + row.loginname + ")",title:this.defaultMsgConfig.title,content:this.defaultMsgConfig.content}) this.$set(this, "sendUserDialogVisible", true) }, closeSendByUser() { @@ -286,6 +288,16 @@ layout("/layouts/platform.html"){ }).catch(() => {}) }) }, + loadBirthdayConfig() { + this.$axios.post(loc() + "/getConfig").then((res) => { + if (res.code !== 0 || !res.data) return + this.$set(this, "birthdayDays", res.data.birthdayDays || 15) + this.$set(this, "defaultMsgConfig", { + title:res.data.sendTitle || "", + content:res.data.sendContent || "" + }) + }) + }, openConfig() { this.$set(this, "formLoading", true) this.$axios.post(loc() + "/getConfig").then((res) => { @@ -321,6 +333,7 @@ layout("/layouts/platform.html"){ }, created() { this.initOrganizationOptions() + this.loadBirthdayConfig() this.pageData() } })