新增站内信功能

This commit is contained in:
YunaiV 2023-01-29 18:44:51 +08:00
parent aaf84aae03
commit c107095d22
42 changed files with 2252 additions and 20 deletions

View File

@ -92,6 +92,7 @@
| | 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 |
| 🚀 | 短信管理 | 短信渠道、短息模板、短信日志,对接阿里云、腾讯云等主流短信平台 |
| 🚀 | 邮件管理 | 邮箱账号、邮件模版、邮件发送日志,支持所有邮件平台 |
| 🚀 | 站内信 | 系统内的消息通知,提供站内信模版、站内信消息 |
| 🚀 | 操作日志 | 系统正常操作日志记录和查询,集成 Swagger 生成日志内容 |
| ⭐️ | 登录日志 | 系统登录日志记录查询,包含登录异常 |
| 🚀 | 错误码管理 | 系统所有错误码的管理,可在线修改错误提示,无需重启服务 |

View File

@ -11,7 +11,7 @@
Target Server Version : 80026
File Encoding : 65001
Date: 27/01/2023 20:57:31
Date: 29/01/2023 18:44:35
*/
SET NAMES utf8mb4;
@ -546,7 +546,7 @@ CREATE TABLE `infra_api_error_log` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 949 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志';
) ENGINE = InnoDB AUTO_INCREMENT = 965 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志';
-- ----------------------------
-- Records of infra_api_error_log
@ -584,7 +584,7 @@ CREATE TABLE `infra_codegen_column` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1582 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表字段定义';
) ENGINE = InnoDB AUTO_INCREMENT = 1612 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表字段定义';
-- ----------------------------
-- Records of infra_codegen_column
@ -616,7 +616,7 @@ CREATE TABLE `infra_codegen_table` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 122 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表定义';
) ENGINE = InnoDB AUTO_INCREMENT = 124 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表定义';
-- ----------------------------
-- Records of infra_codegen_table
@ -1191,7 +1191,7 @@ CREATE TABLE `system_dict_data` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1227 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典数据表';
) ENGINE = InnoDB AUTO_INCREMENT = 1229 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典数据表';
-- ----------------------------
-- Records of system_dict_data
@ -1395,6 +1395,8 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1224, 10, '发送成功', '10', 'system_mail_send_status', 0, 'success', '', '邮件发送状态 - 发送成功', '1', '2023-01-26 09:54:28', '1', '2023-01-26 16:36:22', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1225, 20, '发送失败', '20', 'system_mail_send_status', 0, 'danger', '', '邮件发送状态 - 发送失败', '1', '2023-01-26 09:54:50', '1', '2023-01-26 16:36:26', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1226, 30, '不发送', '30', 'system_mail_send_status', 0, 'info', '', '邮件发送状态 - 不发送', '1', '2023-01-26 09:55:06', '1', '2023-01-26 16:36:36', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1227, 1, '通知公告', '1', 'system_notify_template_type', 0, 'primary', '', '站内信模版的类型 - 通知公告', '1', '2023-01-28 10:35:59', '1', '2023-01-28 10:35:59', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1228, 2, '系统消息', '2', 'system_notify_template_type', 0, 'success', '', '站内信模版的类型 - 系统消息', '1', '2023-01-28 10:36:20', '1', '2023-01-28 10:36:25', b'0');
COMMIT;
-- ----------------------------
@ -1415,7 +1417,7 @@ CREATE TABLE `system_dict_type` (
`deleted_time` datetime NULL DEFAULT NULL COMMENT '删除时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `dict_type`(`type` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 167 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表';
) ENGINE = InnoDB AUTO_INCREMENT = 168 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表';
-- ----------------------------
-- Records of system_dict_type
@ -1479,6 +1481,7 @@ INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creat
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (164, '公众号自动回复的请求关键字匹配模式', 'mp_auto_reply_request_match', 0, '公众号自动回复的请求关键字匹配模式', '1', '2023-01-16 23:29:56', '1', '2023-01-16 23:29:56', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (165, '公众号的消息类型', 'mp_message_type', 0, '公众号的消息类型', '1', '2023-01-17 22:17:09', '1', '2023-01-17 22:17:09', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (166, '邮件发送状态', 'system_mail_send_status', 0, '邮件发送状态', '1', '2023-01-26 09:53:13', '1', '2023-01-26 09:53:13', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (167, '站内信模版的类型', 'system_notify_template_type', 0, '站内信模版的类型', '1', '2023-01-28 10:35:10', '1', '2023-01-28 10:35:10', b'0', '1970-01-01 00:00:00');
COMMIT;
-- ----------------------------
@ -1527,7 +1530,7 @@ CREATE TABLE `system_login_log` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1980 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录';
) ENGINE = InnoDB AUTO_INCREMENT = 1985 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录';
-- ----------------------------
-- Records of system_login_log
@ -1620,7 +1623,7 @@ CREATE TABLE `system_mail_template` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 15 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '邮件模版表';
) ENGINE = InnoDB AUTO_INCREMENT = 16 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '邮件模版表';
-- ----------------------------
-- Records of system_mail_template
@ -1654,7 +1657,7 @@ CREATE TABLE `system_menu` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2144 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '菜单权限表';
) ENGINE = InnoDB AUTO_INCREMENT = 2153 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '菜单权限表';
-- ----------------------------
-- Records of system_menu
@ -1877,7 +1880,7 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1250, '敏感词更新', 'system:sensitive-word:update', 3, 3, 1247, '', '', '', 0, b'1', b'1', '', '2022-04-07 16:55:03', '', '2022-04-20 17:03:10', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1251, '敏感词删除', 'system:sensitive-word:delete', 3, 4, 1247, '', '', '', 0, b'1', b'1', '', '2022-04-07 16:55:03', '', '2022-04-20 17:03:10', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1252, '敏感词导出', 'system:sensitive-word:export', 3, 5, 1247, '', '', '', 0, b'1', b'1', '', '2022-04-07 16:55:03', '', '2022-04-20 17:03:10', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1254, '作者动态', '', 1, 0, 0, 'https://www.iocoder.cn', 'people', NULL, 0, b'1', b'1', '1', '2022-04-23 01:03:15', '1', '2023-01-25 20:05:55', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1254, '作者动态', '', 1, 0, 0, 'https://www.iocoder.cn', 'people', NULL, 0, b'1', b'1', '1', '2022-04-23 01:03:15', '1', '2023-01-28 12:33:52', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1255, '数据源配置', '', 2, 1, 2, 'data-source-config', 'rate', 'infra/dataSourceConfig/index', 0, b'1', b'1', '', '2022-04-27 14:37:32', '1', '2022-04-27 22:42:06', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1256, '数据源配置查询', 'infra:data-source-config:query', 3, 1, 1255, '', '', '', 0, b'1', b'1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1257, '数据源配置创建', 'infra:data-source-config:create', 3, 2, 1255, '', '', '', 0, b'1', b'1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', b'0');
@ -2023,6 +2026,15 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2141, '邮件记录', '', 2, 0, 2130, 'mail-log', 'log', 'system/mail/log/index', 0, b'1', b'1', '', '2023-01-26 02:16:50', '1', '2023-01-26 16:38:27', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2142, '日志查询', 'system:mail-log:query', 3, 1, 2141, '', '', '', 0, b'1', b'1', '', '2023-01-26 02:16:50', '', '2023-01-26 02:16:50', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2143, '发送测试邮件', 'system:mail-template:send-mail', 3, 5, 2136, '', '', '', 0, b'1', b'1', '1', '2023-01-26 23:29:15', '1', '2023-01-26 23:29:15', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2144, '站内信管理', '', 1, 11, 1, 'notify', 'message', NULL, 0, b'1', b'1', '1', '2023-01-28 10:25:18', '1', '2023-01-28 10:25:46', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2145, '模板管理', '', 2, 0, 2144, 'notify-template', 'education', 'system/notify/template/index', 0, b'1', b'1', '', '2023-01-28 02:26:42', '1', '2023-01-28 10:27:47', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2146, '站内信模板查询', 'system:notify-template:query', 3, 1, 2145, '', '', '', 0, b'1', b'1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2147, '站内信模板创建', 'system:notify-template:create', 3, 2, 2145, '', '', '', 0, b'1', b'1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2148, '站内信模板更新', 'system:notify-template:update', 3, 3, 2145, '', '', '', 0, b'1', b'1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2149, '站内信模板删除', 'system:notify-template:delete', 3, 4, 2145, '', '', '', 0, b'1', b'1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2150, '发送测试站内信', 'system:notify-template:send-notify', 3, 5, 2145, '', '', '', 0, b'1', b'1', '1', '2023-01-28 10:54:43', '1', '2023-01-28 10:54:43', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2151, '消息记录', '', 2, 0, 2144, 'notify-message', 'edit', 'system/notify/message/index', 0, b'1', b'1', '', '2023-01-28 04:28:22', '1', '2023-01-28 20:59:53', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2152, '站内信消息查询', 'system:notify-message:query', 3, 1, 2151, '', '', '', 0, b'1', b'1', '', '2023-01-28 04:28:22', '', '2023-01-28 04:28:22', b'0');
COMMIT;
-- ----------------------------
@ -2053,6 +2065,72 @@ INSERT INTO `system_notice` (`id`, `title`, `content`, `type`, `status`, `creato
INSERT INTO `system_notice` (`id`, `title`, `content`, `type`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4, '我是测试标题', '<p>哈哈哈哈123</p>', 1, 0, '110', '2022-02-22 01:01:25', '110', '2022-02-22 01:01:46', b'0', 121);
COMMIT;
-- ----------------------------
-- Table structure for system_notify_message
-- ----------------------------
DROP TABLE IF EXISTS `system_notify_message`;
CREATE TABLE `system_notify_message` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID',
`user_id` bigint NOT NULL COMMENT '用户id',
`user_type` tinyint NOT NULL COMMENT '用户类型',
`template_id` bigint NOT NULL COMMENT '模版编号',
`template_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模板编码',
`template_nickname` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模版发送人名称',
`template_content` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模版内容',
`template_type` int NOT NULL COMMENT '模版类型',
`template_params` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模版参数',
`read_status` bit(1) NOT NULL COMMENT '是否已读',
`read_time` datetime NULL DEFAULT NULL COMMENT '阅读时间',
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '站内信消息表';
-- ----------------------------
-- Records of system_notify_message
-- ----------------------------
BEGIN;
INSERT INTO `system_notify_message` (`id`, `user_id`, `user_type`, `template_id`, `template_code`, `template_nickname`, `template_content`, `template_type`, `template_params`, `read_status`, `read_time`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, 1, 2, 1, 'test', '123', '我是 1我开始 2 了', 1, '{\"name\":\"1\",\"what\":\"2\"}', b'0', '2023-01-28 21:06:10', '1', '2023-01-28 11:44:08', '1', '2023-01-29 02:51:50', b'0', 1);
INSERT INTO `system_notify_message` (`id`, `user_id`, `user_type`, `template_id`, `template_code`, `template_nickname`, `template_content`, `template_type`, `template_params`, `read_status`, `read_time`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3, 1, 2, 1, 'test', '123', '我是 1我开始 2 了', 1, '{\"name\":\"1\",\"what\":\"2\"}', b'0', '2023-01-29 10:34:13', '1', '2023-01-28 11:45:04', '1', '2023-01-29 02:51:52', b'0', 1);
INSERT INTO `system_notify_message` (`id`, `user_id`, `user_type`, `template_id`, `template_code`, `template_nickname`, `template_content`, `template_type`, `template_params`, `read_status`, `read_time`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4, 103, 2, 2, 'register', '系统消息', '你好,欢迎 哈哈 加入大家庭!', 2, '{\"name\":\"哈哈\"}', b'0', NULL, '1', '2023-01-28 21:02:20', '1', '2023-01-28 21:02:20', b'0', 1);
INSERT INTO `system_notify_message` (`id`, `user_id`, `user_type`, `template_id`, `template_code`, `template_nickname`, `template_content`, `template_type`, `template_params`, `read_status`, `read_time`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5, 1, 2, 1, 'test', '123', '我是 芋艿,我开始 写代码 了', 1, '{\"name\":\"芋艿\",\"what\":\"写代码\"}', b'0', '2023-01-29 10:41:45', '1', '2023-01-28 22:21:42', '1', '2023-01-29 02:51:54', b'0', 1);
INSERT INTO `system_notify_message` (`id`, `user_id`, `user_type`, `template_id`, `template_code`, `template_nickname`, `template_content`, `template_type`, `template_params`, `read_status`, `read_time`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6, 1, 2, 1, 'test', '123', '我是 芋艿,我开始 写代码 了', 1, '{\"name\":\"芋艿\",\"what\":\"写代码\"}', b'1', '2023-01-29 10:52:06', '1', '2023-01-28 22:22:07', '1', '2023-01-29 10:52:06', b'0', 1);
INSERT INTO `system_notify_message` (`id`, `user_id`, `user_type`, `template_id`, `template_code`, `template_nickname`, `template_content`, `template_type`, `template_params`, `read_status`, `read_time`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (7, 1, 2, 1, 'test', '123', '我是 2我开始 3 了', 1, '{\"name\":\"2\",\"what\":\"3\"}', b'1', '2023-01-29 10:52:06', '1', '2023-01-28 23:45:21', '1', '2023-01-29 10:52:06', b'0', 1);
INSERT INTO `system_notify_message` (`id`, `user_id`, `user_type`, `template_id`, `template_code`, `template_nickname`, `template_content`, `template_type`, `template_params`, `read_status`, `read_time`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (8, 1, 2, 2, 'register', '系统消息', '你好,欢迎 123 加入大家庭!', 2, '{\"name\":\"123\"}', b'1', '2023-01-29 10:52:06', '1', '2023-01-28 23:50:21', '1', '2023-01-29 10:52:06', b'0', 1);
COMMIT;
-- ----------------------------
-- Table structure for system_notify_template
-- ----------------------------
DROP TABLE IF EXISTS `system_notify_template`;
CREATE TABLE `system_notify_template` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模板名称',
`code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模版编码',
`nickname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '发送人名称',
`content` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模版内容',
`type` tinyint NOT NULL COMMENT '类型',
`params` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '参数数组',
`status` tinyint NOT NULL COMMENT '状态',
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注',
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '站内信模板表';
-- ----------------------------
-- Records of system_notify_template
-- ----------------------------
BEGIN;
COMMIT;
-- ----------------------------
-- Table structure for system_oauth2_access_token
-- ----------------------------
@ -2073,7 +2151,7 @@ CREATE TABLE `system_oauth2_access_token` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1214 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌';
) ENGINE = InnoDB AUTO_INCREMENT = 1249 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌';
-- ----------------------------
-- Records of system_oauth2_access_token
@ -2195,7 +2273,7 @@ CREATE TABLE `system_oauth2_refresh_token` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 588 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌';
) ENGINE = InnoDB AUTO_INCREMENT = 593 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌';
-- ----------------------------
-- Records of system_oauth2_refresh_token
@ -2235,7 +2313,7 @@ CREATE TABLE `system_operate_log` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4177 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录';
) ENGINE = InnoDB AUTO_INCREMENT = 4245 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录';
-- ----------------------------
-- Records of system_operate_log
@ -3353,7 +3431,7 @@ CREATE TABLE `system_users` (
-- Records of system_users
-- ----------------------------
BEGIN;
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 'admin', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '芋道源码', '管理员', 103, '[1]', 'aoteman@126.com', '15612345678', 1, 'http://test.yudao.iocoder.cn/e1fdd7271685ec143a0900681606406621717a666ad0b2798b096df41422b32f.png', 0, '0:0:0:0:0:0:0:1', '2023-01-27 14:31:00', 'admin', '2021-01-05 17:03:47', NULL, '2023-01-27 14:31:00', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 'admin', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '芋道源码', '管理员', 103, '[1]', 'aoteman@126.com', '15612345678', 1, 'http://test.yudao.iocoder.cn/e1fdd7271685ec143a0900681606406621717a666ad0b2798b096df41422b32f.png', 0, '127.0.0.1', '2023-01-29 10:05:18', 'admin', '2021-01-05 17:03:47', NULL, '2023-01-29 10:05:18', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (100, 'yudao', '$2a$10$11U48RhyJ5pSBYWSn12AD./ld671.ycSzJHbyrtpeoMeYiw31eo8a', '芋道', '不要吓我', 104, '[1]', 'yudao@iocoder.cn', '15601691300', 1, '', 1, '127.0.0.1', '2022-07-09 23:03:33', '', '2021-01-07 09:07:17', NULL, '2022-07-09 23:03:33', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (103, 'yuanma', '$2a$10$YMpimV4T6BtDhIaA8jSW.u8UTGBeGhc/qwXP4oxoMr4mOw9.qttt6', '源码', NULL, 106, NULL, 'yuanma@iocoder.cn', '15601701300', 0, '', 0, '127.0.0.1', '2022-07-08 01:26:27', '', '2021-01-13 23:50:35', NULL, '2022-07-08 01:26:27', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (104, 'test', '$2a$10$GP8zvqHB//TekuzYZSBYAuBQJiNq1.fxQVDYJ.uBCOnWCtDVKE4H6', '测试号', NULL, 107, '[1,2]', '111@qq.com', '15601691200', 1, '', 0, '127.0.0.1', '2022-05-28 15:43:17', '', '2021-01-21 02:13:53', NULL, '2022-07-09 09:00:33', b'0', 1);

View File

@ -1,8 +1,11 @@
package cn.iocoder.yudao.framework.common.enums;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 通用状态枚举
*
@ -10,11 +13,13 @@ import lombok.Getter;
*/
@Getter
@AllArgsConstructor
public enum CommonStatusEnum {
public enum CommonStatusEnum implements IntArrayValuable {
ENABLE(0, "开启"),
DISABLE(1, "关闭");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CommonStatusEnum::getStatus).toArray();
/**
* 状态值
*/
@ -24,4 +29,9 @@ public enum CommonStatusEnum {
*/
private final String name;
@Override
public int[] array() {
return ARRAYS;
}
}

View File

@ -94,6 +94,19 @@ public class QueryWrapperX<T> extends QueryWrapper<T> {
return this;
}
public QueryWrapperX<T> betweenIfPresent(String column, Object[] values) {
if (values!= null && values.length != 0 && values[0] != null && values[1] != null) {
return (QueryWrapperX<T>) super.between(column, values[0], values[1]);
}
if (values!= null && values.length != 0 && values[0] != null) {
return (QueryWrapperX<T>) ge(column, values[0]);
}
if (values!= null && values.length != 0 && values[1] != null) {
return (QueryWrapperX<T>) le(column, values[1]);
}
return this;
}
// ========== 重写父类方法方便链式调用 ==========
@Override
@ -133,19 +146,19 @@ public class QueryWrapperX<T> extends QueryWrapper<T> {
*
* @return this
*/
public QueryWrapperX<T> limit1() {
public QueryWrapperX<T> limitN(int n) {
Assert.notNull(SqlConstants.DB_TYPE, "获取不到数据库的类型");
switch (SqlConstants.DB_TYPE) {
case ORACLE:
case ORACLE_12C:
super.eq("ROWNUM", 1);
super.eq("ROWNUM", n);
break;
case SQL_SERVER:
case SQL_SERVER2005:
super.select("TOP 1 *"); // 由于 SQL Server 是通过 SELECT TOP 1 实现限制一条所以只好使用 * 查询剩余字段
super.select("TOP " + n + " *"); // 由于 SQL Server 是通过 SELECT TOP 1 实现限制一条所以只好使用 * 查询剩余字段
break;
default:
super.last("LIMIT 1");
super.last("LIMIT " + n);
}
return this;
}

View File

@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.system.api.notify;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
import cn.iocoder.yudao.module.system.enums.ApiConstants;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import javax.validation.Valid;
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿fallbackFactory =
@Api(tags = "RPC 服务 - 站内信发送")
public interface NotifyMessageSendApi {
String PREFIX = ApiConstants.PREFIX + "/notify/send";
@PostMapping(PREFIX + "/send-single-admin")
@ApiOperation(value = "发送单条站内信给 Admin 用户")
CommonResult<Long> sendSingleMessageToAdmin(@Valid NotifySendSingleToUserReqDTO reqDTO);
@PostMapping(PREFIX + "/send-single-member")
@ApiOperation(value = "发送单条站内信给 Member 用户")
CommonResult<Long> sendSingleMessageToMember(@Valid NotifySendSingleToUserReqDTO reqDTO);
}

View File

@ -0,0 +1,24 @@
package cn.iocoder.yudao.module.system.api.notify.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Map;
@ApiModel("RPC 服务 - 站内信发送给 Admin 或者 Member 用户 Request DTO")
@Data
public class NotifySendSingleToUserReqDTO {
@ApiModelProperty(value = "用户编号", required = true, example = "1024")
@NotNull(message = "用户编号不能为空")
private Long userId;
@ApiModelProperty(value = "站内信模板编号", required = true, example = "USER_SEND")
@NotEmpty(message = "站内信模板编号不能为空")
private String templateCode;
@ApiModelProperty(value = "邮件模板参数")
private Map<String, Object> templateParams;
}

View File

@ -153,4 +153,13 @@ public interface ErrorCodeConstants {
ErrorCode MAIL_SEND_TEMPLATE_PARAM_MISS = new ErrorCode(1002025000, "模板参数({})缺失");
ErrorCode MAIL_SEND_MAIL_NOT_EXISTS = new ErrorCode(1002025000, "邮箱不存在");
// ========== 站内信模版 1002026000 ==========
ErrorCode NOTIFY_TEMPLATE_NOT_EXISTS = new ErrorCode(1002026000, "站内信模版不存在");
ErrorCode NOTIFY_TEMPLATE_CODE_DUPLICATE = new ErrorCode(1002026001, "已经存在编码为【{}】的站内信模板");
// ========== 站内信模版 1002027000 ==========
// ========== 站内信发送 1002028000 ==========
ErrorCode NOTIFY_SEND_TEMPLATE_PARAM_MISS = new ErrorCode(1002025000, "模板参数({})缺失");
}

View File

@ -150,6 +150,11 @@
<artifactId>yudao-spring-boot-starter-captcha</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- 监控相关 -->
<dependency>
<groupId>cn.iocoder.cloud</groupId>

View File

@ -0,0 +1,37 @@
package cn.iocoder.yudao.module.system.api.notify.notify;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi;
import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
import cn.iocoder.yudao.module.system.service.notify.NotifySendService;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.module.system.enums.ApiConstants.VERSION;
@RestController // 提供 RESTful API 接口 Feign 调用
@DubboService(version = VERSION) // 提供 Dubbo RPC 接口 Dubbo Consumer 调用
@Validated
public class NotifyMessageSendApiImpl implements NotifyMessageSendApi {
@Resource
private NotifySendService notifySendService;
@Override
public CommonResult<Long> sendSingleMessageToAdmin(NotifySendSingleToUserReqDTO reqDTO) {
return success(notifySendService.sendSingleNotifyToAdmin(reqDTO.getUserId(),
reqDTO.getTemplateCode(), reqDTO.getTemplateParams()));
}
@Override
public CommonResult<Long> sendSingleMessageToMember(NotifySendSingleToUserReqDTO reqDTO) {
return success(notifySendService.sendSingleNotifyToMember(reqDTO.getUserId(),
reqDTO.getTemplateCode(), reqDTO.getTemplateParams()));
}
}

View File

@ -0,0 +1,95 @@
package cn.iocoder.yudao.module.system.controller.admin.notify;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessageRespVO;
import cn.iocoder.yudao.module.system.convert.notify.NotifyMessageConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO;
import cn.iocoder.yudao.module.system.service.notify.NotifyMessageService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@Api(tags = "管理后台 - 我的站内信")
@RestController
@RequestMapping("/system/notify-message")
@Validated
public class NotifyMessageController {
@Resource
private NotifyMessageService notifyMessageService;
// ========== 管理所有的站内信 ==========
@GetMapping("/get")
@ApiOperation("获得站内信")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('system:notify-message:query')")
public CommonResult<NotifyMessageRespVO> getNotifyMessage(@RequestParam("id") Long id) {
NotifyMessageDO notifyMessage = notifyMessageService.getNotifyMessage(id);
return success(NotifyMessageConvert.INSTANCE.convert(notifyMessage));
}
@GetMapping("/page")
@ApiOperation("获得站内信分页")
@PreAuthorize("@ss.hasPermission('system:notify-message:query')")
public CommonResult<PageResult<NotifyMessageRespVO>> getNotifyMessagePage(@Valid NotifyMessagePageReqVO pageVO) {
PageResult<NotifyMessageDO> pageResult = notifyMessageService.getNotifyMessagePage(pageVO);
return success(NotifyMessageConvert.INSTANCE.convertPage(pageResult));
}
// ========== 查看自己的站内信 ==========
@GetMapping("/my-page")
@ApiOperation("获得我的站内信分页")
public CommonResult<PageResult<NotifyMessageRespVO>> getMyMyNotifyMessagePage(@Valid NotifyMessageMyPageReqVO pageVO) {
PageResult<NotifyMessageDO> pageResult = notifyMessageService.getMyMyNotifyMessagePage(pageVO,
getLoginUserId(), UserTypeEnum.ADMIN.getValue());
return success(NotifyMessageConvert.INSTANCE.convertPage(pageResult));
}
@PutMapping("/update-read")
@ApiOperation("标记站内信为已读")
@ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class)
public CommonResult<Boolean> updateNotifyMessageRead(@RequestParam("ids") List<Long> ids) {
notifyMessageService.updateNotifyMessageRead(ids, getLoginUserId(), UserTypeEnum.ADMIN.getValue());
return success(Boolean.TRUE);
}
@PutMapping("/update-all-read")
@ApiOperation("标记所有站内信为已读")
public CommonResult<Boolean> updateAllNotifyMessageRead() {
notifyMessageService.updateAllNotifyMessageRead(getLoginUserId(), UserTypeEnum.ADMIN.getValue());
return success(Boolean.TRUE);
}
@GetMapping("/get-unread-list")
@ApiOperation("获取当前用户的最新站内信列表,默认 10 条")
@ApiImplicitParam(name = "size", value = "10", defaultValue = "10", dataTypeClass = Integer.class)
public CommonResult<List<NotifyMessageRespVO>> getUnreadNotifyMessageList(
@RequestParam(name = "size", defaultValue = "10") Integer size) {
List<NotifyMessageDO> list = notifyMessageService.getUnreadNotifyMessageList(
getLoginUserId(), UserTypeEnum.ADMIN.getValue(), size);
return success(NotifyMessageConvert.INSTANCE.convertList(list));
}
@GetMapping("/get-unread-count")
@ApiOperation("获得当前用户的未读站内信数量")
public CommonResult<Long> getUnreadNotifyMessageCount() {
return success(notifyMessageService.getUnreadNotifyMessageCount(getLoginUserId(), UserTypeEnum.ADMIN.getValue()));
}
}

View File

@ -0,0 +1,83 @@
package cn.iocoder.yudao.module.system.controller.admin.notify;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.*;
import cn.iocoder.yudao.module.system.convert.notify.NotifyTemplateConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
import cn.iocoder.yudao.module.system.service.notify.NotifySendService;
import cn.iocoder.yudao.module.system.service.notify.NotifyTemplateService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Api(tags = "管理后台 - 站内信模版")
@RestController
@RequestMapping("/system/notify-template")
@Validated
public class NotifyTemplateController {
@Resource
private NotifyTemplateService notifyTemplateService;
@Resource
private NotifySendService notifySendService;
@PostMapping("/create")
@ApiOperation("创建站内信模版")
@PreAuthorize("@ss.hasPermission('system:notify-template:create')")
public CommonResult<Long> createNotifyTemplate(@Valid @RequestBody NotifyTemplateCreateReqVO createReqVO) {
return success(notifyTemplateService.createNotifyTemplate(createReqVO));
}
@PutMapping("/update")
@ApiOperation("更新站内信模版")
@PreAuthorize("@ss.hasPermission('system:notify-template:update')")
public CommonResult<Boolean> updateNotifyTemplate(@Valid @RequestBody NotifyTemplateUpdateReqVO updateReqVO) {
notifyTemplateService.updateNotifyTemplate(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@ApiOperation("删除站内信模版")
@ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('system:notify-template:delete')")
public CommonResult<Boolean> deleteNotifyTemplate(@RequestParam("id") Long id) {
notifyTemplateService.deleteNotifyTemplate(id);
return success(true);
}
@GetMapping("/get")
@ApiOperation("获得站内信模版")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('system:notify-template:query')")
public CommonResult<NotifyTemplateRespVO> getNotifyTemplate(@RequestParam("id") Long id) {
NotifyTemplateDO notifyTemplate = notifyTemplateService.getNotifyTemplate(id);
return success(NotifyTemplateConvert.INSTANCE.convert(notifyTemplate));
}
@GetMapping("/page")
@ApiOperation("获得站内信模版分页")
@PreAuthorize("@ss.hasPermission('system:notify-template:query')")
public CommonResult<PageResult<NotifyTemplateRespVO>> getNotifyTemplatePage(@Valid NotifyTemplatePageReqVO pageVO) {
PageResult<NotifyTemplateDO> pageResult = notifyTemplateService.getNotifyTemplatePage(pageVO);
return success(NotifyTemplateConvert.INSTANCE.convertPage(pageResult));
}
@PostMapping("/send-notify")
@ApiOperation("发送站内信")
@PreAuthorize("@ss.hasPermission('system:notify-template:send-notify')")
public CommonResult<Long> sendNotify(@Valid @RequestBody NotifyTemplateSendReqVO sendReqVO) {
return success(notifySendService.sendSingleNotifyToAdmin(sendReqVO.getUserId(),
sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams()));
}
}

View File

@ -0,0 +1,60 @@
package cn.iocoder.yudao.module.system.controller.admin.notify.vo.message;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
/**
* 站内信消息 Base VO提供给添加修改详细的子 VO 使用
* 如果子 VO 存在差异的字段请不要添加到这里影响 Swagger 文档生成
*/
@Data
public class NotifyMessageBaseVO {
@ApiModelProperty(value = "用户编号", required = true, example = "25025")
@NotNull(message = "用户编号不能为空")
private Long userId;
@ApiModelProperty(value = "用户类型", required = true, example = "1", notes = "参见 UserTypeEnum 枚举")
@NotNull(message = "用户类型不能为空")
private Byte userType;
@ApiModelProperty(value = "模版编号", required = true, example = "13013")
@NotNull(message = "模版编号不能为空")
private Long templateId;
@ApiModelProperty(value = "模板编码", required = true, example = "test_01")
@NotNull(message = "模板编码不能为空")
private String templateCode;
@ApiModelProperty(value = "模版发送人名称", required = true, example = "芋艿")
@NotNull(message = "模版发送人名称不能为空")
private String templateNickname;
@ApiModelProperty(value = "模版内容", required = true, example = "测试内容")
@NotNull(message = "模版内容不能为空")
private String templateContent;
@ApiModelProperty(value = "模版类型", required = true, example = "2")
@NotNull(message = "模版类型不能为空")
private Integer templateType;
@ApiModelProperty(value = "模版参数", required = true)
@NotNull(message = "模版参数不能为空")
private Map<String, Object> templateParams;
@ApiModelProperty(value = "是否已读", required = true, example = "true")
@NotNull(message = "是否已读不能为空")
private Boolean readStatus;
@ApiModelProperty(value = "阅读时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime readTime;
}

View File

@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.system.controller.admin.notify.vo.message;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel("管理后台 - 站内信分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class NotifyMessageMyPageReqVO extends PageParam {
@ApiModelProperty(value = "是否已读", example = "true")
private Boolean readStatus;
@ApiModelProperty(value = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -0,0 +1,37 @@
package cn.iocoder.yudao.module.system.controller.admin.notify.vo.message;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel("管理后台 - 站内信分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class NotifyMessagePageReqVO extends PageParam {
@ApiModelProperty(value = "用户编号", example = "25025")
private Long userId;
@ApiModelProperty(value = "用户类型", example = "1")
private Integer userType;
@ApiModelProperty(value = "模板编码", example = "test_01")
private String templateCode;
@ApiModelProperty(value = "模版类型", example = "2")
private Integer templateType;
@ApiModelProperty(value = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -0,0 +1,23 @@
package cn.iocoder.yudao.module.system.controller.admin.notify.vo.message;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.util.Date;
@ApiModel("管理后台 - 站内信 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class NotifyMessageRespVO extends NotifyMessageBaseVO {
@ApiModelProperty(value = "ID", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "创建时间", required = true)
private Date createTime;
}

View File

@ -0,0 +1,46 @@
package cn.iocoder.yudao.module.system.controller.admin.notify.vo.template;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* 站内信模版 Base VO提供给添加修改详细的子 VO 使用
* 如果子 VO 存在差异的字段请不要添加到这里影响 Swagger 文档生成
*/
@Data
public class NotifyTemplateBaseVO {
@ApiModelProperty(value = "模版名称", required = true, example = "测试模版")
@NotEmpty(message = "模版名称不能为空")
private String name;
@ApiModelProperty(value = "模版编码", required = true, example = "SEND_TEST")
@NotNull(message = "模版编码不能为空")
private String code;
@ApiModelProperty(value = "模版类型", required = true, example = "1", notes = "对应 system_notify_template_type 字典")
@NotNull(message = "模版类型不能为空")
private Integer type;
@ApiModelProperty(value = "发送人名称", required = true, example = "土豆")
@NotEmpty(message = "发送人名称不能为空")
private String nickname;
@ApiModelProperty(value = "模版内容", required = true, example = "我是模版内容")
@NotEmpty(message = "模版内容不能为空")
private String content;
@ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举")
@NotNull(message = "状态不能为空")
@InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}")
private Integer status;
@ApiModelProperty(value = "备注", example = "我是备注")
private String remark;
}

View File

@ -0,0 +1,13 @@
package cn.iocoder.yudao.module.system.controller.admin.notify.vo.template;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@ApiModel("管理后台 - 站内信模版创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class NotifyTemplateCreateReqVO extends NotifyTemplateBaseVO {
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.system.controller.admin.notify.vo.template;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel("管理后台 - 站内信模版分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class NotifyTemplatePageReqVO extends PageParam {
@ApiModelProperty(value = "模版编码", example = "test_01")
private String code;
@ApiModelProperty(value = "模版名称", example = "我是名称")
private String name;
@ApiModelProperty(value = "状态", example = "1", notes = "参见 CommonStatusEnum 枚举类")
private Integer status;
@ApiModelProperty(value = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.system.controller.admin.notify.vo.template;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.util.Date;
import java.util.List;
@ApiModel("管理后台 - 站内信模版 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class NotifyTemplateRespVO extends NotifyTemplateBaseVO {
@ApiModelProperty(value = "ID", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "参数数组", example = "name,code")
private List<String> params;
@ApiModelProperty(value = "创建时间", required = true)
private Date createTime;
}

View File

@ -0,0 +1,25 @@
package cn.iocoder.yudao.module.system.controller.admin.notify.vo.template;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Map;
@ApiModel("管理后台 - 站内信模板的发送 Request VO")
@Data
public class NotifyTemplateSendReqVO {
@ApiModelProperty(value = "用户id", required = true, example = "01")
@NotNull(message = "用户id不能为空")
private Long userId;
@ApiModelProperty(value = "模板编码", required = true, example = "01")
@NotEmpty(message = "模板编码不能为空")
private String templateCode;
@ApiModelProperty(value = "模板参数")
private Map<String, Object> templateParams;
}

View File

@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.system.controller.admin.notify.vo.template;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.constraints.NotNull;
@ApiModel("管理后台 - 站内信模版更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class NotifyTemplateUpdateReqVO extends NotifyTemplateBaseVO {
@ApiModelProperty(value = "ID", required = true, example = "1024")
@NotNull(message = "ID 不能为空")
private Long id;
}

View File

@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.system.convert.notify;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessageRespVO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
/**
* 站内信 Convert
*
* @author xrcoder
*/
@Mapper
public interface NotifyMessageConvert {
NotifyMessageConvert INSTANCE = Mappers.getMapper(NotifyMessageConvert.class);
NotifyMessageRespVO convert(NotifyMessageDO bean);
List<NotifyMessageRespVO> convertList(List<NotifyMessageDO> list);
PageResult<NotifyMessageRespVO> convertPage(PageResult<NotifyMessageDO> page);
}

View File

@ -0,0 +1,33 @@
package cn.iocoder.yudao.module.system.convert.notify;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateCreateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateRespVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateUpdateReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
/**
* 站内信模版 Convert
*
* @author xrcoder
*/
@Mapper
public interface NotifyTemplateConvert {
NotifyTemplateConvert INSTANCE = Mappers.getMapper(NotifyTemplateConvert.class);
NotifyTemplateDO convert(NotifyTemplateCreateReqVO bean);
NotifyTemplateDO convert(NotifyTemplateUpdateReqVO bean);
NotifyTemplateRespVO convert(NotifyTemplateDO bean);
List<NotifyTemplateRespVO> convertList(List<NotifyTemplateDO> list);
PageResult<NotifyTemplateRespVO> convertPage(PageResult<NotifyTemplateDO> page);
}

View File

@ -0,0 +1,99 @@
package cn.iocoder.yudao.module.system.dal.dataobject.notify;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.*;
import java.time.LocalDateTime;
import java.util.Map;
/**
* 站内信 DO
*
* @author xrcoder
*/
@TableName(value = "system_notify_message", autoResultMap = true)
@KeySequence("system_notify_message_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class NotifyMessageDO extends BaseDO {
/**
* 站内信编号自增
*/
@TableId
private Long id;
/**
* 用户编号
*
* 关联 MemberUserDO id 字段或者 AdminUserDO id 字段
*/
private Long userId;
/**
* 用户类型
*
* 枚举 {@link UserTypeEnum}
*/
private Integer userType;
// ========= 模板相关字段 =========
/**
* 模版编号
*
* 关联 {@link NotifyTemplateDO#getId()}
*/
private Long templateId;
/**
* 模版编码
*
* 关联 {@link NotifyTemplateDO#getCode()}
*/
private String templateCode;
/**
* 模版类型
*
* 冗余 {@link NotifyTemplateDO#getType()}
*/
private Integer templateType;
/**
* 模版发送人名称
*
* 冗余 {@link NotifyTemplateDO#getNickname()}
*/
private String templateNickname;
/**
* 模版内容
*
* 基于 {@link NotifyTemplateDO#getContent()} 格式化后的内容
*/
private String templateContent;
/**
* 模版参数
*
* 基于 {@link NotifyTemplateDO#getParams()} 输入后的参数
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private Map<String, Object> templateParams;
// ========= 读取相关字段 =========
/**
* 是否已读
*/
private Boolean readStatus;
/**
* 阅读时间
*/
private LocalDateTime readTime;
}

View File

@ -0,0 +1,72 @@
package cn.iocoder.yudao.module.system.dal.dataobject.notify;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.*;
import java.util.List;
/**
* 站内信模版 DO
*
* @author xrcoder
*/
@TableName(value = "system_notify_template", autoResultMap = true)
@KeySequence("system_notify_template_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class NotifyTemplateDO extends BaseDO {
/**
* ID
*/
@TableId
private Long id;
/**
* 模版名称
*/
private String name;
/**
* 模版编码
*/
private String code;
/**
* 模版类型
*
* 对应 system_notify_template_type 字典
*/
private Integer type;
/**
* 发送人名称
*/
private String nickname;
/**
* 模版内容
*/
private String content;
/**
* 参数数组
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private List<String> params;
/**
* 状态
*
* 枚举 {@link CommonStatusEnum}
*/
private Integer status;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,70 @@
package cn.iocoder.yudao.module.system.dal.mysql.notify;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO;
import org.apache.ibatis.annotations.Mapper;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
@Mapper
public interface NotifyMessageMapper extends BaseMapperX<NotifyMessageDO> {
default PageResult<NotifyMessageDO> selectPage(NotifyMessagePageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<NotifyMessageDO>()
.eqIfPresent(NotifyMessageDO::getUserId, reqVO.getUserId())
.eqIfPresent(NotifyMessageDO::getUserType, reqVO.getUserType())
.likeIfPresent(NotifyMessageDO::getTemplateCode, reqVO.getTemplateCode())
.eqIfPresent(NotifyMessageDO::getTemplateType, reqVO.getTemplateType())
.betweenIfPresent(NotifyMessageDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(NotifyMessageDO::getId));
}
default PageResult<NotifyMessageDO> selectPage(NotifyMessageMyPageReqVO reqVO, Long userId, Integer userType) {
return selectPage(reqVO, new LambdaQueryWrapperX<NotifyMessageDO>()
.eqIfPresent(NotifyMessageDO::getReadStatus, reqVO.getReadStatus())
.betweenIfPresent(NotifyMessageDO::getCreateTime, reqVO.getCreateTime())
.eq(NotifyMessageDO::getUserId, userId)
.eq(NotifyMessageDO::getUserType, userType)
.orderByDesc(NotifyMessageDO::getId));
}
default int updateListRead(Collection<Long> ids, Long userId, Integer userType) {
return update(new NotifyMessageDO().setReadStatus(true).setReadTime(LocalDateTime.now()),
new LambdaQueryWrapperX<NotifyMessageDO>()
.in(NotifyMessageDO::getId, ids)
.eq(NotifyMessageDO::getUserId, userId)
.eq(NotifyMessageDO::getUserType, userType)
.eq(NotifyMessageDO::getReadStatus, false));
}
default int updateListRead(Long userId, Integer userType) {
return update(new NotifyMessageDO().setReadStatus(true).setReadTime(LocalDateTime.now()),
new LambdaQueryWrapperX<NotifyMessageDO>()
.eq(NotifyMessageDO::getUserId, userId)
.eq(NotifyMessageDO::getUserType, userType)
.eq(NotifyMessageDO::getReadStatus, false));
}
default List<NotifyMessageDO> selectUnreadListByUserIdAndUserType(Long userId, Integer userType, Integer size) {
return selectList(new QueryWrapperX<NotifyMessageDO>() // 由于要使用 limitN 语句所以只能用 QueryWrapperX
.eq("user_id", userId)
.eq("user_type", userType)
.eq("read_status", false)
.orderByDesc("id").limitN(size));
}
default Long selectUnreadCountByUserIdAndUserType(Long userId, Integer userType) {
return selectCount(new LambdaQueryWrapperX<NotifyMessageDO>()
.eq(NotifyMessageDO::getReadStatus, false)
.eq(NotifyMessageDO::getUserId, userId)
.eq(NotifyMessageDO::getUserType, userType));
}
}

View File

@ -0,0 +1,26 @@
package cn.iocoder.yudao.module.system.dal.mysql.notify;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface NotifyTemplateMapper extends BaseMapperX<NotifyTemplateDO> {
default NotifyTemplateDO selectByCode(String code) {
return selectOne(NotifyTemplateDO::getCode, code);
}
default PageResult<NotifyTemplateDO> selectPage(NotifyTemplatePageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<NotifyTemplateDO>()
.likeIfPresent(NotifyTemplateDO::getCode, reqVO.getCode())
.likeIfPresent(NotifyTemplateDO::getName, reqVO.getName())
.eqIfPresent(NotifyTemplateDO::getStatus, reqVO.getStatus())
.betweenIfPresent(NotifyTemplateDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(NotifyTemplateDO::getId));
}
}

View File

@ -22,7 +22,7 @@ public interface SmsCodeMapper extends BaseMapperX<SmsCodeDO> {
.eqIfPresent("scene", scene)
.eqIfPresent("code", code)
.orderByDesc("id")
.limit1());
.limitN(1));
}
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.system.mq.consumer.notify;
import cn.iocoder.yudao.module.system.mq.message.notify.NotifyTemplateRefreshMessage;
import cn.iocoder.yudao.module.system.service.notify.NotifyTemplateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* 针对 {@link NotifyTemplateRefreshMessage} 的消费者
*
* @author xrcoder
*/
@Component
@Slf4j
public class NotifyTemplateRefreshConsumer {
@Resource
private NotifyTemplateService notifyTemplateService;
@EventListener
public void onMessage(NotifyTemplateRefreshMessage message) {
log.info("[onMessage][收到 NotifyTemplate 刷新消息]");
notifyTemplateService.initLocalCache();
}
}

View File

@ -0,0 +1,23 @@
package cn.iocoder.yudao.module.system.mq.message.notify;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.cloud.bus.event.RemoteApplicationEvent;
/**
* 站内信模板的数据刷新 Message
*
* @author xrcoder
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class NotifyTemplateRefreshMessage extends RemoteApplicationEvent {
public NotifyTemplateRefreshMessage() {
}
public NotifyTemplateRefreshMessage(Object source, String originService, String destinationService) {
super(source, originService, DEFAULT_DESTINATION_FACTORY.getDestination(destinationService));
}
}

View File

@ -0,0 +1,26 @@
package cn.iocoder.yudao.module.system.mq.producer.notify;
import cn.iocoder.yudao.framework.mq.core.bus.AbstractBusProducer;
import cn.iocoder.yudao.module.system.mq.message.notify.NotifyTemplateRefreshMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* Notify 站内信相关消息的 Producer
*
* @author xrcoder
* @since 2022-08-06
*/
@Slf4j
@Component
public class NotifyProducer extends AbstractBusProducer {
/**
* 发送 {@link NotifyTemplateRefreshMessage} 消息
*/
public void sendNotifyTemplateRefreshMessage() {
publishEvent(new NotifyTemplateRefreshMessage(this, getBusId(), selfDestinationService()));
}
}

View File

@ -0,0 +1,97 @@
package cn.iocoder.yudao.module.system.service.notify;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 站内信 Service 接口
*
* @author xrcoder
*/
public interface NotifyMessageService {
/**
* 创建站内信
*
* @param userId 用户编号
* @param userType 用户类型
* @param template 模版信息
* @param templateContent 模版内容
* @param templateParams 模版参数
* @return 站内信编号
*/
Long createNotifyMessage(Long userId, Integer userType,
NotifyTemplateDO template, String templateContent, Map<String, Object> templateParams);
/**
* 获得站内信分页
*
* @param pageReqVO 分页查询
* @return 站内信分页
*/
PageResult<NotifyMessageDO> getNotifyMessagePage(NotifyMessagePageReqVO pageReqVO);
/**
* 获得我的站内信分页
*
* @param pageReqVO 分页查询
* @param userId 用户编号
* @param userType 用户类型
* @return 站内信分页
*/
PageResult<NotifyMessageDO> getMyMyNotifyMessagePage(NotifyMessageMyPageReqVO pageReqVO, Long userId, Integer userType);
/**
* 获得站内信
*
* @param id 编号
* @return 站内信
*/
NotifyMessageDO getNotifyMessage(Long id);
/**
* 获得我的未读站内信列表
*
* @param userId 用户编号
* @param userType 用户类型
* @param size 数量
* @return 站内信列表
*/
List<NotifyMessageDO> getUnreadNotifyMessageList(Long userId, Integer userType, Integer size);
/**
* 统计用户未读站内信条数
*
* @param userId 用户编号
* @param userType 用户类型
* @return 返回未读站内信条数
*/
Long getUnreadNotifyMessageCount(Long userId, Integer userType);
/**
* 标记站内信为已读
*
* @param ids 站内信编号集合
* @param userId 用户编号
* @param userType 用户类型
* @return 更新到的条数
*/
int updateNotifyMessageRead(Collection<Long> ids, Long userId, Integer userType);
/**
* 标记所有站内信为已读
*
* @param userId 用户编号
* @param userType 用户类型
* @return 更新到的条数
*/
int updateAllNotifyMessageRead(Long userId, Integer userType);
}

View File

@ -0,0 +1,75 @@
package cn.iocoder.yudao.module.system.service.notify;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyMessageMapper;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 站内信 Service 实现类
*
* @author xrcoder
*/
@Service
@Validated
public class NotifyMessageServiceImpl implements NotifyMessageService {
@Resource
private NotifyMessageMapper notifyMessageMapper;
@Override
public Long createNotifyMessage(Long userId, Integer userType,
NotifyTemplateDO template, String templateContent, Map<String, Object> templateParams) {
NotifyMessageDO message = new NotifyMessageDO().setUserId(userId).setUserType(userType)
.setTemplateId(template.getId()).setTemplateCode(template.getCode())
.setTemplateType(template.getType()).setTemplateNickname(template.getNickname())
.setTemplateContent(templateContent).setTemplateParams(templateParams).setReadStatus(false);
notifyMessageMapper.insert(message);
return message.getId();
}
@Override
public PageResult<NotifyMessageDO> getNotifyMessagePage(NotifyMessagePageReqVO pageReqVO) {
return notifyMessageMapper.selectPage(pageReqVO);
}
@Override
public PageResult<NotifyMessageDO> getMyMyNotifyMessagePage(NotifyMessageMyPageReqVO pageReqVO, Long userId, Integer userType) {
return notifyMessageMapper.selectPage(pageReqVO, userId, userType);
}
@Override
public NotifyMessageDO getNotifyMessage(Long id) {
return notifyMessageMapper.selectById(id);
}
@Override
public List<NotifyMessageDO> getUnreadNotifyMessageList(Long userId, Integer userType, Integer size) {
return notifyMessageMapper.selectUnreadListByUserIdAndUserType(userId, userType, size);
}
@Override
public Long getUnreadNotifyMessageCount(Long userId, Integer userType) {
return notifyMessageMapper.selectUnreadCountByUserIdAndUserType(userId, userType);
}
@Override
public int updateNotifyMessageRead(Collection<Long> ids, Long userId, Integer userType) {
return notifyMessageMapper.updateListRead(ids, userId, userType);
}
@Override
public int updateAllNotifyMessageRead(Long userId, Integer userType) {
return notifyMessageMapper.updateListRead(userId, userType);
}
}

View File

@ -0,0 +1,55 @@
package cn.iocoder.yudao.module.system.service.notify;
import java.util.List;
import java.util.Map;
/**
* 站内信发送 Service 接口
*
* @author xrcoder
*/
public interface NotifySendService {
/**
* 发送单条站内信给管理后台的用户
*
* mobile 为空时使用 userId 加载对应管理员的手机号
*
* @param userId 用户编号
* @param templateCode 短信模板编号
* @param templateParams 短信模板参数
* @return 发送日志编号
*/
Long sendSingleNotifyToAdmin(Long userId,
String templateCode, Map<String, Object> templateParams);
/**
* 发送单条站内信给用户 APP 的用户
*
* mobile 为空时使用 userId 加载对应会员的手机号
*
* @param userId 用户编号
* @param templateCode 站内信模板编号
* @param templateParams 站内信模板参数
* @return 发送日志编号
*/
Long sendSingleNotifyToMember(Long userId,
String templateCode, Map<String, Object> templateParams);
/**
* 发送单条站内信给用户
*
* @param userId 用户编号
* @param userType 用户类型
* @param templateCode 站内信模板编号
* @param templateParams 站内信模板参数
* @return 发送日志编号
*/
Long sendSingleNotify( Long userId, Integer userType,
String templateCode, Map<String, Object> templateParams);
default void sendBatchNotify(List<String> mobiles, List<Long> userIds, Integer userType,
String templateCode, Map<String, Object> templateParams) {
throw new UnsupportedOperationException("暂时不支持该操作,感兴趣可以实现该功能哟!");
}
}

View File

@ -0,0 +1,86 @@
package cn.iocoder.yudao.module.system.service.notify;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
import com.google.common.annotations.VisibleForTesting;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.Map;
import java.util.Objects;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
/**
* 站内信发送 Service 实现类
*
* @author xrcoder
*/
@Service
@Validated
@Slf4j
public class NotifySendServiceImpl implements NotifySendService {
@Resource
private NotifyTemplateService notifyTemplateService;
@Resource
private NotifyMessageService notifyMessageService;
@Override
public Long sendSingleNotifyToAdmin(Long userId, String templateCode, Map<String, Object> templateParams) {
return sendSingleNotify(userId, UserTypeEnum.ADMIN.getValue(), templateCode, templateParams);
}
@Override
public Long sendSingleNotifyToMember(Long userId, String templateCode, Map<String, Object> templateParams) {
return sendSingleNotify(userId, UserTypeEnum.MEMBER.getValue(), templateCode, templateParams);
}
@Override
public Long sendSingleNotify(Long userId, Integer userType, String templateCode, Map<String, Object> templateParams) {
// 校验模版
NotifyTemplateDO template = checkNotifyTemplateValid(templateCode);
if (Objects.equals(template.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
log.info("[sendSingleNotify][模版({})已经关闭,无法给用户({}/{})发送]", templateCode, userId, userType);
return null;
}
// 校验参数
checkTemplateParams(template, templateParams);
// 发送站内信
String content = notifyTemplateService.formatNotifyTemplateContent(template.getContent(), templateParams);
return notifyMessageService.createNotifyMessage(userId, userType, template, content, templateParams);
}
@VisibleForTesting
public NotifyTemplateDO checkNotifyTemplateValid(String templateCode) {
// 获得站内信模板考虑到效率从缓存中获取
NotifyTemplateDO template = notifyTemplateService.getNotifyTemplateByCodeFromCache(templateCode);
// 站内信模板不存在
if (template == null) {
throw exception(NOTICE_NOT_FOUND);
}
return template;
}
/**
* 校验站内信模版参数是否确实
*
* @param template 邮箱模板
* @param templateParams 参数列表
*/
@VisibleForTesting
public void checkTemplateParams(NotifyTemplateDO template, Map<String, Object> templateParams) {
template.getParams().forEach(key -> {
Object value = templateParams.get(key);
if (value == null) {
throw exception(NOTIFY_SEND_TEMPLATE_PARAM_MISS, key);
}
});
}
}

View File

@ -0,0 +1,79 @@
package cn.iocoder.yudao.module.system.service.notify;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateCreateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateUpdateReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
import javax.validation.Valid;
import java.util.Map;
/**
* 站内信模版 Service 接口
*
* @author xrcoder
*/
public interface NotifyTemplateService {
/**
* 初始化站内信模板的本地缓存
*/
void initLocalCache();
/**
* 获得站内信模板从缓存中
*
* @param code 模板编码
* @return 站内信模板
*/
NotifyTemplateDO getNotifyTemplateByCodeFromCache(String code);
/**
* 创建站内信模版
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createNotifyTemplate(@Valid NotifyTemplateCreateReqVO createReqVO);
/**
* 更新站内信模版
*
* @param updateReqVO 更新信息
*/
void updateNotifyTemplate(@Valid NotifyTemplateUpdateReqVO updateReqVO);
/**
* 删除站内信模版
*
* @param id 编号
*/
void deleteNotifyTemplate(Long id);
/**
* 获得站内信模版
*
* @param id 编号
* @return 站内信模版
*/
NotifyTemplateDO getNotifyTemplate(Long id);
/**
* 获得站内信模版分页
*
* @param pageReqVO 分页查询
* @return 站内信模版分页
*/
PageResult<NotifyTemplateDO> getNotifyTemplatePage(NotifyTemplatePageReqVO pageReqVO);
/**
* 格式化站内信内容
*
* @param content 站内信模板的内容
* @param params 站内信内容的参数
* @return 格式化后的内容
*/
String formatNotifyTemplateContent(String content, Map<String, Object> params);
}

View File

@ -0,0 +1,164 @@
package cn.iocoder.yudao.module.system.service.notify;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateCreateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateUpdateReqVO;
import cn.iocoder.yudao.module.system.convert.notify.NotifyTemplateConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyTemplateMapper;
import cn.iocoder.yudao.module.system.mq.producer.notify.NotifyProducer;
import com.google.common.annotations.VisibleForTesting;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
/**
* 站内信模版 Service 实现类
*
* @author xrcoder
*/
@Service
@Validated
@Slf4j
public class NotifyTemplateServiceImpl implements NotifyTemplateService {
/**
* 正则表达式匹配 {} 中的变量
*/
private static final Pattern PATTERN_PARAMS = Pattern.compile("\\{(.*?)}");
@Resource
private NotifyTemplateMapper notifyTemplateMapper;
@Resource
private NotifyProducer notifyProducer;
/**
* 站内信模板缓存
* key站内信模板编码 {@link NotifyTemplateDO#getCode()}
* <p>
* 这里声明 volatile 修饰的原因是每次刷新时直接修改指向
*/
private volatile Map<String, NotifyTemplateDO> notifyTemplateCache;
/**
* 初始化站内信模板的本地缓存
*/
@Override
@PostConstruct
public void initLocalCache() {
// 第一步查询数据
List<NotifyTemplateDO> templates = notifyTemplateMapper.selectList();
log.info("[initLocalCache][缓存站内信模版,数量为:{}]", templates.size());
// 第二步构建缓存
notifyTemplateCache = CollectionUtils.convertMap(templates, NotifyTemplateDO::getCode);
}
@Override
public NotifyTemplateDO getNotifyTemplateByCodeFromCache(String code) {
return notifyTemplateCache.get(code);
}
@Override
public Long createNotifyTemplate(NotifyTemplateCreateReqVO createReqVO) {
// 校验站内信编码是否重复
checkNotifyTemplateCodeDuplicate(null, createReqVO.getCode());
// 插入
NotifyTemplateDO notifyTemplate = NotifyTemplateConvert.INSTANCE.convert(createReqVO);
notifyTemplate.setParams(parseTemplateContentParams(notifyTemplate.getContent()));
notifyTemplateMapper.insert(notifyTemplate);
// 发送刷新消息
notifyProducer.sendNotifyTemplateRefreshMessage();
return notifyTemplate.getId();
}
@Override
public void updateNotifyTemplate(NotifyTemplateUpdateReqVO updateReqVO) {
// 校验存在
validateNotifyTemplateExists(updateReqVO.getId());
// 校验站内信编码是否重复
checkNotifyTemplateCodeDuplicate(updateReqVO.getId(), updateReqVO.getCode());
// 更新
NotifyTemplateDO updateObj = NotifyTemplateConvert.INSTANCE.convert(updateReqVO);
updateObj.setParams(parseTemplateContentParams(updateObj.getContent()));
notifyTemplateMapper.updateById(updateObj);
// 发送刷新消息
notifyProducer.sendNotifyTemplateRefreshMessage();
}
@VisibleForTesting
public List<String> parseTemplateContentParams(String content) {
return ReUtil.findAllGroup1(PATTERN_PARAMS, content);
}
@Override
public void deleteNotifyTemplate(Long id) {
// 校验存在
validateNotifyTemplateExists(id);
// 删除
notifyTemplateMapper.deleteById(id);
// 发送刷新消息
notifyProducer.sendNotifyTemplateRefreshMessage();
}
private void validateNotifyTemplateExists(Long id) {
if (notifyTemplateMapper.selectById(id) == null) {
throw exception(NOTIFY_TEMPLATE_NOT_EXISTS);
}
}
@Override
public NotifyTemplateDO getNotifyTemplate(Long id) {
return notifyTemplateMapper.selectById(id);
}
@Override
public PageResult<NotifyTemplateDO> getNotifyTemplatePage(NotifyTemplatePageReqVO pageReqVO) {
return notifyTemplateMapper.selectPage(pageReqVO);
}
@VisibleForTesting
public void checkNotifyTemplateCodeDuplicate(Long id, String code) {
NotifyTemplateDO template = notifyTemplateMapper.selectByCode(code);
if (template == null) {
return;
}
// 如果 id 为空说明不用比较是否为相同 id 的字典类型
if (id == null) {
throw exception(NOTIFY_TEMPLATE_CODE_DUPLICATE, code);
}
if (!template.getId().equals(id)) {
throw exception(NOTIFY_TEMPLATE_CODE_DUPLICATE, code);
}
}
/**
* 格式化站内信内容
*
* @param content 站内信模板的内容
* @param params 站内信内容的参数
* @return 格式化后的内容
*/
@Override
public String formatNotifyTemplateContent(String content, Map<String, Object> params) {
return StrUtil.format(content, params);
}
}

View File

@ -0,0 +1,266 @@
package cn.iocoder.yudao.module.system.service.notify;
import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.enums.SqlConstants;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyMessageMapper;
import com.baomidou.mybatisplus.annotation.DbType;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import static cn.hutool.core.util.RandomUtil.randomEle;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
import static org.junit.jupiter.api.Assertions.*;
/**
* {@link NotifyMessageServiceImpl} 的单元测试类
*
* @author 芋道源码
*/
@Import(NotifyMessageServiceImpl.class)
public class NotifyMessageServiceImplTest extends BaseDbUnitTest {
@Resource
private NotifyMessageServiceImpl notifyMessageService;
@Resource
private NotifyMessageMapper notifyMessageMapper;
@Test
public void testCreateNotifyMessage_success() {
// 准备参数
Long userId = randomLongId();
Integer userType = randomEle(UserTypeEnum.values()).getValue();
NotifyTemplateDO template = randomPojo(NotifyTemplateDO.class);
String templateContent = randomString();
Map<String, Object> templateParams = randomTemplateParams();
// mock 方法
// 调用
Long messageId = notifyMessageService.createNotifyMessage(userId, userType,
template, templateContent, templateParams);
// 断言
NotifyMessageDO message = notifyMessageMapper.selectById(messageId);
assertNotNull(message);
assertEquals(userId, message.getUserId());
assertEquals(userType, message.getUserType());
assertEquals(template.getId(), message.getTemplateId());
assertEquals(template.getCode(), message.getTemplateCode());
assertEquals(template.getType(), message.getTemplateType());
assertEquals(template.getNickname(), message.getTemplateNickname());
assertEquals(templateContent, message.getTemplateContent());
assertEquals(templateParams, message.getTemplateParams());
assertEquals(false, message.getReadStatus());
assertNull(message.getReadTime());
}
@Test
public void testGetNotifyMessagePage() {
// mock 数据
NotifyMessageDO dbNotifyMessage = randomPojo(NotifyMessageDO.class, o -> { // 等会查询到
o.setUserId(1L);
o.setUserType(UserTypeEnum.ADMIN.getValue());
o.setTemplateCode("test_01");
o.setTemplateType(10);
o.setCreateTime(buildTime(2022, 1, 2));
o.setTemplateParams(randomTemplateParams());
});
notifyMessageMapper.insert(dbNotifyMessage);
// 测试 userId 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserId(2L)));
// 测试 userType 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
// 测试 templateCode 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setTemplateCode("test_11")));
// 测试 templateType 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setTemplateType(20)));
// 测试 createTime 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setCreateTime(buildTime(2022, 2, 1))));
// 准备参数
NotifyMessagePageReqVO reqVO = new NotifyMessagePageReqVO();
reqVO.setUserId(1L);
reqVO.setUserType(UserTypeEnum.ADMIN.getValue());
reqVO.setTemplateCode("est_01");
reqVO.setTemplateType(10);
reqVO.setCreateTime(buildBetweenTime(2022, 1, 1, 2022, 1, 10));
// 调用
PageResult<NotifyMessageDO> pageResult = notifyMessageService.getNotifyMessagePage(reqVO);
// 断言
assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size());
assertPojoEquals(dbNotifyMessage, pageResult.getList().get(0));
}
@Test
public void testGetMyNotifyMessagePage() {
// mock 数据
NotifyMessageDO dbNotifyMessage = randomPojo(NotifyMessageDO.class, o -> { // 等会查询到
o.setUserId(1L);
o.setUserType(UserTypeEnum.ADMIN.getValue());
o.setReadStatus(true);
o.setCreateTime(buildTime(2022, 1, 2));
o.setTemplateParams(randomTemplateParams());
});
notifyMessageMapper.insert(dbNotifyMessage);
// 测试 userId 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserId(2L)));
// 测试 userType 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
// 测试 readStatus 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setReadStatus(false)));
// 测试 createTime 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setCreateTime(buildTime(2022, 2, 1))));
// 准备参数
Long userId = 1L;
Integer userType = UserTypeEnum.ADMIN.getValue();
NotifyMessageMyPageReqVO reqVO = new NotifyMessageMyPageReqVO();
reqVO.setReadStatus(true);
reqVO.setCreateTime(buildBetweenTime(2022, 1, 1, 2022, 1, 10));
// 调用
PageResult<NotifyMessageDO> pageResult = notifyMessageService.getMyMyNotifyMessagePage(reqVO, userId, userType);
// 断言
assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size());
assertPojoEquals(dbNotifyMessage, pageResult.getList().get(0));
}
@Test
public void testGetUnreadNotifyMessageList() {
SqlConstants.init(DbType.MYSQL);
// mock 数据
NotifyMessageDO dbNotifyMessage = randomPojo(NotifyMessageDO.class, o -> { // 等会查询到
o.setUserId(1L);
o.setUserType(UserTypeEnum.ADMIN.getValue());
o.setReadStatus(false);
o.setTemplateParams(randomTemplateParams());
});
notifyMessageMapper.insert(dbNotifyMessage);
// 测试 userId 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserId(2L)));
// 测试 userType 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
// 测试 readStatus 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setReadStatus(true)));
// 准备参数
Long userId = 1L;
Integer userType = UserTypeEnum.ADMIN.getValue();
Integer size = 10;
// 调用
List<NotifyMessageDO> list = notifyMessageService.getUnreadNotifyMessageList(userId, userType, size);
// 断言
assertEquals(1, list.size());
assertPojoEquals(dbNotifyMessage, list.get(0));
}
@Test
public void testGetUnreadNotifyMessageCount() {
SqlConstants.init(DbType.MYSQL);
// mock 数据
NotifyMessageDO dbNotifyMessage = randomPojo(NotifyMessageDO.class, o -> { // 等会查询到
o.setUserId(1L);
o.setUserType(UserTypeEnum.ADMIN.getValue());
o.setReadStatus(false);
o.setTemplateParams(randomTemplateParams());
});
notifyMessageMapper.insert(dbNotifyMessage);
// 测试 userId 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserId(2L)));
// 测试 userType 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
// 测试 readStatus 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setReadStatus(true)));
// 准备参数
Long userId = 1L;
Integer userType = UserTypeEnum.ADMIN.getValue();
// 调用并断言
assertEquals(1, notifyMessageService.getUnreadNotifyMessageCount(userId, userType));
}
@Test
public void testUpdateNotifyMessageRead() {
// mock 数据
NotifyMessageDO dbNotifyMessage = randomPojo(NotifyMessageDO.class, o -> { // 等会查询到
o.setUserId(1L);
o.setUserType(UserTypeEnum.ADMIN.getValue());
o.setReadStatus(false);
o.setReadTime(null);
o.setTemplateParams(randomTemplateParams());
});
notifyMessageMapper.insert(dbNotifyMessage);
// 测试 userId 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserId(2L)));
// 测试 userType 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
// 测试 readStatus 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setReadStatus(true)));
// 准备参数
Collection<Long> ids = Arrays.asList(dbNotifyMessage.getId(), dbNotifyMessage.getId() + 1,
dbNotifyMessage.getId() + 2, dbNotifyMessage.getId() + 3);
Long userId = 1L;
Integer userType = UserTypeEnum.ADMIN.getValue();
// 调用
int updateCount = notifyMessageService.updateNotifyMessageRead(ids, userId, userType);
// 断言
assertEquals(1, updateCount);
NotifyMessageDO notifyMessage = notifyMessageMapper.selectById(dbNotifyMessage.getId());
assertTrue(notifyMessage.getReadStatus());
assertNotNull(notifyMessage.getReadTime());
}
@Test
public void testUpdateAllNotifyMessageRead() {
// mock 数据
NotifyMessageDO dbNotifyMessage = randomPojo(NotifyMessageDO.class, o -> { // 等会查询到
o.setUserId(1L);
o.setUserType(UserTypeEnum.ADMIN.getValue());
o.setReadStatus(false);
o.setReadTime(null);
o.setTemplateParams(randomTemplateParams());
});
notifyMessageMapper.insert(dbNotifyMessage);
// 测试 userId 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserId(2L)));
// 测试 userType 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
// 测试 readStatus 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setReadStatus(true)));
// 准备参数
Long userId = 1L;
Integer userType = UserTypeEnum.ADMIN.getValue();
// 调用
int updateCount = notifyMessageService.updateAllNotifyMessageRead(userId, userType);
// 断言
assertEquals(1, updateCount);
NotifyMessageDO notifyMessage = notifyMessageMapper.selectById(dbNotifyMessage.getId());
assertTrue(notifyMessage.getReadStatus());
assertNotNull(notifyMessage.getReadTime());
}
private static Map<String, Object> randomTemplateParams() {
return MapUtil.<String, Object>builder().put(randomString(), randomString())
.put(randomString(), randomString()).build();
}
}

View File

@ -0,0 +1,120 @@
package cn.iocoder.yudao.module.system.service.notify;
import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
import org.assertj.core.util.Lists;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import java.util.HashMap;
import java.util.Map;
import static cn.hutool.core.util.RandomUtil.randomEle;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.NOTICE_NOT_FOUND;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.NOTIFY_SEND_TEMPLATE_PARAM_MISS;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
class NotifySendServiceImplTest extends BaseMockitoUnitTest {
@InjectMocks
private NotifySendServiceImpl notifySendService;
@Mock
private NotifyTemplateService notifyTemplateService;
@Mock
private NotifyMessageService notifyMessageService;
/**
* 发送成功当短信模板开启时
*/
@Test
public void testSendSingleNotify_successWhenMailTemplateEnable() {
// 准备参数
Long userId = randomLongId();
Integer userType = randomEle(UserTypeEnum.values()).getValue();
String templateCode = randomString();
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
.put("op", "login").build();
// mock NotifyTemplateService 的方法
NotifyTemplateDO template = randomPojo(NotifyTemplateDO.class, o -> {
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setContent("验证码为{code}, 操作为{op}");
o.setParams(Lists.newArrayList("code", "op"));
});
when(notifyTemplateService.getNotifyTemplateByCodeFromCache(eq(templateCode))).thenReturn(template);
String content = randomString();
when(notifyTemplateService.formatNotifyTemplateContent(eq(template.getContent()), eq(templateParams)))
.thenReturn(content);
// mock NotifyMessageService 的方法
Long messageId = randomLongId();
when(notifyMessageService.createNotifyMessage(eq(userId), eq(userType),
eq(template), eq(content), eq(templateParams))).thenReturn(messageId);
// 调用
Long resultMessageId = notifySendService.sendSingleNotify(userId, userType, templateCode, templateParams);
// 断言
assertEquals(messageId, resultMessageId);
}
/**
* 发送成功当短信模板关闭时
*/
@Test
public void testSendSingleMail_successWhenSmsTemplateDisable() {
// 准备参数
Long userId = randomLongId();
Integer userType = randomEle(UserTypeEnum.values()).getValue();
String templateCode = randomString();
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
.put("op", "login").build();
// mock NotifyTemplateService 的方法
NotifyTemplateDO template = randomPojo(NotifyTemplateDO.class, o -> {
o.setStatus(CommonStatusEnum.DISABLE.getStatus());
o.setContent("验证码为{code}, 操作为{op}");
o.setParams(Lists.newArrayList("code", "op"));
});
when(notifyTemplateService.getNotifyTemplateByCodeFromCache(eq(templateCode))).thenReturn(template);
// 调用
Long resultMessageId = notifySendService.sendSingleNotify(userId, userType, templateCode, templateParams);
// 断言
assertNull(resultMessageId);
verify(notifyTemplateService, never()).formatNotifyTemplateContent(anyString(), anyMap());
verify(notifyMessageService, never()).createNotifyMessage(anyLong(), anyInt(), any(), anyString(), anyMap());
}
@Test
public void testCheckMailTemplateValid_notExists() {
// 准备参数
String templateCode = randomString();
// mock 方法
// 调用并断言异常
assertServiceException(() -> notifySendService.checkNotifyTemplateValid(templateCode),
NOTICE_NOT_FOUND);
}
@Test
public void testCheckTemplateParams_paramMiss() {
// 准备参数
NotifyTemplateDO template = randomPojo(NotifyTemplateDO.class,
o -> o.setParams(Lists.newArrayList("code")));
Map<String, Object> templateParams = new HashMap<>();
// mock 方法
// 调用并断言异常
assertServiceException(() -> notifySendService.checkTemplateParams(template, templateParams),
NOTIFY_SEND_TEMPLATE_PARAM_MISS, "code");
}
}

View File

@ -0,0 +1,146 @@
package cn.iocoder.yudao.module.system.service.notify;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateCreateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateUpdateReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyTemplateMapper;
import cn.iocoder.yudao.module.system.mq.producer.notify.NotifyProducer;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import javax.annotation.Resource;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.NOTIFY_TEMPLATE_NOT_EXISTS;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.verify;
/**
* {@link NotifyTemplateServiceImpl} 的单元测试类
*
* @author 芋道源码
*/
@Import(NotifyTemplateServiceImpl.class)
public class NotifyTemplateServiceImplTest extends BaseDbUnitTest {
@Resource
private NotifyTemplateServiceImpl notifyTemplateService;
@Resource
private NotifyTemplateMapper notifyTemplateMapper;
@MockBean
private NotifyProducer notifyProducer;
@Test
public void testCreateNotifyTemplate_success() {
// 准备参数
NotifyTemplateCreateReqVO reqVO = randomPojo(NotifyTemplateCreateReqVO.class,
o -> o.setStatus(randomCommonStatus()));
// 调用
Long notifyTemplateId = notifyTemplateService.createNotifyTemplate(reqVO);
// 断言
assertNotNull(notifyTemplateId);
// 校验记录的属性是否正确
NotifyTemplateDO notifyTemplate = notifyTemplateMapper.selectById(notifyTemplateId);
assertPojoEquals(reqVO, notifyTemplate);
verify(notifyProducer).sendNotifyTemplateRefreshMessage();
}
@Test
public void testUpdateNotifyTemplate_success() {
// mock 数据
NotifyTemplateDO dbNotifyTemplate = randomPojo(NotifyTemplateDO.class);
notifyTemplateMapper.insert(dbNotifyTemplate);// @Sql: 先插入出一条存在的数据
// 准备参数
NotifyTemplateUpdateReqVO reqVO = randomPojo(NotifyTemplateUpdateReqVO.class, o -> {
o.setId(dbNotifyTemplate.getId()); // 设置更新的 ID
o.setStatus(randomCommonStatus());
});
// 调用
notifyTemplateService.updateNotifyTemplate(reqVO);
// 校验是否更新正确
NotifyTemplateDO notifyTemplate = notifyTemplateMapper.selectById(reqVO.getId()); // 获取最新的
assertPojoEquals(reqVO, notifyTemplate);
verify(notifyProducer).sendNotifyTemplateRefreshMessage();
}
@Test
public void testUpdateNotifyTemplate_notExists() {
// 准备参数
NotifyTemplateUpdateReqVO reqVO = randomPojo(NotifyTemplateUpdateReqVO.class);
// 调用, 并断言异常
assertServiceException(() -> notifyTemplateService.updateNotifyTemplate(reqVO), NOTIFY_TEMPLATE_NOT_EXISTS);
}
@Test
public void testDeleteNotifyTemplate_success() {
// mock 数据
NotifyTemplateDO dbNotifyTemplate = randomPojo(NotifyTemplateDO.class);
notifyTemplateMapper.insert(dbNotifyTemplate);// @Sql: 先插入出一条存在的数据
// 准备参数
Long id = dbNotifyTemplate.getId();
// 调用
notifyTemplateService.deleteNotifyTemplate(id);
// 校验数据不存在了
assertNull(notifyTemplateMapper.selectById(id));
verify(notifyProducer).sendNotifyTemplateRefreshMessage();
}
@Test
public void testDeleteNotifyTemplate_notExists() {
// 准备参数
Long id = randomLongId();
// 调用, 并断言异常
assertServiceException(() -> notifyTemplateService.deleteNotifyTemplate(id), NOTIFY_TEMPLATE_NOT_EXISTS);
}
@Test
public void testGetNotifyTemplatePage() {
// mock 数据
NotifyTemplateDO dbNotifyTemplate = randomPojo(NotifyTemplateDO.class, o -> { // 等会查询到
o.setName("芋头");
o.setCode("test_01");
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setCreateTime(buildTime(2022, 2, 3));
});
notifyTemplateMapper.insert(dbNotifyTemplate);
// 测试 name 不匹配
notifyTemplateMapper.insert(cloneIgnoreId(dbNotifyTemplate, o -> o.setName("")));
// 测试 code 不匹配
notifyTemplateMapper.insert(cloneIgnoreId(dbNotifyTemplate, o -> o.setCode("test_02")));
// 测试 status 不匹配
notifyTemplateMapper.insert(cloneIgnoreId(dbNotifyTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 测试 createTime 不匹配
notifyTemplateMapper.insert(cloneIgnoreId(dbNotifyTemplate, o -> o.setCreateTime(buildTime(2022, 1, 5))));
// 准备参数
NotifyTemplatePageReqVO reqVO = new NotifyTemplatePageReqVO();
reqVO.setName("");
reqVO.setCode("est_01");
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
reqVO.setCreateTime(buildBetweenTime(2022, 2, 1, 2022, 2, 5));
// 调用
PageResult<NotifyTemplateDO> pageResult = notifyTemplateService.getNotifyTemplatePage(reqVO);
// 断言
assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size());
assertPojoEquals(dbNotifyTemplate, pageResult.getList().get(0));
}
}

View File

@ -28,3 +28,5 @@ DELETE FROM "system_oauth2_code";
DELETE FROM "system_mail_account";
DELETE FROM "system_mail_template";
DELETE FROM "system_mail_log";
DELETE FROM "system_notify_template";
DELETE FROM "system_notify_message";

View File

@ -626,3 +626,43 @@ CREATE TABLE IF NOT EXISTS "system_mail_log" (
"deleted" bit NOT NULL DEFAULT FALSE,
PRIMARY KEY ("id")
) COMMENT '邮件日志表';
-- 将该建表 SQL 语句,添加到 yudao-module-system-biz 模块的 test/resources/sql/create_tables.sql 文件里
CREATE TABLE IF NOT EXISTS "system_notify_template" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"name" varchar NOT NULL,
"code" varchar NOT NULL,
"nickname" varchar NOT NULL,
"content" varchar NOT NULL,
"type" varchar NOT NULL,
"params" varchar,
"status" varchar NOT NULL,
"remark" varchar,
"creator" varchar DEFAULT '',
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar DEFAULT '',
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
PRIMARY KEY ("id")
) COMMENT '站内信模板表';
CREATE TABLE IF NOT EXISTS "system_notify_message" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"user_id" bigint NOT NULL,
"user_type" varchar NOT NULL,
"template_id" bigint NOT NULL,
"template_code" varchar NOT NULL,
"template_nickname" varchar NOT NULL,
"template_content" varchar NOT NULL,
"template_type" int NOT NULL,
"template_params" varchar NOT NULL,
"read_status" bit NOT NULL,
"read_time" varchar,
"creator" varchar DEFAULT '',
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar DEFAULT '',
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint not null default '0',
PRIMARY KEY ("id")
) COMMENT '站内信消息表';