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 d6d6871..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,16 +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/staff-manage/user_birthday_config_add_settings.sql b/src/main/resources/db/staff-manage/user_birthday_config_add_settings.sql new file mode 100644 index 0000000..356aeaf --- /dev/null +++ b/src/main/resources/db/staff-manage/user_birthday_config_add_settings.sql @@ -0,0 +1,10 @@ +-- 已有生日配置表增加查询和发送配置字段。 +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 '默认发送内容'; + + +INSERT INTO sys_menu (id, parentId, path, name, aliasName, type, href, target, icon, showit, disabled, permission, note, location, hasChildren, createdBy, createdAt, updatedBy, updatedAt, delFlag, processKey, platform, moduleId, isQuickEntry, picIcon, initialPinyinName, isRecommendApp, isRecommendService) VALUES ('df478143ff1846ddab704616d9fdae41', '93487f22face4e18887d90154b70094a', '01610005', '生日模板配置', null, 'menu', '/platform/staffManage/birthday/config', null, null, true, false, 'staff.birthday.config', null, 1014, false, '17a7f8ad3ee947b4a26175049a9c253d', 1790220577535, '17a7f8ad3ee947b4a26175049a9c253d', 1790220577536, false, null, 'PC', '07d940ba34bd47399cda140894f5d86b', false, '/platform/sys/file/download?id=f71c9e07faf05ac4bf8a5364ae0bfd85', 's', false, false); +INSERT INTO sys_role_menu (roleId, menuId) VALUES ('7f4a820d5a394bb8a0a92d6699afe7c8', 'df478143ff1846ddab704616d9fdae41'); 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() } })