mirror of
https://gitee.com/yudaocode/yudao-boot-mini.git
synced 2026-10-06 14:13:14 +08:00
Merge branch 'master-jdk17' of https://gitee.com/zhijiantianya/ruoyi-vue-pro
This commit is contained in:
@@ -26,6 +26,7 @@
|
||||
<!-- <module>yudao-module-iot</module>-->
|
||||
<!-- <module>yudao-module-mes</module>-->
|
||||
<!-- <module>yudao-module-wms</module>-->
|
||||
<!-- <module>yudao-module-im</module>-->
|
||||
<!-- 请参考 https://doc.iocoder.cn/ai/build/ 文档,完成 AI 模块的启动!!! -->
|
||||
<!-- <module>yudao-module-ai</module>-->
|
||||
</modules>
|
||||
|
||||
+80
-30
@@ -11,7 +11,7 @@
|
||||
Target Server Version : 80200 (8.2.0)
|
||||
File Encoding : 65001
|
||||
|
||||
Date: 16/05/2026 06:24:32
|
||||
Date: 31/05/2026 22:29:18
|
||||
*/
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
@@ -92,7 +92,7 @@ CREATE TABLE `infra_api_error_log` (
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `idx_create_time`(`create_time` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 23883 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志';
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 23958 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of infra_api_error_log
|
||||
@@ -253,7 +253,7 @@ CREATE TABLE `infra_file` (
|
||||
`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 = 2216 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表';
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 2233 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of infra_file
|
||||
@@ -284,17 +284,17 @@ CREATE TABLE `infra_file_config` (
|
||||
-- Records of infra_file_config
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4, '数据库(示例)', 1, '我是数据库', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClientConfig\",\"domain\":\"http://127.0.0.1:48080\"}', '1', '2022-03-15 23:56:24', '1', '2025-11-24 20:57:14', b'0');
|
||||
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (22, '七牛存储器(示例)', 20, '请换成你自己的密钥!!!', b'1', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"s3.cn-south-1.qiniucs.com\",\"domain\":\"http://test.yudao.iocoder.cn\",\"bucket\":\"ruoyi-vue-pro\",\"accessKey\":\"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS\",\"accessSecret\":\"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-01-13 22:11:12', '1', '2025-11-24 20:57:14', b'0');
|
||||
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (24, '腾讯云存储(示例)', 20, '请换成你的密钥!!!', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"https://cos.ap-shanghai.myqcloud.com\",\"domain\":\"http://tengxun-oss.iocoder.cn\",\"bucket\":\"aoteman-1255880240\",\"accessKey\":\"AKIDAF6WSh1uiIjwqtrOsGSN3WryqTM6cTMt\",\"accessSecret\":\"X\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-11-09 16:03:22', '1', '2025-11-24 20:57:14', b'0');
|
||||
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (25, '阿里云存储(示例)', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"oss-cn-beijing.aliyuncs.com\",\"domain\":\"http://ali-oss.iocoder.cn\",\"bucket\":\"yunai-aoteman\",\"accessKey\":\"LTAI5tEQLgnDyjh3WpNcdMKA\",\"accessSecret\":\"X\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-11-09 16:47:08', '1', '2025-11-24 20:57:14', b'0');
|
||||
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (26, '火山云存储(示例)', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"tos-s3-cn-beijing.volces.com\",\"domain\":null,\"bucket\":\"yunai\",\"accessKey\":\"AKLTZjc3Zjc4MzZmMjU3NDk0ZTgxYmIyMmFkNTIwMDI1ZGE\",\"accessSecret\":\"X==\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-11-09 16:56:42', '1', '2025-11-24 20:57:14', b'0');
|
||||
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (27, '华为云存储(示例)', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"obs.cn-east-3.myhuaweicloud.com\",\"domain\":\"\",\"bucket\":\"yudao\",\"accessKey\":\"PVDONDEIOTW88LF8DC4U\",\"accessSecret\":\"X\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-11-09 17:18:41', '1', '2025-11-24 20:57:14', b'0');
|
||||
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (28, 'MinIO 存储(示例)', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"http://127.0.0.1:9000\",\"domain\":\"http://127.0.0.1:9000/yudao\",\"bucket\":\"yudao\",\"accessKey\":\"admin\",\"accessSecret\":\"password\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-11-09 17:43:10', '1', '2025-11-24 20:57:14', b'0');
|
||||
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (29, '本地存储(示例)', 10, 'mac/linux 使用 /,windows 使用 \\', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.local.LocalFileClientConfig\",\"basePath\":\"/Users/yunai/tmp/file\",\"domain\":\"http://127.0.0.1:48080\"}', '1', '2025-05-02 11:25:45', '1', '2025-11-24 20:57:14', b'0');
|
||||
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (30, 'SFTP 存储(示例)', 12, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.sftp.SftpFileClientConfig\",\"basePath\":\"/upload\",\"domain\":\"http://127.0.0.1:48080\",\"host\":\"127.0.0.1\",\"port\":2222,\"username\":\"foo\",\"password\":\"pass\"}', '1', '2025-05-02 16:34:10', '1', '2025-11-24 20:57:14', b'0');
|
||||
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (34, '七牛云存储【私有】(示例)', 20, '请换成你自己的密钥!!!', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"s3.cn-south-1.qiniucs.com\",\"domain\":\"http://t151glocd.hn-bkt.clouddn.com\",\"bucket\":\"ruoyi-vue-pro-private\",\"accessKey\":\"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS\",\"accessSecret\":\"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":false}', '1', '2025-08-17 21:22:00', '1', '2025-11-24 20:57:14', b'0');
|
||||
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (35, '1', 20, '1', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"http://www.baidu.com\",\"domain\":\"http://www.xxx.com\",\"bucket\":\"1\",\"accessKey\":\"2\",\"accessSecret\":\"3\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":false,\"region\":\"1\"}', '1', '2025-10-02 14:32:12', '1', '2025-11-29 15:59:39', b'0');
|
||||
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4, '数据库(示例)', 1, '我是数据库', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClientConfig\",\"domain\":\"http://127.0.0.1:48080\"}', '1', '2022-03-15 23:56:24', '1', '2026-05-17 14:05:15', b'0');
|
||||
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (22, '七牛存储器(示例)', 20, '请换成你自己的密钥!!!', b'1', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"s3.cn-south-1.qiniucs.com\",\"domain\":\"http://test.yudao.iocoder.cn\",\"bucket\":\"ruoyi-vue-pro\",\"accessKey\":\"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS\",\"accessSecret\":\"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-01-13 22:11:12', '1', '2026-05-17 14:05:15', b'0');
|
||||
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (24, '腾讯云存储(示例)', 20, '请换成你的密钥!!!', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"https://cos.ap-shanghai.myqcloud.com\",\"domain\":\"http://tengxun-oss.iocoder.cn\",\"bucket\":\"aoteman-1255880240\",\"accessKey\":\"AKIDAF6WSh1uiIjwqtrOsGSN3WryqTM6cTMt\",\"accessSecret\":\"X\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-11-09 16:03:22', '1', '2026-05-17 14:05:15', b'0');
|
||||
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (25, '阿里云存储(示例)', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"oss-cn-beijing.aliyuncs.com\",\"domain\":\"http://ali-oss.iocoder.cn\",\"bucket\":\"yunai-aoteman\",\"accessKey\":\"LTAI5tEQLgnDyjh3WpNcdMKA\",\"accessSecret\":\"X\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-11-09 16:47:08', '1', '2026-05-17 14:05:15', b'0');
|
||||
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (26, '火山云存储(示例)', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"tos-s3-cn-beijing.volces.com\",\"domain\":null,\"bucket\":\"yunai\",\"accessKey\":\"AKLTZjc3Zjc4MzZmMjU3NDk0ZTgxYmIyMmFkNTIwMDI1ZGE\",\"accessSecret\":\"X==\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-11-09 16:56:42', '1', '2026-05-17 14:05:15', b'0');
|
||||
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (27, '华为云存储(示例)', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"obs.cn-east-3.myhuaweicloud.com\",\"domain\":\"\",\"bucket\":\"yudao\",\"accessKey\":\"PVDONDEIOTW88LF8DC4U\",\"accessSecret\":\"X\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-11-09 17:18:41', '1', '2026-05-17 14:05:15', b'0');
|
||||
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (28, 'MinIO 存储(示例)', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"http://127.0.0.1:9000\",\"domain\":\"http://127.0.0.1:9000/yudao\",\"bucket\":\"yudao\",\"accessKey\":\"admin\",\"accessSecret\":\"password\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-11-09 17:43:10', '1', '2026-05-17 14:05:15', b'0');
|
||||
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (29, '本地存储(示例)', 10, 'mac/linux 使用 /,windows 使用 \\', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.local.LocalFileClientConfig\",\"basePath\":\"/Users/yunai/tmp/file\",\"domain\":\"http://127.0.0.1:48080\"}', '1', '2025-05-02 11:25:45', '1', '2026-05-17 14:05:15', b'0');
|
||||
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (30, 'SFTP 存储(示例)', 12, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.sftp.SftpFileClientConfig\",\"basePath\":\"/upload\",\"domain\":\"http://127.0.0.1:48080\",\"host\":\"127.0.0.1\",\"port\":2222,\"username\":\"foo\",\"password\":\"pass\"}', '1', '2025-05-02 16:34:10', '1', '2026-05-17 14:05:15', b'0');
|
||||
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (34, '七牛云存储【私有】(示例)', 20, '请换成你自己的密钥!!!', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"s3.cn-south-1.qiniucs.com\",\"domain\":\"http://t151glocd.hn-bkt.clouddn.com\",\"bucket\":\"ruoyi-vue-pro-private\",\"accessKey\":\"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS\",\"accessSecret\":\"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":false}', '1', '2025-08-17 21:22:00', '1', '2026-05-17 14:05:15', b'0');
|
||||
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (35, '1', 20, '1', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"http://www.baidu.com\",\"domain\":\"http://www.xxx.com\",\"bucket\":\"1\",\"accessKey\":\"2\",\"accessSecret\":\"3\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":false,\"region\":\"1\"}', '1', '2025-10-02 14:32:12', '1', '2026-05-17 14:05:15', b'0');
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
@@ -313,7 +313,7 @@ CREATE TABLE `infra_file_content` (
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `idx_config_id_path`(`config_id` ASC, `path` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 286 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表';
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 288 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of infra_file_content
|
||||
@@ -462,7 +462,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 = 1061096 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典数据表';
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 1061122 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典数据表';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of system_dict_data
|
||||
@@ -1095,6 +1095,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 (3034, 1, 'ttt', 'tt', 'iot_ota_task_record_status', 0, 'success', '', NULL, '1', '2025-09-06 00:02:21', '1', '2025-09-06 00:02:31', 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 (3035, 40, '支付宝小程序', '40', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', 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 (3036, 60, 'Admin Uniapp 移动端', '60', 'infra_codegen_front_type', 0, '', '', NULL, '1', '2025-12-16 19:25:51', '1', '2025-12-17 09:46:15', 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 (3037, 42, 'Vben5.0 Antdv Next Schema 模版', '42', 'infra_codegen_front_type', 0, '', '', '', '1', '2026-05-23 13:52:25', '1', '2026-05-23 13:52:25', 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 (3038, 43, 'Vben5.0 Antdv Next 标准模版', '43', 'infra_codegen_front_type', 0, '', '', '', '1', '2026-05-23 13:52:25', '1', '2026-05-23 13:52:25', 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 (3040, 1, 'UDP', 'udp', 'iot_protocol_type', 0, '', '', 'UDP 协议', '1', '2026-02-04 00:32:47', '1', '2026-02-04 00:32:47', 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 (3041, 2, 'WebSocket', 'websocket', 'iot_protocol_type', 0, '', '', 'WebSocket 协议', '1', '2026-02-04 00:32:55', '1', '2026-02-04 00:32:55', 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 (3042, 3, 'HTTP', 'http', 'iot_protocol_type', 0, '', '', 'HTTP 协议', '1', '2026-02-04 00:32:55', '1', '2026-02-04 00:32:55', b'0');
|
||||
@@ -1454,8 +1456,32 @@ 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 (1061091, 1, '退货出库', '200', 'wms_shipment_order_type', 0, 'warning', '', '退货出库', '1', '2026-05-12 17:48:35', '1', '2026-05-12 17:48:35', 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 (1061092, 2, '销售出库', '201', 'wms_shipment_order_type', 0, 'primary', '', '销售出库', '1', '2026-05-12 17:48:35', '1', '2026-05-12 17:48:35', 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 (1061093, 3, '生产出库', '202', 'wms_shipment_order_type', 0, 'success', '', '生产出库', '1', '2026-05-12 17:48:35', '1', '2026-05-12 17:48:35', 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 (1061094, 1, 'è¯éŸ³', '1', 'im_rtc_call_media_type', 0, '', '', 'è¯éŸ³é€šè¯', 'admin', '2026-05-14 13:48:31', 'admin', '2026-05-14 13:48:31', 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 (1061095, 2, '视频', '2', 'im_rtc_call_media_type', 0, '', '', '视频通è¯', 'admin', '2026-05-14 13:48:31', 'admin', '2026-05-14 13:48:31', 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 (1061096, 1, '语音', '1', 'im_rtc_call_media_type', 0, '', '', '语音通话', 'admin', '2026-05-16 11:34:50', 'admin', '2026-05-16 11:34:50', 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 (1061097, 2, '视频', '2', 'im_rtc_call_media_type', 0, '', '', '视频通话', 'admin', '2026-05-16 11:34:50', 'admin', '2026-05-16 11:34:50', 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 (1061098, 1, '私聊', '1', 'im_rtc_call_conversation_type', 0, 'primary', '', '一对一私聊通话', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', 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 (1061099, 2, '群聊', '2', 'im_rtc_call_conversation_type', 0, 'success', '', '群内多人通话', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', 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 (1061100, 1, '创建', '10', 'im_rtc_call_status', 0, 'info', '', '通话已创建,等待接通', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', 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 (1061101, 2, '进行中', '20', 'im_rtc_call_status', 0, 'primary', '', '已有人接通,通话中', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', 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 (1061102, 3, '已结束', '30', 'im_rtc_call_status', 0, 'success', '', '通话结束', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', 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 (1061103, 1, '通话结束', '1', 'im_rtc_call_end_reason', 0, 'success', '', '接通后任一方主动挂断', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', 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 (1061104, 2, '已拒绝', '2', 'im_rtc_call_end_reason', 0, 'warning', '', '被叫接通前点拒接', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', 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 (1061105, 3, '已取消', '3', 'im_rtc_call_end_reason', 0, 'info', '', '主叫接通前主动取消', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', 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 (1061106, 4, '无人接听', '4', 'im_rtc_call_end_reason', 0, 'info', '', '振铃超时未接通', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', 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 (1061107, 5, '对方正忙', '5', 'im_rtc_call_end_reason', 0, 'warning', '', '对方在另一通话中', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', 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 (1061108, 6, '通话异常', '9', 'im_rtc_call_end_reason', 0, 'danger', '', '网络中断、设备失败等', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', 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 (1061109, 1, '发起人', '1', 'im_rtc_participant_role', 0, 'primary', '', '通话发起者', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', 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 (1061110, 2, '被邀请者', '2', 'im_rtc_participant_role', 0, 'info', '', '被邀请加入', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', 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 (1061111, 3, '主动加入者', '3', 'im_rtc_participant_role', 0, 'success', '', '群通话场景,旁观者主动加入', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', 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 (1061112, 1, '邀请中', '10', 'im_rtc_participant_status', 0, 'info', '', '已发出 invite,等待响应', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', 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 (1061113, 2, '已加入', '20', 'im_rtc_participant_status', 0, 'primary', '', '已接通并进入房间', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', 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 (1061114, 3, '已拒绝', '30', 'im_rtc_participant_status', 0, 'warning', '', '接通前点拒接', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', 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 (1061115, 4, '未应答', '40', 'im_rtc_participant_status', 0, 'info', '', '通话已结束仍未应答', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', 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 (1061116, 5, '已离开', '50', 'im_rtc_participant_status', 0, 'success', '', '接通后挂断 / 离开', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', 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 (1061117, 1610, '通话开始', '1610', 'im_message_type', 0, 'info', '', '入消息流;私聊定向通知,群聊全员广播', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', 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 (1061118, 1611, '通话结束', '1611', 'im_message_type', 0, 'info', '', '入消息流;私聊准气泡,群聊系统 tip', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', 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 (1061119, 125, '素材', '125', 'im_message_type', 0, 'success', '', '频道运营推送的图文卡片消息', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', 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 (1061120, 1, '富文本', '1', 'im_channel_material_type', 0, 'primary', '', '', '1', '2026-05-19 14:09:25', '1', '2026-05-19 14:09:25', 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 (1061121, 2, '外链', '2', 'im_channel_material_type', 0, 'info', '', '', '1', '2026-05-19 14:09:25', '1', '2026-05-19 14:09:25', b'0');
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
@@ -1475,7 +1501,7 @@ CREATE TABLE `system_dict_type` (
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`deleted_time` datetime NULL DEFAULT NULL COMMENT '删除时间',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 1061092 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表';
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 1061099 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of system_dict_type
|
||||
@@ -1682,7 +1708,13 @@ 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 (1061070, 'WMS 单据状态', 'wms_order_status', 0, 'WMS 单据状态', '1', '2026-05-12 13:40:29', '1', '2026-05-12 13:40:29', b'0', NULL);
|
||||
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1061080, '入库单类型', 'wms_receipt_order_type', 0, 'WMS 入库单类型', '1', '2026-05-11 11:21:49', '1', '2026-05-12 13:40:29', b'0', NULL);
|
||||
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1061090, '出库单类型', 'wms_shipment_order_type', 0, 'WMS 出库单类型', '1', '2026-05-12 17:48:35', '1', '2026-05-12 17:48:35', b'0', NULL);
|
||||
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1061091, 'IM 通è¯åª’体类型', 'im_rtc_call_media_type', 0, NULL, 'admin', '2026-05-14 13:48:31', 'admin', '2026-05-14 13:48:31', b'0', NULL);
|
||||
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1061092, 'IM 通话媒体类型', 'im_rtc_call_media_type', 0, NULL, 'admin', '2026-05-16 11:34:50', 'admin', '2026-05-16 11:34:50', b'0', NULL);
|
||||
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1061093, 'IM 通话会话类型', 'im_rtc_call_conversation_type', 0, '1=私聊;2=群聊', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0', NULL);
|
||||
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1061094, 'IM 通话状态', 'im_rtc_call_status', 0, '10=创建;20=进行中;30=已结束', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0', NULL);
|
||||
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1061095, 'IM 通话结束原因', 'im_rtc_call_end_reason', 0, '1=通话结束;2=已拒绝;3=已取消;4=无人接听;5=对方正忙;9=通话异常', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0', NULL);
|
||||
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1061096, 'IM 通话参与角色', 'im_rtc_participant_role', 0, '1=发起人;2=被邀请者;3=主动加入者', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0', NULL);
|
||||
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1061097, 'IM 通话参与状态', 'im_rtc_participant_status', 0, '10=邀请中;20=已加入;30=已拒绝;40=未应答;50=已离开', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0', NULL);
|
||||
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1061098, 'IM 频道素材内容类型', 'im_channel_material_type', 0, '1=站内富文本 / 2=外链', '1', '2026-05-19 14:09:25', '1', '2026-05-19 14:09:25', b'0', NULL);
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
@@ -1708,7 +1740,7 @@ CREATE TABLE `system_login_log` (
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `idx_username`(`username` ASC) USING BTREE,
|
||||
INDEX `idx_create_time`(`create_time` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 4557 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录';
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 4697 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of system_login_log
|
||||
@@ -1841,7 +1873,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 = 6611 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '菜单权限表';
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 6735 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '菜单权限表';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of system_menu
|
||||
@@ -2773,7 +2805,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`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5034, 'OTA 固件创建', 'iot:ota-firmware:create', 3, 2, 5032, '', '', '', '', 0, b'1', b'1', b'1', '', '2025-06-30 07:50:29', '\"1\"', '2025-06-30 17:38:21', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5035, 'OTA 固件更新', 'iot:ota-firmware:update', 3, 3, 5032, '', '', '', '', 0, b'1', b'1', b'1', '', '2025-06-30 07:50:29', '\"1\"', '2025-06-30 17:38:29', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5036, 'OTA 固件删除', 'iot:ota-firmware:delete', 3, 4, 5032, '', '', '', '', 0, b'1', b'1', b'1', '', '2025-06-30 07:50:29', '\"1\"', '2025-06-30 17:38:37', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5037, 'OTA 升级任务查询', 'iot:ota-task:create', 3, 11, 5032, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-07-02 23:56:56', '1', '2025-07-02 23:56:56', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5037, 'OTA 升级任务查询', 'iot:ota-task:query', 3, 11, 5032, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-07-02 23:56:56', '1', '2026-05-19 08:48:53', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5038, 'OTA 升级任务取消', 'iot:ota-task:cancel', 3, 13, 5032, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-07-02 23:57:26', '1', '2025-07-02 23:57:26', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5039, 'OTA 升级任务创建', 'iot:ota-task:create', 3, 12, 5032, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-07-02 23:57:52', '1', '2025-07-02 23:57:52', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5040, 'OTA 升级记录查询', 'iot:ota-task-record:query', 3, 21, 5032, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-07-02 23:58:30', '1', '2025-07-02 23:58:30', b'0');
|
||||
@@ -3270,6 +3302,24 @@ 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`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6582, '用户表情删除', 'im:manager:face-user-item:delete', 3, 20, 6580, '', '', '', '', 0, b'1', b'1', b'1', '', '2026-05-06 13:56:08', '', '2026-05-06 13:56:08', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6600, '私聊管理', '', 1, 20, 6500, 'private', 'ep:chat-round', NULL, NULL, 0, b'1', b'1', b'1', '1', '2026-05-07 00:40:35', '1', '2026-05-07 00:40:35', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6610, '群聊管理', '', 1, 30, 6500, 'group', 'ep:chat-line-round', NULL, NULL, 0, b'1', b'1', b'1', '1', '2026-05-07 00:40:35', '1', '2026-05-07 00:40:35', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6611, '通话记录', '', 2, 40, 6500, 'rtc', 'ep:phone', 'im/manager/rtc/index', 'ImRtcCall', 0, b'1', b'1', b'1', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6612, '通话记录查询', 'im:manager:rtc:query', 3, 1, 6611, '', '', NULL, NULL, 0, b'1', b'1', b'1', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6700, '频道管理', '', 1, 90, 6500, 'channel', 'ep:promotion', NULL, NULL, 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6710, '频道列表', '', 2, 1, 6700, 'list', 'ep:promotion', 'im/manager/channel/list/index', 'ImChannel', 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-19 09:44:34', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6711, '频道查询', 'im:manager:channel:query', 3, 1, 6710, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6712, '频道创建', 'im:manager:channel:create', 3, 2, 6710, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6713, '频道修改', 'im:manager:channel:update', 3, 3, 6710, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6714, '频道删除', 'im:manager:channel:delete', 3, 4, 6710, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6720, '频道素材', '', 2, 2, 6700, 'material', 'ep:document', 'im/manager/channel/material/index', 'ImChannelMaterial', 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-19 09:44:34', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6721, '素材查询', 'im:manager:channel-material:query', 3, 1, 6720, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6722, '素材创建', 'im:manager:channel-material:create', 3, 2, 6720, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6723, '素材修改', 'im:manager:channel-material:update', 3, 3, 6720, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6724, '素材删除', 'im:manager:channel-material:delete', 3, 4, 6720, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6730, '频道消息', '', 2, 3, 6700, 'message', 'ep:message', 'im/manager/channel/message/index', 'ImChannelMessage', 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-19 09:44:34', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6731, '消息查询', 'im:manager:channel-message:query', 3, 1, 6730, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6732, '立即推送', 'im:manager:channel-message:send', 3, 2, 6730, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6733, '消息删除', 'im:manager:channel-message:delete', 3, 3, 6730, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', b'0');
|
||||
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6734, '解散群', 'im:manager:group:dissolve', 3, 21, 6540, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2026-05-24 12:02:38', '1', '2026-05-24 12:02:38', b'0');
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
@@ -3392,7 +3442,7 @@ CREATE TABLE `system_oauth2_access_token` (
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `idx_access_token`(`access_token` ASC) USING BTREE,
|
||||
INDEX `idx_refresh_token`(`refresh_token` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 54457 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌';
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 57395 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of system_oauth2_access_token
|
||||
@@ -3518,7 +3568,7 @@ CREATE TABLE `system_oauth2_refresh_token` (
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `idx_refresh_token`(`refresh_token` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 2590 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌';
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 2728 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of system_oauth2_refresh_token
|
||||
@@ -3554,7 +3604,7 @@ CREATE TABLE `system_operate_log` (
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `idx_user_id`(`user_id` ASC) USING BTREE,
|
||||
INDEX `idx_create_time`(`create_time` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 9194 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录 V2 版本';
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 9195 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录 V2 版本';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of system_operate_log
|
||||
@@ -4952,16 +5002,16 @@ CREATE TABLE `system_users` (
|
||||
INDEX `idx_mobile`(`mobile` ASC) USING BTREE,
|
||||
INDEX `idx_email`(`email` ASC) USING BTREE,
|
||||
INDEX `idx_dept_id`(`dept_id` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 145 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户信息表';
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 225 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户信息表';
|
||||
|
||||
-- ----------------------------
|
||||
-- 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$04$.vd8nPeLwxt6hnSzmAoAyul8BOLX7Cib6QhcxRe30rfvrIPQHH1OG', '芋道源码', '管理员', 103, '[1,2]', '13aoteman@126.com', '18818260272', 1, 'http://test.yudao.iocoder.cn/user/avatar/20251220/blob_1766215463801.jpg', 0, '0:0:0:0:0:0:0:1', '2026-05-15 22:24:39', 'admin', '2021-01-05 17:03:47', NULL, '2026-05-15 22:24:39', 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$04$.vd8nPeLwxt6hnSzmAoAyul8BOLX7Cib6QhcxRe30rfvrIPQHH1OG', '芋道源码', '管理员', 103, '[1,2]', '13aoteman@126.com', '18818260272', 1, 'http://test.yudao.iocoder.cn/20260517/blob_1778998103688.png', 0, '0:0:0:0:0:0:0:1', '2026-05-31 21:54:49', 'admin', '2021-01-05 17:03:47', NULL, '2026-05-31 21:54:49', 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$04$.vd8nPeLwxt6hnSzmAoAyul8BOLX7Cib6QhcxRe30rfvrIPQHH1OG', '芋道', '不要吓我', 104, '[1]', 'yudao@iocoder.cn', '15601691300', 1, NULL, 0, '0:0:0:0:0:0:0:1', '2026-04-19 17:40:55', '', '2021-01-07 09:07:17', NULL, '2026-04-19 17:40:55', 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$04$k/d6mc0nySN0i2udwcI8Ee8V5aM5OHixBRbQfXmPuFTUl3Zf/DBs.', '源码', NULL, 106, NULL, 'yuanma@iocoder.cn', '15601701300', 0, NULL, 0, '0:0:0:0:0:0:0:1', '2026-04-27 13:19:27', '', '2021-01-13 23:50:35', NULL, '2026-04-27 13:19: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$04$BrwaYn303hjA/6TnXqdGoOLhyHOAA0bVrAFu6.1dJKycqKUnIoRz2', '测试号', NULL, 107, '[1,2]', '111@qq.com', '15601691200', 1, NULL, 0, '0:0:0:0:0:0:0:1', '2026-05-09 09:57:13', '', '2021-01-21 02:13:53', NULL, '2026-05-09 09:57:13', 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$04$BrwaYn303hjA/6TnXqdGoOLhyHOAA0bVrAFu6.1dJKycqKUnIoRz2', '测试号', NULL, 107, '[1,2]', '111@qq.com', '15601691200', 1, NULL, 0, '0:0:0:0:0:0:0:1', '2026-05-20 23:37:11', '', '2021-01-21 02:13:53', NULL, '2026-05-20 23:37:11', 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 (107, 'admin107', '$2a$10$dYOOBKMO93v/.ReCqzyFg.o67Tqk.bbc2bhrpyBGkIw9aypCtr2pm', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, NULL, 0, '', NULL, '1', '2022-02-20 22:59:33', '1', '2025-04-21 14:23:08', b'0', 118);
|
||||
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 (108, 'admin108', '$2a$10$y6mfvKoNYL1GXWak8nYwVOH.kCWqjactkzdoIDgiKl93WN3Ejg.Lu', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, NULL, 0, '', NULL, '1', '2022-02-20 23:00:50', '1', '2025-04-21 14:23:08', b'0', 119);
|
||||
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 (109, 'admin109', '$2a$10$JAqvH0tEc0I7dfDVBI7zyuB4E3j.uH6daIjV53.vUS6PknFkDJkuK', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, NULL, 0, '', NULL, '1', '2022-02-20 23:11:50', '1', '2025-04-21 14:23:08', b'0', 120);
|
||||
@@ -4977,7 +5027,7 @@ INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`,
|
||||
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 (141, 'admin1', '$2a$04$oj6F6d7HrZ70kYVD3TNzEu.m3TPUzajOVuC66zdKna8KRerK1FmVa', '新用户', NULL, NULL, NULL, '', '', 0, '', 0, '0:0:0:0:0:0:0:1', '2025-04-08 13:09:07', '1', '2025-04-08 13:09:07', '1', '2025-05-14 19:11:48', 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 (142, 'test01', '$2a$04$4bCYWZkjxxOC4QE0LY2M9uEEKWeJbLfs489NFtQoyidL5I0FndRaO', 'test01', '', NULL, '[]', '', '19021719925', 1, '', 0, '0:0:0:0:0:0:0:1', '2025-07-29 19:47:17', '1', '2025-07-09 21:07:10', NULL, '2025-12-02 13:23:11', 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 (143, 'a00001', '$2a$04$GhVHFviOw/SsTmiQtifHJesDYFlHMeGK7OWh7aGCCjGGVCmbHVAwa', 'a00001', NULL, 104, NULL, '', '', 0, '', 0, '0:0:0:0:0:0:0:1', '2025-12-01 16:10:13', NULL, '2025-12-01 16:10:13', '1', '2025-12-05 21:34:05', 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 (144, 'aoteman001', '$2a$04$omQOmhz8OyUFBKw77nr8KOtMp6xdvoQ1gWStjk9r8.OYT3Bv6oEYe', 'aoteman001', NULL, 116, NULL, '', '', 0, '', 1, '0:0:0:0:0:0:0:1', '2025-12-01 17:05:27', '1', '2025-12-01 17:05:27', '1', '2025-12-15 15:55:54', 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 (144, 'aoteman001', '$2a$04$omQOmhz8OyUFBKw77nr8KOtMp6xdvoQ1gWStjk9r8.OYT3Bv6oEYe', 'aoteman001', NULL, 104, NULL, '', '', 0, '', 1, '0:0:0:0:0:0:0:1', '2025-12-01 17:05:27', '1', '2025-12-01 17:05:27', '1', '2026-05-31 21:52:48', b'0', 1);
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
|
||||
@@ -53,6 +53,8 @@
|
||||
<!-- 工具类相关 -->
|
||||
<anji-plus-captcha.version>1.4.0</anji-plus-captcha.version>
|
||||
<jsoup.version>1.22.2</jsoup.version>
|
||||
<sensitive-word.version>0.29.5</sensitive-word.version>
|
||||
<pinyin4j.version>2.5.1</pinyin4j.version>
|
||||
<lombok.version>1.18.46</lombok.version>
|
||||
<mapstruct.version>1.6.3</mapstruct.version>
|
||||
<hutool-5.version>5.8.44</hutool-5.version>
|
||||
@@ -578,6 +580,18 @@
|
||||
<version>${jsoup.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.houbb</groupId>
|
||||
<artifactId>sensitive-word</artifactId> <!-- 敏感词检测:trie 树高效匹配 -->
|
||||
<version>${sensitive-word.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.belerweb</groupId>
|
||||
<artifactId>pinyin4j</artifactId> <!-- 汉字转拼音:作为 hutool PinyinUtil 的底层引擎 -->
|
||||
<version>${pinyin4j.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Vert.x -->
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
|
||||
+26
@@ -124,6 +124,22 @@ public class CollectionUtils {
|
||||
return from.stream().filter(filter).map(func).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public static <T, U> Set<U> convertLinkedSet(Collection<T> from, Function<T, U> func) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new LinkedHashSet<>();
|
||||
}
|
||||
return from.stream().map(func).filter(Objects::nonNull)
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
}
|
||||
|
||||
public static <T, U> Set<U> convertLinkedSet(Collection<T> from, Function<T, U> func, Predicate<T> filter) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new LinkedHashSet<>();
|
||||
}
|
||||
return from.stream().filter(filter).map(func).filter(Objects::nonNull)
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
}
|
||||
|
||||
public static <T, K> Map<K, T> convertMapByFilter(Collection<T> from, Predicate<T> filter, Function<T, K> keyFunc) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new HashMap<>();
|
||||
@@ -372,4 +388,14 @@ public class CollectionUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 把单元素 head 与集合 tail 合并成新 List(head 在前,tail 顺序保留)
|
||||
*/
|
||||
public static <T> List<T> of(T head, Collection<T> tail) {
|
||||
List<T> list = new ArrayList<>();
|
||||
list.add(head);
|
||||
CollUtil.addAll(list, tail);
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
||||
+17
@@ -236,6 +236,23 @@ public class LocalDateTimeUtils {
|
||||
return LocalDateTime.now().with(TemporalAdjusters.firstDayOfYear()).with(LocalTime.MIN);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最近 N 天的 0 点时刻序列(升序,含今天)
|
||||
* <p>
|
||||
* 例:getLatestDays(3) 返回 [前天 00:00, 昨天 00:00, 今天 00:00]
|
||||
*
|
||||
* @param days 天数(含今天)
|
||||
* @return 升序的 LocalDateTime 列表
|
||||
*/
|
||||
public static List<LocalDateTime> getLatestDays(int days) {
|
||||
LocalDateTime today = getToday();
|
||||
List<LocalDateTime> dates = new ArrayList<>(days);
|
||||
for (int i = days - 1; i >= 0; i--) {
|
||||
dates.add(today.minusDays(i));
|
||||
}
|
||||
return dates;
|
||||
}
|
||||
|
||||
public static List<LocalDateTime[]> getDateRangeList(LocalDateTime startTime,
|
||||
LocalDateTime endTime,
|
||||
Integer interval) {
|
||||
|
||||
+10
@@ -204,4 +204,14 @@ public class HttpUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* WebSocket URL 切换成 HTTP URL:ws:// → http://;wss:// → https://;其它格式原样保留
|
||||
*
|
||||
* @param url 原始 URL
|
||||
* @return 切换协议后的 URL
|
||||
*/
|
||||
public static String wsUrlToHttp(String url) {
|
||||
return StrUtil.startWithIgnoreCase(url, "ws") ? "http" + url.substring(2) : url;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+18
@@ -22,6 +22,7 @@ import java.lang.reflect.Type;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* JSON 工具类
|
||||
@@ -173,6 +174,23 @@ public class JsonUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 JSON 字符串成 Map,空字符串或解析失败返回 null
|
||||
*
|
||||
* @param text JSON 字符串
|
||||
* @return Map 对象
|
||||
*/
|
||||
public static Map<String, Object> parseMap(String text) {
|
||||
if (StrUtil.isEmpty(text)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return objectMapper.readValue(text, new TypeReference<Map<String, Object>>() {});
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 JSON 字符串成指定类型的对象,如果解析失败,则返回 null
|
||||
*
|
||||
|
||||
+20
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.common.util.string;
|
||||
import cn.hutool.core.text.StrPool;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.pinyin.PinyinUtil;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
|
||||
import java.util.Arrays;
|
||||
@@ -78,6 +79,25 @@ public class StrUtils {
|
||||
.collect(Collectors.joining("\n"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 转小写拼音,字之间以空格分隔,便于调用方按需拼接 / 取首字母 / 拼音搜索
|
||||
*
|
||||
* 例:「老张」→ "lao zhang"、「ZhangSan」→ "zhangsan"
|
||||
* 英文 / 数字 / 符号原样返回,空值返回 null
|
||||
*
|
||||
* 注意:底层依赖 hutool-extra 的 {@link PinyinUtil},需要业务模块自行引入拼音引擎依赖
|
||||
* (pinyin4j / TinyPinyin / Bopomofo4j 任选其一),否则运行时会抛 NoClassDefFoundError
|
||||
*
|
||||
* @param str 字符串
|
||||
* @return 拼音串(保留空格分隔)
|
||||
*/
|
||||
public static String toPinyin(String str) {
|
||||
if (StrUtil.isBlank(str)) {
|
||||
return null;
|
||||
}
|
||||
return PinyinUtil.getPinyin(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼接方法的参数
|
||||
*
|
||||
|
||||
+6
-1
@@ -195,7 +195,12 @@ public class YudaoTenantAutoConfiguration {
|
||||
RedisCacheWriter cacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory,
|
||||
BatchStrategies.scan(yudaoCacheProperties.getRedisScanBatchSize()));
|
||||
// 创建 TenantRedisCacheManager 对象
|
||||
return new TenantRedisCacheManager(cacheWriter, redisCacheConfiguration, tenantProperties.getIgnoreCaches());
|
||||
TenantRedisCacheManager cacheManager = new TenantRedisCacheManager(cacheWriter, redisCacheConfiguration,
|
||||
tenantProperties.getIgnoreCaches());
|
||||
// 开启事务感知:@Transactional 方法内的 @CacheEvict / @CachePut 自动延迟到 afterCommit,
|
||||
// 避免事务未提交就清缓存被并发读穿写脏值;无事务时立即生效,行为不变
|
||||
cacheManager.setTransactionAware(true);
|
||||
return cacheManager;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+11
@@ -170,6 +170,17 @@ public interface BaseMapperX<T> extends MPJBaseMapper<T> {
|
||||
return CollUtil.getFirst(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取满足条件的最新一条记录
|
||||
* <p>
|
||||
* 目的:解决并发场景下,插入多条记录后,使用 selectOne 会报错的问题
|
||||
*
|
||||
* @param queryWrapper 查询条件
|
||||
* @return 最新一条;不存在返回 null
|
||||
*/
|
||||
default T selectLastOne(LambdaQueryWrapper<T> queryWrapper) {
|
||||
return CollUtil.getLast(selectList(queryWrapper));
|
||||
}
|
||||
|
||||
default Long selectCount() {
|
||||
return selectCount(new QueryWrapper<>());
|
||||
|
||||
+6
-2
@@ -75,8 +75,12 @@ public class YudaoCacheAutoConfiguration {
|
||||
RedisConnectionFactory connectionFactory = Objects.requireNonNull(redisTemplate.getConnectionFactory());
|
||||
RedisCacheWriter cacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory,
|
||||
BatchStrategies.scan(yudaoCacheProperties.getRedisScanBatchSize()));
|
||||
// 创建 TenantRedisCacheManager 对象
|
||||
return new TimeoutRedisCacheManager(cacheWriter, redisCacheConfiguration);
|
||||
// 创建 TimeoutRedisCacheManager 对象
|
||||
TimeoutRedisCacheManager cacheManager = new TimeoutRedisCacheManager(cacheWriter, redisCacheConfiguration);
|
||||
// 开启事务感知:@Transactional 方法内的 @CacheEvict / @CachePut 自动延迟到 afterCommit,
|
||||
// 避免事务未提交就清缓存被并发读穿写脏值;无事务时立即生效,行为不变
|
||||
cacheManager.setTransactionAware(true);
|
||||
return cacheManager;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -76,7 +76,7 @@ public class JsonWebSocketMessageHandler extends TextWebSocketHandler {
|
||||
Long tenantId = WebSocketFrameworkUtils.getTenantId(session);
|
||||
TenantUtils.execute(tenantId, () -> messageListener.onMessage(session, messageObj));
|
||||
} catch (Throwable ex) {
|
||||
log.error("[handleTextMessage][session({}) message({}) 处理异常]", session.getId(), message.getPayload());
|
||||
log.error("[handleTextMessage][session({}) message({}) 处理异常]", session.getId(), message.getPayload(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -27,9 +27,10 @@ public class LoginUserHandshakeInterceptor implements HandshakeInterceptor {
|
||||
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
|
||||
WebSocketHandler wsHandler, Map<String, Object> attributes) {
|
||||
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
|
||||
if (loginUser != null) {
|
||||
WebSocketFrameworkUtils.setLoginUser(loginUser, attributes);
|
||||
if (loginUser == null) {
|
||||
return false;
|
||||
}
|
||||
WebSocketFrameworkUtils.setLoginUser(loginUser, attributes);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>yudao-module-im</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
<description>
|
||||
im 模块,我们放即时通讯业务。
|
||||
例如说:单聊、群聊、消息收发、消息撤回、消息已读等等
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-module-system</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Web 相关 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- DB 相关 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-mybatis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 工具类相关 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-excel</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 敏感词检测:sensitive-word(trie 树高效匹配,支持忽略大小写 / 全半角 / 数字风格),版本由 yudao-dependencies 统一管理 -->
|
||||
<dependency>
|
||||
<groupId>com.github.houbb</groupId>
|
||||
<artifactId>sensitive-word</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 汉字转拼音:作为 hutool PinyinUtil 的底层引擎,业务侧调用 StrUtils.toPinyin 时按需引入 -->
|
||||
<dependency>
|
||||
<groupId>com.belerweb</groupId>
|
||||
<artifactId>pinyin4j</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Test 测试相关 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-test</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* @author anhaohao
|
||||
* @since 2024/3/9 下午8:59
|
||||
*/
|
||||
package cn.iocoder.yudao.module.im.api;
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.channel;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.material.ImChannelMaterialRespVO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.channel.ImChannelMaterialDO;
|
||||
import cn.iocoder.yudao.module.im.service.channel.ImChannelMaterialService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "用户 APP - IM 频道素材")
|
||||
@RestController
|
||||
@RequestMapping("/im/channel/material")
|
||||
@Validated
|
||||
public class ImChannelMaterialController {
|
||||
|
||||
@Resource
|
||||
private ImChannelMaterialService channelMaterialService;
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获取素材详情;用于客户端点击图文卡片渲染详情页")
|
||||
@Parameter(name = "id", description = "素材编号", required = true, example = "1024")
|
||||
public CommonResult<ImChannelMaterialRespVO> getMaterial(@RequestParam("id") Long id) {
|
||||
ImChannelMaterialDO material = channelMaterialService.validateMaterialExists(id);
|
||||
return success(BeanUtils.toBean(material, ImChannelMaterialRespVO.class));
|
||||
}
|
||||
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.face;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.face.vo.pack.ImFacePackUserRespVO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFacePackDO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFacePackItemDO;
|
||||
import cn.iocoder.yudao.module.im.service.face.ImFacePackItemService;
|
||||
import cn.iocoder.yudao.module.im.service.face.ImFacePackService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap;
|
||||
|
||||
@Tag(name = "管理后台 - IM 表情包")
|
||||
@RestController
|
||||
@RequestMapping("/im/face-pack")
|
||||
@Validated
|
||||
public class ImFacePackController {
|
||||
|
||||
@Resource
|
||||
private ImFacePackService facePackService;
|
||||
@Resource
|
||||
private ImFacePackItemService facePackItemService;
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获得启用的表情包列表(含表情)")
|
||||
public CommonResult<List<ImFacePackUserRespVO>> getFacePackList() {
|
||||
// 1.1 拉所有启用表情包
|
||||
List<ImFacePackDO> packs = facePackService.getEnabledFacePackList();
|
||||
if (packs.isEmpty()) {
|
||||
return success(List.of());
|
||||
}
|
||||
// 1.2 拉这些包下所有启用表情,按 packId 分组
|
||||
List<ImFacePackItemDO> items = facePackItemService.getEnabledItemListByPackIds(
|
||||
convertList(packs, ImFacePackDO::getId));
|
||||
Map<Long, List<ImFacePackItemDO>> itemsByPackId = convertMultiMap(items, ImFacePackItemDO::getPackId);
|
||||
|
||||
// 2. 拼装:BeanUtils 把 pack 字段映射 + 自己塞 items
|
||||
List<ImFacePackUserRespVO> result = convertList(packs, pack -> {
|
||||
ImFacePackUserRespVO vo = BeanUtils.toBean(pack, ImFacePackUserRespVO.class);
|
||||
vo.setItems(BeanUtils.toBean(itemsByPackId.getOrDefault(pack.getId(), List.of()), ImFacePackUserRespVO.Item.class));
|
||||
return vo;
|
||||
});
|
||||
return success(result);
|
||||
}
|
||||
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.face;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.face.vo.useritem.ImFaceUserItemRespVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.face.vo.useritem.ImFaceUserItemSaveReqVO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO;
|
||||
import cn.iocoder.yudao.module.im.service.face.ImFaceUserItemService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
|
||||
|
||||
@Tag(name = "管理后台 - IM 个人表情")
|
||||
@RestController
|
||||
@RequestMapping("/im/face-user-item")
|
||||
@Validated
|
||||
public class ImFaceUserItemController {
|
||||
|
||||
@Resource
|
||||
private ImFaceUserItemService faceUserItemService;
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获得我的个人表情列表")
|
||||
public CommonResult<List<ImFaceUserItemRespVO>> getFaceUserItemList() {
|
||||
List<ImFaceUserItemDO> items = faceUserItemService.getFaceUserItemList(getLoginUserId());
|
||||
return success(BeanUtils.toBean(items, ImFaceUserItemRespVO.class));
|
||||
}
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "添加个人表情")
|
||||
public CommonResult<Long> createFaceUserItem(@Valid @RequestBody ImFaceUserItemSaveReqVO reqVO) {
|
||||
return success(faceUserItemService.createFaceUserItem(getLoginUserId(), reqVO));
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除个人表情")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "4096")
|
||||
public CommonResult<Boolean> deleteFaceUserItem(@RequestParam("id") Long id) {
|
||||
faceUserItemService.deleteFaceUserItem(getLoginUserId(), id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.face.vo.pack;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "IM 表情包(用户端) Response VO")
|
||||
@Data
|
||||
public class ImFacePackUserRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "表情包名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "猫主子")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "表情包图标", example = "https://cdn.example.com/face/pack/cat.png")
|
||||
private String icon;
|
||||
|
||||
@Schema(description = "表情列表", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private List<Item> items;
|
||||
|
||||
@Schema(description = "IM 表情包项(用户端)")
|
||||
@Data
|
||||
public static class Item {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "表情图 URL", requiredMode = Schema.RequiredMode.REQUIRED,
|
||||
example = "https://cdn.example.com/face/pack/cat-001.png")
|
||||
private String url;
|
||||
|
||||
@Schema(description = "表情名", example = "狗头")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "渲染宽度(像素)", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
|
||||
private Integer width;
|
||||
|
||||
@Schema(description = "渲染高度(像素)", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
|
||||
private Integer height;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.face.vo.useritem;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "IM 个人表情 Response VO")
|
||||
@Data
|
||||
public class ImFaceUserItemRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4096")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "表情图 URL", requiredMode = Schema.RequiredMode.REQUIRED,
|
||||
example = "https://cdn.example.com/face/user/abc.gif")
|
||||
private String url;
|
||||
|
||||
@Schema(description = "表情名", example = "狗头")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "渲染宽度(像素)", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
|
||||
private Integer width;
|
||||
|
||||
@Schema(description = "渲染高度(像素)", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
|
||||
private Integer height;
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.face.vo.useritem;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "IM 个人表情新增 Request VO")
|
||||
@Data
|
||||
public class ImFaceUserItemSaveReqVO {
|
||||
|
||||
@Schema(description = "表情图 URL", requiredMode = Schema.RequiredMode.REQUIRED,
|
||||
example = "https://cdn.example.com/face/user/abc.gif")
|
||||
@NotBlank(message = "表情图 URL 不能为空")
|
||||
@Size(max = 512, message = "表情图 URL 长度不能超过 512")
|
||||
private String url;
|
||||
|
||||
@Schema(description = "表情名", example = "狗头")
|
||||
@Size(max = 64, message = "表情名长度不能超过 64")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "渲染宽度(像素)", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
|
||||
@NotNull(message = "渲染宽度不能为空")
|
||||
@Min(value = 1, message = "渲染宽度不能小于 1 像素")
|
||||
@Max(value = 2048, message = "渲染宽度不能大于 2048 像素")
|
||||
private Integer width;
|
||||
|
||||
@Schema(description = "渲染高度(像素)", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
|
||||
@NotNull(message = "渲染高度不能为空")
|
||||
@Min(value = 1, message = "渲染高度不能小于 1 像素")
|
||||
@Max(value = 2048, message = "渲染高度不能大于 2048 像素")
|
||||
private Integer height;
|
||||
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.friend;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.friend.vo.ImFriendRespVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.friend.vo.ImFriendUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendDO;
|
||||
import cn.iocoder.yudao.module.im.service.friend.ImFriendService;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.singleton;
|
||||
import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
|
||||
|
||||
@Tag(name = "管理后台 - IM 好友")
|
||||
@RestController
|
||||
@RequestMapping("/im/friend")
|
||||
@Validated
|
||||
public class ImFriendController {
|
||||
|
||||
@Resource
|
||||
private ImFriendService friendService;
|
||||
|
||||
@Resource
|
||||
private AdminUserApi adminUserApi;
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获得当前登录用户的好友列表")
|
||||
public CommonResult<List<ImFriendRespVO>> getMyFriendList() {
|
||||
// 含 DISABLE 历史好友:保留给前端展示「已删除好友」的历史对话信息;前端按 status 决定会话级联清理
|
||||
List<ImFriendDO> friends = friendService.getFriendList(getLoginUserId());
|
||||
return success(buildFriendRespVOList(friends));
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得好友详情")
|
||||
@Parameter(name = "friendUserId", description = "好友的用户编号", required = true, example = "2048")
|
||||
public CommonResult<ImFriendRespVO> getFriend(@RequestParam("friendUserId") Long friendUserId) {
|
||||
ImFriendDO friend = friendService.getFriend(getLoginUserId(), friendUserId);
|
||||
return success(buildFriendRespVO(friend));
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除好友(单向软删除)")
|
||||
@Parameters({
|
||||
@Parameter(description = "好友的用户编号", required = true, example = "2048"),
|
||||
@Parameter(description = "是否级联清理本端相关数据(如私聊会话)")
|
||||
})
|
||||
public CommonResult<Boolean> deleteFriend(
|
||||
@RequestParam("friendUserId") @NotNull(message = "好友用户编号不能为空") Long friendUserId,
|
||||
@RequestParam(value = "clear", required = false) Boolean clear) {
|
||||
friendService.deleteFriend(getLoginUserId(), friendUserId, clear);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新好友单边属性(备注 / 免打扰 / 联系人置顶)")
|
||||
public CommonResult<Boolean> updateFriend(@Valid @RequestBody ImFriendUpdateReqVO reqVO) {
|
||||
friendService.updateFriend(getLoginUserId(), reqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/block")
|
||||
@Operation(summary = "拉黑好友(必须先是好友;单边屏蔽对方私聊消息)")
|
||||
@Parameter(name = "friendUserId", description = "好友的用户编号", required = true, example = "2048")
|
||||
public CommonResult<Boolean> blockFriend(
|
||||
@RequestParam("friendUserId") @NotNull(message = "好友用户编号不能为空") Long friendUserId) {
|
||||
friendService.blockFriend(getLoginUserId(), friendUserId);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/unblock")
|
||||
@Operation(summary = "移出黑名单")
|
||||
@Parameter(name = "friendUserId", description = "好友的用户编号", required = true, example = "2048")
|
||||
public CommonResult<Boolean> unblockFriend(
|
||||
@RequestParam("friendUserId") @NotNull(message = "好友用户编号不能为空") Long friendUserId) {
|
||||
friendService.unblockFriend(getLoginUserId(), friendUserId);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
// ========== 私有方法:VO 组装 ==========
|
||||
|
||||
private List<ImFriendRespVO> buildFriendRespVOList(Collection<ImFriendDO> friends) {
|
||||
if (CollUtil.isEmpty(friends)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// 批量聚合 AdminUser 信息(昵称 / 头像),避免 N+1
|
||||
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
|
||||
convertList(friends, ImFriendDO::getFriendUserId));
|
||||
return convertList(friends, friend -> {
|
||||
ImFriendRespVO vo = BeanUtils.toBean(friend, ImFriendRespVO.class);
|
||||
MapUtils.findAndThen(userMap, friend.getFriendUserId(), user ->
|
||||
vo.setNickname(user.getNickname()).setAvatar(user.getAvatar()));
|
||||
// 备注 / 昵称的拼音,给前端做字母分桶 + 拼音搜索
|
||||
vo.setDisplayNamePinyin(StrUtils.toPinyin(vo.getDisplayName()))
|
||||
.setNicknamePinyin(StrUtils.toPinyin(vo.getNickname()));
|
||||
return vo;
|
||||
});
|
||||
}
|
||||
|
||||
private ImFriendRespVO buildFriendRespVO(ImFriendDO friend) {
|
||||
if (friend == null) {
|
||||
return null;
|
||||
}
|
||||
return CollUtil.getFirst(buildFriendRespVOList(singleton(friend)));
|
||||
}
|
||||
|
||||
}
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.friend;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.friend.vo.request.ImFriendRequestApplyReqVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.friend.vo.request.ImFriendRequestRespVO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendRequestDO;
|
||||
import cn.iocoder.yudao.module.im.service.friend.ImFriendRequestService;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
|
||||
import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
|
||||
|
||||
/**
|
||||
* IM 好友申请记录 Controller
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Tag(name = "管理后台 - IM 好友申请")
|
||||
@RestController
|
||||
@RequestMapping("/im/friend-request")
|
||||
@Validated
|
||||
public class ImFriendRequestController {
|
||||
|
||||
@Resource
|
||||
private ImFriendRequestService friendRequestService;
|
||||
|
||||
@Resource
|
||||
private AdminUserApi adminUserApi;
|
||||
|
||||
@PostMapping("/apply")
|
||||
@Operation(summary = "发起好友申请")
|
||||
public CommonResult<Long> applyFriend(@Valid @RequestBody ImFriendRequestApplyReqVO reqVO) {
|
||||
ImFriendRequestDO request = friendRequestService.applyFriend(getLoginUserId(), reqVO);
|
||||
return success(request != null ? request.getId() : null);
|
||||
}
|
||||
|
||||
@PutMapping("/agree")
|
||||
@Operation(summary = "同意好友申请")
|
||||
@Parameter(name = "id", description = "申请编号", required = true, example = "1024")
|
||||
public CommonResult<Boolean> agreeFriendRequest(
|
||||
@RequestParam("id") @NotNull(message = "申请编号不能为空") Long id) {
|
||||
friendRequestService.agreeFriendRequest(getLoginUserId(), id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/refuse")
|
||||
@Operation(summary = "拒绝好友申请")
|
||||
public CommonResult<Boolean> refuseFriendRequest(
|
||||
@RequestParam("id") @NotNull(message = "申请编号不能为空") Long id,
|
||||
@RequestParam(value = "handleContent", required = false)
|
||||
@Size(max = 255, message = "处理理由最多 255 个字符") String handleContent) {
|
||||
friendRequestService.refuseFriendRequest(getLoginUserId(), id, handleContent);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "查询「我相关」的好友申请列表(游标分页:传 maxId 加载更多)")
|
||||
public CommonResult<List<ImFriendRequestRespVO>> getMyFriendRequestList(
|
||||
@Parameter(description = "当前列表最旧记录的 id;首页不传")
|
||||
@RequestParam(value = "maxId", required = false) Long maxId,
|
||||
@Parameter(description = "单次拉取条数", required = true)
|
||||
@RequestParam("limit") @Min(1) @Max(200) Integer limit) {
|
||||
List<ImFriendRequestDO> list = friendRequestService.getMyFriendRequestList(getLoginUserId(), maxId, limit);
|
||||
return success(buildList(list));
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "按 id 单查「我相关」的申请记录(带越权过滤;WebSocket 通知到达后用)")
|
||||
@Parameter(name = "id", description = "申请记录编号", required = true)
|
||||
public CommonResult<ImFriendRequestRespVO> getMyFriendRequest(@RequestParam("id") Long id) {
|
||||
ImFriendRequestDO request = friendRequestService.getFriendRequest(id);
|
||||
// 越权过滤:fromUser / toUser 必有一方是当前用户,否则当不存在返回 null
|
||||
Long currentUserId = getLoginUserId();
|
||||
if (request == null || (ObjUtil.notEqual(request.getFromUserId(), currentUserId)
|
||||
&& ObjUtil.notEqual(request.getToUserId(), currentUserId))) {
|
||||
return success(null);
|
||||
}
|
||||
return success(CollUtil.getFirst(buildList(Collections.singletonList(request))));
|
||||
}
|
||||
|
||||
// ========== 私有方法:VO 组装 ==========
|
||||
|
||||
private List<ImFriendRequestRespVO> buildList(List<ImFriendRequestDO> list) {
|
||||
if (CollUtil.isEmpty(list)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// 双向 OR 列表,userIds 取 from + to 两组并集
|
||||
Set<Long> userIds = convertSetByFlatMap(list,
|
||||
request -> Stream.of(request.getFromUserId(), request.getToUserId()));
|
||||
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
|
||||
return convertList(list, request -> {
|
||||
ImFriendRequestRespVO vo = BeanUtils.toBean(request, ImFriendRequestRespVO.class);
|
||||
MapUtils.findAndThen(userMap, request.getFromUserId(), user ->
|
||||
vo.setFromNickname(user.getNickname()).setFromAvatar(user.getAvatar()));
|
||||
MapUtils.findAndThen(userMap, request.getToUserId(), user ->
|
||||
vo.setToNickname(user.getNickname()).setToAvatar(user.getAvatar()));
|
||||
return vo;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.friend.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* IM 好友 Response VO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Schema(description = "管理后台 - IM 好友 Response VO")
|
||||
@Data
|
||||
public class ImFriendRespVO {
|
||||
|
||||
@Schema(description = "关系记录编号", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "好友的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
|
||||
private Long friendUserId;
|
||||
|
||||
@Schema(description = "是否免打扰", example = "false")
|
||||
private Boolean silent;
|
||||
|
||||
@Schema(description = "好友展示备注(仅自己可见)", example = "老张")
|
||||
private String displayName;
|
||||
|
||||
@Schema(description = "好友展示备注的拼音(小写无空格)", example = "laozhang")
|
||||
private String displayNamePinyin;
|
||||
|
||||
@Schema(description = "添加来源", example = "1")
|
||||
private Integer addSource; // 参见 ImFriendAddSourceEnum 枚举
|
||||
|
||||
@Schema(description = "是否置顶联系人", example = "false")
|
||||
private Boolean pinned;
|
||||
|
||||
@Schema(description = "是否拉黑(仅自己可见)", example = "false")
|
||||
private Boolean blocked;
|
||||
|
||||
@Schema(description = "好友状态", example = "0")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "添加好友时间")
|
||||
private LocalDateTime addTime;
|
||||
|
||||
@Schema(description = "删除好友时间")
|
||||
private LocalDateTime deleteTime;
|
||||
|
||||
// ========== 下面是聚合字段,方便前端显示 ==========
|
||||
|
||||
@Schema(description = "好友昵称(实时聚合自 AdminUser)", example = "芋道")
|
||||
private String nickname;
|
||||
|
||||
@Schema(description = "好友昵称的拼音(小写无空格)", example = "yudao")
|
||||
private String nicknamePinyin;
|
||||
|
||||
@Schema(description = "好友头像(实时聚合自 AdminUser)")
|
||||
private String avatar;
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.friend.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - IM 好友更新 Request VO")
|
||||
@Data
|
||||
public class ImFriendUpdateReqVO {
|
||||
|
||||
@Schema(description = "好友的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
|
||||
@NotNull(message = "好友用户编号不能为空")
|
||||
private Long friendUserId;
|
||||
|
||||
@Schema(description = "是否免打扰;不传表示不修改", example = "true")
|
||||
private Boolean silent;
|
||||
|
||||
@Schema(description = "好友展示备注(仅自己可见);不传表示不修改,传空串表示清空", example = "老张")
|
||||
@Size(max = 16, message = "好友备注最多 16 个字符")
|
||||
private String displayName;
|
||||
|
||||
@Schema(description = "是否置顶联系人;不传表示不修改", example = "true")
|
||||
private Boolean pinned;
|
||||
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.friend.vo.request;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.module.im.enums.friend.ImFriendAddSourceEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* IM 好友申请 - 发起 Request VO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Schema(description = "管理后台 - IM 好友申请发起 Request VO")
|
||||
@Data
|
||||
public class ImFriendRequestApplyReqVO {
|
||||
|
||||
@Schema(description = "接收方用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
|
||||
@NotNull(message = "接收方用户编号不能为空")
|
||||
private Long toUserId;
|
||||
|
||||
@Schema(description = "申请理由", example = "我是芋艿(一种食材)")
|
||||
@Size(max = 255, message = "申请理由最多 255 个字符")
|
||||
private String applyContent;
|
||||
|
||||
@Schema(description = "对接收方的备注(仅自己可见)", example = "老张")
|
||||
@Size(max = 16, message = "好友备注最多 16 个字符")
|
||||
private String displayName;
|
||||
|
||||
@Schema(description = "添加来源", example = "1")
|
||||
@InEnum(ImFriendAddSourceEnum.class)
|
||||
private Integer addSource;
|
||||
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.friend.vo.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* IM 好友申请 Response VO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Schema(description = "管理后台 - IM 好友申请 Response VO")
|
||||
@Data
|
||||
public class ImFriendRequestRespVO {
|
||||
|
||||
@Schema(description = "申请编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "发起方用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
|
||||
private Long fromUserId;
|
||||
|
||||
@Schema(description = "接收方用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
|
||||
private Long toUserId;
|
||||
|
||||
@Schema(description = "处理结果", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
private Integer handleResult; // 参见 ImFriendRequestHandleResultEnum 枚举
|
||||
|
||||
@Schema(description = "申请理由", example = "我是芋艿(一种食材)")
|
||||
private String applyContent;
|
||||
|
||||
@Schema(description = "处理理由(接收方拒绝时可选填)", example = "暂不通过")
|
||||
private String handleContent;
|
||||
|
||||
@Schema(description = "添加来源", example = "1")
|
||||
private Integer addSource; // 参见 ImFriendAddSourceEnum 枚举
|
||||
|
||||
@Schema(description = "处理时间")
|
||||
private LocalDateTime handleTime;
|
||||
|
||||
@Schema(description = "申请创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
// ========== 下面是聚合字段,方便前端显示 ==========
|
||||
|
||||
@Schema(description = "发起方昵称(实时聚合自 AdminUser)", example = "芋道")
|
||||
private String fromNickname;
|
||||
|
||||
@Schema(description = "发起方头像(实时聚合自 AdminUser)")
|
||||
private String fromAvatar;
|
||||
|
||||
@Schema(description = "接收方昵称(实时聚合自 AdminUser)", example = "老张")
|
||||
private String toNickname;
|
||||
|
||||
@Schema(description = "接收方头像(实时聚合自 AdminUser)")
|
||||
private String toAvatar;
|
||||
|
||||
}
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.group;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.group.vo.*;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberInviteReqVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberRemoveReqVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.message.vo.group.ImGroupMessageRespVO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.message.ImGroupMessageDO;
|
||||
import cn.iocoder.yudao.module.im.service.group.ImGroupMemberService;
|
||||
import cn.iocoder.yudao.module.im.service.group.ImGroupService;
|
||||
import cn.iocoder.yudao.module.im.service.message.ImGroupMessageService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||
import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
|
||||
|
||||
@Tag(name = "管理后台 - 群")
|
||||
@RestController
|
||||
@RequestMapping("/im/group")
|
||||
@Validated
|
||||
public class ImGroupController {
|
||||
|
||||
@Resource
|
||||
private ImGroupService groupService;
|
||||
@Resource
|
||||
private ImGroupMemberService groupMemberService;
|
||||
@Resource
|
||||
private ImGroupMessageService groupMessageService;
|
||||
|
||||
// ==================== 群的写操作 ====================
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建群")
|
||||
public CommonResult<ImGroupRespVO> createGroup(@Valid @RequestBody ImGroupCreateReqVO createReqVO) {
|
||||
ImGroupDO group = groupService.createGroup(createReqVO, getLoginUserId());
|
||||
// 新建群必无 pinnedMessages,跳过关联回填
|
||||
return success(BeanUtils.toBean(group, ImGroupRespVO.class));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新群")
|
||||
public CommonResult<ImGroupRespVO> updateGroup(@Valid @RequestBody ImGroupUpdateReqVO updateReqVO) {
|
||||
ImGroupDO group = groupService.updateGroup(updateReqVO, getLoginUserId());
|
||||
return success(buildGroupRespVO(group, getLoginUserId()));
|
||||
}
|
||||
|
||||
@DeleteMapping("/dissolve")
|
||||
@Operation(summary = "解散群")
|
||||
@Parameter(name = "id", description = "群编号", required = true)
|
||||
public CommonResult<Boolean> dissolveGroup(@RequestParam("id") Long id) {
|
||||
groupService.dissolveGroup(id, getLoginUserId());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
// ==================== 群的读操作 ====================
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得群")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
public CommonResult<ImGroupRespVO> getGroup(@RequestParam("id") Long id) {
|
||||
ImGroupDO group = groupService.getGroup(id);
|
||||
return success(buildGroupRespVO(group, getLoginUserId()));
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获得当前登录用户的群列表")
|
||||
public CommonResult<List<ImGroupRespVO>> getMyGroupList() {
|
||||
Long loginUserId = getLoginUserId();
|
||||
List<ImGroupDO> groups = groupService.getMyGroupList(loginUserId);
|
||||
return success(buildGroupRespVOList(groups, loginUserId));
|
||||
}
|
||||
|
||||
// ==================== 群成员的写操作 ====================
|
||||
|
||||
@PostMapping("/invite")
|
||||
@Operation(summary = "邀请用户加入群")
|
||||
public CommonResult<Boolean> inviteGroupMember(@Valid @RequestBody ImGroupMemberInviteReqVO inviteReqVO) {
|
||||
groupService.inviteGroupMember(getLoginUserId(), inviteReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/quit")
|
||||
@Operation(summary = "退出群")
|
||||
@Parameter(name = "groupId", description = "群编号", required = true)
|
||||
public CommonResult<Boolean> quitGroup(@RequestParam("groupId") Long groupId) {
|
||||
groupService.quitGroup(groupId, getLoginUserId());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/kicking")
|
||||
@Operation(summary = "移除群成员")
|
||||
public CommonResult<Boolean> removeGroupMember(@Valid @RequestBody ImGroupMemberRemoveReqVO removeReqVO) {
|
||||
groupService.removeGroupMember(getLoginUserId(), removeReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/add-admin")
|
||||
@Operation(summary = "添加群管理员")
|
||||
public CommonResult<Boolean> addGroupAdmin(@Valid @RequestBody ImGroupAdminAddReqVO reqVO) {
|
||||
groupService.addGroupAdmin(getLoginUserId(), reqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/remove-admin")
|
||||
@Operation(summary = "撤销群管理员")
|
||||
public CommonResult<Boolean> removeGroupAdmin(@Valid @RequestBody ImGroupAdminRemoveReqVO reqVO) {
|
||||
groupService.removeGroupAdmin(getLoginUserId(), reqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/transfer-owner")
|
||||
@Operation(summary = "转让群主")
|
||||
public CommonResult<Boolean> transferGroupOwner(@Valid @RequestBody ImGroupTransferOwnerReqVO transferReqVO) {
|
||||
groupService.transferGroupOwner(getLoginUserId(), transferReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
// ==================== 群消息置顶 ====================
|
||||
|
||||
@PutMapping("/pin-message")
|
||||
@Operation(summary = "置顶群消息(群主 / 管理员)")
|
||||
public CommonResult<Boolean> pinGroupMessage(@Valid @RequestBody ImGroupMessagePinReqVO reqVO) {
|
||||
groupService.pinGroupMessage(getLoginUserId(), reqVO.getId(), reqVO.getMessageId());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/unpin-message")
|
||||
@Operation(summary = "取消置顶群消息(群主 / 管理员)")
|
||||
public CommonResult<Boolean> unpinGroupMessage(@Valid @RequestBody ImGroupMessagePinReqVO reqVO) {
|
||||
groupService.unpinGroupMessage(getLoginUserId(), reqVO.getId(), reqVO.getMessageId());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
// ==================== 群禁言 ====================
|
||||
|
||||
@PutMapping("/mute-all")
|
||||
@Operation(summary = "全群禁言 / 取消(群主 / 管理员)")
|
||||
public CommonResult<Boolean> muteAll(@Valid @RequestBody ImGroupMuteAllReqVO reqVO) {
|
||||
groupService.muteAll(getLoginUserId(), reqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/mute-member")
|
||||
@Operation(summary = "禁言成员")
|
||||
public CommonResult<Boolean> muteMember(@Valid @RequestBody ImGroupMuteMemberReqVO reqVO) {
|
||||
groupService.muteMember(getLoginUserId(), reqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/cancel-mute-member")
|
||||
@Operation(summary = "取消成员禁言")
|
||||
public CommonResult<Boolean> cancelMuteMember(@Valid @RequestBody ImGroupCancelMuteMemberReqVO reqVO) {
|
||||
groupService.cancelMuteMember(getLoginUserId(), reqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
/** 单群转 VO + 关联回填 pinnedMessages(仅当登录用户是该群有效成员) */
|
||||
private ImGroupRespVO buildGroupRespVO(ImGroupDO group, Long loginUserId) {
|
||||
if (group == null) {
|
||||
return null;
|
||||
}
|
||||
return buildGroupRespVOList(Collections.singletonList(group), loginUserId).get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 群列表批量转 VO + 关联回填 pinnedMessages
|
||||
* <p>
|
||||
* 仅当登录用户是某群的有效成员时才回填该群的 pinnedMessages,避免非成员 / 已退群用户越权拿到置顶消息内容
|
||||
*/
|
||||
private List<ImGroupRespVO> buildGroupRespVOList(List<ImGroupDO> groups, Long loginUserId) {
|
||||
if (CollUtil.isEmpty(groups)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// 仅当前用户是有效成员的群才允许回填置顶消息
|
||||
Set<Long> activeGroupIds = convertSet(
|
||||
groupMemberService.getActiveGroupMemberListByUserId(loginUserId), ImGroupMemberDO::getGroupId);
|
||||
Set<Long> allMessageIds = convertSetByFlatMap(groups, group -> activeGroupIds.contains(group.getId())
|
||||
? CollUtil.emptyIfNull(group.getPinnedMessageIds()).stream() : Stream.empty());
|
||||
Map<Long, ImGroupMessageDO> messageMap = groupMessageService.getGroupMessageMap(allMessageIds);
|
||||
// 转换输出
|
||||
return convertList(groups, group -> {
|
||||
ImGroupRespVO vo = BeanUtils.toBean(group, ImGroupRespVO.class);
|
||||
if (!activeGroupIds.contains(group.getId()) || CollUtil.isEmpty(group.getPinnedMessageIds())) {
|
||||
return vo;
|
||||
}
|
||||
// 按 pin 顺序输出,已被删除的消息(messageMap 没命中)跳过
|
||||
List<ImGroupMessageDO> pinnedMesages = convertList(group.getPinnedMessageIds(), messageMap::get);
|
||||
return vo.setPinnedMessages(BeanUtils.toBean(pinnedMesages, ImGroupMessageRespVO.class));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.group;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberRespVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
|
||||
import cn.iocoder.yudao.module.im.service.group.ImGroupMemberService;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||
import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
|
||||
import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.GROUP_MEMBER_NOT_IN_GROUP;
|
||||
|
||||
@Tag(name = "管理后台 - 群成员")
|
||||
@RestController
|
||||
@RequestMapping("/im/group-member")
|
||||
@Validated
|
||||
public class ImGroupMemberController {
|
||||
|
||||
@Resource
|
||||
private ImGroupMemberService groupMemberService;
|
||||
|
||||
@Resource
|
||||
private AdminUserApi adminUserApi;
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新群成员")
|
||||
public CommonResult<Boolean> updateGroupMember(@Valid @RequestBody ImGroupMemberUpdateReqVO updateReqVO) {
|
||||
groupMemberService.updateGroupMember(getLoginUserId(), updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得群成员")
|
||||
@Parameters({
|
||||
@Parameter(name = "id", description = "编号(与 groupId + userId 二选一)", example = "1024"),
|
||||
@Parameter(name = "groupId", description = "群编号(与 userId 配合查)", example = "1"),
|
||||
@Parameter(name = "userId", description = "用户编号(与 groupId 配合查)", example = "100")
|
||||
})
|
||||
public CommonResult<ImGroupMemberRespVO> getGroupMember(@RequestParam(value = "id", required = false) Long id,
|
||||
@RequestParam(value = "groupId", required = false) Long groupId,
|
||||
@RequestParam(value = "userId", required = false) Long userId) {
|
||||
// 1. 查询群成员
|
||||
ImGroupMemberDO member;
|
||||
if (id != null) {
|
||||
member = groupMemberService.getGroupMember(id);
|
||||
} else if (groupId != null && userId != null) {
|
||||
member = groupMemberService.getGroupMember(groupId, userId);
|
||||
} else {
|
||||
// 避免 selectByGroupIdAndUserId 收到 null 参数走全表扫 / 抛 SQL 异常
|
||||
throw new IllegalArgumentException("参数缺失:需传 id 或 (groupId, userId)");
|
||||
}
|
||||
if (member == null) {
|
||||
return success(null);
|
||||
}
|
||||
|
||||
// 2. 校验当前登录用户是该成员所在群的有效成员
|
||||
Long loginUserId = getLoginUserId();
|
||||
groupMemberService.validateMemberInGroup(member.getGroupId(), loginUserId);
|
||||
|
||||
// 3. 转化 VO
|
||||
ImGroupMemberRespVO memberVO = BeanUtils.toBean(member, ImGroupMemberRespVO.class);
|
||||
AdminUserRespDTO user = adminUserApi.getUser(member.getUserId());
|
||||
if (user != null) {
|
||||
memberVO.setNickname(user.getNickname()).setAvatar(user.getAvatar());
|
||||
}
|
||||
hidePrivateFieldsIfNotSelf(memberVO, member.getUserId(), loginUserId);
|
||||
return success(memberVO);
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获得指定群的成员列表")
|
||||
@Parameter(name = "groupId", description = "群编号", required = true, example = "1024")
|
||||
public CommonResult<List<ImGroupMemberRespVO>> getGroupMemberList(@RequestParam("groupId") Long groupId) {
|
||||
// 1.1 查询群成员列表(包含 DISABLE 已退群的成员,不按时间过滤)
|
||||
// 说明:保留已退群成员,是为了前端展示历史消息时,仍能通过该接口拿到已退群成员的昵称 / 头像信息,避免显示为空
|
||||
List<ImGroupMemberDO> members = groupMemberService.getGroupMemberListByGroupId(groupId);
|
||||
// 1.2 校验当前登录用户是否为群的有效成员,非成员不可查看
|
||||
Long loginUserId = getLoginUserId();
|
||||
if (CollUtil.findOne(members, member -> loginUserId.equals(member.getUserId())
|
||||
&& CommonStatusEnum.ENABLE.getStatus().equals(member.getStatus())) == null) {
|
||||
throw exception(GROUP_MEMBER_NOT_IN_GROUP);
|
||||
}
|
||||
|
||||
// 2.批量聚合 AdminUser 信息(昵称 / 头像)
|
||||
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
|
||||
convertList(members, ImGroupMemberDO::getUserId));
|
||||
return success(convertList(members, m -> {
|
||||
ImGroupMemberRespVO vo = BeanUtils.toBean(m, ImGroupMemberRespVO.class);
|
||||
MapUtils.findAndThen(userMap, m.getUserId(), user ->
|
||||
vo.setNickname(user.getNickname()).setAvatar(user.getAvatar()));
|
||||
hidePrivateFieldsIfNotSelf(vo, m.getUserId(), loginUserId);
|
||||
return vo;
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* 非本人查看时,置空成员的私人设置字段(groupRemark / silent)
|
||||
*/
|
||||
private void hidePrivateFieldsIfNotSelf(ImGroupMemberRespVO vo, Long memberUserId, Long loginUserId) {
|
||||
if (ObjUtil.notEqual(loginUserId, memberUserId)) {
|
||||
vo.setGroupRemark(null).setSilent(null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.group;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.group.vo.request.ImGroupRequestApplyReqVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.group.vo.request.ImGroupRequestRespVO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupRequestDO;
|
||||
import cn.iocoder.yudao.module.im.enums.group.ImGroupMemberRoleEnum;
|
||||
import cn.iocoder.yudao.module.im.service.group.ImGroupMemberService;
|
||||
import cn.iocoder.yudao.module.im.service.group.ImGroupRequestService;
|
||||
import cn.iocoder.yudao.module.im.service.group.ImGroupService;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||
import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
|
||||
|
||||
/**
|
||||
* IM 加群申请 Controller
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Tag(name = "管理后台 - IM 加群申请")
|
||||
@RestController
|
||||
@RequestMapping("/im/group-request")
|
||||
@Validated
|
||||
public class ImGroupRequestController {
|
||||
|
||||
@Resource
|
||||
private ImGroupRequestService groupRequestService;
|
||||
@Resource
|
||||
private ImGroupService groupService;
|
||||
@Resource
|
||||
private ImGroupMemberService groupMemberService;
|
||||
|
||||
@Resource
|
||||
private AdminUserApi adminUserApi;
|
||||
|
||||
@PostMapping("/apply")
|
||||
@Operation(summary = "申请加群")
|
||||
public CommonResult<Long> applyJoinGroup(@Valid @RequestBody ImGroupRequestApplyReqVO reqVO) {
|
||||
ImGroupRequestDO request = groupRequestService.applyJoinGroup(getLoginUserId(), reqVO);
|
||||
return success(request != null ? request.getId() : null);
|
||||
}
|
||||
|
||||
@PutMapping("/agree")
|
||||
@Operation(summary = "同意加群申请(群主或管理员)")
|
||||
@Parameter(name = "id", description = "申请编号", required = true, example = "1024")
|
||||
public CommonResult<Boolean> agreeGroupRequest(
|
||||
@RequestParam("id") @NotNull(message = "申请编号不能为空") Long id) {
|
||||
groupRequestService.agreeGroupRequest(getLoginUserId(), id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/refuse")
|
||||
@Operation(summary = "拒绝加群申请(群主或管理员)")
|
||||
public CommonResult<Boolean> refuseGroupRequest(
|
||||
@RequestParam("id") @NotNull(message = "申请编号不能为空") Long id,
|
||||
@RequestParam(value = "handleContent", required = false)
|
||||
@Size(max = 255, message = "处理理由最多 255 个字符") String handleContent) {
|
||||
groupRequestService.refuseGroupRequest(getLoginUserId(), id, handleContent);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/unhandled-list")
|
||||
@Operation(summary = "查询「我管理的所有群」下的未处理加群申请列表(不分页);前端 store 据此派生横幅红点 + Drawer 列表")
|
||||
public CommonResult<List<ImGroupRequestRespVO>> getUnhandledRequestList() {
|
||||
List<ImGroupRequestDO> list = groupRequestService.getUnhandledRequestListByOwnerOrAdmin(getLoginUserId());
|
||||
return success(buildVOList(list));
|
||||
}
|
||||
|
||||
@GetMapping("/list-by-group")
|
||||
@Operation(summary = "查询指定群下的全部加群申请(含已处理);仅群主 / 管理员可查")
|
||||
@Parameter(name = "groupId", description = "群编号", required = true, example = "1024")
|
||||
public CommonResult<List<ImGroupRequestRespVO>> getGroupRequestListByGroupId(
|
||||
@RequestParam("groupId") @NotNull(message = "群编号不能为空") Long groupId) {
|
||||
List<ImGroupRequestDO> list = groupRequestService.getGroupRequestListByGroupId(getLoginUserId(), groupId);
|
||||
return success(buildVOList(list));
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "按 id 单查申请记录(带越权过滤;WebSocket 通知到达后用)")
|
||||
@Parameter(name = "id", description = "申请记录编号", required = true)
|
||||
public CommonResult<ImGroupRequestRespVO> getGroupRequest(@RequestParam("id") Long id) {
|
||||
ImGroupRequestDO request = groupRequestService.getGroupRequest(id);
|
||||
if (request == null) {
|
||||
return success(null);
|
||||
}
|
||||
// 越权过滤:申请人 / 邀请人 / 群主 / 管理员之外,当不存在返回 null
|
||||
Long currentUserId = getLoginUserId();
|
||||
boolean canSee = ObjUtil.equal(request.getUserId(), currentUserId)
|
||||
|| ObjUtil.equal(request.getInviterUserId(), currentUserId)
|
||||
|| isGroupOwnerOrAdmin(request.getGroupId(), currentUserId);
|
||||
if (!canSee) {
|
||||
return success(null);
|
||||
}
|
||||
|
||||
// 转换并返回
|
||||
return success(CollUtil.getFirst(buildVOList(Collections.singletonList(request))));
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前用户是否该群的有效群主 / 管理员
|
||||
*/
|
||||
private boolean isGroupOwnerOrAdmin(Long groupId, Long userId) {
|
||||
ImGroupMemberDO member = groupMemberService.getGroupMember(groupId, userId);
|
||||
return member != null
|
||||
&& !CommonStatusEnum.DISABLE.getStatus().equals(member.getStatus())
|
||||
&& ImGroupMemberRoleEnum.isOwnerOrAdmin(member.getRole());
|
||||
}
|
||||
|
||||
/** 申请记录列表批量转 VO + 关联回填用户 / 群信息 */
|
||||
private List<ImGroupRequestRespVO> buildVOList(List<ImGroupRequestDO> list) {
|
||||
if (CollUtil.isEmpty(list)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// 1. 聚合 user / inviter 用户信息;convertSetByFlatMap 内部已过滤 null
|
||||
Set<Long> userIds = convertSetByFlatMap(list,
|
||||
request -> Stream.of(request.getUserId(), request.getInviterUserId()));
|
||||
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
|
||||
// 2. 聚合群信息(封禁 / 解散群也要回填,便于前端展示历史)
|
||||
Set<Long> groupIds = convertSet(list, ImGroupRequestDO::getGroupId);
|
||||
Map<Long, ImGroupDO> groupMap = groupService.getGroupMap(groupIds);
|
||||
return convertList(list, request -> {
|
||||
ImGroupRequestRespVO vo = BeanUtils.toBean(request, ImGroupRequestRespVO.class);
|
||||
MapUtils.findAndThen(userMap, request.getUserId(), user ->
|
||||
vo.setUserNickname(user.getNickname()).setUserAvatar(user.getAvatar()));
|
||||
MapUtils.findAndThen(userMap, request.getInviterUserId(), user ->
|
||||
vo.setInviterNickname(user.getNickname()).setInviterAvatar(user.getAvatar()));
|
||||
MapUtils.findAndThen(groupMap, request.getGroupId(), group ->
|
||||
vo.setGroupName(group.getName()).setGroupAvatar(group.getAvatar()));
|
||||
return vo;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.group.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 添加群管理员 Request VO")
|
||||
@Data
|
||||
public class ImGroupAdminAddReqVO {
|
||||
|
||||
@Schema(description = "群编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13279")
|
||||
@NotNull(message = "群编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "目标用户编号列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "[101, 102]")
|
||||
@NotEmpty(message = "目标用户编号列表不能为空")
|
||||
private List<Long> userIds;
|
||||
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.group.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 撤销群管理员 Request VO")
|
||||
@Data
|
||||
public class ImGroupAdminRemoveReqVO {
|
||||
|
||||
@Schema(description = "群编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13279")
|
||||
@NotNull(message = "群编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "目标用户编号列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "[101, 102]")
|
||||
@NotEmpty(message = "目标用户编号列表不能为空")
|
||||
private List<Long> userIds;
|
||||
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.group.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - 取消成员禁言 Request VO")
|
||||
@Data
|
||||
public class ImGroupCancelMuteMemberReqVO {
|
||||
|
||||
@Schema(description = "群编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "群编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "被取消禁言的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
private Long userId;
|
||||
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.group.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 群创建 Request VO")
|
||||
@Data
|
||||
public class ImGroupCreateReqVO {
|
||||
|
||||
@Schema(description = "群名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道技术交流群")
|
||||
@NotBlank(message = "群名称不能为空")
|
||||
@Size(max = 64, message = "群名称长度不能超过 64")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "初始成员用户编号列表(建群同时邀请的好友,不含创建者自己)", example = "[1024, 2048]")
|
||||
private List<Long> memberUserIds;
|
||||
|
||||
@Schema(description = "进群是否需群主 / 管理员审批;不传默认 false 自由进群", example = "false")
|
||||
private Boolean joinApproval;
|
||||
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.group.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 管理后台 - 群消息置顶 / 取消置顶 Request VO
|
||||
*/
|
||||
@Schema(description = "管理后台 - 群消息置顶 / 取消置顶 Request VO")
|
||||
@Data
|
||||
public class ImGroupMessagePinReqVO {
|
||||
|
||||
@Schema(description = "群编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13279")
|
||||
@NotNull(message = "群编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "消息编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "9527")
|
||||
@NotNull(message = "消息编号不能为空")
|
||||
private Long messageId;
|
||||
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.group.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - 全群禁言 / 取消 Request VO")
|
||||
@Data
|
||||
public class ImGroupMuteAllReqVO {
|
||||
|
||||
@Schema(description = "群编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "群编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "是否全群禁言", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
@NotNull(message = "是否全群禁言不能为空")
|
||||
private Boolean mutedAll;
|
||||
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.group.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - 成员禁言 Request VO")
|
||||
@Data
|
||||
public class ImGroupMuteMemberReqVO {
|
||||
|
||||
@Schema(description = "群编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "群编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "被禁言的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "禁言时长(秒),0 表示永久禁言", requiredMode = Schema.RequiredMode.REQUIRED, example = "600")
|
||||
@NotNull(message = "禁言时长不能为空")
|
||||
@Min(value = 0, message = "禁言时长不能小于 0 秒")
|
||||
private Integer mutedSeconds;
|
||||
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.group.vo;
|
||||
|
||||
import lombok.*;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
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;
|
||||
|
||||
@Schema(description = "管理后台 - 群分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ImGroupPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "群名称", example = "芋艿")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "群主用户编号", example = "31460")
|
||||
private Long ownerUserId;
|
||||
|
||||
@Schema(description = "群公告")
|
||||
private String notice;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.group.vo;
|
||||
|
||||
import cn.iocoder.yudao.module.im.controller.admin.message.vo.group.ImGroupMessageRespVO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 群 Response VO")
|
||||
@Data
|
||||
public class ImGroupRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1003")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "群名称", example = "芋艿")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "群主用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31460")
|
||||
private Long ownerUserId;
|
||||
|
||||
@Schema(description = "群头像")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "群公告")
|
||||
private String notice;
|
||||
|
||||
@Schema(description = "是否封禁")
|
||||
private Boolean banned;
|
||||
|
||||
@Schema(description = "是否全群禁言")
|
||||
private Boolean mutedAll;
|
||||
|
||||
@Schema(description = "进群是否需群主 / 管理员审批", example = "false")
|
||||
private Boolean joinApproval;
|
||||
|
||||
@Schema(description = "封禁时间")
|
||||
private LocalDateTime bannedTime;
|
||||
|
||||
@Schema(description = "群状态", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "解散时间")
|
||||
private LocalDateTime dissolvedTime;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "群置顶消息列表,按 pin 顺序(最先置顶的在前);非该群有效成员时为空")
|
||||
private List<ImGroupMessageRespVO> pinnedMessages;
|
||||
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.group.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.*;
|
||||
import jakarta.validation.constraints.*;
|
||||
|
||||
@Schema(description = "管理后台 - 群新增/修改 Request VO")
|
||||
@Data
|
||||
public class ImGroupSaveReqVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1003")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "群名称", example = "芋艿")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "群主用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31460")
|
||||
@NotNull(message = "群主用户编号不能为空")
|
||||
private Long ownerUserId;
|
||||
|
||||
@Schema(description = "群头像")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "群公告")
|
||||
private String notice;
|
||||
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.group.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - 群主转让 Request VO")
|
||||
@Data
|
||||
public class ImGroupTransferOwnerReqVO {
|
||||
|
||||
@Schema(description = "群编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13279")
|
||||
@NotNull(message = "群编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "新群主用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "202")
|
||||
@NotNull(message = "新群主用户编号不能为空")
|
||||
private Long newOwnerUserId;
|
||||
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.group.vo;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.AssertTrue;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - 群更新 Request VO")
|
||||
@Data
|
||||
public class ImGroupUpdateReqVO {
|
||||
|
||||
@Schema(description = "群编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1003")
|
||||
@NotNull(message = "群编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "群名称", example = "芋道技术交流群")
|
||||
@Size(max = 64, message = "群名称长度不能超过 64")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "群头像")
|
||||
@Size(max = 512, message = "群头像长度不能超过 512")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "群公告")
|
||||
@Size(max = 2048, message = "群公告长度不能超过 2048")
|
||||
private String notice;
|
||||
|
||||
@Schema(description = "进群是否需群主 / 管理员审批", example = "true")
|
||||
private Boolean joinApproval;
|
||||
|
||||
@AssertTrue(message = "群名称不能为空")
|
||||
@JsonIgnore
|
||||
public boolean isNameValid() {
|
||||
return name == null || StrUtil.isNotBlank(name);
|
||||
}
|
||||
|
||||
@AssertTrue(message = "群头像不能为空")
|
||||
@JsonIgnore
|
||||
public boolean isAvatarValid() {
|
||||
return avatar == null || StrUtil.isNotBlank(avatar);
|
||||
}
|
||||
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.group.vo.member;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - 群成员邀请 Request VO")
|
||||
@Data
|
||||
public class ImGroupMemberCreateReqVO {
|
||||
|
||||
@Schema(description = "群编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13279")
|
||||
@NotNull(message = "群编号不能为空")
|
||||
private Long groupId;
|
||||
|
||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "21730")
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
private Long userId;
|
||||
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.group.vo.member;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 群成员邀请 Request VO")
|
||||
@Data
|
||||
public class ImGroupMemberInviteReqVO {
|
||||
|
||||
@Schema(description = "群编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13279")
|
||||
@NotNull(message = "群编号不能为空")
|
||||
private Long groupId;
|
||||
|
||||
@Schema(description = "被邀请的用户编号列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 2, 3]")
|
||||
@NotEmpty(message = "被邀请的用户编号列表不能为空")
|
||||
private List<Long> memberUserIds;
|
||||
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.group.vo.member;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 群成员移除 Request VO")
|
||||
@Data
|
||||
public class ImGroupMemberRemoveReqVO {
|
||||
|
||||
@Schema(description = "群编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "群编号不能为空")
|
||||
private Long groupId;
|
||||
|
||||
@Schema(description = "被移除的用户编号列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 2, 3]")
|
||||
@NotEmpty(message = "被移除的用户编号列表不能为空")
|
||||
private List<Long> memberUserIds;
|
||||
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.group.vo.member;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 群成员 Response VO")
|
||||
@Data
|
||||
public class ImGroupMemberRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17071")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "群编号", example = "13279")
|
||||
private Long groupId;
|
||||
|
||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "21730")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "组内显示名", example = "芋艿")
|
||||
private String displayUserName;
|
||||
|
||||
@Schema(description = "群备注", example = "核心群")
|
||||
private String groupRemark;
|
||||
|
||||
@Schema(description = "是否免打扰")
|
||||
private Boolean silent;
|
||||
|
||||
@Schema(description = "成员状态", example = "0")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "成员角色", example = "3")
|
||||
private Integer role; // 参见 ImGroupMemberRoleEnum 枚举类
|
||||
|
||||
@Schema(description = "入群时间")
|
||||
private LocalDateTime joinTime;
|
||||
|
||||
@Schema(description = "退群时间")
|
||||
private LocalDateTime quitTime;
|
||||
|
||||
@Schema(description = "禁言到期时间")
|
||||
private LocalDateTime muteEndTime;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
// ========== 关联 AdminUser 的字段 ==========
|
||||
|
||||
@Schema(description = "用户昵称", example = "芋道")
|
||||
private String nickname;
|
||||
|
||||
@Schema(description = "用户头像")
|
||||
private String avatar;
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.group.vo.member;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Schema(description = "管理后台 - 群成员更新 Request VO")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class ImGroupMemberUpdateReqVO {
|
||||
|
||||
@Schema(description = "群编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "群编号不能为空")
|
||||
private Long groupId;
|
||||
|
||||
@Schema(description = "群内昵称", example = "芋头")
|
||||
private String displayUserName;
|
||||
|
||||
@Schema(description = "群备注", example = "公司群")
|
||||
private String groupRemark;
|
||||
|
||||
@Schema(description = "是否免打扰")
|
||||
private Boolean silent;
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.group.vo.request;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.module.im.enums.group.ImGroupAddSourceEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - IM 加群申请发起 Request VO")
|
||||
@Data
|
||||
public class ImGroupRequestApplyReqVO {
|
||||
|
||||
@Schema(description = "群编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "群编号不能为空")
|
||||
private Long groupId;
|
||||
|
||||
@Schema(description = "申请理由", example = "我是芋艿(一种食材)")
|
||||
@Size(max = 255, message = "申请理由最多 255 个字符")
|
||||
private String applyContent;
|
||||
|
||||
@Schema(description = "加入来源", example = "1")
|
||||
@InEnum(ImGroupAddSourceEnum.class)
|
||||
private Integer addSource;
|
||||
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.group.vo.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - IM 加群申请 Response VO")
|
||||
@Data
|
||||
public class ImGroupRequestRespVO {
|
||||
|
||||
@Schema(description = "申请编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "群编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long groupId;
|
||||
|
||||
@Schema(description = "申请人 / 被邀请人用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "邀请人用户编号;NULL 表示用户主动申请", example = "200")
|
||||
private Long inviterUserId;
|
||||
|
||||
@Schema(description = "处理结果", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
private Integer handleResult; // 参见 ImGroupRequestHandleResultEnum 枚举
|
||||
|
||||
@Schema(description = "申请理由", example = "我想加入这个群")
|
||||
private String applyContent;
|
||||
|
||||
@Schema(description = "处理理由(拒绝时可选填)", example = "暂不通过")
|
||||
private String handleContent;
|
||||
|
||||
@Schema(description = "处理人用户编号", example = "31460")
|
||||
private Long handleUserId;
|
||||
|
||||
@Schema(description = "加入来源", example = "1")
|
||||
private Integer addSource; // 参见 ImGroupAddSourceEnum 枚举
|
||||
|
||||
@Schema(description = "处理时间")
|
||||
private LocalDateTime handleTime;
|
||||
|
||||
@Schema(description = "申请创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
// ========== 下面是聚合字段,方便前端显示 ==========
|
||||
|
||||
@Schema(description = "申请人 / 被邀请人昵称(实时聚合自 AdminUser)", example = "芋道")
|
||||
private String userNickname;
|
||||
|
||||
@Schema(description = "申请人 / 被邀请人头像(实时聚合自 AdminUser)")
|
||||
private String userAvatar;
|
||||
|
||||
@Schema(description = "邀请人昵称(实时聚合自 AdminUser)", example = "老张")
|
||||
private String inviterNickname;
|
||||
|
||||
@Schema(description = "邀请人头像(实时聚合自 AdminUser)")
|
||||
private String inviterAvatar;
|
||||
|
||||
@Schema(description = "群名称(实时聚合自 ImGroup)", example = "芋道技术交流群")
|
||||
private String groupName;
|
||||
|
||||
@Schema(description = "群头像(实时聚合自 ImGroup)")
|
||||
private String groupAvatar;
|
||||
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.channel;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.channel.ImChannelPageReqVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.channel.ImChannelRespVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.channel.ImChannelSaveReqVO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.channel.ImChannelDO;
|
||||
import cn.iocoder.yudao.module.im.service.channel.ImChannelService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - IM 频道")
|
||||
@RestController
|
||||
@RequestMapping("/im/manager/channel")
|
||||
@Validated
|
||||
public class ImChannelManagerController {
|
||||
|
||||
@Resource
|
||||
private ImChannelService channelService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "新增频道")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:channel:create')")
|
||||
public CommonResult<Long> createChannel(@Valid @RequestBody ImChannelSaveReqVO reqVO) {
|
||||
return success(channelService.createChannel(reqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "修改频道")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:channel:update')")
|
||||
public CommonResult<Boolean> updateChannel(@Valid @RequestBody ImChannelSaveReqVO reqVO) {
|
||||
channelService.updateChannel(reqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除频道")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:channel:delete')")
|
||||
public CommonResult<Boolean> deleteChannel(@RequestParam("id") Long id) {
|
||||
channelService.deleteChannel(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得频道分页")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:channel:query')")
|
||||
public CommonResult<PageResult<ImChannelRespVO>> getChannelPage(@Valid ImChannelPageReqVO pageReqVO) {
|
||||
PageResult<ImChannelDO> pageResult = channelService.getChannelPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, ImChannelRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得频道详情")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:channel:query')")
|
||||
public CommonResult<ImChannelRespVO> getChannel(@RequestParam("id") Long id) {
|
||||
ImChannelDO channel = channelService.getChannel(id);
|
||||
return success(BeanUtils.toBean(channel, ImChannelRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/simple-list")
|
||||
@Operation(summary = "获得启用的频道精简列表;前端表单选择频道时调用")
|
||||
public CommonResult<List<ImChannelRespVO>> getSimpleChannelList() {
|
||||
// TODO DONE @AI:getChannelListByStatus 统一命名
|
||||
List<ImChannelDO> list = channelService.getChannelListByStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
return success(BeanUtils.toBean(list, ImChannelRespVO.class));
|
||||
}
|
||||
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.channel;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.material.ImChannelMaterialPageReqVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.material.ImChannelMaterialRespVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.material.ImChannelMaterialSaveReqVO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.channel.ImChannelDO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.channel.ImChannelMaterialDO;
|
||||
import cn.iocoder.yudao.module.im.service.channel.ImChannelMaterialService;
|
||||
import cn.iocoder.yudao.module.im.service.channel.ImChannelService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
|
||||
@Tag(name = "管理后台 - IM 频道素材")
|
||||
@RestController
|
||||
@RequestMapping("/im/manager/channel-material")
|
||||
@Validated
|
||||
public class ImChannelMaterialManagerController {
|
||||
|
||||
@Resource
|
||||
private ImChannelMaterialService channelMaterialService;
|
||||
@Resource
|
||||
private ImChannelService channelService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "新增素材")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:channel-material:create')")
|
||||
public CommonResult<Long> createMaterial(@Valid @RequestBody ImChannelMaterialSaveReqVO reqVO) {
|
||||
return success(channelMaterialService.createMaterial(reqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "修改素材")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:channel-material:update')")
|
||||
public CommonResult<Boolean> updateMaterial(@Valid @RequestBody ImChannelMaterialSaveReqVO reqVO) {
|
||||
channelMaterialService.updateMaterial(reqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除素材")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:channel-material:delete')")
|
||||
public CommonResult<Boolean> deleteMaterial(@RequestParam("id") Long id) {
|
||||
channelMaterialService.deleteMaterial(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得素材分页;含频道名回填")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:channel-material:query')")
|
||||
public CommonResult<PageResult<ImChannelMaterialRespVO>> getMaterialPage(@Valid ImChannelMaterialPageReqVO pageReqVO) {
|
||||
PageResult<ImChannelMaterialDO> pageResult = channelMaterialService.getMaterialPage(pageReqVO);
|
||||
if (CollUtil.isEmpty(pageResult.getList())) {
|
||||
return success(PageResult.empty(pageResult.getTotal()));
|
||||
}
|
||||
// 回填频道名
|
||||
List<ImChannelDO> channels = channelService.getChannelList(
|
||||
convertSet(pageResult.getList(), ImChannelMaterialDO::getChannelId));
|
||||
Map<Long, ImChannelDO> channelMap = convertMap(channels, ImChannelDO::getId);
|
||||
return success(BeanUtils.toBean(pageResult, ImChannelMaterialRespVO.class, vo ->
|
||||
MapUtils.findAndThen(channelMap, vo.getChannelId(), c -> vo.setChannelName(c.getName()))));
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得素材详情(含富文本正文)")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:channel-material:query')")
|
||||
public CommonResult<ImChannelMaterialRespVO> getMaterial(@RequestParam("id") Long id) {
|
||||
ImChannelMaterialDO material = channelMaterialService.getMaterial(id);
|
||||
return success(BeanUtils.toBean(material, ImChannelMaterialRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/simple-list")
|
||||
@Operation(summary = "获得指定频道下的素材精简列表;用于推送弹窗的素材下拉")
|
||||
@Parameter(name = "channelId", description = "频道编号", required = true, example = "1")
|
||||
public CommonResult<List<ImChannelMaterialRespVO>> getSimpleMaterialList(@RequestParam("channelId") Long channelId) {
|
||||
List<ImChannelMaterialDO> list = channelMaterialService.getMaterialListByChannelId(channelId);
|
||||
return success(BeanUtils.toBean(list, ImChannelMaterialRespVO.class));
|
||||
}
|
||||
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.channel;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Schema(description = "管理后台 - IM 频道分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ImChannelPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "频道业务码", example = "system_notice")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "频道名称", example = "系统")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "状态", example = "0")
|
||||
private Integer status; // 参见 CommonStatusEnum 枚举类
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.channel;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - IM 频道 Response VO")
|
||||
@Data
|
||||
public class ImChannelRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "频道业务码", requiredMode = Schema.RequiredMode.REQUIRED, example = "system_notice")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "频道名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "系统公告")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "频道头像")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
private Integer status; // 参见 CommonStatusEnum 枚举类
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.channel;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - IM 频道新增 / 修改 Request VO")
|
||||
@Data
|
||||
public class ImChannelSaveReqVO {
|
||||
|
||||
@Schema(description = "编号(修改时必填)", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "频道业务码;唯一", requiredMode = Schema.RequiredMode.REQUIRED, example = "system_notice")
|
||||
@NotBlank(message = "频道编码不能为空")
|
||||
@Size(max = 64, message = "频道编码长度不能超过 64")
|
||||
@Pattern(regexp = "^[a-z][a-z0-9_]*$", message = "频道编码只能由小写字母 / 数字 / 下划线组成,且必须以字母开头")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "频道名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "系统公告")
|
||||
@NotBlank(message = "频道名称不能为空")
|
||||
@Size(max = 64, message = "频道名称长度不能超过 64")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "频道头像", example = "https://cdn.example.com/channel/system_notice.png")
|
||||
@Size(max = 512, message = "头像长度不能超过 512")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
@NotNull(message = "排序不能为空")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
@NotNull(message = "状态不能为空")
|
||||
private Integer status; // 参见 CommonStatusEnum 枚举类(0 启用 / 1 禁用)
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.material;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
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;
|
||||
|
||||
@Schema(description = "管理后台 - IM 频道素材分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ImChannelMaterialPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "频道编号", example = "1")
|
||||
private Long channelId;
|
||||
|
||||
@Schema(description = "内容类型", example = "1")
|
||||
private Integer type; // 参见 ImChannelMaterialTypeEnum 枚举类
|
||||
|
||||
@Schema(description = "标题", example = "活动")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "创建时间", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.material;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - IM 频道素材 Response VO")
|
||||
@Data
|
||||
public class ImChannelMaterialRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "频道编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Long channelId;
|
||||
|
||||
@Schema(description = "频道名称(关联查询填充)")
|
||||
private String channelName;
|
||||
|
||||
@Schema(description = "内容类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer type; // 参见 ImChannelMaterialTypeEnum 枚举类
|
||||
|
||||
@Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String title;
|
||||
|
||||
@Schema(description = "封面图")
|
||||
private String coverUrl;
|
||||
|
||||
@Schema(description = "摘要")
|
||||
private String summary;
|
||||
|
||||
@Schema(description = "正文;富文本 HTML")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "跳转链接")
|
||||
private String url;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.material;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - IM 频道素材新增 / 修改 Request VO")
|
||||
@Data
|
||||
public class ImChannelMaterialSaveReqVO {
|
||||
|
||||
@Schema(description = "编号(修改时必填)", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "频道编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "频道编号不能为空")
|
||||
private Long channelId;
|
||||
|
||||
@Schema(description = "内容类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "内容类型不能为空")
|
||||
private Integer type; // 参见 ImChannelMaterialTypeEnum 枚举类
|
||||
|
||||
@Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "双十一活动来啦")
|
||||
@NotBlank(message = "标题不能为空")
|
||||
@Size(max = 128, message = "标题长度不能超过 128")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "封面图", example = "https://cdn.example.com/cover.png")
|
||||
@Size(max = 512, message = "封面图长度不能超过 512")
|
||||
private String coverUrl;
|
||||
|
||||
@Schema(description = "摘要", example = "全场五折,戳详情看玩法")
|
||||
@Size(max = 255, message = "摘要长度不能超过 255")
|
||||
private String summary;
|
||||
|
||||
@Schema(description = "正文;富文本 HTML")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "跳转链接;为空表示走客户端内置详情页", example = "https://example.com/activity/123")
|
||||
@Size(max = 512, message = "跳转链接长度不能超过 512")
|
||||
private String url;
|
||||
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.face;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.item.ImFacePackItemPageReqVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.item.ImFacePackItemRespVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.item.ImFacePackItemSaveReqVO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFacePackItemDO;
|
||||
import cn.iocoder.yudao.module.im.service.face.ImFacePackItemService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - IM 表情包项")
|
||||
@RestController
|
||||
@RequestMapping("/im/manager/face-pack-item")
|
||||
@Validated
|
||||
public class ImFacePackItemManagerController {
|
||||
|
||||
@Resource
|
||||
private ImFacePackItemService facePackItemService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "新增表情")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:face-pack-item:create')")
|
||||
public CommonResult<Long> createFacePackItem(@Valid @RequestBody ImFacePackItemSaveReqVO reqVO) {
|
||||
return success(facePackItemService.createFacePackItem(reqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "修改表情")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:face-pack-item:update')")
|
||||
public CommonResult<Boolean> updateFacePackItem(@Valid @RequestBody ImFacePackItemSaveReqVO reqVO) {
|
||||
facePackItemService.updateFacePackItem(reqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除表情")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "2048")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:face-pack-item:delete')")
|
||||
public CommonResult<Boolean> deleteFacePackItem(@RequestParam("id") Long id) {
|
||||
facePackItemService.deleteFacePackItem(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete-list")
|
||||
@Operation(summary = "批量删除表情")
|
||||
@Parameter(name = "ids", description = "编号列表", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:face-pack-item:delete')")
|
||||
public CommonResult<Boolean> deleteFacePackItemList(
|
||||
@RequestParam("ids") @Size(max = 100, message = "批量删除最多 100 条") List<Long> ids) {
|
||||
facePackItemService.deleteFacePackItemList(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得表情分页")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:face-pack-item:query')")
|
||||
public CommonResult<PageResult<ImFacePackItemRespVO>> getFacePackItemPage(@Valid ImFacePackItemPageReqVO pageReqVO) {
|
||||
PageResult<ImFacePackItemDO> pageResult = facePackItemService.getFacePackItemPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, ImFacePackItemRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得表情详情")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "2048")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:face-pack-item:query')")
|
||||
public CommonResult<ImFacePackItemRespVO> getFacePackItem(@RequestParam("id") Long id) {
|
||||
ImFacePackItemDO item = facePackItemService.getFacePackItem(id);
|
||||
return success(BeanUtils.toBean(item, ImFacePackItemRespVO.class));
|
||||
}
|
||||
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.face;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.pack.ImFacePackPageReqVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.pack.ImFacePackRespVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.pack.ImFacePackSaveReqVO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFacePackDO;
|
||||
import cn.iocoder.yudao.module.im.service.face.ImFacePackService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - IM 表情包")
|
||||
@RestController
|
||||
@RequestMapping("/im/manager/face-pack")
|
||||
@Validated
|
||||
public class ImFacePackManagerController {
|
||||
|
||||
@Resource
|
||||
private ImFacePackService facePackService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "新增表情包")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:face-pack:create')")
|
||||
public CommonResult<Long> createFacePack(@Valid @RequestBody ImFacePackSaveReqVO reqVO) {
|
||||
return success(facePackService.createFacePack(reqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "修改表情包")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:face-pack:update')")
|
||||
public CommonResult<Boolean> updateFacePack(@Valid @RequestBody ImFacePackSaveReqVO reqVO) {
|
||||
facePackService.updateFacePack(reqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除表情包")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:face-pack:delete')")
|
||||
public CommonResult<Boolean> deleteFacePack(@RequestParam("id") Long id) {
|
||||
facePackService.deleteFacePack(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete-list")
|
||||
@Operation(summary = "批量删除表情包")
|
||||
@Parameter(name = "ids", description = "编号列表", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:face-pack:delete')")
|
||||
public CommonResult<Boolean> deleteFacePackList(@RequestParam("ids")
|
||||
@Size(max = 100, message = "批量删除最多 100 条") List<Long> ids) {
|
||||
facePackService.deleteFacePackList(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得表情包分页")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:face-pack:query')")
|
||||
public CommonResult<PageResult<ImFacePackRespVO>> getFacePackPage(@Valid ImFacePackPageReqVO pageReqVO) {
|
||||
PageResult<ImFacePackDO> pageResult = facePackService.getFacePackPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, ImFacePackRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得表情包详情")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:face-pack:query')")
|
||||
public CommonResult<ImFacePackRespVO> getFacePack(@RequestParam("id") Long id) {
|
||||
ImFacePackDO pack = facePackService.getFacePack(id);
|
||||
return success(BeanUtils.toBean(pack, ImFacePackRespVO.class));
|
||||
}
|
||||
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.face;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.useritem.ImFaceUserItemManagerPageReqVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.useritem.ImFaceUserItemManagerRespVO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO;
|
||||
import cn.iocoder.yudao.module.im.service.face.ImFaceUserItemService;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - IM 用户表情")
|
||||
@RestController
|
||||
@RequestMapping("/im/manager/face-user-item")
|
||||
@Validated
|
||||
public class ImFaceUserItemManagerController {
|
||||
|
||||
@Resource
|
||||
private ImFaceUserItemService faceUserItemService;
|
||||
@Resource
|
||||
private AdminUserApi adminUserApi;
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得用户表情分页")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:face-user-item:query')")
|
||||
public CommonResult<PageResult<ImFaceUserItemManagerRespVO>> getFaceUserItemPage(
|
||||
@Valid ImFaceUserItemManagerPageReqVO pageReqVO) {
|
||||
PageResult<ImFaceUserItemDO> pageResult = faceUserItemService.getFaceUserItemPage(pageReqVO);
|
||||
// 关联回填用户昵称
|
||||
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
|
||||
CollectionUtils.convertSet(pageResult.getList(), ImFaceUserItemDO::getUserId));
|
||||
List<ImFaceUserItemManagerRespVO> voList = CollectionUtils.convertList(pageResult.getList(), item -> {
|
||||
ImFaceUserItemManagerRespVO vo = BeanUtils.toBean(item, ImFaceUserItemManagerRespVO.class);
|
||||
AdminUserRespDTO user = userMap.get(item.getUserId());
|
||||
if (user != null) {
|
||||
vo.setUserNickname(user.getNickname());
|
||||
}
|
||||
return vo;
|
||||
});
|
||||
return success(new PageResult<>(voList, pageResult.getTotal()));
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除用户表情")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "4096")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:face-user-item:delete')")
|
||||
public CommonResult<Boolean> deleteFaceUserItem(@RequestParam("id") Long id) {
|
||||
faceUserItemService.deleteFaceUserItem(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.item;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Schema(description = "管理后台 - IM 表情包项分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ImFacePackItemPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "所属表情包编号", example = "1024")
|
||||
private Long packId;
|
||||
|
||||
@Schema(description = "表情名,模糊匹配", example = "狗")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "状态", example = "0")
|
||||
@InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}")
|
||||
private Integer status; // 参见 CommonStatusEnum 枚举类
|
||||
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.item;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - IM 表情包项 Response VO")
|
||||
@Data
|
||||
public class ImFacePackItemRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "所属表情包编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long packId;
|
||||
|
||||
@Schema(description = "表情图 URL", requiredMode = Schema.RequiredMode.REQUIRED,
|
||||
example = "https://cdn.example.com/face/pack/cat-001.png")
|
||||
private String url;
|
||||
|
||||
@Schema(description = "表情名", example = "狗头")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "渲染宽度(像素)", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
|
||||
private Integer width;
|
||||
|
||||
@Schema(description = "渲染高度(像素)", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
|
||||
private Integer height;
|
||||
|
||||
@Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
private Integer status; // 参见 CommonStatusEnum 枚举类
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.item;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - IM 表情包项新增 / 修改 Request VO")
|
||||
@Data
|
||||
public class ImFacePackItemSaveReqVO {
|
||||
|
||||
@Schema(description = "编号(修改时必填)", example = "2048")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "所属表情包编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "表情包编号不能为空")
|
||||
private Long packId;
|
||||
|
||||
@Schema(description = "表情图 URL", requiredMode = Schema.RequiredMode.REQUIRED,
|
||||
example = "https://cdn.example.com/face/pack/cat-001.png")
|
||||
@NotBlank(message = "表情图 URL 不能为空")
|
||||
@Size(max = 512, message = "表情图 URL 长度不能超过 512")
|
||||
private String url;
|
||||
|
||||
@Schema(description = "表情名", example = "狗头")
|
||||
@Size(max = 64, message = "表情名长度不能超过 64")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "渲染宽度(像素)", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
|
||||
@NotNull(message = "渲染宽度不能为空")
|
||||
@Min(value = 1, message = "渲染宽度不能小于 1 像素")
|
||||
@Max(value = 2048, message = "渲染宽度不能大于 2048 像素")
|
||||
private Integer width;
|
||||
|
||||
@Schema(description = "渲染高度(像素)", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
|
||||
@NotNull(message = "渲染高度不能为空")
|
||||
@Min(value = 1, message = "渲染高度不能小于 1 像素")
|
||||
@Max(value = 2048, message = "渲染高度不能大于 2048 像素")
|
||||
private Integer height;
|
||||
|
||||
@Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
@NotNull(message = "排序不能为空")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
@NotNull(message = "状态不能为空")
|
||||
@InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}")
|
||||
private Integer status; // 参见 CommonStatusEnum 枚举类(0 启用 / 1 禁用)
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.pack;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
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;
|
||||
|
||||
@Schema(description = "管理后台 - IM 表情包分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ImFacePackPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "表情包名称,模糊匹配", example = "猫")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "状态", example = "0")
|
||||
@InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}")
|
||||
private Integer status; // 参见 CommonStatusEnum 枚举类
|
||||
|
||||
@Schema(description = "创建时间", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.pack;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - IM 表情包 Response VO")
|
||||
@Data
|
||||
public class ImFacePackRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "表情包名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "猫主子")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "表情包图标", example = "https://cdn.example.com/face/pack/cat.png")
|
||||
private String icon;
|
||||
|
||||
@Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
private Integer status; // 参见 CommonStatusEnum 枚举类
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.pack;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - IM 表情包新增 / 修改 Request VO")
|
||||
@Data
|
||||
public class ImFacePackSaveReqVO {
|
||||
|
||||
@Schema(description = "编号(修改时必填)", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "表情包名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "猫主子")
|
||||
@NotBlank(message = "表情包名称不能为空")
|
||||
@Size(max = 64, message = "表情包名称长度不能超过 64")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "表情包图标", example = "https://cdn.example.com/face/pack/cat.png")
|
||||
@Size(max = 512, message = "图标长度不能超过 512")
|
||||
private String icon;
|
||||
|
||||
@Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
@NotNull(message = "排序不能为空")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
@NotNull(message = "状态不能为空")
|
||||
@InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}")
|
||||
private Integer status; // 参见 CommonStatusEnum 枚举类(0 启用 / 1 禁用)
|
||||
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.useritem;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
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;
|
||||
|
||||
@Schema(description = "管理后台 - IM 用户表情分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ImFaceUserItemManagerPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "所属用户编号", example = "1024")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "表情名,模糊匹配", example = "狗")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "添加时间", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.useritem;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - IM 用户表情 Response VO")
|
||||
@Data
|
||||
public class ImFaceUserItemManagerRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4096")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "所属用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "所属用户昵称", example = "张三")
|
||||
private String userNickname;
|
||||
|
||||
@Schema(description = "表情图 URL", requiredMode = Schema.RequiredMode.REQUIRED,
|
||||
example = "https://cdn.example.com/face/user/abc.gif")
|
||||
private String url;
|
||||
|
||||
@Schema(description = "表情名", example = "狗头")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "渲染宽度(像素)", example = "200")
|
||||
private Integer width;
|
||||
|
||||
@Schema(description = "渲染高度(像素)", example = "200")
|
||||
private Integer height;
|
||||
|
||||
@Schema(description = "添加时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.friend;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.friend.vo.ImFriendManagerPageReqVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.friend.vo.ImFriendManagerRespVO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendDO;
|
||||
import cn.iocoder.yudao.module.im.service.friend.ImFriendService;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
|
||||
|
||||
@Tag(name = "管理后台 - IM 好友管理")
|
||||
@RestController
|
||||
@RequestMapping("/im/manager/friend")
|
||||
@Validated
|
||||
public class ImFriendManagerController {
|
||||
|
||||
@Resource
|
||||
private ImFriendService friendService;
|
||||
@Resource
|
||||
private AdminUserApi adminUserApi;
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得好友关系分页")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:friend:query')")
|
||||
public CommonResult<PageResult<ImFriendManagerRespVO>> getFriendPage(
|
||||
@Valid ImFriendManagerPageReqVO pageReqVO) {
|
||||
// 1. 分页查询
|
||||
PageResult<ImFriendDO> pageResult = friendService.getFriendPage(pageReqVO);
|
||||
if (CollUtil.isEmpty(pageResult.getList())) {
|
||||
return success(PageResult.empty(pageResult.getTotal()));
|
||||
}
|
||||
// 2.1 一次性批量查询用户 + 好友的昵称
|
||||
Set<Long> userIds = convertSetByFlatMap(pageResult.getList(),
|
||||
f -> Stream.of(f.getUserId(), f.getFriendUserId()));
|
||||
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
|
||||
// 2.2 转换为 VO,填充昵称
|
||||
return success(BeanUtils.toBean(pageResult, ImFriendManagerRespVO.class, vo -> {
|
||||
MapUtils.findAndThen(userMap, vo.getUserId(),
|
||||
user -> vo.setUserNickname(user.getNickname()));
|
||||
MapUtils.findAndThen(userMap, vo.getFriendUserId(),
|
||||
user -> vo.setFriendNickname(user.getNickname()));
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.friend;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.friend.vo.ImFriendRequestManagerPageReqVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.friend.vo.ImFriendRequestManagerRespVO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendRequestDO;
|
||||
import cn.iocoder.yudao.module.im.service.friend.ImFriendRequestService;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
|
||||
|
||||
@Tag(name = "管理后台 - IM 好友申请管理")
|
||||
@RestController
|
||||
@RequestMapping("/im/manager/friend-request")
|
||||
@Validated
|
||||
public class ImFriendRequestManagerController {
|
||||
|
||||
@Resource
|
||||
private ImFriendRequestService friendRequestService;
|
||||
@Resource
|
||||
private AdminUserApi adminUserApi;
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得好友申请分页")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:friend-request:query')")
|
||||
public CommonResult<PageResult<ImFriendRequestManagerRespVO>> getFriendRequestPage(
|
||||
@Valid ImFriendRequestManagerPageReqVO pageReqVO) {
|
||||
// 1. 分页查询
|
||||
PageResult<ImFriendRequestDO> pageResult = friendRequestService.getFriendRequestPage(pageReqVO);
|
||||
if (CollUtil.isEmpty(pageResult.getList())) {
|
||||
return success(PageResult.empty(pageResult.getTotal()));
|
||||
}
|
||||
|
||||
// 2.1 一次性批量查询发起方 + 接收方的昵称
|
||||
Set<Long> userIds = convertSetByFlatMap(pageResult.getList(),
|
||||
request -> Stream.of(request.getFromUserId(), request.getToUserId()));
|
||||
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
|
||||
// 2.2 转换为 VO,填充昵称
|
||||
return success(BeanUtils.toBean(pageResult, ImFriendRequestManagerRespVO.class, vo -> {
|
||||
MapUtils.findAndThen(userMap, vo.getFromUserId(),
|
||||
user -> vo.setFromNickname(user.getNickname()));
|
||||
MapUtils.findAndThen(userMap, vo.getToUserId(),
|
||||
user -> vo.setToNickname(user.getNickname()));
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.friend.vo;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
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;
|
||||
|
||||
@Schema(description = "管理后台 - IM 好友关系分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ImFriendManagerPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "用户编号", example = "1024")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "好友用户编号", example = "2048")
|
||||
private Long friendUserId;
|
||||
|
||||
@Schema(description = "好友状态", example = "0")
|
||||
private Integer status; // 参见 CommonStatusEnum 枚举类
|
||||
|
||||
@Schema(description = "是否免打扰", example = "false")
|
||||
private Boolean silent;
|
||||
|
||||
@Schema(description = "添加好友时间", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] addTime;
|
||||
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.friend.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - IM 好友关系 Response VO")
|
||||
@Data
|
||||
public class ImFriendManagerRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "用户昵称", example = "张三")
|
||||
private String userNickname;
|
||||
|
||||
@Schema(description = "好友用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
|
||||
private Long friendUserId;
|
||||
|
||||
@Schema(description = "好友昵称", example = "李四")
|
||||
private String friendNickname;
|
||||
|
||||
@Schema(description = "好友展示备注")
|
||||
private String displayName;
|
||||
|
||||
@Schema(description = "添加来源", example = "1")
|
||||
private Integer addSource; // 参见 ImFriendAddSourceEnum 枚举类
|
||||
|
||||
@Schema(description = "是否免打扰", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
|
||||
private Boolean silent;
|
||||
|
||||
@Schema(description = "是否置顶联系人", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
|
||||
private Boolean pinned;
|
||||
|
||||
@Schema(description = "是否拉黑", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
|
||||
private Boolean blocked;
|
||||
|
||||
@Schema(description = "好友状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
private Integer status; // 参见 CommonStatusEnum 枚举类
|
||||
|
||||
@Schema(description = "添加好友时间")
|
||||
private LocalDateTime addTime;
|
||||
|
||||
@Schema(description = "删除好友时间")
|
||||
private LocalDateTime deleteTime;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.friend.vo;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
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;
|
||||
|
||||
@Schema(description = "管理后台 - IM 好友申请分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ImFriendRequestManagerPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "发起方用户编号", example = "1024")
|
||||
private Long fromUserId;
|
||||
|
||||
@Schema(description = "接收方用户编号", example = "2048")
|
||||
private Long toUserId;
|
||||
|
||||
@Schema(description = "处理结果", example = "0")
|
||||
private Integer handleResult; // 参见 ImFriendRequestHandleResultEnum 枚举类
|
||||
|
||||
@Schema(description = "添加来源", example = "1")
|
||||
private Integer addSource; // 参见 ImFriendAddSourceEnum 枚举类
|
||||
|
||||
@Schema(description = "创建时间", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.friend.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - IM 好友申请 Response VO")
|
||||
@Data
|
||||
public class ImFriendRequestManagerRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "发起方用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long fromUserId;
|
||||
|
||||
@Schema(description = "发起方昵称", example = "张三")
|
||||
private String fromNickname;
|
||||
|
||||
@Schema(description = "接收方用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
|
||||
private Long toUserId;
|
||||
|
||||
@Schema(description = "接收方昵称", example = "李四")
|
||||
private String toNickname;
|
||||
|
||||
@Schema(description = "申请理由", example = "我是芋艿")
|
||||
private String applyContent;
|
||||
|
||||
@Schema(description = "发起方对接收方的备注")
|
||||
private String displayName;
|
||||
|
||||
@Schema(description = "添加来源", example = "1")
|
||||
private Integer addSource; // 参见 ImFriendAddSourceEnum 枚举类
|
||||
|
||||
@Schema(description = "处理结果", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
private Integer handleResult; // 参见 ImFriendRequestHandleResultEnum 枚举类
|
||||
|
||||
@Schema(description = "处理理由", example = "暂不通过")
|
||||
private String handleContent;
|
||||
|
||||
@Schema(description = "处理时间")
|
||||
private LocalDateTime handleTime;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.group;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.group.vo.ImGroupManagerBanReqVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.group.vo.ImGroupManagerPageReqVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.group.vo.ImGroupManagerRespVO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
|
||||
import cn.iocoder.yudao.module.im.service.group.ImGroupMemberService;
|
||||
import cn.iocoder.yudao.module.im.service.group.ImGroupService;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
|
||||
@Tag(name = "管理后台 - IM 群聊管理")
|
||||
@RestController
|
||||
@RequestMapping("/im/manager/group")
|
||||
@Validated
|
||||
public class ImGroupManagerController {
|
||||
|
||||
@Resource
|
||||
private ImGroupService groupService;
|
||||
@Resource
|
||||
private ImGroupMemberService groupMemberService;
|
||||
|
||||
@Resource
|
||||
private AdminUserApi adminUserApi;
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得群分页")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:group:query')")
|
||||
public CommonResult<PageResult<ImGroupManagerRespVO>> getGroupPage(@Valid ImGroupManagerPageReqVO pageReqVO) {
|
||||
// 1. 分页查询群
|
||||
PageResult<ImGroupDO> pageResult = groupService.getGroupPage(pageReqVO);
|
||||
if (CollUtil.isEmpty(pageResult.getList())) {
|
||||
return success(PageResult.empty(pageResult.getTotal()));
|
||||
}
|
||||
// 2.1 批量查询相关数据
|
||||
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
|
||||
convertSet(pageResult.getList(), ImGroupDO::getOwnerUserId));
|
||||
Map<Long, Long> memberCountMap = groupMemberService.getActiveMemberCountMap(
|
||||
convertSet(pageResult.getList(), ImGroupDO::getId));
|
||||
// 2.2 转换为 VO,填充群主昵称、群成员数量
|
||||
return success(BeanUtils.toBean(pageResult, ImGroupManagerRespVO.class, vo -> {
|
||||
MapUtils.findAndThen(userMap, vo.getOwnerUserId(),
|
||||
user -> vo.setOwnerNickname(user.getNickname()));
|
||||
vo.setMemberCount(memberCountMap.getOrDefault(vo.getId(), 0L).intValue());
|
||||
}));
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得群详情")
|
||||
@Parameter(name = "id", description = "群编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:group:query')")
|
||||
public CommonResult<ImGroupManagerRespVO> getGroup(@RequestParam("id") Long id) {
|
||||
ImGroupDO group = groupService.getGroup(id);
|
||||
return success(BeanUtils.toBean(group, ImGroupManagerRespVO.class));
|
||||
}
|
||||
|
||||
@PutMapping("/ban")
|
||||
@Operation(summary = "封禁群")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:group:ban')")
|
||||
public CommonResult<Boolean> banGroup(@Valid @RequestBody ImGroupManagerBanReqVO reqVO) {
|
||||
groupService.banGroup(getLoginUserId(), reqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/unban")
|
||||
@Operation(summary = "解封群")
|
||||
@Parameter(name = "id", description = "群编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:group:ban')")
|
||||
public CommonResult<Boolean> unbanGroup(@RequestParam("id") Long id) {
|
||||
groupService.unbanGroup(getLoginUserId(), id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/dissolve")
|
||||
@Operation(summary = "解散群")
|
||||
@Parameter(name = "id", description = "群编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:group:dissolve')")
|
||||
public CommonResult<Boolean> dissolveGroup(@RequestParam("id") Long id) {
|
||||
groupService.dissolveGroupByManager(getLoginUserId(), id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.group;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.group.vo.member.ImGroupMemberManagerRespVO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
|
||||
import cn.iocoder.yudao.module.im.service.group.ImGroupMemberService;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
|
||||
@Tag(name = "管理后台 - IM 群成员管理")
|
||||
@RestController
|
||||
@RequestMapping("/im/manager/group/member")
|
||||
@Validated
|
||||
public class ImGroupMemberManagerController {
|
||||
|
||||
@Resource
|
||||
private ImGroupMemberService groupMemberService;
|
||||
@Resource
|
||||
private AdminUserApi adminUserApi;
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获得群成员列表(含已退群成员,由前端按需过滤)")
|
||||
@Parameter(name = "groupId", description = "群编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:group:query')")
|
||||
public CommonResult<List<ImGroupMemberManagerRespVO>> getGroupMemberList(@RequestParam("groupId") Long groupId) {
|
||||
// 1. 查询群全部成员(含已退群)
|
||||
List<ImGroupMemberDO> members = groupMemberService.getGroupMemberListByGroupId(groupId);
|
||||
if (CollUtil.isEmpty(members)) {
|
||||
return success(Collections.emptyList());
|
||||
}
|
||||
// 2.1 批量查询用户信息
|
||||
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
|
||||
convertSet(members, ImGroupMemberDO::getUserId));
|
||||
// 2.2 转换为 VO,填充昵称、头像
|
||||
return success(BeanUtils.toBean(members, ImGroupMemberManagerRespVO.class, vo ->
|
||||
MapUtils.findAndThen(userMap, vo.getUserId(), user ->
|
||||
vo.setNickname(user.getNickname()).setAvatar(user.getAvatar()))));
|
||||
}
|
||||
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.group;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.group.vo.ImGroupRequestManagerPageReqVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.group.vo.ImGroupRequestManagerRespVO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupRequestDO;
|
||||
import cn.iocoder.yudao.module.im.service.group.ImGroupRequestService;
|
||||
import cn.iocoder.yudao.module.im.service.group.ImGroupService;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
|
||||
|
||||
@Tag(name = "管理后台 - IM 加群申请管理")
|
||||
@RestController
|
||||
@RequestMapping("/im/manager/group-request")
|
||||
@Validated
|
||||
public class ImGroupRequestManagerController {
|
||||
|
||||
@Resource
|
||||
private ImGroupRequestService groupRequestService;
|
||||
@Resource
|
||||
private ImGroupService groupService;
|
||||
@Resource
|
||||
private AdminUserApi adminUserApi;
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得加群申请分页")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:group-request:query')")
|
||||
public CommonResult<PageResult<ImGroupRequestManagerRespVO>> getGroupRequestPage(
|
||||
@Valid ImGroupRequestManagerPageReqVO pageReqVO) {
|
||||
// 1. 分页查询
|
||||
PageResult<ImGroupRequestDO> pageResult = groupRequestService.getGroupRequestPage(pageReqVO);
|
||||
if (CollUtil.isEmpty(pageResult.getList())) {
|
||||
return success(PageResult.empty(pageResult.getTotal()));
|
||||
}
|
||||
|
||||
// 2.1 批量聚合 user / inviter / handler 用户昵称
|
||||
Set<Long> userIds = convertSetByFlatMap(pageResult.getList(),
|
||||
request -> Stream.of(request.getUserId(), request.getInviterUserId(), request.getHandleUserId())
|
||||
.filter(Objects::nonNull));
|
||||
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
|
||||
// 2.2 批量聚合群信息(取群名)
|
||||
Set<Long> groupIds = convertSet(pageResult.getList(), ImGroupRequestDO::getGroupId);
|
||||
Map<Long, ImGroupDO> groupMap = groupService.getGroupMap(groupIds);
|
||||
return success(BeanUtils.toBean(pageResult, ImGroupRequestManagerRespVO.class, vo -> {
|
||||
MapUtils.findAndThen(userMap, vo.getUserId(), user -> vo.setUserNickname(user.getNickname()));
|
||||
MapUtils.findAndThen(userMap, vo.getInviterUserId(), user -> vo.setInviterNickname(user.getNickname()));
|
||||
MapUtils.findAndThen(userMap, vo.getHandleUserId(), user -> vo.setHandleNickname(user.getNickname()));
|
||||
MapUtils.findAndThen(groupMap, vo.getGroupId(), group -> vo.setGroupName(group.getName()));
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.group.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - IM 群聊封禁 Request VO")
|
||||
@Data
|
||||
public class ImGroupManagerBanReqVO {
|
||||
|
||||
@Schema(description = "群编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "群编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "封禁原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "违规内容")
|
||||
@NotBlank(message = "封禁原因不能为空")
|
||||
@Size(max = 200, message = "封禁原因长度不能超过 200")
|
||||
private String reason;
|
||||
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.group.vo;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
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;
|
||||
|
||||
@Schema(description = "管理后台 - IM 群聊分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ImGroupManagerPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "群名称,模糊匹配", example = "技术交流群")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "群主用户编号", example = "1024")
|
||||
private Long ownerUserId;
|
||||
|
||||
@Schema(description = "群状态", example = "0")
|
||||
private Integer status; // 参见 CommonStatusEnum 枚举类(0 正常 / 1 已解散)
|
||||
|
||||
@Schema(description = "是否封禁", example = "false")
|
||||
private Boolean banned;
|
||||
|
||||
@Schema(description = "创建时间", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.group.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - IM 群聊 Response VO")
|
||||
@Data
|
||||
public class ImGroupManagerRespVO {
|
||||
|
||||
@Schema(description = "群编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "群名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "技术交流群")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "群头像")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "群公告")
|
||||
private String notice;
|
||||
|
||||
@Schema(description = "群主用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long ownerUserId;
|
||||
|
||||
@Schema(description = "群主昵称", example = "张三")
|
||||
private String ownerNickname;
|
||||
|
||||
@Schema(description = "群成员数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "12")
|
||||
private Integer memberCount;
|
||||
|
||||
@Schema(description = "群状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
private Integer status; // 参见 CommonStatusEnum 枚举类
|
||||
|
||||
@Schema(description = "解散时间")
|
||||
private LocalDateTime dissolvedTime;
|
||||
|
||||
@Schema(description = "是否封禁", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
|
||||
private Boolean banned;
|
||||
|
||||
@Schema(description = "是否全群禁言")
|
||||
private Boolean mutedAll;
|
||||
|
||||
@Schema(description = "封禁原因")
|
||||
private String bannedReason;
|
||||
|
||||
@Schema(description = "封禁时间")
|
||||
private LocalDateTime bannedTime;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.group.vo;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
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;
|
||||
|
||||
@Schema(description = "管理后台 - IM 加群申请分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ImGroupRequestManagerPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "群编号", example = "1024")
|
||||
private Long groupId;
|
||||
|
||||
@Schema(description = "申请人 / 被邀请人用户编号", example = "2048")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "邀请人用户编号", example = "31460")
|
||||
private Long inviterUserId;
|
||||
|
||||
@Schema(description = "处理结果", example = "0")
|
||||
private Integer handleResult; // 参见 ImGroupRequestHandleResultEnum 枚举类
|
||||
|
||||
@Schema(description = "加入来源", example = "1")
|
||||
private Integer addSource; // 参见 ImGroupAddSourceEnum 枚举类
|
||||
|
||||
@Schema(description = "创建时间", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.group.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - IM 加群申请 Response VO")
|
||||
@Data
|
||||
public class ImGroupRequestManagerRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "群编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long groupId;
|
||||
|
||||
@Schema(description = "群名称", example = "芋道技术交流群")
|
||||
private String groupName;
|
||||
|
||||
@Schema(description = "申请人 / 被邀请人用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "申请人 / 被邀请人昵称", example = "张三")
|
||||
private String userNickname;
|
||||
|
||||
@Schema(description = "邀请人用户编号;NULL 表示用户主动申请", example = "200")
|
||||
private Long inviterUserId;
|
||||
|
||||
@Schema(description = "邀请人昵称", example = "老张")
|
||||
private String inviterNickname;
|
||||
|
||||
@Schema(description = "申请理由", example = "我想加入这个群")
|
||||
private String applyContent;
|
||||
|
||||
@Schema(description = "加入来源", example = "1")
|
||||
private Integer addSource; // 参见 ImGroupAddSourceEnum 枚举类
|
||||
|
||||
@Schema(description = "处理结果", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
private Integer handleResult; // 参见 ImGroupRequestHandleResultEnum 枚举类
|
||||
|
||||
@Schema(description = "处理人用户编号", example = "31460")
|
||||
private Long handleUserId;
|
||||
|
||||
@Schema(description = "处理人昵称", example = "管理员")
|
||||
private String handleNickname;
|
||||
|
||||
@Schema(description = "处理理由", example = "暂不通过")
|
||||
private String handleContent;
|
||||
|
||||
@Schema(description = "处理时间")
|
||||
private LocalDateTime handleTime;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.group.vo.member;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - IM 群成员 Response VO")
|
||||
@Data
|
||||
public class ImGroupMemberManagerRespVO {
|
||||
|
||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "用户昵称", example = "张三")
|
||||
private String nickname;
|
||||
|
||||
@Schema(description = "用户头像")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "组内显示名", example = "三哥")
|
||||
private String displayUserName;
|
||||
|
||||
@Schema(description = "群备注", example = "技术交流群")
|
||||
private String groupRemark;
|
||||
|
||||
@Schema(description = "是否免打扰", example = "false")
|
||||
private Boolean silent;
|
||||
|
||||
@Schema(description = "成员状态", example = "0")
|
||||
private Integer status; // 参见 CommonStatusEnum 枚举类
|
||||
|
||||
@Schema(description = "成员角色;1=群主 2=管理员 3=普通成员", example = "3")
|
||||
private Integer role; // 参见 ImGroupMemberRoleEnum 枚举类
|
||||
|
||||
@Schema(description = "入群时间")
|
||||
private LocalDateTime joinTime;
|
||||
|
||||
@Schema(description = "退群时间")
|
||||
private LocalDateTime quitTime;
|
||||
|
||||
@Schema(description = "禁言到期时间")
|
||||
private LocalDateTime muteEndTime;
|
||||
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.message;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.channel.ImChannelMessagePageReqVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.channel.ImChannelMessageRespVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.channel.ImChannelMessageSendReqVO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.channel.ImChannelDO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.channel.ImChannelMaterialDO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.message.ImChannelMessageDO;
|
||||
import cn.iocoder.yudao.module.im.service.channel.ImChannelMaterialService;
|
||||
import cn.iocoder.yudao.module.im.service.message.ImChannelMessageService;
|
||||
import cn.iocoder.yudao.module.im.service.channel.ImChannelService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
|
||||
@Tag(name = "管理后台 - IM 频道消息")
|
||||
@RestController
|
||||
@RequestMapping("/im/manager/channel-message")
|
||||
@Validated
|
||||
public class ImChannelMessageManagerController {
|
||||
|
||||
@Resource
|
||||
private ImChannelMessageService channelMessageService;
|
||||
@Resource
|
||||
private ImChannelService channelService;
|
||||
@Resource
|
||||
private ImChannelMaterialService channelMaterialService;
|
||||
|
||||
@PostMapping("/send")
|
||||
@Operation(summary = "立即推送频道消息")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:channel-message:send')")
|
||||
public CommonResult<Long> sendMessage(@Valid @RequestBody ImChannelMessageSendReqVO reqVO) {
|
||||
return success(channelMessageService.sendMessage(reqVO));
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除频道消息")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:channel-message:delete')")
|
||||
public CommonResult<Boolean> deleteMessage(@RequestParam("id") Long id) {
|
||||
channelMessageService.deleteMessage(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得频道消息分页;回填频道名 / 素材标题")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:channel-message:query')")
|
||||
public CommonResult<PageResult<ImChannelMessageRespVO>> getMessagePage(@Valid ImChannelMessagePageReqVO pageReqVO) {
|
||||
PageResult<ImChannelMessageDO> pageResult = channelMessageService.getMessagePage(pageReqVO);
|
||||
if (CollUtil.isEmpty(pageResult.getList())) {
|
||||
return success(PageResult.empty(pageResult.getTotal()));
|
||||
}
|
||||
// 批量查询频道和素材,并回填频道名 / 素材标题
|
||||
Map<Long, ImChannelDO> channelMap = channelService.getChannelMap(
|
||||
convertSet(pageResult.getList(), ImChannelMessageDO::getChannelId));
|
||||
Map<Long, ImChannelMaterialDO> materialMap = channelMaterialService.getMaterialMap(
|
||||
convertSet(pageResult.getList(), ImChannelMessageDO::getMaterialId));
|
||||
return success(BeanUtils.toBean(pageResult, ImChannelMessageRespVO.class, vo -> {
|
||||
MapUtils.findAndThen(channelMap, vo.getChannelId(), c -> vo.setChannelName(c.getName()));
|
||||
MapUtils.findAndThen(materialMap, vo.getMaterialId(),
|
||||
material -> vo.setMaterialTitle(material.getTitle()).setMaterialCoverUrl(material.getCoverUrl()));
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.message;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.group.ImGroupMessageManagerPageReqVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.group.ImGroupMessageManagerRespVO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.message.ImGroupMessageDO;
|
||||
import cn.iocoder.yudao.module.im.service.group.ImGroupService;
|
||||
import cn.iocoder.yudao.module.im.service.message.ImGroupMessageService;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
|
||||
import static cn.iocoder.yudao.module.im.enums.ImCommonConstants.AT_USER_ID_ALL;
|
||||
|
||||
@Tag(name = "管理后台 - IM 群聊消息")
|
||||
@RestController
|
||||
@RequestMapping("/im/manager/message/group")
|
||||
@Validated
|
||||
public class ImGroupMessageManagerController {
|
||||
|
||||
@Resource
|
||||
private ImGroupMessageService groupMessageService;
|
||||
@Resource
|
||||
private ImGroupService groupService;
|
||||
@Resource
|
||||
private AdminUserApi adminUserApi;
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得群聊消息分页")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:message:query')")
|
||||
public CommonResult<PageResult<ImGroupMessageManagerRespVO>> getGroupMessagePage(
|
||||
@Valid ImGroupMessageManagerPageReqVO pageReqVO) {
|
||||
// 1. 分页查询
|
||||
PageResult<ImGroupMessageDO> pageResult = groupMessageService.getGroupMessagePage(pageReqVO);
|
||||
if (CollUtil.isEmpty(pageResult.getList())) {
|
||||
return success(PageResult.empty(pageResult.getTotal()));
|
||||
}
|
||||
// 2.1 批量查询群名称、发送人昵称、@ 用户昵称(-1 表示 @所有人,跳过查询,由前端判断渲染)
|
||||
Map<Long, ImGroupDO> groupMap = groupService.getGroupMap(
|
||||
convertSet(pageResult.getList(), ImGroupMessageDO::getGroupId));
|
||||
Set<Long> userIds = convertSetByFlatMap(pageResult.getList(), m -> Stream.concat(
|
||||
Stream.of(m.getSenderId()),
|
||||
CollUtil.emptyIfNull(m.getAtUserIds()).stream()
|
||||
.filter(id -> !Objects.equals(id, AT_USER_ID_ALL))));
|
||||
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
|
||||
// 2.2 转换为 VO,填充群名 / 发送人昵称 / @ 用户昵称(-1 位置留 null,由前端展示「@所有人」)
|
||||
return success(BeanUtils.toBean(pageResult, ImGroupMessageManagerRespVO.class, vo -> {
|
||||
MapUtils.findAndThen(groupMap, vo.getGroupId(), group -> vo.setGroupName(group.getName()));
|
||||
MapUtils.findAndThen(userMap, vo.getSenderId(), user -> vo.setSenderNickname(user.getNickname()));
|
||||
if (CollUtil.isNotEmpty(vo.getAtUserIds())) {
|
||||
vo.setAtUserNicknames(convertList(vo.getAtUserIds(), id -> {
|
||||
AdminUserRespDTO user = userMap.get(id);
|
||||
return user != null ? user.getNickname() : null;
|
||||
}));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得群聊消息详情")
|
||||
@Parameter(name = "id", description = "消息编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:message:query')")
|
||||
public CommonResult<ImGroupMessageManagerRespVO> getGroupMessage(@RequestParam("id") Long id) {
|
||||
ImGroupMessageDO message = groupMessageService.getGroupMessage(id);
|
||||
return success(BeanUtils.toBean(message, ImGroupMessageManagerRespVO.class));
|
||||
}
|
||||
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.message;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.privates.ImPrivateMessageManagerPageReqVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.privates.ImPrivateMessageManagerRespVO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.message.ImPrivateMessageDO;
|
||||
import cn.iocoder.yudao.module.im.service.message.ImPrivateMessageService;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
|
||||
|
||||
@Tag(name = "管理后台 - IM 私聊消息")
|
||||
@RestController
|
||||
@RequestMapping("/im/manager/message/private")
|
||||
@Validated
|
||||
public class ImPrivateMessageManagerController {
|
||||
|
||||
@Resource
|
||||
private ImPrivateMessageService privateMessageService;
|
||||
@Resource
|
||||
private AdminUserApi adminUserApi;
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得私聊消息分页")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:message:query')")
|
||||
public CommonResult<PageResult<ImPrivateMessageManagerRespVO>> getPrivateMessagePage(
|
||||
@Valid ImPrivateMessageManagerPageReqVO pageReqVO) {
|
||||
// 1. 分页查询
|
||||
PageResult<ImPrivateMessageDO> pageResult = privateMessageService.getPrivateMessagePage(pageReqVO);
|
||||
if (CollUtil.isEmpty(pageResult.getList())) {
|
||||
return success(PageResult.empty(pageResult.getTotal()));
|
||||
}
|
||||
// 2.1 一次性批量查询发送人 + 接收人昵称
|
||||
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertSetByFlatMap(pageResult.getList(),
|
||||
m -> Stream.of(m.getSenderId(), m.getReceiverId())));
|
||||
// 2.2 转换为 VO,填充昵称
|
||||
return success(BeanUtils.toBean(pageResult, ImPrivateMessageManagerRespVO.class, vo -> {
|
||||
MapUtils.findAndThen(userMap, vo.getSenderId(), user -> vo.setSenderNickname(user.getNickname()));
|
||||
MapUtils.findAndThen(userMap, vo.getReceiverId(), user -> vo.setReceiverNickname(user.getNickname()));
|
||||
}));
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得私聊消息详情")
|
||||
@Parameter(name = "id", description = "消息编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:message:query')")
|
||||
public CommonResult<ImPrivateMessageManagerRespVO> getPrivateMessage(@RequestParam("id") Long id) {
|
||||
ImPrivateMessageDO message = privateMessageService.getPrivateMessage(id);
|
||||
return success(BeanUtils.toBean(message, ImPrivateMessageManagerRespVO.class));
|
||||
}
|
||||
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.channel;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
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;
|
||||
|
||||
@Schema(description = "管理后台 - IM 频道消息分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ImChannelMessagePageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "频道编号", example = "1")
|
||||
private Long channelId;
|
||||
|
||||
@Schema(description = "素材编号", example = "1024")
|
||||
private Long materialId;
|
||||
|
||||
@Schema(description = "发送时间", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] sendTime;
|
||||
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.channel;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - IM 频道消息 Response VO")
|
||||
@Data
|
||||
public class ImChannelMessageRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "频道编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Long channelId;
|
||||
|
||||
@Schema(description = "频道名称(关联查询填充)")
|
||||
private String channelName;
|
||||
|
||||
@Schema(description = "素材编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long materialId;
|
||||
|
||||
@Schema(description = "素材标题(关联查询填充)")
|
||||
private String materialTitle;
|
||||
|
||||
@Schema(description = "素材封面 URL(关联查询填充)")
|
||||
private String materialCoverUrl;
|
||||
|
||||
@Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "125")
|
||||
private Integer type; // 参见 ImMessageTypeEnum 枚举类
|
||||
|
||||
@Schema(description = "消息内容;payload JSON 快照")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "接收人编号列表;为空表示全员")
|
||||
private List<Long> receiverUserIds;
|
||||
|
||||
@Schema(description = "发送时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime sendTime;
|
||||
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.channel;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - IM 频道消息推送 Request VO")
|
||||
@Data
|
||||
public class ImChannelMessageSendReqVO {
|
||||
|
||||
@Schema(description = "素材编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "素材编号不能为空")
|
||||
private Long materialId;
|
||||
|
||||
@Schema(description = "接收人编号列表;为空表示全员", example = "[1024, 2048]")
|
||||
private List<Long> receiverUserIds;
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.group;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
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;
|
||||
|
||||
@Schema(description = "管理后台 - IM 群聊消息分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ImGroupMessageManagerPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "群编号", example = "1024")
|
||||
private Long groupId;
|
||||
|
||||
@Schema(description = "发送人编号", example = "1024")
|
||||
private Long senderId;
|
||||
|
||||
@Schema(description = "消息类型", example = "1")
|
||||
private Integer type; // 参见 ImMessageTypeEnum 枚举类
|
||||
|
||||
@Schema(description = "消息内容", example = "你好")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "消息状态", example = "0")
|
||||
private Integer status; // 参见 ImMessageStatusEnum 枚举类
|
||||
|
||||
@Schema(description = "发送时间", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] sendTime;
|
||||
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.group;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - IM 群聊消息 Response VO")
|
||||
@Data
|
||||
public class ImGroupMessageManagerRespVO {
|
||||
|
||||
@Schema(description = "消息编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "客户端消息编号", example = "c-uuid-xxx")
|
||||
private String clientMessageId;
|
||||
|
||||
@Schema(description = "群编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long groupId;
|
||||
|
||||
@Schema(description = "群名称", example = "技术交流群")
|
||||
private String groupName;
|
||||
|
||||
@Schema(description = "发送人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long senderId;
|
||||
|
||||
@Schema(description = "发送人昵称", example = "张三")
|
||||
private String senderNickname;
|
||||
|
||||
@Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer type; // 参见 ImMessageTypeEnum 枚举类
|
||||
|
||||
@Schema(description = "消息内容(JSON 格式)", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String content;
|
||||
|
||||
@Schema(description = "消息状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
private Integer status; // 参见 ImMessageStatusEnum 枚举类
|
||||
|
||||
@Schema(description = "@ 目标用户编号列表(-1 表示 @所有人)")
|
||||
private List<Long> atUserIds;
|
||||
@Schema(description = "@ 目标用户昵称列表(-1 位置为 null,前端根据 atUserIds 自行展示「@所有人」)")
|
||||
private List<String> atUserNicknames;
|
||||
|
||||
@Schema(description = "回执状态", example = "0")
|
||||
private Integer receiptStatus; // 参见 ImGroupMessageReceiptStatusEnum 枚举类
|
||||
|
||||
@Schema(description = "发送时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime sendTime;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.privates;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
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;
|
||||
|
||||
@Schema(description = "管理后台 - IM 私聊消息分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ImPrivateMessageManagerPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "发送人编号", example = "1024")
|
||||
private Long senderId;
|
||||
|
||||
@Schema(description = "接收人编号", example = "2048")
|
||||
private Long receiverId;
|
||||
|
||||
@Schema(description = "消息类型", example = "1")
|
||||
private Integer type; // 参见 ImMessageTypeEnum 枚举类
|
||||
|
||||
@Schema(description = "消息内容", example = "你好")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "消息状态", example = "0")
|
||||
private Integer status; // 参见 ImMessageStatusEnum 枚举类
|
||||
|
||||
@Schema(description = "发送时间", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] sendTime;
|
||||
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.privates;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - IM 私聊消息 Response VO")
|
||||
@Data
|
||||
public class ImPrivateMessageManagerRespVO {
|
||||
|
||||
@Schema(description = "消息编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "客户端消息编号", example = "c-uuid-xxx")
|
||||
private String clientMessageId;
|
||||
|
||||
@Schema(description = "发送人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long senderId;
|
||||
|
||||
@Schema(description = "发送人昵称", example = "张三")
|
||||
private String senderNickname;
|
||||
|
||||
@Schema(description = "接收人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
|
||||
private Long receiverId;
|
||||
|
||||
@Schema(description = "接收人昵称", example = "李四")
|
||||
private String receiverNickname;
|
||||
|
||||
@Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer type; // 参见 ImMessageTypeEnum 枚举类
|
||||
|
||||
@Schema(description = "消息内容(JSON 格式)", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String content;
|
||||
|
||||
@Schema(description = "消息状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
private Integer status; // 参见 ImMessageStatusEnum 枚举类
|
||||
|
||||
@Schema(description = "发送时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime sendTime;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.rtc;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.rtc.vo.ImRtcCallManagerPageReqVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.rtc.vo.ImRtcCallManagerRespVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.rtc.vo.ImRtcParticipantManagerRespVO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcCallDO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcParticipantDO;
|
||||
import cn.iocoder.yudao.module.im.service.group.ImGroupService;
|
||||
import cn.iocoder.yudao.module.im.service.rtc.ImRtcCallService;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
|
||||
@Tag(name = "管理后台 - IM 通话记录")
|
||||
@RestController
|
||||
@RequestMapping("/im/manager/rtc")
|
||||
@Validated
|
||||
public class ImRtcCallManagerController {
|
||||
|
||||
@Resource
|
||||
private ImRtcCallService rtcCallService;
|
||||
@Resource
|
||||
private ImGroupService groupService;
|
||||
|
||||
@Resource
|
||||
private AdminUserApi adminUserApi;
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得通话记录分页")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:rtc:query')")
|
||||
public CommonResult<PageResult<ImRtcCallManagerRespVO>> getCallPage(@Valid ImRtcCallManagerPageReqVO pageReqVO) {
|
||||
PageResult<ImRtcCallDO> pageResult = rtcCallService.getCallPage(pageReqVO);
|
||||
return success(buildCallRespVOPage(pageResult));
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得通话记录详情")
|
||||
@Parameter(name = "id", description = "通话编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:rtc:query')")
|
||||
public CommonResult<ImRtcCallManagerRespVO> getCall(@RequestParam("id") Long id) {
|
||||
ImRtcCallDO call = rtcCallService.getCall(id);
|
||||
if (call == null) {
|
||||
return success(null);
|
||||
}
|
||||
return success(CollUtil.getFirst(buildCallRespVOList(Collections.singletonList(call))));
|
||||
}
|
||||
|
||||
@GetMapping("/participant-list")
|
||||
@Operation(summary = "获得通话参与者列表")
|
||||
@Parameter(name = "id", description = "通话编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:rtc:query')")
|
||||
public CommonResult<List<ImRtcParticipantManagerRespVO>> getCallParticipantList(@RequestParam("id") Long id) {
|
||||
List<ImRtcParticipantDO> participants = rtcCallService.getCallParticipantListByCallId(id);
|
||||
if (CollUtil.isEmpty(participants)) {
|
||||
return success(Collections.emptyList());
|
||||
}
|
||||
// 查询用户信息
|
||||
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
|
||||
convertSet(participants, ImRtcParticipantDO::getUserId));
|
||||
// 组装返回
|
||||
return success(BeanUtils.toBean(participants, ImRtcParticipantManagerRespVO.class, vo ->
|
||||
MapUtils.findAndThen(userMap, vo.getUserId(),
|
||||
user -> vo.setUserNickname(user.getNickname()))));
|
||||
}
|
||||
|
||||
// ========== 私有方法:VO 组装 ==========
|
||||
|
||||
private PageResult<ImRtcCallManagerRespVO> buildCallRespVOPage(PageResult<ImRtcCallDO> pageResult) {
|
||||
if (CollUtil.isEmpty(pageResult.getList())) {
|
||||
return PageResult.empty(pageResult.getTotal());
|
||||
}
|
||||
return new PageResult<>(buildCallRespVOList(pageResult.getList()), pageResult.getTotal());
|
||||
}
|
||||
|
||||
private List<ImRtcCallManagerRespVO> buildCallRespVOList(List<ImRtcCallDO> calls) {
|
||||
// 查询用户信息
|
||||
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
|
||||
convertSet(calls, ImRtcCallDO::getInviterUserId));
|
||||
Map<Long, ImGroupDO> groupMap = groupService.getGroupMap(
|
||||
convertSet(calls, ImRtcCallDO::getGroupId));
|
||||
// 组装返回
|
||||
return BeanUtils.toBean(calls, ImRtcCallManagerRespVO.class, vo -> {
|
||||
MapUtils.findAndThen(userMap, vo.getInviterUserId(),
|
||||
user -> vo.setInviterNickname(user.getNickname()));
|
||||
MapUtils.findAndThen(groupMap, vo.getGroupId(),
|
||||
group -> vo.setGroupName(group.getName()));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.rtc.vo;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
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;
|
||||
|
||||
@Schema(description = "管理后台 - IM 通话记录分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ImRtcCallManagerPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "发起人用户编号", example = "1024")
|
||||
private Long inviterUserId;
|
||||
|
||||
@Schema(description = "会话类型", example = "1")
|
||||
private Integer conversationType; // 参见 ImConversationTypeEnum 枚举类
|
||||
|
||||
@Schema(description = "媒体类型", example = "1")
|
||||
private Integer mediaType; // 参见 ImRtcCallMediaTypeEnum 枚举类
|
||||
|
||||
@Schema(description = "通话状态", example = "10")
|
||||
private Integer status; // 参见 ImRtcCallStatusEnum 枚举类
|
||||
|
||||
@Schema(description = "结束原因", example = "1")
|
||||
private Integer endReason; // 参见 ImRtcCallEndReasonEnum 枚举类
|
||||
|
||||
@Schema(description = "发起时间", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] startTime;
|
||||
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.rtc.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - IM 通话记录 Response VO")
|
||||
@Data
|
||||
public class ImRtcCallManagerRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "业务通话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "uuid-xxx")
|
||||
private String room;
|
||||
|
||||
@Schema(description = "会话类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer conversationType; // 参见 ImConversationTypeEnum 枚举类
|
||||
|
||||
@Schema(description = "媒体类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer mediaType; // 参见 ImRtcCallMediaTypeEnum 枚举类
|
||||
|
||||
@Schema(description = "发起人用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long inviterUserId;
|
||||
|
||||
@Schema(description = "发起人昵称", example = "张三")
|
||||
private String inviterNickname;
|
||||
|
||||
@Schema(description = "群编号;私聊为空", example = "999")
|
||||
private Long groupId;
|
||||
|
||||
@Schema(description = "群名称;私聊为空", example = "测试群")
|
||||
private String groupName;
|
||||
|
||||
@Schema(description = "通话状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||
private Integer status; // 参见 ImRtcCallStatusEnum 枚举类
|
||||
|
||||
@Schema(description = "结束原因", example = "1")
|
||||
private Integer endReason; // 参见 ImRtcCallEndReasonEnum 枚举类
|
||||
|
||||
@Schema(description = "发起时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime startTime;
|
||||
|
||||
@Schema(description = "接通时间;未接通为空")
|
||||
private LocalDateTime acceptTime;
|
||||
|
||||
@Schema(description = "结束时间;未结束为空")
|
||||
private LocalDateTime endTime;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.rtc.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - IM 通话参与者 Response VO")
|
||||
@Data
|
||||
public class ImRtcParticipantManagerRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "通话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
|
||||
private Long callId;
|
||||
|
||||
@Schema(description = "参与者用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "参与者昵称", example = "张三")
|
||||
private String userNickname;
|
||||
|
||||
@Schema(description = "参与角色", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer role; // 参见 ImRtcParticipantRoleEnum 枚举类
|
||||
|
||||
@Schema(description = "参与状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
|
||||
private Integer status; // 参见 ImRtcParticipantStatusEnum 枚举类
|
||||
|
||||
@Schema(description = "被邀请时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime inviteTime;
|
||||
|
||||
@Schema(description = "接听时间;未接听为空")
|
||||
private LocalDateTime acceptTime;
|
||||
|
||||
@Schema(description = "离开时间;未加入为空")
|
||||
private LocalDateTime leaveTime;
|
||||
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.sensitiveword;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.sensitiveword.vo.ImSensitiveWordPageReqVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.sensitiveword.vo.ImSensitiveWordRespVO;
|
||||
import cn.iocoder.yudao.module.im.controller.admin.manager.sensitiveword.vo.ImSensitiveWordSaveReqVO;
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.sensitiveword.ImSensitiveWordDO;
|
||||
import cn.iocoder.yudao.module.im.service.sensitiveword.ImSensitiveWordService;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
|
||||
@Tag(name = "管理后台 - IM 敏感词")
|
||||
@RestController
|
||||
@RequestMapping("/im/manager/sensitive-word")
|
||||
@Validated
|
||||
public class ImSensitiveWordManagerController {
|
||||
|
||||
@Resource
|
||||
private ImSensitiveWordService sensitiveWordService;
|
||||
@Resource
|
||||
private AdminUserApi adminUserApi;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "新增敏感词")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:sensitive-word:create')")
|
||||
public CommonResult<Long> createSensitiveWord(@Valid @RequestBody ImSensitiveWordSaveReqVO reqVO) {
|
||||
return success(sensitiveWordService.createSensitiveWord(reqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "修改敏感词")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:sensitive-word:update')")
|
||||
public CommonResult<Boolean> updateSensitiveWord(@Valid @RequestBody ImSensitiveWordSaveReqVO reqVO) {
|
||||
sensitiveWordService.updateSensitiveWord(reqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除敏感词")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:sensitive-word:delete')")
|
||||
public CommonResult<Boolean> deleteSensitiveWord(@RequestParam("id") Long id) {
|
||||
sensitiveWordService.deleteSensitiveWord(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete-list")
|
||||
@Operation(summary = "批量删除敏感词")
|
||||
@Parameter(name = "ids", description = "编号列表", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:sensitive-word:delete')")
|
||||
public CommonResult<Boolean> deleteSensitiveWordList(
|
||||
@RequestParam("ids")
|
||||
@Size(max = 100, message = "批量删除最多 100 条") List<Long> ids) {
|
||||
sensitiveWordService.deleteSensitiveWordList(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得敏感词分页")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:sensitive-word:query')")
|
||||
public CommonResult<PageResult<ImSensitiveWordRespVO>> getSensitiveWordPage(
|
||||
@Valid ImSensitiveWordPageReqVO pageReqVO) {
|
||||
// 1. 分页查询
|
||||
PageResult<ImSensitiveWordDO> pageResult = sensitiveWordService.getSensitiveWordPage(pageReqVO);
|
||||
if (CollUtil.isEmpty(pageResult.getList())) {
|
||||
return success(PageResult.empty(pageResult.getTotal()));
|
||||
}
|
||||
// 2.1 批量查询创建人昵称
|
||||
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertSet(pageResult.getList(),
|
||||
word -> NumberUtils.parseLong(word.getCreator())));
|
||||
// 2.2 转换为 VO,填充创建人昵称
|
||||
return success(BeanUtils.toBean(pageResult, ImSensitiveWordRespVO.class, vo ->
|
||||
MapUtils.findAndThen(userMap, NumberUtils.parseLong(vo.getCreator()),
|
||||
user -> vo.setCreatorName(user.getNickname()))));
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得敏感词详情")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('im:manager:sensitive-word:query')")
|
||||
public CommonResult<ImSensitiveWordRespVO> getSensitiveWord(@RequestParam("id") Long id) {
|
||||
ImSensitiveWordDO word = sensitiveWordService.getSensitiveWord(id);
|
||||
return success(BeanUtils.toBean(word, ImSensitiveWordRespVO.class));
|
||||
}
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.sensitiveword.vo;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
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;
|
||||
|
||||
@Schema(description = "管理后台 - IM 敏感词分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ImSensitiveWordPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "敏感词,模糊匹配", example = "敏感")
|
||||
private String word;
|
||||
|
||||
@Schema(description = "状态", example = "0")
|
||||
@InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}")
|
||||
private Integer status; // 参见 CommonStatusEnum 枚举类(0 启用 / 1 禁用)
|
||||
|
||||
@Schema(description = "创建时间", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package cn.iocoder.yudao.module.im.controller.admin.manager.sensitiveword.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - IM 敏感词 Response VO")
|
||||
@Data
|
||||
public class ImSensitiveWordRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "敏感词", requiredMode = Schema.RequiredMode.REQUIRED, example = "敏感词内容")
|
||||
private String word;
|
||||
|
||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
private Integer status; // 参见 CommonStatusEnum 枚举类
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String creator;
|
||||
@Schema(description = "创建人昵称", example = "张三")
|
||||
private String creatorName;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user