diff --git a/docs/install/sql/luohuo_dev.sql b/docs/install/sql/luohuo_dev.sql index 3627bb82..c7b100b8 100644 --- a/docs/install/sql/luohuo_dev.sql +++ b/docs/install/sql/luohuo_dev.sql @@ -11,12 +11,522 @@ Target Server Version : 80030 (8.0.30) File Encoding : 65001 - Date: 20/10/2025 17:27:06 + Date: 28/10/2025 17:10:28 */ SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; +-- ---------------------------- +-- Table structure for ai_api_key +-- ---------------------------- +DROP TABLE IF EXISTS `ai_api_key`; +CREATE TABLE `ai_api_key` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '名称', + `api_key` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '密钥', + `platform` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '平台', + `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '自定义 API 地址', + `status` int NOT NULL COMMENT '状态', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 23 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'AI API 密钥表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of ai_api_key +-- ---------------------------- +INSERT INTO `ai_api_key` VALUES (1, '【OpenAI】ChatGPT', 'sk-aN6nWn3fILjrgLFT0fC4Aa60B72e4253826c77B29dC94f17', 'OpenAI', 'https://api.holdai.top', 0, '', '2024-05-10 01:37:55', '1', '2025-02-23 16:58:46', b'0', 1); +INSERT INTO `ai_api_key` VALUES (2, '呵呵', '123321', 'OpenAI', NULL, 0, '1', '2024-05-11 16:46:18', '1', '2024-05-17 15:15:08', b'1', 1); +INSERT INTO `ai_api_key` VALUES (3, '【Meta】Ollama', ' ', 'Ollama', 'http://127.0.0.1:11434', 0, '1', '2024-05-17 23:04:13', '1', '2024-07-05 01:30:10', b'0', 1); +INSERT INTO `ai_api_key` VALUES (4, '【百度】文心一言', 'x0cuLZ7XsaTCU08vuJWO87Lg|R9mYF9dl9KASgi5RUq0FQt3wRisSnOcK', 'YiYan', NULL, 0, '1', '2024-05-18 09:26:02', '1', '2024-07-05 01:30:10', b'0', 1); +INSERT INTO `ai_api_key` VALUES (5, '【讯飞】星火', '75b161ed2aef4719b275d6e7f2a4d4cd|YWYxYWI2MTA4ODI2NGZlYTQyNjAzZTcz', 'XingHuo', NULL, 0, '1', '2024-05-18 10:09:42', '1', '2025-02-23 18:35:06', b'0', 1); +INSERT INTO `ai_api_key` VALUES (6, '【阿里】通义千问', 'sk-7d903764249848cfa912733146da12d1', 'TongYi', NULL, 0, '1', '2024-05-18 10:33:12', '1', '2025-02-24 10:24:50', b'0', 1); +INSERT INTO `ai_api_key` VALUES (7, 'StableDiffusion', 'sk-e53UqbboF8QJCscYvzJscJxJXoFcFg4iJjl1oqgE7baJETmx', 'StableDiffusion', NULL, 0, '1', '2024-06-01 15:11:18', '1', '2024-07-05 01:30:10', b'0', 1); +INSERT INTO `ai_api_key` VALUES (8, '【本地】Ollama', 'null', 'Ollama', 'http://localhost:11434', 0, '1', '2024-06-01 20:04:43', '1', '2025-02-24 09:21:16', b'0', 1); +INSERT INTO `ai_api_key` VALUES (9, 'Suno', 'Suno', 'Suno', 'http://127.0.0.1:3001', 0, '1', '2024-06-29 09:14:28', '1', '2024-07-05 01:30:10', b'0', 1); +INSERT INTO `ai_api_key` VALUES (10, 'Midjourney', 'sk-dZEPiVaNcT3FHhef51996bAa0bC74806BeAb620dA5Da10Bf', 'Midjourney', 'https://api.holdai.top/mj', 0, '1', '2024-06-29 09:40:20', '1', '2024-07-05 01:30:10', b'0', 1); +INSERT INTO `ai_api_key` VALUES (11, 'DeepSeek', 'sk-5b612c071f904fd59808dc07c9a4f1b8', 'DeepSeek', NULL, 0, '1', '2024-07-06 12:06:04', '1', '2025-03-13 21:18:31', b'0', 1); +INSERT INTO `ai_api_key` VALUES (12, '智谱', '2f35fb6ca4ea41fab898729b7fac086c.6ESSfPcCkxaKEUlR', 'ZhiPu', NULL, 0, '1', '2024-07-06 18:01:15', '1', '2025-03-11 07:47:46', b'0', 1); +INSERT INTO `ai_api_key` VALUES (13, '【微软 OpenAI】ChatGPT', 'XXX', 'AzureOpenAI', 'https://eastusprejade.openai.azure.com', 0, '1', '2024-08-10 14:09:27', '1', '2024-08-10 15:08:27', b'0', 1); +INSERT INTO `ai_api_key` VALUES (14, '字节豆包', '5c1b5747-26d2-4ebd-a4e0-dd0e8d8b4272', 'DouBao', NULL, 0, '1', '2025-02-23 19:52:37', '1', '2025-02-23 19:52:37', b'0', 1); +INSERT INTO `ai_api_key` VALUES (15, '腾讯混元', 'sk-bcd', 'HunYuan', NULL, 0, '1', '2025-02-23 20:59:10', '1', '2025-02-24 09:20:04', b'0', 1); +INSERT INTO `ai_api_key` VALUES (16, '腾讯知识引擎', 'sk-abc', 'HunYuan', 'https://api.lkeap.cloud.tencent.com', 0, '1', '2025-02-23 20:59:49', '1', '2025-02-24 09:20:00', b'0', 1); +INSERT INTO `ai_api_key` VALUES (17, '【本地】deepseek-r1', 'null', 'Ollama', 'http://localhost:11434', 0, '1', '2025-02-24 09:20:31', '1', '2025-02-24 09:21:40', b'1', 1); +INSERT INTO `ai_api_key` VALUES (18, '硅基流动', 'sk-epsakfenqnyzoxhmbucsxlhkdqlcbnimslqoivkshalvdozz', 'SiliconFlow', '', 0, '1', '2025-02-24 20:34:19', '1', '2025-02-24 20:34:19', b'0', 1); +INSERT INTO `ai_api_key` VALUES (19, 'MiniMax', 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJHcm91cE5hbWUiOiLnjovmlofmlowiLCJVc2VyTmFtZSI6IueOi-aWh-aWjCIsIkFjY291bnQiOiIiLCJTdWJqZWN0SUQiOiIxODk3Mjg3MjQ5NDU2ODA4MzQ2IiwiUGhvbmUiOiIxNTYwMTY5MTM5OSIsIkdyb3VwSUQiOiIxODk3Mjg3MjQ5NDQ4NDE5NzM4IiwiUGFnZU5hbWUiOiIiLCJNYWlsIjoiIiwiQ3JlYXRlVGltZSI6IjIwMjUtMDMtMTEgMTI6NTI6MDIiLCJUb2tlblR5cGUiOjEsImlzcyI6Im1pbmltYXgifQ.aAuB7gWW_oA4IYhh-CF7c9MfWWxKN49B_HK-DYjXaDwwffhiG-H1571z1WQhp9QytWG-DqgLejneeSxkiq1wQIe3FsEP2wz4BmGBct31LehbJu8ehLxg_vg75Uod1nFAHbm5mZz6JSVLNIlSo87Xr3UtSzJhAXlapEkcqlA4YOzOpKrZ8l5_OJPTORTCmHWZYgJcRS-faNiH62ZnUEHUozesTFhubJHo5GfJCw_edlnmfSUocERV1BjWvenhZ9My-aYXNktcW9WaSj9l6gayV7A0Ium_PL55T9ln1PcI8gayiVUKJGJDoqNyF1AF9_aF9NOKtTnQzwNqnZdlTYH6hw', 'MiniMax', NULL, 0, '1', '2025-03-11 20:06:35', '1', '2025-03-11 20:06:35', b'0', 1); +INSERT INTO `ai_api_key` VALUES (20, '月之暗灭', 'sk-g9ZpHUj5nEBwY9JJCyUxaxKOwC5M8cvpQFg211ksPJ64yIlm', 'Moonshot', NULL, 0, '1', '2025-03-11 20:07:27', '1', '2025-10-28 09:03:46', b'0', 1); +INSERT INTO `ai_api_key` VALUES (21, 'FastGPT', 'fastgpt-aqcc61kFtF8CeaglnGAfQOCIDWwjGdJVJHv6hIlMo28otFlva2aZNK', 'OpenAI', 'https://cloud.fastgpt.cn/api', 0, '1', '2025-03-12 13:51:06', '1', '2025-03-12 20:06:12', b'0', 1); +INSERT INTO `ai_api_key` VALUES (22, 'Dify', 'app-4hy2d7fJauSbrKbzTKX1afuP', 'OpenAI', 'http://127.0.0.1:3000', 0, '1', '2025-03-12 21:26:34', '1', '2025-03-12 21:50:29', b'0', 1); + +-- ---------------------------- +-- Table structure for ai_chat_conversation +-- ---------------------------- +DROP TABLE IF EXISTS `ai_chat_conversation`; +CREATE TABLE `ai_chat_conversation` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '对话编号', + `user_id` bigint NOT NULL COMMENT '用户编号', + `role_id` bigint NULL DEFAULT NULL COMMENT '聊天角色', + `title` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '对话标题', + `model_id` bigint NOT NULL COMMENT '模型编号', + `model` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模型标识', + `pinned` bit(1) NOT NULL COMMENT '是否置顶', + `pinned_time` datetime NULL DEFAULT NULL COMMENT '置顶时间', + `system_message` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '角色设定', + `temperature` double NOT NULL COMMENT '温度参数', + `max_tokens` int NOT NULL COMMENT '单条回复的最大 Token 数量', + `max_contexts` int NOT NULL COMMENT '上下文的最大 Message 数量', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '创建人', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '更新人', + `update_time` datetime NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1781604279872581774 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'AI 聊天对话表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of ai_chat_conversation +-- ---------------------------- +INSERT INTO `ai_chat_conversation` VALUES (1781604279872581684, 20901198351872, 10, '新对话', 53, 'qwen-72b-chat', b'0', NULL, '您好,我是您的AI智能助手,我会尽力回答您的问题或提供有用的建议!!!!', 1, 20, 2, '1', '2024-05-20 22:22:39', '1', '2025-10-28 03:38:52', b'1', 1); +INSERT INTO `ai_chat_conversation` VALUES (1781604279872581685, 20901198351872, 10, 'gpt测试', 53, 'gpt-3.5-turbo', b'1', '2024-05-21 16:26:29', '您好,我是您的AI智能助手,我会尽力回答您的问题或提供有用的建议!!!!', 1, 20, 20, '1', '2024-05-21 09:37:38', '1', '2025-10-28 03:38:52', b'1', 1); +INSERT INTO `ai_chat_conversation` VALUES (1781604279872581686, 20901198351872, 10, '新的gpt测试', 53, 'gpt-3.5-turbo', b'0', NULL, '您好,我是您的AI智能助手,我会尽力回答您的问题或提供有用的建议!!!!', 1, 20, 20, '1', '2024-05-21 14:43:32', '1', '2025-10-28 03:38:52', b'1', 1); +INSERT INTO `ai_chat_conversation` VALUES (1781604279872581687, 20901198351872, 10, '新对话', 53, 'gpt-3.5-turbo', b'0', NULL, '您好,我是您的AI智能助手,我会尽力回答您的问题或提供有用的建议!!!!', 1, 20, 20, '1', '2024-05-21 16:37:12', '1', '2025-10-28 03:38:52', b'1', 1); + +-- ---------------------------- +-- Table structure for ai_chat_message +-- ---------------------------- +DROP TABLE IF EXISTS `ai_chat_message`; +CREATE TABLE `ai_chat_message` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '消息编号', + `conversation_id` bigint NOT NULL COMMENT '对话编号', + `reply_id` bigint NULL DEFAULT NULL COMMENT '回复编号', + `user_id` bigint NOT NULL COMMENT '用户编号', + `role_id` bigint NULL DEFAULT NULL COMMENT '角色编号', + `type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '消息类型', + `model` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模型标识', + `model_id` bigint NOT NULL COMMENT '模型编号', + `content` varchar(10240) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '消息内容', + `use_context` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否携带上下文', + `segment_ids` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '段落编号数组', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '创建人', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '更新人', + `update_time` datetime NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 2737 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'AI 聊天消息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of ai_chat_message +-- ---------------------------- +INSERT INTO `ai_chat_message` VALUES (1481, 1781604279872581686, NULL, 1, 10, 'user', 'gpt-3.5-turbo', 11, '测试小苹果?', b'0', NULL, '1', '2024-05-21 14:47:37', '1', '2024-07-05 01:30:39', b'0', 1); +INSERT INTO `ai_chat_message` VALUES (1482, 1781604279872581686, 1481, 1, 10, 'assistant', 'gpt-3.5-turbo', 11, '很,我抱无法提供果歉关于\"测试小苹\"的信息。请问您有其他问题或者需要帮助吗?我会尽力回答提或者供帮助。', b'0', NULL, '1', '2024-05-21 14:47:37', NULL, '2024-07-05 01:30:39', b'0', 1); +INSERT INTO `ai_chat_message` VALUES (1483, 1781604279872581686, NULL, 1, 10, 'user', 'gpt-3.5-turbo', 11, '真的么?', b'0', NULL, '1', '2024-05-21 14:47:59', '1', '2024-07-05 01:30:39', b'0', 1); +INSERT INTO `ai_chat_message` VALUES (1484, 1781604279872581686, 1483, 1, 10, 'assistant', 'gpt-3.5-turbo', 11, '', b'0', NULL, '1', '2024-05-21 14:47:59', '1', '2024-07-05 01:30:39', b'0', 1); + +-- ---------------------------- +-- Table structure for ai_chat_role +-- ---------------------------- +DROP TABLE IF EXISTS `ai_chat_role`; +CREATE TABLE `ai_chat_role` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '角色编号', + `user_id` bigint NULL DEFAULT NULL COMMENT '用户编号', + `model_id` bigint NULL DEFAULT NULL COMMENT '模型编号', + `name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '角色名称', + `avatar` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '头像', + `category` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '角色类别', + `sort` int NOT NULL DEFAULT 0 COMMENT '角色排序', + `description` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '角色描述', + `system_message` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '角色上下文', + `knowledge_ids` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '关联的知识库编号数组', + `tool_ids` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '关联的工具编号数组', + `public_status` bit(1) NOT NULL COMMENT '是否公开', + `status` tinyint NULL DEFAULT NULL COMMENT '状态', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 18 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'AI 聊天角色表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of ai_chat_role +-- ---------------------------- +INSERT INTO `ai_chat_role` VALUES (10, NULL, 11, '通用 AI 助手', 'http://test.yudao.iocoder.cn/eaef5f41acb911dd718429a0702dcc3c61160d16e57ba1d543132fab58934f9f.png', '助手', 1, '默认角色', '您好,我是您的AI智能助手,我会尽力回答您的问题或提供有用的建议!!!!', NULL, NULL, b'1', 0, '1', '2024-05-13 20:44:48', '1', '2024-07-05 01:30:30', b'0', 1); +INSERT INTO `ai_chat_role` VALUES (11, NULL, 14, 'Python 专家', 'http://test.yudao.iocoder.cn/5c5528504c307d34af504f39bc4e7007d2f6f31ee00dab699cc91584d1af8aca.png', '编程开发', 2, 'Python', '我希望你能作为一名 python 专家。我将向你提供有关我的技术问题的所有信息,而你的角色是解决我的问题。你应该用你的计算机科学、网络基础设施和 IT 安全知识来解决我的问题。在你的回答中,使用聪明的、简单的、为各种层次的人所理解的语言会有帮助。逐步解释你的解决方案并使用要点是很有帮助的。尽量避免过多的技术细节,但在必要时使用它们。我希望你用解决方案来回答,而不是写任何解释。', NULL, '17', b'1', 0, '1', '2024-05-17 23:23:20', '1', '2025-03-14 21:10:47', b'0', 1); +INSERT INTO `ai_chat_role` VALUES (12, 1, NULL, '小可爱角色', 'http://test.yudao.iocoder.cn/5752750225f522ba794b16ad0b0e73d268093760546ebc2519b1a5dfc5b064d1.jpg', NULL, 0, '卡比兽,爱睡觉', '你好,我是宠物小精灵大师!', NULL, NULL, b'0', 0, '1', '2024-05-25 13:25:46', '1', '2024-07-05 01:30:30', b'0', 1); +INSERT INTO `ai_chat_role` VALUES (13, NULL, 17, '写作助手', 'http://test.yudao.iocoder.cn/2a124ba5743f9572fcbd2718a64ba599618c96ddba6c7391ad35906cd3f37f94.png', '写作', 10, '一个厉害的写手高手', '你是一个非常会写作的人!', NULL, NULL, b'1', 0, '1', '2024-07-10 22:55:58', '1', '2024-07-10 22:56:04', b'0', 1); +INSERT INTO `ai_chat_role` VALUES (14, NULL, 17, '脑图助手', 'http://test.yudao.iocoder.cn/7401c394a43280732e6aaa715fbfefadc33eeb8fab8f45f6b53f1acf6b22ae29.png', '写作', 11, '一个厉害的思维大师!', '你是一位非常优秀的思维导图助手,你会把用户的所有提问都总结成思维导图,然后以 Markdown 格式输出。markdown 只需要输出一级标题,二级标题,三级标题,四级标题,最多输出四级,除此之外不要输出任何其他 markdown 标记。下面是一个合格的例子:\n # Geek-AI 助手\n ## 完整的开源系统\n ### 前端开源\n ### 后端开源\n ## 支持各种大模型\n ### OpenAI\n ### Azure\n ### 文心一言\n ### 通义千问\n ## 集成多种收费方式\n ### 支付宝\n ### 微信\n 除此之外不要任何解释性语句。', NULL, NULL, b'1', 0, '1', '2024-07-29 21:47:20', '1', '2024-07-29 21:48:00', b'0', 1); +INSERT INTO `ai_chat_role` VALUES (15, NULL, 26, '测试知识库', 'http://test.yudao.iocoder.cn/d3a7656aae53c8f063d4578c7a65f9045ef25420ff32cc32dd121a60abcf9127.png', '助手', 10, '我只是个小助手', '一个问答助手', '3', NULL, b'1', 0, '1', '2025-03-09 17:35:36', '1', '2025-03-09 18:32:34', b'1', 1); +INSERT INTO `ai_chat_role` VALUES (16, 1, 21, '测试知识库', 'http://test.yudao.iocoder.cn/a2cfbf52d157911ecfb29c4a26b4a19247f6bb2c97a5104c46c970fc235880ef.png', '助手', 0, '测试一下', '一个小助手', '2', NULL, b'0', 0, '1', '2025-03-09 18:33:01', '1', '2025-03-09 18:51:04', b'0', 1); +INSERT INTO `ai_chat_role` VALUES (17, 1, NULL, '一个可以查询天气的小助手', 'http://test.yudao.iocoder.cn/de74fdbe9ad40173345d4cd1e2b684fcbb5e797f7b7cc37b42dcbaa20dcf6bb3.png', NULL, 0, '查查查天气', '天气小助手', '', '18', b'0', 0, '1', '2025-03-14 20:03:27', '1', '2025-03-14 20:03:27', b'0', 1); + +-- ---------------------------- +-- Table structure for ai_image +-- ---------------------------- +DROP TABLE IF EXISTS `ai_image`; +CREATE TABLE `ai_image` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `user_id` bigint NOT NULL COMMENT '用户编号', + `prompt` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '提示词', + `platform` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '平台', + `model_id` bigint NULL DEFAULT NULL COMMENT '模型编号', + `model` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模型', + `width` int NOT NULL COMMENT '图片宽度', + `height` int NOT NULL COMMENT '图片高度', + `status` tinyint NOT NULL COMMENT '绘画状态', + `finish_time` datetime NULL DEFAULT NULL COMMENT '完成时间', + `error_message` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '错误信息', + `public_status` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否发布', + `pic_url` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '图片地址', + `options` json NULL COMMENT '绘制参数', + `task_id` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '任务编号', + `buttons` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'mj buttons 按钮', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 198 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'AI 绘画表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of ai_image +-- ---------------------------- +INSERT INTO `ai_image` VALUES (143, 1, '中国旗袍', 'Midjourney', 0, 'midjourney', 1, 1, 20, NULL, '', b'0', 'https://api.holdai.top/mj/image/1719316376919887', '{\"model\": \"midjourney\", \"width\": 1, \"height\": 1, \"prompt\": \"中国旗袍\", \"version\": \"6.0\", \"base64Array\": []}', '1719316376919887', '[{\"customId\":\"MJ::JOB::upsample::1::06aa3e66-0e97-49cc-8201-e0295d883de4\",\"emoji\":\"\",\"label\":\"U1\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::JOB::upsample::2::06aa3e66-0e97-49cc-8201-e0295d883de4\",\"emoji\":\"\",\"label\":\"U2\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::JOB::upsample::3::06aa3e66-0e97-49cc-8201-e0295d883de4\",\"emoji\":\"\",\"label\":\"U3\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::JOB::upsample::4::06aa3e66-0e97-49cc-8201-e0295d883de4\",\"emoji\":\"\",\"label\":\"U4\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::JOB::reroll::0::06aa3e66-0e97-49cc-8201-e0295d883de4::SOLO\",\"emoji\":\"🔄\",\"label\":\"\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::JOB::variation::1::06aa3e66-0e97-49cc-8201-e0295d883de4\",\"emoji\":\"\",\"label\":\"V1\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::JOB::variation::2::06aa3e66-0e97-49cc-8201-e0295d883de4\",\"emoji\":\"\",\"label\":\"V2\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::JOB::variation::3::06aa3e66-0e97-49cc-8201-e0295d883de4\",\"emoji\":\"\",\"label\":\"V3\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::JOB::variation::4::06aa3e66-0e97-49cc-8201-e0295d883de4\",\"emoji\":\"\",\"label\":\"V4\",\"type\":\"2\",\"style\":\"2\"}]', '1', '2024-06-25 19:52:56', '1', '2024-07-05 01:30:19', b'1', 1); +INSERT INTO `ai_image` VALUES (144, 1, '中国旗袍', 'Midjourney', 0, 'midjourney', 1, 1, 20, NULL, '', b'0', 'https://api.holdai.top/mj/image/1719317928368230', '{\"model\": \"midjourney\", \"width\": 1, \"height\": 1, \"prompt\": \"中国旗袍\", \"version\": \"6.0\", \"base64Array\": []}', '1719317928368230', '[{\"customId\":\"MJ::JOB::upsample_v6_2x_subtle::1::5a1bbe5d-8e98-4a2c-a904-b820cf17c5d8::SOLO\",\"emoji\":\"upscale_1\",\"label\":\"Upscale (Subtle)\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::JOB::upsample_v6_2x_creative::1::5a1bbe5d-8e98-4a2c-a904-b820cf17c5d8::SOLO\",\"emoji\":\"upscale_1\",\"label\":\"Upscale (Creative)\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::JOB::low_variation::1::5a1bbe5d-8e98-4a2c-a904-b820cf17c5d8::SOLO\",\"emoji\":\"🪄\",\"label\":\"Vary (Subtle)\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::JOB::high_variation::1::5a1bbe5d-8e98-4a2c-a904-b820cf17c5d8::SOLO\",\"emoji\":\"🪄\",\"label\":\"Vary (Strong)\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::Inpaint::1::5a1bbe5d-8e98-4a2c-a904-b820cf17c5d8::SOLO\",\"emoji\":\"🖌️\",\"label\":\"Vary (Region)\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::Outpaint::50::1::5a1bbe5d-8e98-4a2c-a904-b820cf17c5d8::SOLO\",\"emoji\":\"🔍\",\"label\":\"Zoom Out 2x\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::Outpaint::75::1::5a1bbe5d-8e98-4a2c-a904-b820cf17c5d8::SOLO\",\"emoji\":\"🔍\",\"label\":\"Zoom Out 1.5x\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::CustomZoom::5a1bbe5d-8e98-4a2c-a904-b820cf17c5d8\",\"emoji\":\"🔍\",\"label\":\"Custom Zoom\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::JOB::pan_left::1::5a1bbe5d-8e98-4a2c-a904-b820cf17c5d8::SOLO\",\"emoji\":\"⬅️\",\"label\":\"\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::JOB::pan_right::1::5a1bbe5d-8e98-4a2c-a904-b820cf17c5d8::SOLO\",\"emoji\":\"➡️\",\"label\":\"\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::JOB::pan_up::1::5a1bbe5d-8e98-4a2c-a904-b820cf17c5d8::SOLO\",\"emoji\":\"⬆️\",\"label\":\"\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::JOB::pan_down::1::5a1bbe5d-8e98-4a2c-a904-b820cf17c5d8::SOLO\",\"emoji\":\"⬇️\",\"label\":\"\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::BOOKMARK::5a1bbe5d-8e98-4a2c-a904-b820cf17c5d8\",\"emoji\":\"❤️\",\"label\":\"\",\"type\":\"2\",\"style\":\"2\"}]', '1', '2024-06-25 20:18:53', '1', '2024-07-05 01:30:19', b'1', 1); +INSERT INTO `ai_image` VALUES (145, 1, '中国长城', 'StableDiffusion', 0, 'stable-diffusion-v1-6', 1024, 1024, 30, NULL, NULL, b'0', NULL, NULL, NULL, NULL, '1', '2024-06-25 20:19:32', NULL, '2024-07-05 01:30:19', b'1', 1); +INSERT INTO `ai_image` VALUES (149, 1, '中国旗袍', 'Midjourney', 0, 'midjourney', 1, 1, 10, NULL, '', b'0', NULL, '{\"model\": \"midjourney\", \"width\": 1, \"height\": 1, \"prompt\": \"中国旗袍\", \"version\": \"6.0\", \"base64Array\": []}', '1719321552804536', '[]', '1', '2024-06-25 21:19:12', NULL, '2024-07-05 01:30:19', b'1', 1); +INSERT INTO `ai_image` VALUES (150, 1, '中国旗袍', 'Midjourney', 0, 'midjourney', 1, 1, 20, NULL, '', b'0', 'https://api.holdai.top/mj/image/1719321858504740', '{\"model\": \"midjourney\", \"width\": 1, \"height\": 1, \"prompt\": \"中国旗袍\", \"version\": \"6.0\", \"base64Array\": []}', '1719321858504740', '[{\"customId\":\"MJ::JOB::upsample::1::3ad9cb8d-bd10-416d-b782-f0bd1c7b978a\",\"emoji\":\"\",\"label\":\"U1\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::JOB::upsample::2::3ad9cb8d-bd10-416d-b782-f0bd1c7b978a\",\"emoji\":\"\",\"label\":\"U2\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::JOB::upsample::3::3ad9cb8d-bd10-416d-b782-f0bd1c7b978a\",\"emoji\":\"\",\"label\":\"U3\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::JOB::upsample::4::3ad9cb8d-bd10-416d-b782-f0bd1c7b978a\",\"emoji\":\"\",\"label\":\"U4\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::JOB::reroll::0::3ad9cb8d-bd10-416d-b782-f0bd1c7b978a::SOLO\",\"emoji\":\"🔄\",\"label\":\"\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::JOB::variation::1::3ad9cb8d-bd10-416d-b782-f0bd1c7b978a\",\"emoji\":\"\",\"label\":\"V1\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::JOB::variation::2::3ad9cb8d-bd10-416d-b782-f0bd1c7b978a\",\"emoji\":\"\",\"label\":\"V2\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::JOB::variation::3::3ad9cb8d-bd10-416d-b782-f0bd1c7b978a\",\"emoji\":\"\",\"label\":\"V3\",\"type\":\"2\",\"style\":\"2\"},{\"customId\":\"MJ::JOB::variation::4::3ad9cb8d-bd10-416d-b782-f0bd1c7b978a\",\"emoji\":\"\",\"label\":\"V4\",\"type\":\"2\",\"style\":\"2\"}]', '1', '2024-06-25 21:24:17', NULL, '2024-07-05 01:30:19', b'1', 1); +INSERT INTO `ai_image` VALUES (151, 1, '元气少女', 'StableDiffusion', 0, 'stable-diffusion-v1-6', 512, 512, 30, NULL, '403 - {\"id\":\"ce0ccae3ff85b8b2f80b7540f8149663\",\"message\":\"Your request was flagged by our content moderation system, as a result your request was denied and you were not charged.\",\"name\":\"content_moderation\"}\n', b'0', NULL, '{\"seed\": \"-1\", \"steps\": \"20\", \"sampler\": \"Euler a\"}', NULL, NULL, '1', '2024-06-26 12:58:27', NULL, '2024-07-05 01:30:19', b'1', 1); +INSERT INTO `ai_image` VALUES (152, 1, '元气少女1111', 'StableDiffusion', 0, 'stable-diffusion-v1-6', 512, 512, 10, NULL, NULL, b'0', NULL, '{\"seed\": \"-1\", \"steps\": \"20\", \"sampler\": \"Euler a\"}', NULL, NULL, '1', '2024-06-26 12:59:33', '1', '2024-07-05 01:30:19', b'1', 1); +INSERT INTO `ai_image` VALUES (153, 1, '中国长城', 'StableDiffusion', 0, 'stable-diffusion-v1-6', 1024, 1024, 10, NULL, NULL, b'0', NULL, NULL, NULL, NULL, '1', '2024-06-26 13:00:53', '1', '2024-07-05 01:30:19', b'1', 1); + +-- ---------------------------- +-- Table structure for ai_knowledge +-- ---------------------------- +DROP TABLE IF EXISTS `ai_knowledge`; +CREATE TABLE `ai_knowledge` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '知识库名称', + `description` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '知识库描述', + `embedding_model_id` bigint NOT NULL COMMENT '向量模型编号', + `embedding_model` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '向量模型标识', + `top_k` int NOT NULL COMMENT 'topK', + `similarity_threshold` double NOT NULL COMMENT '相似度阈值', + `status` tinyint NOT NULL COMMENT '是否启用', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'AI 知识库表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of ai_knowledge +-- ---------------------------- +INSERT INTO `ai_knowledge` VALUES (2, '测试标题', '测试描述', 45, 'embo-01', 3, 0.5, 0, '1', '2025-03-02 18:23:35', '1', '2025-03-11 20:15:45', b'0', 1); +INSERT INTO `ai_knowledge` VALUES (3, '测试 QdrantVectorStore', '测试 QdrantVectorStore', 45, 'minimax-text-01', 2, 0.5, 0, '1', '2025-03-05 12:57:33', '1', '2025-03-11 20:13:01', b'0', 1); +INSERT INTO `ai_knowledge` VALUES (4, '测试 RedisVectorStore', NULL, 30, 'nomic-embed-text', 10, 0.1, 0, '1', '2025-03-08 17:51:34', '1', '2025-03-08 17:51:34', b'0', 1); +INSERT INTO `ai_knowledge` VALUES (5, '测试 MilvusVectorStore', NULL, 30, 'nomic-embed-text', 10, 0.1, 0, '1', '2025-03-09 09:15:12', '1', '2025-03-09 09:15:12', b'0', 1); + +-- ---------------------------- +-- Table structure for ai_knowledge_document +-- ---------------------------- +DROP TABLE IF EXISTS `ai_knowledge_document`; +CREATE TABLE `ai_knowledge_document` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `knowledge_id` bigint NOT NULL COMMENT '知识库编号', + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '文档名称', + `url` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '文件 URL', + `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '内容', + `content_length` int NOT NULL COMMENT '字符数', + `tokens` int NOT NULL COMMENT 'token 数量', + `segment_max_tokens` int NOT NULL COMMENT '分片最大 Token 数', + `retrieval_count` int NOT NULL DEFAULT 0 COMMENT '召回次数', + `status` tinyint NOT NULL COMMENT '是否启用', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 25 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'AI 知识库文档表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of ai_knowledge_document +-- ---------------------------- +INSERT INTO `ai_knowledge_document` VALUES (11, 2, '测试文档', 'https://static.iocoder.cn/README.md', '# yunaiv.github.io\n\n', 20, 7, 800, 0, 0, '1', '2025-03-02 18:30:24', '1', '2025-03-02 21:51:50', b'1', 1); +INSERT INTO `ai_knowledge_document` VALUES (12, 2, '测试文档', 'https://static.iocoder.cn/README.md', '# yunaiv.github.io\n\n', 20, 7, 800, 0, 0, '1', '2025-03-02 18:31:46', '1', '2025-03-02 21:51:45', b'1', 1); +INSERT INTO `ai_knowledge_document` VALUES (13, 2, '测试文档', 'https://static.iocoder.cn/README.md', '# yunaiv.github.io\n\n', 20, 7, 800, 0, 0, '1', '2025-03-02 18:32:20', '1', '2025-03-02 21:51:41', b'1', 1); +INSERT INTO `ai_knowledge_document` VALUES (14, 2, '测试文档', 'https://static.iocoder.cn/README.md', '# yunaiv.github.io\n\n', 20, 7, 800, 0, 0, '1', '2025-03-02 18:36:33', '1', '2025-03-09 18:50:03', b'1', 1); +INSERT INTO `ai_knowledge_document` VALUES (15, 2, 'Java开发工程师-xxx .docx', 'http://test.yudao.iocoder.cn/8905418ef0076f1817bee7fda02175ed694a8694f80a6c27a7a973f07ae41158.docx', '个人简历\n\n基本资料 \n姓 名: 岳晓威  出生年月: 1992.09.26 \n手 机: 17326899616 邮 箱: 17326899616yxw@sina.com \n工作经验: 7年 语言能力: CET4,读写熟练\n\n求职意向 \n期望职位: Java开发工程师  期望薪资: 面议 \n\n工作经历 \n2019.02-至今 中电金信软件有限公司\n2016.06-2019.02 英大清源(北京)科技有限公司 \n工作职责: \n1. 负责所属模块的关键逻辑代码开发\n2. 独立负责基础架构及相关表结构的设计并协调团队开发 \n3. 协助测试人员完成软件系统及模块的测试,定位、修复程序缺陷\n4. 对所开发的产品进行版本更新及维护,以满足业务运营要求 \n\n教育经历\n河北工程大学( 2012.09 - 2016.06 ) \n专业名称: 计算机科学与技术 学历: 统招本科   \n专业技能 \n* 精通Java基础、集合框架、并发编程、JVM,有实际调优经验\n* 精通锁(单机到分布式)\n* 精通事务(单机到分布式)\n* 熟练使用Spring、SpringMVC、Mybatis等主流开源应用框架 \n* 熟练使用git版本管理工具以及maven项目构建工具 \n* 熟悉分布式架构\n* 熟悉MySQL以及数据库调优、SQL优化\n* 熟悉基本的数据机构和算法,了解多线程编程和异步IO编程以及常用线程同步机制\n* 熟练使用网络通信以及HTTP、TCP/IP、UDP通信协议\n* 熟悉Linux环境,了解Linux下Java项目的部署以及优化\n* 熟悉单例模式、代理模式、模板方法模式、工厂模式\n* 熟悉SpringBoot、SpringCloud\n* 了解RabbitMQ、Redis、ElasticSearch、Ngnix、Zookeeper中间件 \n项目经历 \n统计微讯报表服务 \n项目描述:本项目拟在优化数据服务定制功能,开发可向业务部门用户开放基于指标的内容快捷定制功能,降低业务用户使用指标数据资源的技术门槛,拓展数据服务用户群,提高指标资源的利用率,充分发挥其作为重要的移动端数据服务渠道的价值,为我行数字化转型做出贡献;强化系统管理力度、细化管理粒度,实现对移动数据服务全流程管理,增强应急情况处理能力,提升数据服务体验。\n 开发技术: SpringBoot+SpringCloud+Spring + Mybatis+MySQL+Redis+RabbitMQ+Vue+Activiti\n项目职责: 带领团队实现微信息定制、消息状态监控、消息推送模块\n 微信息定制包括选择模板、选择指标、添加指标校验规则、选择推送人员名单、选择推送时间、选择推送频次,微信息定制完成后,经过流程审批进入消息测试发送状态,待消息审批人确认通过后,进入正式推送状态。\n 消息状态监控包括数仓上游ETL任务加工状态、数仓ETL任务加工状态、数据下载、数据校验、生成消息、消息推送。如果某个状态出现异常,即推送异常通知消息给业务部门管理人员\n 消息推送包括根据微信息定制中配置的推送人员名单和推送频次以及推送时间,进行消息定点推送。\n\n公司业务数字化营销支持平台 \n项目描述: 为顺应“互联网+”新形势,应对经济周期性调整以及利率市场化和金融脱媒化带来的冲击,进一步提升民生银行公司条线客户服务能力,提高前中后台各部门运行效率,按照行领导“加强公司条线信息管理系统整合”,“打造业界先进的公司业务数字化营销支持平台”开发的公司业务数字营销支持平台\n本系统一共有八大业务组件,客户中心、客群中心、决策支持中心、营销支持中心、营销管理中心、营销作业中心、线上协同中心、业务消息中心;两大目标:营销数字化转型、服务数字化转型;三大核心定位:管理平台、作业平台、信息平台;三大系统功能:数字化营销管理、线上化营销作业、智能化决策支持;六大基础维度:客户、客群、机构、团队、员工、产品\n 开发技术: SpringBoot+SpringCloud+Spring + Mybatis+MySQL\n项目职责: 本人主要负责八大业务组件中的线上协同中心,线上协同不仅是单独的一个业务组件,可以配合其他组件实现一些业务需求,线上协同包含三大元素,报送、载体、指标,线上协同有一个模板配置,因为有了模板配置,所以报送非常灵活,可以针对各种业务需求进行相应的配置生成报送,给分行以及支行相关人员进行报送\n模板配置包括业务模板配置和流程模板配置,业务模板配置包括基础属性和扩展属性,可以配置报送相关的参数,载体的具体内容,指标的具体内容,流程模板配置包括流程图的配置,流程节点相关配置、流程业务单元配置\n报送配置包括报送列表、报送明细、报送简版、业务数据汇总、子工单、报送统计,报送列表展示的是所有的报送任务,查看权限是机构向下的,报送明细展示的是报送所有的指标以横向排列,报送简版展示的是所有报送指标以纵向排列,业务数据汇总展示的是报送所有数值类型的指标值的汇总,子工单展示的所有报送任务的子任务,报送统计展示的是所有报送状态的数量\n\n北京建工集团法律风险管理信息系统 \n项目描述: 北京建工集团作为一家大型工程承包商,难免会和第三方产生合同纠纷,甚至在法庭上打官司,尤其是合同的数据量是非常庞大的,很难全部人为得来管理,为了让法务管理信息化,法律风险信息系统应运而生,此系统极大方便了合同信息的管理,在系统中就可以处理合同以及合同引起的法律纠纷的登记审批流程,无需再为了合同及其法律纠纷的审批来回跑各个部门。 . \n开发技术: SpringBoot+Spring +Mybatis+MySQL+Swagger2+Redis\n项目职责: 本人负责系统管理下的纠纷管理、案件管理、合同管理、律师管理信息管理四个子模块\n合同管理实现的功能是合同新增、合同编辑、合同用印、合同生效、合同归档、动态模糊查询。合同都是基于项目发起的,纠纷及案件也是在有了合同的前提下而建立的。\n 纠纷管理,未进入(仲裁)程序的为非诉,非诉登记完毕以后,选择发文审批或者收文上报,发文审批是建工作为原告、需要经过部门领导的审批真正发起非诉,收文上报是建工作为被告,需要经过领导的审批确认,非诉案件如果严重的话,可以直接转为诉讼案件\n诉讼管理,进入(仲裁)程序的为诉讼,也就是说是需要在法院打官司的,登记完基本信息以后,需要添加过程记录,来表示案件进入什么状态 \n 律师管理实现的功能是律师以及律所的增加、删除、修改、动态模糊查询\n自我评价 \n具有较强的分析、解决问题能力,方案设计以及持续学习和业务推进能力\n良好的团队协作精神、具备一定的自我驱动力,能独立承担任务和有系统进度把控能力\n\n', 3436, 2522, 500, 0, 0, '1', '2025-03-03 09:33:43', '1', '2025-03-09 18:50:01', b'1', 1); +INSERT INTO `ai_knowledge_document` VALUES (16, 3, 'README_yudao.md', 'http://test.yudao.iocoder.cn/167d6d2372997b1fc0ac52c0756bc4bc2a5e84a690ecc8fa2f8c56ecc3adc788.md', '

\n \"Downloads\"\n \"Downloads\"\n \"Downloads\"\n

\n\n**严肃声明:现在、未来都不会有商业版本,所有代码全部开源!!**\n\n**「我喜欢写代码,乐此不疲」** \n**「我喜欢做开源,以此为乐」**\n\n我 🐶 在上海艰苦奋斗,早中晚在 top3 大厂认真搬砖,夜里为开源做贡献。\n\n如果这个项目让你有所收获,记得 Star 关注哦,这对我是非常不错的鼓励与支持。\n\n## 🐶 新手必读\n\n* 演示地址【Vue3 + element-plus】:\n* 演示地址【Vue3 + vben(ant-design-vue)】:\n* 演示地址【Vue2 + element-ui】:\n* 启动文档:\n* 视频教程:\n\n## 🐰 版本说明\n\n| 版本 | JDK 8 + Spring Boot 2.7 | JDK 17/21 + Spring Boot 3.2 |\n|---------------------------------------------------------------------|---------------------------------------------------------------------------|---------------------------------------------------------------------------------------|\n| 【完整版】[ruoyi-vue-pro](https://gitee.com/zhijiantianya/ruoyi-vue-pro) | [`master`](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/) 分支 | [`master-jdk17`](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master-jdk17/) 分支 |\n| 【精简版】[yudao-boot-mini](https://gitee.com/yudaocode/yudao-boot-mini) | [`master`](https://gitee.com/yudaocode/yudao-boot-mini/tree/master/) 分支 | [`master-jdk17`](https://gitee.com/yudaocode/yudao-boot-mini/tree/master-jdk17/) 分支 |\n\n* 【完整版】:包括系统功能、基础设施、会员中心、数据报表、工作流程、商城系统、微信公众号、CRM、ERP 等功能\n* 【精简版】:只包括系统功能、基础设施功能,不包括会员中心、数据报表、工作流程、商城系统、微信公众号、CRM、ERP 等功能\n\n可参考 [《迁移文档》](https://doc.iocoder.cn/migrate-module/) ,只需要 5-10 分钟,即可将【完整版】按需迁移到【精简版】\n\n## 🐯 平台简介\n\n**芋道**,以开发者为中心,打造中国第一流的快速开发平台,全部开源,个人与企业可 100% 免费使用。\n\n> 有任何问题,或者想要的功能,可以在 _Issues_ 中提给艿艿。\n>\n> 😜 给项目点点 Star 吧,这对我们真的很重要!\n\n![架构图](/.image/common/ruoyi-vue-pro-architecture.png)\n\n* Java 后端:`master` 分支为 JDK 8 + Spring Boot 2.7,`master-jdk17` 分支为 JDK 17/21 + Spring Boot 3.2\n* 管理后台的电脑端:Vue3 提供 `element-plus`、`vben(ant-design-vue)` 两个版本,Vue2 提供 `element-ui` 版本\n* 管理后台的移动端:采用 `uni-app` 方案,一份代码多终端适配,同时支持 APP、小程序、H5!\n* 后端采用 Spring Boot 多模块架构、MySQL + MyBatis Plus、Redis + Redisson\n* 数据库可使用 MySQL、Oracle、PostgreSQL、SQL Server、MariaDB、国产达梦 DM、TiDB 等\n* 消息队列可使用 Event、Redis、RabbitMQ、Kafka、RocketMQ 等\n* 权限认证使用 Spring Security & Token & Redis,支持多终端、多种用户的认证系统,支持 SSO 单点登录\n* 支持加载动态权限菜单,按钮级别权限控制,Redis 缓存提升性能\n* 支持 SaaS 多租户,可自定义每个租户的权限,提供透明化的多租户底层封装\n* 工作流使用 Flowable,支持动态表单、在线设计流程、会签 / 或签、多种任务分配方式\n* 高效率开发,使用代码生成器可以一键生成 Java、Vue 前后端代码、SQL 脚本、接口文档,支持单表、树表、主子表\n* 实时通信,采用 Spring WebSocket 实现,内置 Token 身份校验,支持 WebSocket 集群\n* 集成微信小程序、微信公众号、企业微信、钉钉等三方登陆,集成支付宝、微信等支付与退款\n* 集成阿里云、腾讯云等短信渠道,集成 MinIO、阿里云、腾讯云、七牛云等云存储服务\n* 集成报表设计器、大屏设计器,通过拖拽即可生成酷炫的报表与大屏\n\n## 🐳 项目关系\n\n![架构演进](/.image/common/yudao-roadmap.png)\n\n三个项目的功能对比,可见社区共同整理的 [国产开源项目对比](https://www.yuque.com/xiatian-bsgny/lm0ec1/wqf8mn) 表格。\n\n### 后端项目\n\n| 项目 | Star | 简介 |\n|-----------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------|\n| [ruoyi-vue-pro](https://gitee.com/zhijiantianya/ruoyi-vue-pro) | [![Gitee star](https://gitee.com/zhijiantianya/ruoyi-vue-pro/badge/star.svg?theme=white)](https://gitee.com/zhijiantianya/ruoyi-vue-pro) [![GitHub stars](https://img.shields.io/github/stars/YunaiV/ruoyi-vue-pro.svg?style=social&label=Stars)](https://github.com/YunaiV/ruoyi-vue-pro) | 基于 Spring Boot 多模块架构 |\n| [yudao-cloud](https://gitee.com/zhijiantianya/yudao-cloud) | [![Gitee star](https://gitee.com/zhijiantianya/yudao-cloud/badge/star.svg?theme=white)](https://gitee.com/zhijiantianya/yudao-cloud) [![GitHub stars](https://img.shields.io/github/stars/YunaiV/yudao-cloud.svg?style=social&label=Stars)](https://github.com/YunaiV/yudao-cloud) | 基于 Spring Cloud 微服务架构 |\n| [Spring-Boot-Labs](https://gitee.com/yudaocode/SpringBoot-Labs) | [![Gitee star](https://gitee.com/yudaocode/SpringBoot-Labs/badge/star.svg?theme=white)](https://gitee.com/zhijiantianya/yudao-cloud) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/SpringBoot-Labs.svg?style=social&label=Stars)](https://github.com/yudaocode/SpringBoot-Labs) | 系统学习 Spring Boot & Cloud 专栏 |\n\n### 前端项目\n\n| 项目 | Star | 简介 |\n|----------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------|\n| [yudao-ui-admin-vue3](https://gitee.com/yudaocode/yudao-ui-admin-vue3) | [![Gitee star](https://gitee.com/yudaocode/yudao-ui-admin-vue3/badge/star.svg?theme=white)](https://gitee.com/yudaocode/yudao-ui-admin-vue3) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/yudao-ui-admin-vue3.svg?style=social&label=Stars)](https://github.com/yudaocode/yudao-ui-admin-vue3) | 基于 Vue3 + element-plus 实现的管理后台 |\n| [yudao-ui-admin-vben](https://gitee.com/yudaocode/yudao-ui-admin-vben) | [![Gitee star](https://gitee.com/yudaocode/yudao-ui-admin-vben/badge/star.svg?theme=white)](https://gitee.com/yudaocode/yudao-ui-admin-vben) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/yudao-ui-admin-vben.svg?style=social&label=Stars)](https://github.com/yudaocode/yudao-ui-admin-vben) | 基于 Vue3 + vben(ant-design-vue) 实现的管理后台 |\n| [yudao-mall-uniapp](https://gitee.com/yudaocode/yudao-mall-uniapp) | [![Gitee star](https://gitee.com/yudaocode/yudao-mall-uniapp/badge/star.svg?theme=white)](https://gitee.com/yudaocode/yudao-mall-uniapp) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/yudao-mall-uniapp.svg?style=social&label=Stars)](https://github.com/yudaocode/yudao-mall-uniapp) | 基于 uni-app 实现的商城小程序 |\n| [yudao-ui-admin-vue2](https://gitee.com/yudaocode/yudao-ui-admin-vue2) | [![Gitee star](https://gitee.com/yudaocode/yudao-ui-admin-vue2/badge/star.svg?theme=white)](https://gitee.com/yudaocode/yudao-ui-admin-vue2) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/yudao-ui-admin-vue2.svg?style=social&label=Stars)](https://github.com/yudaocode/yudao-ui-admin-vue2) | 基于 Vue2 + element-ui 实现的管理后台 |\n| [yudao-ui-admin-uniapp](https://gitee.com/yudaocode/yudao-ui-admin-uniapp) | [![Gitee star](https://gitee.com/yudaocode/yudao-ui-admin-uniapp/badge/star.svg?theme=white)](https://gitee.com/yudaocode/yudao-ui-admin-uniapp) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/yudao-ui-admin-uniapp.svg?style=social&label=Stars)](https://github.com/yudaocode/yudao-ui-admin-uniapp) | 基于 Vue2 + element-ui 实现的管理后台 |\n| [yudao-ui-go-view](https://gitee.com/yudaocode/yudao-ui-go-view) | [![Gitee star](https://gitee.com/yudaocode/yudao-ui-go-view/badge/star.svg?theme=white)](https://gitee.com/yudaocode/yudao-ui-go-view) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/yudao-ui-go-view.svg?style=social&label=Stars)](https://github.com/yudaocode/yudao-ui-go-view) | 基于 Vue3 + naive-ui 实现的大屏报表 |\n\n## 😎 开源协议\n\n**为什么推荐使用本项目?**\n\n① 本项目采用比 Apache 2.0 更宽松的 [MIT License](https://gitee.com/zhijiantianya/ruoyi-vue-pro/blob/master/LICENSE) 开源协议,个人与企业可 100% 免费使用,不用保留类作者、Copyright 信息。\n\n② 代码全部开源,不会像其他项目一样,只开源部分代码,让你无法了解整个项目的架构设计。[国产开源项目对比](https://www.yuque.com/xiatian-bsgny/lm0ec1/wqf8mn)\n\n![开源项目对比](/.image/common/project-vs.png)\n\n③ 代码整洁、架构整洁,遵循《阿里巴巴 Java 开发手册》规范,代码注释详细,113770 行 Java 代码,42462 行代码注释。\n\n## 🤝 项目外包\n\n我们也是接外包滴,如果你有项目想要外包,可以微信联系【**Aix9975**】。\n\n团队包含专业的项目经理、架构师、前端工程师、后端工程师、测试工程师、运维工程师,可以提供全流程的外包服务。\n\n项目可以是商城、SCRM 系统、OA 系统、物流系统、ERP 系统、CMS 系统、HIS 系统、支付系统、IM 聊天、微信公众号、微信小程序等等。\n\n## 🐼 内置功能\n\n系统内置多种多种业务功能,可以用于快速你的业务系统:\n\n![功能分层](/.image/common/ruoyi-vue-pro-biz.png)\n\n* 通用模块(必选):系统功能、基础设施\n* 通用模块(可选):工作流程、支付系统、数据报表、会员中心\n* 业务系统(按需):ERP 系统、CRM 系统、商城系统、微信公众号、AI 大模型\n\n> 友情提示:本项目基于 RuoYi-Vue 修改,**重构优化**后端的代码,**美化**前端的界面。\n>\n> * 额外新增的功能,我们使用 🚀 标记。\n> * 重新实现的功能,我们使用 ⭐️ 标记。\n\n🙂 所有功能,都通过 **单元测试** 保证高质量。\n\n### 系统功能\n\n| | 功能 | 描述 |\n|-----|-------|---------------------------------|\n| | 用户管理 | 用户是系统操作者,该功能主要完成系统用户配置 |\n| ⭐️ | 在线用户 | 当前系统中活跃用户状态监控,支持手动踢下线 |\n| | 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分 |\n| | 菜单管理 | 配置系统菜单、操作权限、按钮权限标识等,本地缓存提供性能 |\n| | 部门管理 | 配置系统组织机构(公司、部门、小组),树结构展现支持数据权限 |\n| | 岗位管理 | 配置系统用户所属担任职务 |\n| 🚀 | 租户管理 | 配置系统租户,支持 SaaS 场景下的多租户功能 |\n| 🚀 | 租户套餐 | 配置租户套餐,自定每个租户的菜单、操作、按钮的权限 |\n| | 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 |\n| 🚀 | 短信管理 | 短信渠道、短息模板、短信日志,对接阿里云、腾讯云等主流短信平台 |\n| 🚀 | 邮件管理 | 邮箱账号、邮件模版、邮件发送日志,支持所有邮件平台 |\n| 🚀 | 站内信 | 系统内的消息通知,提供站内信模版、站内信消息 |\n| 🚀 | 操作日志 | 系统正常操作日志记录和查询,集成 Swagger 生成日志内容 |\n| ⭐️ | 登录日志 | 系统登录日志记录查询,包含登录异常 |\n| 🚀 | 错误码管理 | 系统所有错误码的管理,可在线修改错误提示,无需重启服务 |\n| | 通知公告 | 系统通知公告信息发布维护 |\n| 🚀 | 敏感词 | 配置系统敏感词,支持标签分组 |\n| 🚀 | 应用管理 | 管理 SSO 单点登录的应用,支持多种 OAuth2 授权方式 |\n| 🚀 | 地区管理 | 展示省份、城市、区镇等城市信息,支持 IP 对应城市 |\n\n![功能图](/.image/common/system-feature.png)\n\n### 工作流程\n\n| | 功能 | 描述 |\n|----|-------|-----------------------------------------|\n| 🚀 | 流程模型 | 配置工作流的流程模型,支持 BPMN 和仿钉钉/飞书设计器 |\n| 🚀 | 流程表单 | 拖动表单元素生成相应的工作流表单,覆盖 Element UI 所有的表单组件 |\n| 🚀 | 用户分组 | 自定义用户分组,可用于工作流的审批分组 |\n| 🚀 | 我的流程 | 查看我发起的工作流程,支持新建、取消流程等操作,高亮流程图、审批时间线 |\n| 🚀 | 待办任务 | 查看自己【未】审批的工作任务,支持通过、不通过、转派、委派、退回、加减签等操作 |\n| 🚀 | 已办任务 | 查看自己【已】审批的工作任务,支持流程预测,展示未来审批人信息 |\n| 🚀 | OA 请假 | 作为业务自定义接入工作流的使用示例,只需创建请求对应的工作流程,即可进行审批 |\n\n![功能图](/.image/common/bpm-feature.png)\n\n| BPMN 设计器 | 钉钉/飞书设计器 |\n|------------------------------|--------------------------------|\n| ![](/.image/工作流设计器-bpmn.jpg) | ![](/.image/工作流设计器-simple.jpg) |\n\n### 支付系统\n\n| | 功能 | 描述 |\n|-----|------|---------------------------|\n| 🚀 | 应用信息 | 配置商户的应用信息,对接支付宝、微信等多个支付渠道 |\n| 🚀 | 支付订单 | 查看用户发起的支付宝、微信等的【支付】订单 |\n| 🚀 | 退款订单 | 查看用户发起的支付宝、微信等的【退款】订单 |\n| 🚀 | 回调通知 | 查看支付回调业务的【支付】【退款】的通知结果 |\n| 🚀 | 接入示例 | 提供接入支付系统的【支付】【退款】的功能实战 |\n\n### 基础设施\n\n| | 功能 | 描述 |\n|-----|-----------|----------------------------------------------|\n| 🚀 | 代码生成 | 前后端代码的生成(Java、Vue、SQL、单元测试),支持 CRUD 下载 |\n| 🚀 | 系统接口 | 基于 Swagger 自动生成相关的 RESTful API 接口文档 |\n| 🚀 | 数据库文档 | 基于 Screw 自动生成数据库文档,支持导出 Word、HTML、MD 格式 |\n| | 表单构建 | 拖动表单元素生成相应的 HTML 代码,支持导出 JSON、Vue 文件 |\n| 🚀 | 配置管理 | 对系统动态配置常用参数,支持 SpringBoot 加载 |\n| ⭐️ | 定时任务 | 在线(添加、修改、删除)任务调度包含执行结果日志 |\n| 🚀 | 文件服务 | 支持将文件存储到 S3(MinIO、阿里云、腾讯云、七牛云)、本地、FTP、数据库等 | \n| 🚀 | WebSocket | 提供 WebSocket 接入示例,支持一对一、一对多发送方式 | \n| 🚀 | API 日志 | 包括 RESTful API 访问日志、异常日志两部分,方便排查 API 相关的问题 |\n| | MySQL 监控 | 监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈 |\n| | Redis 监控 | 监控 Redis 数据库的使用情况,使用的 Redis Key 管理 |\n| 🚀 | 消息队列 | 基于 Redis 实现消息队列,Stream 提供集群消费,Pub/Sub 提供广播消费 |\n| 🚀 | Java 监控 | 基于 Spring Boot Admin 实现 Java 应用的监控 |\n| 🚀 | 链路追踪 | 接入 SkyWalking 组件,实现链路追踪 |\n| 🚀 | 日志中心 | 接入 SkyWalking 组件,实现日志中心 |\n| 🚀 | 服务保障 | 基于 Redis 实现分布式锁、幂等、限流功能,满足高并发场景 |\n| 🚀 | 日志服务 | 轻量级日志中心,查看远程服务器的日志 |\n| 🚀 | 单元测试 | 基于 JUnit + Mockito 实现单元测试,保证功能的正确性、代码的质量等 |\n\n![功能图](/.image/common/infra-feature.png)\n\n### 数据报表\n\n| | 功能 | 描述 |\n|-----|-------|--------------------|\n| 🚀 | 报表设计器 | 支持数据报表、图形报表、打印设计等 |\n| 🚀 | 大屏设计器 | 拖拽生成数据大屏,内置几十种图表组件 |\n\n### 微信公众号\n\n| | 功能 | 描述 |\n|-----|--------|-------------------------------|\n| 🚀 | 账号管理 | 配置接入的微信公众号,可支持多个公众号 |\n| 🚀 | 数据统计 | 统计公众号的用户增减、累计用户、消息概况、接口分析等数据 |\n| 🚀 | 粉丝管理 | 查看已关注、取关的粉丝列表,可对粉丝进行同步、打标签等操作 |\n| 🚀 | 消息管理 | 查看粉丝发送的消息列表,可主动回复粉丝消息 |\n| 🚀 | 自动回复 | 自动回复粉丝发送的消息,支持关注回复、消息回复、关键字回复 |\n| 🚀 | 标签管理 | 对公众号的标签进行创建、查询、修改、删除等操作 |\n| 🚀 | 菜单管理 | 自定义公众号的菜单,也可以从公众号同步菜单 |\n| 🚀 | 素材管理 | 管理公众号的图片、语音、视频等素材,支持在线播放语音、视频 |\n| 🚀 | 图文草稿箱 | 新增常用的图文素材到草稿箱,可发布到公众号 |\n| 🚀 | 图文发表记录 | 查看已发布成功的图文素材,支持删除操作 |\n\n### 商城系统\n\n演示地址:\n\n![功能图](/.image/common/mall-feature.png)\n\n![功能图](/.image/common/mall-preview.png)\n\n### 会员中心\n\n| | 功能 | 描述 |\n|-----|------|----------------------------------|\n| 🚀 | 会员管理 | 会员是 C 端的消费者,该功能用于会员的搜索与管理 |\n| 🚀 | 会员标签 | 对会员的标签进行创建、查询、修改、删除等操作 |\n| 🚀 | 会员等级 | 对会员的等级、成长值进行管理,可用于订单折扣等会员权益 |\n| 🚀 | 会员分组 | 对会员进行分组,用于用户画像、内容推送等运营手段 |\n| 🚀 | 积分签到 | 回馈给签到、消费等行为的积分,会员可订单抵现、积分兑换等途径消耗 |\n\n### ERP 系统\n\n演示地址:\n\n![功能图](/.image/common/erp-feature.png)\n\n### CRM 系统\n\n演示地址:\n\n![功能图](/.image/common/crm-feature.png)\n\n### AI 大模型\n\n演示地址:\n\n![功能图](/.image/common/ai-feature.png)\n\n![功能图](/.image/common/ai-preview.gif)\n\n## 🐨 技术栈\n\n### 模块\n\n| 项目 | 说明 |\n|-----------------------|--------------------|\n| `yudao-dependencies` | Maven 依赖版本管理 |\n| `yudao-framework` | Java 框架拓展 |\n| `yudao-server` | 管理后台 + 用户 APP 的服务端 |\n| `yudao-module-system` | 系统功能的 Module 模块 |\n| `yudao-module-member` | 会员中心的 Module 模块 |\n| `yudao-module-infra` | 基础设施的 Module 模块 |\n| `yudao-module-bpm` | 工作流程的 Module 模块 |\n| `yudao-module-pay` | 支付系统的 Module 模块 |\n| `yudao-module-mall` | 商城系统的 Module 模块 |\n| `yudao-module-erp` | ERP 系统的 Module 模块 |\n| `yudao-module-crm` | CRM 系统的 Module 模块 |\n| `yudao-module-ai` | AI 大模型的 Module 模块 |\n| `yudao-module-mp` | 微信公众号的 Module 模块 |\n| `yudao-module-report` | 大屏报表 Module 模块 |\n\n### 框架\n\n| 框架 | 说明 | 版本 | 学习指南 |\n|---------------------------------------------------------------------------------------------|------------------|----------------|----------------------------------------------------------------|\n| [Spring Boot](https://spring.io/projects/spring-boot) | 应用开发框架 | 3.4.1 | [文档](https://github.com/YunaiV/SpringBoot-Labs) |\n| [MySQL](https://www.mysql.com/cn/) | 数据库服务器 | 5.7 / 8.0+ | |\n| [Druid](https://github.com/alibaba/druid) | JDBC 连接池、监控组件 | 1.2.23 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |\n| [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.5.7 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) |\n| [Dynamic Datasource](https://dynamic-datasource.com/) | 动态数据源 | 4.3.1 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |\n| [Redis](https://redis.io/) | key-value 数据库 | 5.0 / 6.0 /7.0 | |\n| [Redisson](https://github.com/redisson/redisson) | Redis 客户端 | 3.32.0 | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao) |\n| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架 | 6.1.10 | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao) |\n| [Spring Security](https://github.com/spring-projects/spring-security) | Spring 安全框架 | 6.3.1 | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) |\n| [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 8.0.1 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) |\n| [Flowable](https://github.com/flowable/flowable-engine) | 工作流引擎 | 7.0.0 | [文档](https://doc.iocoder.cn/bpm/) |\n| [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) |\n| [Springdoc](https://springdoc.org/) | Swagger 文档 | 2.3.0 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) |\n| [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 9.0.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) |\n| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 监控平台 | 3.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) |\n| [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.17.1 | |\n| [MapStruct](https://mapstruct.org/) | Java Bean 转换 | 1.6.3 | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) |\n| [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.18.34 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) |\n| [JUnit](https://junit.org/junit5/) | Java 单元测试框架 | 5.10.1 | - |\n| [Mockito](https://github.com/mockito/mockito) | Java Mock 框架 | 5.7.0 | - |\n\n## 🐷 演示图\n\n### 系统功能\n\n| 模块 | biu | biu | biu |\n|----------|-----------------------------|---------------------------|--------------------------|\n| 登录 & 首页 | ![登录](/.image/登录.jpg) | ![首页](/.image/首页.jpg) | ![个人中心](/.image/个人中心.jpg) |\n| 用户 & 应用 | ![用户管理](/.image/用户管理.jpg) | ![令牌管理](/.image/令牌管理.jpg) | ![应用管理](/.image/应用管理.jpg) |\n| 租户 & 套餐 | ![租户管理](/.image/租户管理.jpg) | ![租户套餐](/.image/租户套餐.png) | - |\n| 部门 & 岗位 | ![部门管理](/.image/部门管理.jpg) | ![岗位管理](/.image/岗位管理.jpg) | - |\n| 菜单 & 角色 | ![菜单管理](/.image/菜单管理.jpg) | ![角色管理](/.image/角色管理.jpg) | - |\n| 审计日志 | ![操作日志](/.image/操作日志.jpg) | ![登录日志](/.image/登录日志.jpg) | - |\n| 短信 | ![短信渠道](/.image/短信渠道.jpg) | ![短信模板](/.image/短信模板.jpg) | ![短信日志](/.image/短信日志.jpg) |\n| 字典 & 敏感词 | ![字典类型](/.image/字典类型.jpg) | ![字典数据](/.image/字典数据.jpg) | ![敏感词](/.image/敏感词.jpg) |\n| 错误码 & 通知 | ![错误码管理](/.image/错误码管理.jpg) | ![通知公告](/.image/通知公告.jpg) | - |\n\n### 工作流程\n\n| 模块 | biu | biu | biu |\n|---------|---------------------------------|---------------------------------|---------------------------------|\n| 流程模型 | ![流程模型-列表](/.image/流程模型-列表.jpg) | ![流程模型-设计](/.image/流程模型-设计.jpg) | ![流程模型-定义](/.image/流程模型-定义.jpg) |\n| 表单 & 分组 | ![流程表单](/.image/流程表单.jpg) | ![用户分组](/.image/用户分组.jpg) | - |\n| 我的流程 | ![我的流程-列表](/.image/我的流程-列表.jpg) | ![我的流程-发起](/.image/我的流程-发起.jpg) | ![我的流程-详情](/.image/我的流程-详情.jpg) |\n| 待办 & 已办 | ![任务列表-审批](/.image/任务列表-审批.jpg) | ![任务列表-待办](/.image/任务列表-待办.jpg) | ![任务列表-已办](/.image/任务列表-已办.jpg) |\n| OA 请假 | ![OA请假-列表](/.image/OA请假-列表.jpg) | ![OA请假-发起](/.image/OA请假-发起.jpg) | ![OA请假-详情](/.image/OA请假-详情.jpg) |\n\n### 基础设施\n\n| 模块 | biu | biu | biu |\n|---------------|-------------------------------|-----------------------------|---------------------------|\n| 代码生成 | ![代码生成](/.image/代码生成.jpg) | ![生成效果](/.image/生成效果.jpg) | - |\n| 文档 | ![系统接口](/.image/系统接口.jpg) | ![数据库文档](/.image/数据库文档.jpg) | - |\n| 文件 & 配置 | ![文件配置](/.image/文件配置.jpg) | ![文件管理](/.image/文件管理2.jpg) | ![配置管理](/.image/配置管理.jpg) |\n| 定时任务 | ![定时任务](/.image/定时任务.jpg) | ![任务日志](/.image/任务日志.jpg) | - |\n| API 日志 | ![访问日志](/.image/访问日志.jpg) | ![错误日志](/.image/错误日志.jpg) | - |\n| MySQL & Redis | ![MySQL](/.image/MySQL.jpg) | ![Redis](/.image/Redis.jpg) | - |\n| 监控平台 | ![Java监控](/.image/Java监控.jpg) | ![链路追踪](/.image/链路追踪.jpg) | ![日志中心](/.image/日志中心.jpg) |\n\n### 支付系统\n\n| 模块 | biu | biu | biu |\n|---------|---------------------------|---------------------------------|---------------------------------|\n| 商家 & 应用 | ![商户信息](/.image/商户信息.jpg) | ![应用信息-列表](/.image/应用信息-列表.jpg) | ![应用信息-编辑](/.image/应用信息-编辑.jpg) |\n| 支付 & 退款 | ![支付订单](/.image/支付订单.jpg) | ![退款订单](/.image/退款订单.jpg) | --- |\n### 数据报表\n\n| 模块 | biu | biu | biu |\n|-------|---------------------------------|---------------------------------|---------------------------------------|\n| 报表设计器 | ![数据报表](/.image/报表设计器-数据报表.jpg) | ![图形报表](/.image/报表设计器-图形报表.jpg) | ![报表设计器-打印设计](/.image/报表设计器-打印设计.jpg) |\n| 大屏设计器 | ![大屏列表](/.image/大屏设计器-列表.jpg) | ![大屏预览](/.image/大屏设计器-预览.jpg) | ![大屏编辑](/.image/大屏设计器-编辑.jpg) |\n\n### 移动端(管理后台)\n\n| biu | biu | biu |\n|----------------------------------|----------------------------------|----------------------------------|\n| ![](/.image/admin-uniapp/01.png) | ![](/.image/admin-uniapp/02.png) | ![](/.image/admin-uniapp/03.png) |\n| ![](/.image/admin-uniapp/04.png) | ![](/.image/admin-uniapp/05.png) | ![](/.image/admin-uniapp/06.png) |\n| ![](/.image/admin-uniapp/07.png) | ![](/.image/admin-uniapp/08.png) | ![](/.image/admin-uniapp/09.png) |\n\n目前已经实现登录、我的、工作台、编辑资料、头像修改、密码修改、常见问题、关于我们等基础功能。\n\n', 24120, 9676, 500, 0, 0, '1', '2025-03-05 12:58:03', '1', '2025-03-09 18:31:21', b'1', 1); +INSERT INTO `ai_knowledge_document` VALUES (17, 3, '1_yudao-cloud-mini-jdk17-整合seata.docx', 'http://test.yudao.iocoder.cn/d2a8a80545b136192398fbeb5f9b917c7845c4dc186ddf142bf61f83a1cae51f.docx', '一,创建seata子模块\n在yudao-framework模块下新建子模块yudao-spring-boot-starter-seata,\n然后在这个yudao-spring-boot-starter-seata模块的pom文件中引入依赖,\n\n cn.iocoder.cloud\n yudao-common\n 2.3.0-SNAPSHOT\n \n \n com.alibaba.cloud\n spring-cloud-alibaba-seata\n 2023.0.1.2\n \n \n io.seata\n seata-spring-boot-starter\n \n 1.8.0\n \n \n io.seata\n seata-all\n \n 1.8.0\n \n \n log4j\n log4j\n \n \n \n \n io.seata\n seata-spring-autoconfigure-client\n \n 1.8.0\n \n \n com.caucho\n hessian\n 4.0.63\n \n \n io.protostuff\n protostuff-core\n 1.7.2\n \n \n io.protostuff\n protostuff-runtime\n 1.7.2\n \n\n二,部署seata服务端\nseata是用于分布式事务的,\n目前我用的是seata-server2.0.0版的windows版,nacos服务器版本我用的2.0.3\nseata\\conf\\application.yml配置文件中:\n\nserver:\n port: 7091\n\nspring:\n application:\n name: seata-server\n\nlogging:\n config: classpath:logback-spring.xml\n file:\n path: ${log.home:${user.home}/logs/seata}\n extend:\n logstash-appender:\n destination: 127.0.0.1:4560\n kafka-appender:\n bootstrap-servers: 127.0.0.1:9092\n topic: logback_to_logstash\n\nconsole:\n user:\n username: seata\n password: seata\nseata:\n config:\n # support: nacos, consul, apollo, zk, etcd3\n type: nacos\n nacos:\n server-addr: 192.168.1.146:8848\n namespace: zma-dev\n group: SEATA_GROUP\n username: nacos\n password: nacos\n context-path:\n ##if use MSE Nacos with auth, mutex with username/password attribute\n #access-key:\n #secret-key:\n data-id: seataServer.properties\n registry:\n # support: nacos, eureka, redis, zk, consul, etcd3, sofa\n type: nacos\n preferred-networks: 30.240.*\n nacos:\n application: seata-server\n server-addr: 192.168.1.146:8848\n group: SEATA_GROUP\n namespace: zma-dev\n cluster: default\n username: nacod\n password: nacos\n context-path:\n ##if use MSE Nacos with auth, mutex with username/password attribute\n #access-key:\n store:\n # support: file 、 db 、 redis 、 raft\n mode: file\n # server:\n # service-port: 8091 #If not configured, the default is \'${server.port} + 1000\'\n security:\n secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017\n tokenValidityInMilliseconds: 1800000\n ignore:\n urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.jpeg,/**/*.ico,/api/v1/auth/login,/metadata/v1/**\nnacos配置中心里面,建一个seataServer.properties配置文件,内容如下:\nData ID: seataServer.properties\nGroup: SEATA_GROUP\nservice.enableDegrade=false\nservice.disableGlobalTransaction=false\nservice.vgroupMapping.default-tx-group=default\nservice.vgroupMapping.order-service-group=default\n启动seata-server,\n在seata\\bin下,双击seata-server.bat文件启动,查看nacos中是否有seata-server的服务,如果有,证明启动成功。\n或者去访问seata的管理页面地址:http://localhost:7091,如果能正常打开,证明seata已经启动成功。\n二,微服务中配置seata\nspringcloud的微服务中配置seata\n先在微服务的pom.xml中添加依赖\n \n \n cn.iocoder.cloud\n yudao-spring-boot-starter-seata\n 2.3.0-SNAPSHOT\n \n然后在springboot微服务的yml中配置:\n# Seata 配置项,对应 SeataProperties 类\nseata:\n application-id: ${spring.application.name} # Seata 应用编号,默认为 ${spring.application.name}\n tx-service-group: default-tx-group # Seata 事务组编号,用于 TC 集群名\n # Seata 服务配置项,对应 ServiceProperties 类\n service:\n vgroup-mapping:\n default-tx-group: default\n data-source-proxy-mode: AT\n # Seata 注册中心配置项,对应 RegistryProperties 类\n registry:\n type: nacos # 注册中心类型,默认为 file\n nacos:\n cluster: default # 使用的 Seata 分组\n namespace: zma-dev # Nacos 命名空间\n # serverAddr: 192.168.1.17:8848 # Nacos 服务地址\n serverAddr: localhost:8848 # Nacos 服务地址\n group : SEATA_GROUP\n username: nacos\n password: nacos\n然后在微服务启动类上加注解\n//开启seata对数据源的自动代理\n@EnableAutoDataSourceProxy \n//开启seata对FeignClient运程调用的自动配置\n@EnableFeignClients(defaultConfiguration = SeataFeignClientAutoConfiguration.class)\n\n三,测试全局事务\n先写一个测试接口,我是在TenantController中写的\n @GetMapping(\"/test-seata\")\n @Operation(summary = \"测试seata\")\n public CommonResult testSeata() {\n return success(menuService.testSeata());\n }\nmenuService业务实现方法上加注解@GlobalTransactional(name = \"testSeata\",rollbackFor = Exception.class),\n这个注解中的name的值要保证唯一性,我这里直接用的方法,如果你当前项目中有多个方法名与当前方法名相同,那就要区别开,比如前面再加上微服务名-controller名,后面再加后缀的方式,保证唯一就行了,如:systemServer-testController-testSeata-1。\n@Override\n @GlobalTransactional(name = \"testSeata\",rollbackFor = Exception.class)\n public Object testSeata() {\n MenuDO menuDO = menuMapper.selectById(2815);\n menuDO.setName(\"测试111\");\n //本微服务system微服务中修改stem_menu表,此修改操作会成功\n menuMapper.updateById(menuDO);\n //通过FeignClient远程调用infra微服务中的方法testSeata,\n //在testSeata插入一条数据到yudao_demo01_contact表,此插入操作会成功\n Boolean bool = apiErrorLogApi.testSeata();\n //通过FeignClient远程调用infra微服务中的方法testSeata2,\n //在testSeata2方法中插入一条数据到yudao_demo02_category表,此插入操作会失败,因为id与数据库中的已有的id重复\n Boolean common = apiErrorLogApi.testSeata2();\n //执行完会去看数据库中的三张表中的数据是否有回滚,如果有回滚,证明全局事务生效了。\n return true;\n }\n注意1:要用全局事务时,远程调用的方法不能以CommonResult返回,要以实体数据实体返回,比如我当前方法只需要一个String字符串,那就以String返回,再比如我需要一个用户对象,那个直接以User返回,不要封装到带有code,msg,data的Result结果对象中返回,不然事务会不生效。\n注意2:远程调用的方法中不能有try{}catch (Exception e) {},不然事务也不会生效。\n然后,数据库中要加seata处理事务的表,如果有多个数据库,那么每个数据库中都要加这张表。\nCREATE TABLE `undo_log` (\n `id` bigint NOT NULL AUTO_INCREMENT,\n `branch_id` bigint NOT NULL,\n `xid` varchar(100) NOT NULL,\n `context` varchar(128) NOT NULL,\n `rollback_info` longblob NOT NULL,\n `log_status` int NOT NULL,\n `log_created` datetime NOT NULL,\n `log_modified` datetime NOT NULL,\n `ext` varchar(100) DEFAULT NULL,\n PRIMARY KEY (`id`),\n UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)\n) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb3;\n然后启动gateway,system微服务与infra微服务,\n最后,用postman请求system微服务中的这个/test-seata接口,测试数据库的数据的修改与插入是否有回滚,是否有同步成功,同步失败。\n\n一,创建 seata 子模块\n\n在yudao-framework 模块下新建子模块 yudao-spring-boot-starter- seata,\n\n然后在这个 yudao-spring-boot-starter- seata模块的pom文件中引入依赖,\n\n\n\n cn.iocoder.cloud\n\ny udao-common\n\n2.3.0-SNAPSHOT\n\n\n\n\n\ncom.alibaba.cloud\n\nspring-cloud-alibaba-\n\nseata\n\n2023.0.1.2\n\n\n\n\n\nio.seata\n\nseata-spring-boot-\n\nstarter\n\n\n\n1.8.0\n\n\n\n\n\nio.seata\n\nseata-all\n\n\n\n1.8.0\n\n\n\n\n\nlog4j\n\nlog4j\n\n\n\n\n\n\n\n\n\nio.seata\n\n', 8493, 2872, 500, 0, 0, '1', '2025-03-06 22:21:48', '1', '2025-03-09 18:31:07', b'1', 1); +INSERT INTO `ai_knowledge_document` VALUES (18, 4, 'README_yudao.md', 'http://test.yudao.iocoder.cn/167d6d2372997b1fc0ac52c0756bc4bc2a5e84a690ecc8fa2f8c56ecc3adc788.md', '

\n \"Downloads\"\n \"Downloads\"\n \"Downloads\"\n

\n\n**严肃声明:现在、未来都不会有商业版本,所有代码全部开源!!**\n\n**「我喜欢写代码,乐此不疲」** \n**「我喜欢做开源,以此为乐」**\n\n我 🐶 在上海艰苦奋斗,早中晚在 top3 大厂认真搬砖,夜里为开源做贡献。\n\n如果这个项目让你有所收获,记得 Star 关注哦,这对我是非常不错的鼓励与支持。\n\n## 🐶 新手必读\n\n* 演示地址【Vue3 + element-plus】:\n* 演示地址【Vue3 + vben(ant-design-vue)】:\n* 演示地址【Vue2 + element-ui】:\n* 启动文档:\n* 视频教程:\n\n## 🐰 版本说明\n\n| 版本 | JDK 8 + Spring Boot 2.7 | JDK 17/21 + Spring Boot 3.2 |\n|---------------------------------------------------------------------|---------------------------------------------------------------------------|---------------------------------------------------------------------------------------|\n| 【完整版】[ruoyi-vue-pro](https://gitee.com/zhijiantianya/ruoyi-vue-pro) | [`master`](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/) 分支 | [`master-jdk17`](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master-jdk17/) 分支 |\n| 【精简版】[yudao-boot-mini](https://gitee.com/yudaocode/yudao-boot-mini) | [`master`](https://gitee.com/yudaocode/yudao-boot-mini/tree/master/) 分支 | [`master-jdk17`](https://gitee.com/yudaocode/yudao-boot-mini/tree/master-jdk17/) 分支 |\n\n* 【完整版】:包括系统功能、基础设施、会员中心、数据报表、工作流程、商城系统、微信公众号、CRM、ERP 等功能\n* 【精简版】:只包括系统功能、基础设施功能,不包括会员中心、数据报表、工作流程、商城系统、微信公众号、CRM、ERP 等功能\n\n可参考 [《迁移文档》](https://doc.iocoder.cn/migrate-module/) ,只需要 5-10 分钟,即可将【完整版】按需迁移到【精简版】\n\n## 🐯 平台简介\n\n**芋道**,以开发者为中心,打造中国第一流的快速开发平台,全部开源,个人与企业可 100% 免费使用。\n\n> 有任何问题,或者想要的功能,可以在 _Issues_ 中提给艿艿。\n>\n> 😜 给项目点点 Star 吧,这对我们真的很重要!\n\n![架构图](/.image/common/ruoyi-vue-pro-architecture.png)\n\n* Java 后端:`master` 分支为 JDK 8 + Spring Boot 2.7,`master-jdk17` 分支为 JDK 17/21 + Spring Boot 3.2\n* 管理后台的电脑端:Vue3 提供 `element-plus`、`vben(ant-design-vue)` 两个版本,Vue2 提供 `element-ui` 版本\n* 管理后台的移动端:采用 `uni-app` 方案,一份代码多终端适配,同时支持 APP、小程序、H5!\n* 后端采用 Spring Boot 多模块架构、MySQL + MyBatis Plus、Redis + Redisson\n* 数据库可使用 MySQL、Oracle、PostgreSQL、SQL Server、MariaDB、国产达梦 DM、TiDB 等\n* 消息队列可使用 Event、Redis、RabbitMQ、Kafka、RocketMQ 等\n* 权限认证使用 Spring Security & Token & Redis,支持多终端、多种用户的认证系统,支持 SSO 单点登录\n* 支持加载动态权限菜单,按钮级别权限控制,Redis 缓存提升性能\n* 支持 SaaS 多租户,可自定义每个租户的权限,提供透明化的多租户底层封装\n* 工作流使用 Flowable,支持动态表单、在线设计流程、会签 / 或签、多种任务分配方式\n* 高效率开发,使用代码生成器可以一键生成 Java、Vue 前后端代码、SQL 脚本、接口文档,支持单表、树表、主子表\n* 实时通信,采用 Spring WebSocket 实现,内置 Token 身份校验,支持 WebSocket 集群\n* 集成微信小程序、微信公众号、企业微信、钉钉等三方登陆,集成支付宝、微信等支付与退款\n* 集成阿里云、腾讯云等短信渠道,集成 MinIO、阿里云、腾讯云、七牛云等云存储服务\n* 集成报表设计器、大屏设计器,通过拖拽即可生成酷炫的报表与大屏\n\n## 🐳 项目关系\n\n![架构演进](/.image/common/yudao-roadmap.png)\n\n三个项目的功能对比,可见社区共同整理的 [国产开源项目对比](https://www.yuque.com/xiatian-bsgny/lm0ec1/wqf8mn) 表格。\n\n### 后端项目\n\n| 项目 | Star | 简介 |\n|-----------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------|\n| [ruoyi-vue-pro](https://gitee.com/zhijiantianya/ruoyi-vue-pro) | [![Gitee star](https://gitee.com/zhijiantianya/ruoyi-vue-pro/badge/star.svg?theme=white)](https://gitee.com/zhijiantianya/ruoyi-vue-pro) [![GitHub stars](https://img.shields.io/github/stars/YunaiV/ruoyi-vue-pro.svg?style=social&label=Stars)](https://github.com/YunaiV/ruoyi-vue-pro) | 基于 Spring Boot 多模块架构 |\n| [yudao-cloud](https://gitee.com/zhijiantianya/yudao-cloud) | [![Gitee star](https://gitee.com/zhijiantianya/yudao-cloud/badge/star.svg?theme=white)](https://gitee.com/zhijiantianya/yudao-cloud) [![GitHub stars](https://img.shields.io/github/stars/YunaiV/yudao-cloud.svg?style=social&label=Stars)](https://github.com/YunaiV/yudao-cloud) | 基于 Spring Cloud 微服务架构 |\n| [Spring-Boot-Labs](https://gitee.com/yudaocode/SpringBoot-Labs) | [![Gitee star](https://gitee.com/yudaocode/SpringBoot-Labs/badge/star.svg?theme=white)](https://gitee.com/zhijiantianya/yudao-cloud) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/SpringBoot-Labs.svg?style=social&label=Stars)](https://github.com/yudaocode/SpringBoot-Labs) | 系统学习 Spring Boot & Cloud 专栏 |\n\n### 前端项目\n\n| 项目 | Star | 简介 |\n|----------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------|\n| [yudao-ui-admin-vue3](https://gitee.com/yudaocode/yudao-ui-admin-vue3) | [![Gitee star](https://gitee.com/yudaocode/yudao-ui-admin-vue3/badge/star.svg?theme=white)](https://gitee.com/yudaocode/yudao-ui-admin-vue3) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/yudao-ui-admin-vue3.svg?style=social&label=Stars)](https://github.com/yudaocode/yudao-ui-admin-vue3) | 基于 Vue3 + element-plus 实现的管理后台 |\n| [yudao-ui-admin-vben](https://gitee.com/yudaocode/yudao-ui-admin-vben) | [![Gitee star](https://gitee.com/yudaocode/yudao-ui-admin-vben/badge/star.svg?theme=white)](https://gitee.com/yudaocode/yudao-ui-admin-vben) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/yudao-ui-admin-vben.svg?style=social&label=Stars)](https://github.com/yudaocode/yudao-ui-admin-vben) | 基于 Vue3 + vben(ant-design-vue) 实现的管理后台 |\n| [yudao-mall-uniapp](https://gitee.com/yudaocode/yudao-mall-uniapp) | [![Gitee star](https://gitee.com/yudaocode/yudao-mall-uniapp/badge/star.svg?theme=white)](https://gitee.com/yudaocode/yudao-mall-uniapp) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/yudao-mall-uniapp.svg?style=social&label=Stars)](https://github.com/yudaocode/yudao-mall-uniapp) | 基于 uni-app 实现的商城小程序 |\n| [yudao-ui-admin-vue2](https://gitee.com/yudaocode/yudao-ui-admin-vue2) | [![Gitee star](https://gitee.com/yudaocode/yudao-ui-admin-vue2/badge/star.svg?theme=white)](https://gitee.com/yudaocode/yudao-ui-admin-vue2) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/yudao-ui-admin-vue2.svg?style=social&label=Stars)](https://github.com/yudaocode/yudao-ui-admin-vue2) | 基于 Vue2 + element-ui 实现的管理后台 |\n| [yudao-ui-admin-uniapp](https://gitee.com/yudaocode/yudao-ui-admin-uniapp) | [![Gitee star](https://gitee.com/yudaocode/yudao-ui-admin-uniapp/badge/star.svg?theme=white)](https://gitee.com/yudaocode/yudao-ui-admin-uniapp) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/yudao-ui-admin-uniapp.svg?style=social&label=Stars)](https://github.com/yudaocode/yudao-ui-admin-uniapp) | 基于 Vue2 + element-ui 实现的管理后台 |\n| [yudao-ui-go-view](https://gitee.com/yudaocode/yudao-ui-go-view) | [![Gitee star](https://gitee.com/yudaocode/yudao-ui-go-view/badge/star.svg?theme=white)](https://gitee.com/yudaocode/yudao-ui-go-view) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/yudao-ui-go-view.svg?style=social&label=Stars)](https://github.com/yudaocode/yudao-ui-go-view) | 基于 Vue3 + naive-ui 实现的大屏报表 |\n\n## 😎 开源协议\n\n**为什么推荐使用本项目?**\n\n① 本项目采用比 Apache 2.0 更宽松的 [MIT License](https://gitee.com/zhijiantianya/ruoyi-vue-pro/blob/master/LICENSE) 开源协议,个人与企业可 100% 免费使用,不用保留类作者、Copyright 信息。\n\n② 代码全部开源,不会像其他项目一样,只开源部分代码,让你无法了解整个项目的架构设计。[国产开源项目对比](https://www.yuque.com/xiatian-bsgny/lm0ec1/wqf8mn)\n\n![开源项目对比](/.image/common/project-vs.png)\n\n③ 代码整洁、架构整洁,遵循《阿里巴巴 Java 开发手册》规范,代码注释详细,113770 行 Java 代码,42462 行代码注释。\n\n## 🤝 项目外包\n\n我们也是接外包滴,如果你有项目想要外包,可以微信联系【**Aix9975**】。\n\n团队包含专业的项目经理、架构师、前端工程师、后端工程师、测试工程师、运维工程师,可以提供全流程的外包服务。\n\n项目可以是商城、SCRM 系统、OA 系统、物流系统、ERP 系统、CMS 系统、HIS 系统、支付系统、IM 聊天、微信公众号、微信小程序等等。\n\n## 🐼 内置功能\n\n系统内置多种多种业务功能,可以用于快速你的业务系统:\n\n![功能分层](/.image/common/ruoyi-vue-pro-biz.png)\n\n* 通用模块(必选):系统功能、基础设施\n* 通用模块(可选):工作流程、支付系统、数据报表、会员中心\n* 业务系统(按需):ERP 系统、CRM 系统、商城系统、微信公众号、AI 大模型\n\n> 友情提示:本项目基于 RuoYi-Vue 修改,**重构优化**后端的代码,**美化**前端的界面。\n>\n> * 额外新增的功能,我们使用 🚀 标记。\n> * 重新实现的功能,我们使用 ⭐️ 标记。\n\n🙂 所有功能,都通过 **单元测试** 保证高质量。\n\n### 系统功能\n\n| | 功能 | 描述 |\n|-----|-------|---------------------------------|\n| | 用户管理 | 用户是系统操作者,该功能主要完成系统用户配置 |\n| ⭐️ | 在线用户 | 当前系统中活跃用户状态监控,支持手动踢下线 |\n| | 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分 |\n| | 菜单管理 | 配置系统菜单、操作权限、按钮权限标识等,本地缓存提供性能 |\n| | 部门管理 | 配置系统组织机构(公司、部门、小组),树结构展现支持数据权限 |\n| | 岗位管理 | 配置系统用户所属担任职务 |\n| 🚀 | 租户管理 | 配置系统租户,支持 SaaS 场景下的多租户功能 |\n| 🚀 | 租户套餐 | 配置租户套餐,自定每个租户的菜单、操作、按钮的权限 |\n| | 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 |\n| 🚀 | 短信管理 | 短信渠道、短息模板、短信日志,对接阿里云、腾讯云等主流短信平台 |\n| 🚀 | 邮件管理 | 邮箱账号、邮件模版、邮件发送日志,支持所有邮件平台 |\n| 🚀 | 站内信 | 系统内的消息通知,提供站内信模版、站内信消息 |\n| 🚀 | 操作日志 | 系统正常操作日志记录和查询,集成 Swagger 生成日志内容 |\n| ⭐️ | 登录日志 | 系统登录日志记录查询,包含登录异常 |\n| 🚀 | 错误码管理 | 系统所有错误码的管理,可在线修改错误提示,无需重启服务 |\n| | 通知公告 | 系统通知公告信息发布维护 |\n| 🚀 | 敏感词 | 配置系统敏感词,支持标签分组 |\n| 🚀 | 应用管理 | 管理 SSO 单点登录的应用,支持多种 OAuth2 授权方式 |\n| 🚀 | 地区管理 | 展示省份、城市、区镇等城市信息,支持 IP 对应城市 |\n\n![功能图](/.image/common/system-feature.png)\n\n### 工作流程\n\n| | 功能 | 描述 |\n|----|-------|-----------------------------------------|\n| 🚀 | 流程模型 | 配置工作流的流程模型,支持 BPMN 和仿钉钉/飞书设计器 |\n| 🚀 | 流程表单 | 拖动表单元素生成相应的工作流表单,覆盖 Element UI 所有的表单组件 |\n| 🚀 | 用户分组 | 自定义用户分组,可用于工作流的审批分组 |\n| 🚀 | 我的流程 | 查看我发起的工作流程,支持新建、取消流程等操作,高亮流程图、审批时间线 |\n| 🚀 | 待办任务 | 查看自己【未】审批的工作任务,支持通过、不通过、转派、委派、退回、加减签等操作 |\n| 🚀 | 已办任务 | 查看自己【已】审批的工作任务,支持流程预测,展示未来审批人信息 |\n| 🚀 | OA 请假 | 作为业务自定义接入工作流的使用示例,只需创建请求对应的工作流程,即可进行审批 |\n\n![功能图](/.image/common/bpm-feature.png)\n\n| BPMN 设计器 | 钉钉/飞书设计器 |\n|------------------------------|--------------------------------|\n| ![](/.image/工作流设计器-bpmn.jpg) | ![](/.image/工作流设计器-simple.jpg) |\n\n### 支付系统\n\n| | 功能 | 描述 |\n|-----|------|---------------------------|\n| 🚀 | 应用信息 | 配置商户的应用信息,对接支付宝、微信等多个支付渠道 |\n| 🚀 | 支付订单 | 查看用户发起的支付宝、微信等的【支付】订单 |\n| 🚀 | 退款订单 | 查看用户发起的支付宝、微信等的【退款】订单 |\n| 🚀 | 回调通知 | 查看支付回调业务的【支付】【退款】的通知结果 |\n| 🚀 | 接入示例 | 提供接入支付系统的【支付】【退款】的功能实战 |\n\n### 基础设施\n\n| | 功能 | 描述 |\n|-----|-----------|----------------------------------------------|\n| 🚀 | 代码生成 | 前后端代码的生成(Java、Vue、SQL、单元测试),支持 CRUD 下载 |\n| 🚀 | 系统接口 | 基于 Swagger 自动生成相关的 RESTful API 接口文档 |\n| 🚀 | 数据库文档 | 基于 Screw 自动生成数据库文档,支持导出 Word、HTML、MD 格式 |\n| | 表单构建 | 拖动表单元素生成相应的 HTML 代码,支持导出 JSON、Vue 文件 |\n| 🚀 | 配置管理 | 对系统动态配置常用参数,支持 SpringBoot 加载 |\n| ⭐️ | 定时任务 | 在线(添加、修改、删除)任务调度包含执行结果日志 |\n| 🚀 | 文件服务 | 支持将文件存储到 S3(MinIO、阿里云、腾讯云、七牛云)、本地、FTP、数据库等 | \n| 🚀 | WebSocket | 提供 WebSocket 接入示例,支持一对一、一对多发送方式 | \n| 🚀 | API 日志 | 包括 RESTful API 访问日志、异常日志两部分,方便排查 API 相关的问题 |\n| | MySQL 监控 | 监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈 |\n| | Redis 监控 | 监控 Redis 数据库的使用情况,使用的 Redis Key 管理 |\n| 🚀 | 消息队列 | 基于 Redis 实现消息队列,Stream 提供集群消费,Pub/Sub 提供广播消费 |\n| 🚀 | Java 监控 | 基于 Spring Boot Admin 实现 Java 应用的监控 |\n| 🚀 | 链路追踪 | 接入 SkyWalking 组件,实现链路追踪 |\n| 🚀 | 日志中心 | 接入 SkyWalking 组件,实现日志中心 |\n| 🚀 | 服务保障 | 基于 Redis 实现分布式锁、幂等、限流功能,满足高并发场景 |\n| 🚀 | 日志服务 | 轻量级日志中心,查看远程服务器的日志 |\n| 🚀 | 单元测试 | 基于 JUnit + Mockito 实现单元测试,保证功能的正确性、代码的质量等 |\n\n![功能图](/.image/common/infra-feature.png)\n\n### 数据报表\n\n| | 功能 | 描述 |\n|-----|-------|--------------------|\n| 🚀 | 报表设计器 | 支持数据报表、图形报表、打印设计等 |\n| 🚀 | 大屏设计器 | 拖拽生成数据大屏,内置几十种图表组件 |\n\n### 微信公众号\n\n| | 功能 | 描述 |\n|-----|--------|-------------------------------|\n| 🚀 | 账号管理 | 配置接入的微信公众号,可支持多个公众号 |\n| 🚀 | 数据统计 | 统计公众号的用户增减、累计用户、消息概况、接口分析等数据 |\n| 🚀 | 粉丝管理 | 查看已关注、取关的粉丝列表,可对粉丝进行同步、打标签等操作 |\n| 🚀 | 消息管理 | 查看粉丝发送的消息列表,可主动回复粉丝消息 |\n| 🚀 | 自动回复 | 自动回复粉丝发送的消息,支持关注回复、消息回复、关键字回复 |\n| 🚀 | 标签管理 | 对公众号的标签进行创建、查询、修改、删除等操作 |\n| 🚀 | 菜单管理 | 自定义公众号的菜单,也可以从公众号同步菜单 |\n| 🚀 | 素材管理 | 管理公众号的图片、语音、视频等素材,支持在线播放语音、视频 |\n| 🚀 | 图文草稿箱 | 新增常用的图文素材到草稿箱,可发布到公众号 |\n| 🚀 | 图文发表记录 | 查看已发布成功的图文素材,支持删除操作 |\n\n### 商城系统\n\n演示地址:\n\n![功能图](/.image/common/mall-feature.png)\n\n![功能图](/.image/common/mall-preview.png)\n\n### 会员中心\n\n| | 功能 | 描述 |\n|-----|------|----------------------------------|\n| 🚀 | 会员管理 | 会员是 C 端的消费者,该功能用于会员的搜索与管理 |\n| 🚀 | 会员标签 | 对会员的标签进行创建、查询、修改、删除等操作 |\n| 🚀 | 会员等级 | 对会员的等级、成长值进行管理,可用于订单折扣等会员权益 |\n| 🚀 | 会员分组 | 对会员进行分组,用于用户画像、内容推送等运营手段 |\n| 🚀 | 积分签到 | 回馈给签到、消费等行为的积分,会员可订单抵现、积分兑换等途径消耗 |\n\n### ERP 系统\n\n演示地址:\n\n![功能图](/.image/common/erp-feature.png)\n\n### CRM 系统\n\n演示地址:\n\n![功能图](/.image/common/crm-feature.png)\n\n### AI 大模型\n\n演示地址:\n\n![功能图](/.image/common/ai-feature.png)\n\n![功能图](/.image/common/ai-preview.gif)\n\n## 🐨 技术栈\n\n### 模块\n\n| 项目 | 说明 |\n|-----------------------|--------------------|\n| `yudao-dependencies` | Maven 依赖版本管理 |\n| `yudao-framework` | Java 框架拓展 |\n| `yudao-server` | 管理后台 + 用户 APP 的服务端 |\n| `yudao-module-system` | 系统功能的 Module 模块 |\n| `yudao-module-member` | 会员中心的 Module 模块 |\n| `yudao-module-infra` | 基础设施的 Module 模块 |\n| `yudao-module-bpm` | 工作流程的 Module 模块 |\n| `yudao-module-pay` | 支付系统的 Module 模块 |\n| `yudao-module-mall` | 商城系统的 Module 模块 |\n| `yudao-module-erp` | ERP 系统的 Module 模块 |\n| `yudao-module-crm` | CRM 系统的 Module 模块 |\n| `yudao-module-ai` | AI 大模型的 Module 模块 |\n| `yudao-module-mp` | 微信公众号的 Module 模块 |\n| `yudao-module-report` | 大屏报表 Module 模块 |\n\n### 框架\n\n| 框架 | 说明 | 版本 | 学习指南 |\n|---------------------------------------------------------------------------------------------|------------------|----------------|----------------------------------------------------------------|\n| [Spring Boot](https://spring.io/projects/spring-boot) | 应用开发框架 | 3.4.1 | [文档](https://github.com/YunaiV/SpringBoot-Labs) |\n| [MySQL](https://www.mysql.com/cn/) | 数据库服务器 | 5.7 / 8.0+ | |\n| [Druid](https://github.com/alibaba/druid) | JDBC 连接池、监控组件 | 1.2.23 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |\n| [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.5.7 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) |\n| [Dynamic Datasource](https://dynamic-datasource.com/) | 动态数据源 | 4.3.1 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |\n| [Redis](https://redis.io/) | key-value 数据库 | 5.0 / 6.0 /7.0 | |\n| [Redisson](https://github.com/redisson/redisson) | Redis 客户端 | 3.32.0 | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao) |\n| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架 | 6.1.10 | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao) |\n| [Spring Security](https://github.com/spring-projects/spring-security) | Spring 安全框架 | 6.3.1 | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) |\n| [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 8.0.1 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) |\n| [Flowable](https://github.com/flowable/flowable-engine) | 工作流引擎 | 7.0.0 | [文档](https://doc.iocoder.cn/bpm/) |\n| [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) |\n| [Springdoc](https://springdoc.org/) | Swagger 文档 | 2.3.0 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) |\n| [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 9.0.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) |\n| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 监控平台 | 3.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) |\n| [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.17.1 | |\n| [MapStruct](https://mapstruct.org/) | Java Bean 转换 | 1.6.3 | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) |\n| [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.18.34 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) |\n| [JUnit](https://junit.org/junit5/) | Java 单元测试框架 | 5.10.1 | - |\n| [Mockito](https://github.com/mockito/mockito) | Java Mock 框架 | 5.7.0 | - |\n\n## 🐷 演示图\n\n### 系统功能\n\n| 模块 | biu | biu | biu |\n|----------|-----------------------------|---------------------------|--------------------------|\n| 登录 & 首页 | ![登录](/.image/登录.jpg) | ![首页](/.image/首页.jpg) | ![个人中心](/.image/个人中心.jpg) |\n| 用户 & 应用 | ![用户管理](/.image/用户管理.jpg) | ![令牌管理](/.image/令牌管理.jpg) | ![应用管理](/.image/应用管理.jpg) |\n| 租户 & 套餐 | ![租户管理](/.image/租户管理.jpg) | ![租户套餐](/.image/租户套餐.png) | - |\n| 部门 & 岗位 | ![部门管理](/.image/部门管理.jpg) | ![岗位管理](/.image/岗位管理.jpg) | - |\n| 菜单 & 角色 | ![菜单管理](/.image/菜单管理.jpg) | ![角色管理](/.image/角色管理.jpg) | - |\n| 审计日志 | ![操作日志](/.image/操作日志.jpg) | ![登录日志](/.image/登录日志.jpg) | - |\n| 短信 | ![短信渠道](/.image/短信渠道.jpg) | ![短信模板](/.image/短信模板.jpg) | ![短信日志](/.image/短信日志.jpg) |\n| 字典 & 敏感词 | ![字典类型](/.image/字典类型.jpg) | ![字典数据](/.image/字典数据.jpg) | ![敏感词](/.image/敏感词.jpg) |\n| 错误码 & 通知 | ![错误码管理](/.image/错误码管理.jpg) | ![通知公告](/.image/通知公告.jpg) | - |\n\n### 工作流程\n\n| 模块 | biu | biu | biu |\n|---------|---------------------------------|---------------------------------|---------------------------------|\n| 流程模型 | ![流程模型-列表](/.image/流程模型-列表.jpg) | ![流程模型-设计](/.image/流程模型-设计.jpg) | ![流程模型-定义](/.image/流程模型-定义.jpg) |\n| 表单 & 分组 | ![流程表单](/.image/流程表单.jpg) | ![用户分组](/.image/用户分组.jpg) | - |\n| 我的流程 | ![我的流程-列表](/.image/我的流程-列表.jpg) | ![我的流程-发起](/.image/我的流程-发起.jpg) | ![我的流程-详情](/.image/我的流程-详情.jpg) |\n| 待办 & 已办 | ![任务列表-审批](/.image/任务列表-审批.jpg) | ![任务列表-待办](/.image/任务列表-待办.jpg) | ![任务列表-已办](/.image/任务列表-已办.jpg) |\n| OA 请假 | ![OA请假-列表](/.image/OA请假-列表.jpg) | ![OA请假-发起](/.image/OA请假-发起.jpg) | ![OA请假-详情](/.image/OA请假-详情.jpg) |\n\n### 基础设施\n\n| 模块 | biu | biu | biu |\n|---------------|-------------------------------|-----------------------------|---------------------------|\n| 代码生成 | ![代码生成](/.image/代码生成.jpg) | ![生成效果](/.image/生成效果.jpg) | - |\n| 文档 | ![系统接口](/.image/系统接口.jpg) | ![数据库文档](/.image/数据库文档.jpg) | - |\n| 文件 & 配置 | ![文件配置](/.image/文件配置.jpg) | ![文件管理](/.image/文件管理2.jpg) | ![配置管理](/.image/配置管理.jpg) |\n| 定时任务 | ![定时任务](/.image/定时任务.jpg) | ![任务日志](/.image/任务日志.jpg) | - |\n| API 日志 | ![访问日志](/.image/访问日志.jpg) | ![错误日志](/.image/错误日志.jpg) | - |\n| MySQL & Redis | ![MySQL](/.image/MySQL.jpg) | ![Redis](/.image/Redis.jpg) | - |\n| 监控平台 | ![Java监控](/.image/Java监控.jpg) | ![链路追踪](/.image/链路追踪.jpg) | ![日志中心](/.image/日志中心.jpg) |\n\n### 支付系统\n\n| 模块 | biu | biu | biu |\n|---------|---------------------------|---------------------------------|---------------------------------|\n| 商家 & 应用 | ![商户信息](/.image/商户信息.jpg) | ![应用信息-列表](/.image/应用信息-列表.jpg) | ![应用信息-编辑](/.image/应用信息-编辑.jpg) |\n| 支付 & 退款 | ![支付订单](/.image/支付订单.jpg) | ![退款订单](/.image/退款订单.jpg) | --- |\n### 数据报表\n\n| 模块 | biu | biu | biu |\n|-------|---------------------------------|---------------------------------|---------------------------------------|\n| 报表设计器 | ![数据报表](/.image/报表设计器-数据报表.jpg) | ![图形报表](/.image/报表设计器-图形报表.jpg) | ![报表设计器-打印设计](/.image/报表设计器-打印设计.jpg) |\n| 大屏设计器 | ![大屏列表](/.image/大屏设计器-列表.jpg) | ![大屏预览](/.image/大屏设计器-预览.jpg) | ![大屏编辑](/.image/大屏设计器-编辑.jpg) |\n\n### 移动端(管理后台)\n\n| biu | biu | biu |\n|----------------------------------|----------------------------------|----------------------------------|\n| ![](/.image/admin-uniapp/01.png) | ![](/.image/admin-uniapp/02.png) | ![](/.image/admin-uniapp/03.png) |\n| ![](/.image/admin-uniapp/04.png) | ![](/.image/admin-uniapp/05.png) | ![](/.image/admin-uniapp/06.png) |\n| ![](/.image/admin-uniapp/07.png) | ![](/.image/admin-uniapp/08.png) | ![](/.image/admin-uniapp/09.png) |\n\n目前已经实现登录、我的、工作台、编辑资料、头像修改、密码修改、常见问题、关于我们等基础功能。\n\n', 24120, 9676, 500, 0, 0, '1', '2025-03-08 17:51:50', '1', '2025-03-08 17:51:50', b'0', 1); +INSERT INTO `ai_knowledge_document` VALUES (19, 5, '1_yudao-cloud-mini-jdk17-整合seata.docx', 'http://test.yudao.iocoder.cn/d2a8a80545b136192398fbeb5f9b917c7845c4dc186ddf142bf61f83a1cae51f.docx', '一,创建seata子模块\n在yudao-framework模块下新建子模块yudao-spring-boot-starter-seata,\n然后在这个yudao-spring-boot-starter-seata模块的pom文件中引入依赖,\n\n cn.iocoder.cloud\n yudao-common\n 2.3.0-SNAPSHOT\n \n \n com.alibaba.cloud\n spring-cloud-alibaba-seata\n 2023.0.1.2\n \n \n io.seata\n seata-spring-boot-starter\n \n 1.8.0\n \n \n io.seata\n seata-all\n \n 1.8.0\n \n \n log4j\n log4j\n \n \n \n \n io.seata\n seata-spring-autoconfigure-client\n \n 1.8.0\n \n \n com.caucho\n hessian\n 4.0.63\n \n \n io.protostuff\n protostuff-core\n 1.7.2\n \n \n io.protostuff\n protostuff-runtime\n 1.7.2\n \n\n二,部署seata服务端\nseata是用于分布式事务的,\n目前我用的是seata-server2.0.0版的windows版,nacos服务器版本我用的2.0.3\nseata\\conf\\application.yml配置文件中:\n\nserver:\n port: 7091\n\nspring:\n application:\n name: seata-server\n\nlogging:\n config: classpath:logback-spring.xml\n file:\n path: ${log.home:${user.home}/logs/seata}\n extend:\n logstash-appender:\n destination: 127.0.0.1:4560\n kafka-appender:\n bootstrap-servers: 127.0.0.1:9092\n topic: logback_to_logstash\n\nconsole:\n user:\n username: seata\n password: seata\nseata:\n config:\n # support: nacos, consul, apollo, zk, etcd3\n type: nacos\n nacos:\n server-addr: 192.168.1.146:8848\n namespace: zma-dev\n group: SEATA_GROUP\n username: nacos\n password: nacos\n context-path:\n ##if use MSE Nacos with auth, mutex with username/password attribute\n #access-key:\n #secret-key:\n data-id: seataServer.properties\n registry:\n # support: nacos, eureka, redis, zk, consul, etcd3, sofa\n type: nacos\n preferred-networks: 30.240.*\n nacos:\n application: seata-server\n server-addr: 192.168.1.146:8848\n group: SEATA_GROUP\n namespace: zma-dev\n cluster: default\n username: nacod\n password: nacos\n context-path:\n ##if use MSE Nacos with auth, mutex with username/password attribute\n #access-key:\n store:\n # support: file 、 db 、 redis 、 raft\n mode: file\n # server:\n # service-port: 8091 #If not configured, the default is \'${server.port} + 1000\'\n security:\n secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017\n tokenValidityInMilliseconds: 1800000\n ignore:\n urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.jpeg,/**/*.ico,/api/v1/auth/login,/metadata/v1/**\nnacos配置中心里面,建一个seataServer.properties配置文件,内容如下:\nData ID: seataServer.properties\nGroup: SEATA_GROUP\nservice.enableDegrade=false\nservice.disableGlobalTransaction=false\nservice.vgroupMapping.default-tx-group=default\nservice.vgroupMapping.order-service-group=default\n启动seata-server,\n在seata\\bin下,双击seata-server.bat文件启动,查看nacos中是否有seata-server的服务,如果有,证明启动成功。\n或者去访问seata的管理页面地址:http://localhost:7091,如果能正常打开,证明seata已经启动成功。\n二,微服务中配置seata\nspringcloud的微服务中配置seata\n先在微服务的pom.xml中添加依赖\n \n \n cn.iocoder.cloud\n yudao-spring-boot-starter-seata\n 2.3.0-SNAPSHOT\n \n然后在springboot微服务的yml中配置:\n# Seata 配置项,对应 SeataProperties 类\nseata:\n application-id: ${spring.application.name} # Seata 应用编号,默认为 ${spring.application.name}\n tx-service-group: default-tx-group # Seata 事务组编号,用于 TC 集群名\n # Seata 服务配置项,对应 ServiceProperties 类\n service:\n vgroup-mapping:\n default-tx-group: default\n data-source-proxy-mode: AT\n # Seata 注册中心配置项,对应 RegistryProperties 类\n registry:\n type: nacos # 注册中心类型,默认为 file\n nacos:\n cluster: default # 使用的 Seata 分组\n namespace: zma-dev # Nacos 命名空间\n # serverAddr: 192.168.1.17:8848 # Nacos 服务地址\n serverAddr: localhost:8848 # Nacos 服务地址\n group : SEATA_GROUP\n username: nacos\n password: nacos\n然后在微服务启动类上加注解\n//开启seata对数据源的自动代理\n@EnableAutoDataSourceProxy \n//开启seata对FeignClient运程调用的自动配置\n@EnableFeignClients(defaultConfiguration = SeataFeignClientAutoConfiguration.class)\n\n三,测试全局事务\n先写一个测试接口,我是在TenantController中写的\n @GetMapping(\"/test-seata\")\n @Operation(summary = \"测试seata\")\n public CommonResult testSeata() {\n return success(menuService.testSeata());\n }\nmenuService业务实现方法上加注解@GlobalTransactional(name = \"testSeata\",rollbackFor = Exception.class),\n这个注解中的name的值要保证唯一性,我这里直接用的方法,如果你当前项目中有多个方法名与当前方法名相同,那就要区别开,比如前面再加上微服务名-controller名,后面再加后缀的方式,保证唯一就行了,如:systemServer-testController-testSeata-1。\n@Override\n @GlobalTransactional(name = \"testSeata\",rollbackFor = Exception.class)\n public Object testSeata() {\n MenuDO menuDO = menuMapper.selectById(2815);\n menuDO.setName(\"测试111\");\n //本微服务system微服务中修改stem_menu表,此修改操作会成功\n menuMapper.updateById(menuDO);\n //通过FeignClient远程调用infra微服务中的方法testSeata,\n //在testSeata插入一条数据到yudao_demo01_contact表,此插入操作会成功\n Boolean bool = apiErrorLogApi.testSeata();\n //通过FeignClient远程调用infra微服务中的方法testSeata2,\n //在testSeata2方法中插入一条数据到yudao_demo02_category表,此插入操作会失败,因为id与数据库中的已有的id重复\n Boolean common = apiErrorLogApi.testSeata2();\n //执行完会去看数据库中的三张表中的数据是否有回滚,如果有回滚,证明全局事务生效了。\n return true;\n }\n注意1:要用全局事务时,远程调用的方法不能以CommonResult返回,要以实体数据实体返回,比如我当前方法只需要一个String字符串,那就以String返回,再比如我需要一个用户对象,那个直接以User返回,不要封装到带有code,msg,data的Result结果对象中返回,不然事务会不生效。\n注意2:远程调用的方法中不能有try{}catch (Exception e) {},不然事务也不会生效。\n然后,数据库中要加seata处理事务的表,如果有多个数据库,那么每个数据库中都要加这张表。\nCREATE TABLE `undo_log` (\n `id` bigint NOT NULL AUTO_INCREMENT,\n `branch_id` bigint NOT NULL,\n `xid` varchar(100) NOT NULL,\n `context` varchar(128) NOT NULL,\n `rollback_info` longblob NOT NULL,\n `log_status` int NOT NULL,\n `log_created` datetime NOT NULL,\n `log_modified` datetime NOT NULL,\n `ext` varchar(100) DEFAULT NULL,\n PRIMARY KEY (`id`),\n UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)\n) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb3;\n然后启动gateway,system微服务与infra微服务,\n最后,用postman请求system微服务中的这个/test-seata接口,测试数据库的数据的修改与插入是否有回滚,是否有同步成功,同步失败。\n\n一,创建 seata 子模块\n\n在yudao-framework 模块下新建子模块 yudao-spring-boot-starter- seata,\n\n然后在这个 yudao-spring-boot-starter- seata模块的pom文件中引入依赖,\n\n\n\n cn.iocoder.cloud\n\ny udao-common\n\n2.3.0-SNAPSHOT\n\n\n\n\n\ncom.alibaba.cloud\n\nspring-cloud-alibaba-\n\nseata\n\n2023.0.1.2\n\n\n\n\n\nio.seata\n\nseata-spring-boot-\n\nstarter\n\n\n\n1.8.0\n\n\n\n\n\nio.seata\n\nseata-all\n\n\n\n1.8.0\n\n\n\n\n\nlog4j\n\nlog4j\n\n\n\n\n\n\n\n\n\nio.seata\n\n', 8493, 2872, 500, 0, 0, '1', '2025-03-09 09:15:30', '1', '2025-03-09 09:15:30', b'0', 1); +INSERT INTO `ai_knowledge_document` VALUES (20, 3, '1_yudao-cloud-mini-jdk17-整合seata.docx', 'http://test.yudao.iocoder.cn/d2a8a80545b136192398fbeb5f9b917c7845c4dc186ddf142bf61f83a1cae51f.docx', '一,创建seata子模块\n在yudao-framework模块下新建子模块yudao-spring-boot-starter-seata,\n然后在这个yudao-spring-boot-starter-seata模块的pom文件中引入依赖,\n\n cn.iocoder.cloud\n yudao-common\n 2.3.0-SNAPSHOT\n \n \n com.alibaba.cloud\n spring-cloud-alibaba-seata\n 2023.0.1.2\n \n \n io.seata\n seata-spring-boot-starter\n \n 1.8.0\n \n \n io.seata\n seata-all\n \n 1.8.0\n \n \n log4j\n log4j\n \n \n \n \n io.seata\n seata-spring-autoconfigure-client\n \n 1.8.0\n \n \n com.caucho\n hessian\n 4.0.63\n \n \n io.protostuff\n protostuff-core\n 1.7.2\n \n \n io.protostuff\n protostuff-runtime\n 1.7.2\n \n\n二,部署seata服务端\nseata是用于分布式事务的,\n目前我用的是seata-server2.0.0版的windows版,nacos服务器版本我用的2.0.3\nseata\\conf\\application.yml配置文件中:\n\nserver:\n port: 7091\n\nspring:\n application:\n name: seata-server\n\nlogging:\n config: classpath:logback-spring.xml\n file:\n path: ${log.home:${user.home}/logs/seata}\n extend:\n logstash-appender:\n destination: 127.0.0.1:4560\n kafka-appender:\n bootstrap-servers: 127.0.0.1:9092\n topic: logback_to_logstash\n\nconsole:\n user:\n username: seata\n password: seata\nseata:\n config:\n # support: nacos, consul, apollo, zk, etcd3\n type: nacos\n nacos:\n server-addr: 192.168.1.146:8848\n namespace: zma-dev\n group: SEATA_GROUP\n username: nacos\n password: nacos\n context-path:\n ##if use MSE Nacos with auth, mutex with username/password attribute\n #access-key:\n #secret-key:\n data-id: seataServer.properties\n registry:\n # support: nacos, eureka, redis, zk, consul, etcd3, sofa\n type: nacos\n preferred-networks: 30.240.*\n nacos:\n application: seata-server\n server-addr: 192.168.1.146:8848\n group: SEATA_GROUP\n namespace: zma-dev\n cluster: default\n username: nacod\n password: nacos\n context-path:\n ##if use MSE Nacos with auth, mutex with username/password attribute\n #access-key:\n store:\n # support: file 、 db 、 redis 、 raft\n mode: file\n # server:\n # service-port: 8091 #If not configured, the default is \'${server.port} + 1000\'\n security:\n secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017\n tokenValidityInMilliseconds: 1800000\n ignore:\n urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.jpeg,/**/*.ico,/api/v1/auth/login,/metadata/v1/**\nnacos配置中心里面,建一个seataServer.properties配置文件,内容如下:\nData ID: seataServer.properties\nGroup: SEATA_GROUP\nservice.enableDegrade=false\nservice.disableGlobalTransaction=false\nservice.vgroupMapping.default-tx-group=default\nservice.vgroupMapping.order-service-group=default\n启动seata-server,\n在seata\\bin下,双击seata-server.bat文件启动,查看nacos中是否有seata-server的服务,如果有,证明启动成功。\n或者去访问seata的管理页面地址:http://localhost:7091,如果能正常打开,证明seata已经启动成功。\n二,微服务中配置seata\nspringcloud的微服务中配置seata\n先在微服务的pom.xml中添加依赖\n \n \n cn.iocoder.cloud\n yudao-spring-boot-starter-seata\n 2.3.0-SNAPSHOT\n \n然后在springboot微服务的yml中配置:\n# Seata 配置项,对应 SeataProperties 类\nseata:\n application-id: ${spring.application.name} # Seata 应用编号,默认为 ${spring.application.name}\n tx-service-group: default-tx-group # Seata 事务组编号,用于 TC 集群名\n # Seata 服务配置项,对应 ServiceProperties 类\n service:\n vgroup-mapping:\n default-tx-group: default\n data-source-proxy-mode: AT\n # Seata 注册中心配置项,对应 RegistryProperties 类\n registry:\n type: nacos # 注册中心类型,默认为 file\n nacos:\n cluster: default # 使用的 Seata 分组\n namespace: zma-dev # Nacos 命名空间\n # serverAddr: 192.168.1.17:8848 # Nacos 服务地址\n serverAddr: localhost:8848 # Nacos 服务地址\n group : SEATA_GROUP\n username: nacos\n password: nacos\n然后在微服务启动类上加注解\n//开启seata对数据源的自动代理\n@EnableAutoDataSourceProxy \n//开启seata对FeignClient运程调用的自动配置\n@EnableFeignClients(defaultConfiguration = SeataFeignClientAutoConfiguration.class)\n\n三,测试全局事务\n先写一个测试接口,我是在TenantController中写的\n @GetMapping(\"/test-seata\")\n @Operation(summary = \"测试seata\")\n public CommonResult testSeata() {\n return success(menuService.testSeata());\n }\nmenuService业务实现方法上加注解@GlobalTransactional(name = \"testSeata\",rollbackFor = Exception.class),\n这个注解中的name的值要保证唯一性,我这里直接用的方法,如果你当前项目中有多个方法名与当前方法名相同,那就要区别开,比如前面再加上微服务名-controller名,后面再加后缀的方式,保证唯一就行了,如:systemServer-testController-testSeata-1。\n@Override\n @GlobalTransactional(name = \"testSeata\",rollbackFor = Exception.class)\n public Object testSeata() {\n MenuDO menuDO = menuMapper.selectById(2815);\n menuDO.setName(\"测试111\");\n //本微服务system微服务中修改stem_menu表,此修改操作会成功\n menuMapper.updateById(menuDO);\n //通过FeignClient远程调用infra微服务中的方法testSeata,\n //在testSeata插入一条数据到yudao_demo01_contact表,此插入操作会成功\n Boolean bool = apiErrorLogApi.testSeata();\n //通过FeignClient远程调用infra微服务中的方法testSeata2,\n //在testSeata2方法中插入一条数据到yudao_demo02_category表,此插入操作会失败,因为id与数据库中的已有的id重复\n Boolean common = apiErrorLogApi.testSeata2();\n //执行完会去看数据库中的三张表中的数据是否有回滚,如果有回滚,证明全局事务生效了。\n return true;\n }\n注意1:要用全局事务时,远程调用的方法不能以CommonResult返回,要以实体数据实体返回,比如我当前方法只需要一个String字符串,那就以String返回,再比如我需要一个用户对象,那个直接以User返回,不要封装到带有code,msg,data的Result结果对象中返回,不然事务会不生效。\n注意2:远程调用的方法中不能有try{}catch (Exception e) {},不然事务也不会生效。\n然后,数据库中要加seata处理事务的表,如果有多个数据库,那么每个数据库中都要加这张表。\nCREATE TABLE `undo_log` (\n `id` bigint NOT NULL AUTO_INCREMENT,\n `branch_id` bigint NOT NULL,\n `xid` varchar(100) NOT NULL,\n `context` varchar(128) NOT NULL,\n `rollback_info` longblob NOT NULL,\n `log_status` int NOT NULL,\n `log_created` datetime NOT NULL,\n `log_modified` datetime NOT NULL,\n `ext` varchar(100) DEFAULT NULL,\n PRIMARY KEY (`id`),\n UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)\n) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb3;\n然后启动gateway,system微服务与infra微服务,\n最后,用postman请求system微服务中的这个/test-seata接口,测试数据库的数据的修改与插入是否有回滚,是否有同步成功,同步失败。\n\n一,创建 seata 子模块\n\n在yudao-framework 模块下新建子模块 yudao-spring-boot-starter- seata,\n\n然后在这个 yudao-spring-boot-starter- seata模块的pom文件中引入依赖,\n\n\n\n cn.iocoder.cloud\n\ny udao-common\n\n2.3.0-SNAPSHOT\n\n\n\n\n\ncom.alibaba.cloud\n\nspring-cloud-alibaba-\n\nseata\n\n2023.0.1.2\n\n\n\n\n\nio.seata\n\nseata-spring-boot-\n\nstarter\n\n\n\n1.8.0\n\n\n\n\n\nio.seata\n\nseata-all\n\n\n\n1.8.0\n\n\n\n\n\nlog4j\n\nlog4j\n\n\n\n\n\n\n\n\n\nio.seata\n\n', 8493, 2872, 500, 0, 0, '1', '2025-03-09 18:31:44', '1', '2025-03-09 18:44:12', b'1', 1); +INSERT INTO `ai_knowledge_document` VALUES (21, 3, '31.4k!这是我见过最强的后台管理系统 !!.md', 'http://test.yudao.iocoder.cn/530212386f51a33cb452e84599e341ca2f47adb7cfdaff6c99950993759158e4.md', '\n## 🐯 平台简介\n\n**芋道**,以开发者为中心,打造中国第一流的快速开发平台,全部开源,个人与企业可 100% 免费使用。\n\n![架构图](https://static.iocoder.cn/ruoyi-vue-pro-architecture.png)\n\n* 管理后台的 Vue3 版本采用 [vue-element-plus-admin](https://gitee.com/kailong110120130/vue-element-plus-admin) ,Vue2 版本采用 [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin) \n* 管理后台的移动端采用 [uni-app](https://github.com/dcloudio/uni-app) 方案,一份代码多终端适配,同时支持 APP、小程序、H5!\n* 后端采用 Spring Boot、MySQL + MyBatis Plus、Redis + Redisson\n* 数据库可使用 MySQL、Oracle、PostgreSQL、SQL Server、MariaDB、国产达梦 DM、TiDB 等\n* 权限认证使用 Spring Security & Token & Redis,支持多终端、多种用户的认证系统,支持 SSO 单点登录\n* 支持加载动态权限菜单,按钮级别权限控制,本地缓存提升性能\n* 支持 SaaS 多租户系统,可自定义每个租户的权限,提供透明化的多租户底层封装\n* 工作流使用 Flowable,支持动态表单、在线设计流程、会签 / 或签、多种任务分配方式\n* 高效率开发,使用代码生成器可以一键生成前后端代码 + 单元测试 + Swagger 接口文档 + Validator 参数校验\n* 集成微信小程序、微信公众号、企业微信、钉钉等三方登陆,集成支付宝、微信等支付与退款\n* 集成阿里云、腾讯云等短信渠道,集成 MinIO、阿里云、腾讯云、七牛云等云存储服务\n* 集成报表设计器,支持数据报表、图形报表、打印设计等\n\n## 🐳 项目关系\n\n![架构演进](https://static.iocoder.cn/yudao-roadmap.png?imageView2/2/format/webp)\n\n三个项目的功能对比,可见社区共同整理的 [国产开源项目对比](https://www.yuque.com/xiatian-bsgny/lm0ec1/wqf8mn) 表格。\n\n* 项目地址:\n* 官方文档:\n* 演示地址:\n* 视频教程:\n\n### 后端项目\n\n| 项目 | Star | 简介 |\n|-----------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------|\n| [ruoyi-vue-pro](https://gitee.com/zhijiantianya/ruoyi-vue-pro) | [![Gitee star](https://gitee.com/zhijiantianya/ruoyi-vue-pro/badge/star.svg?theme=white)](https://gitee.com/zhijiantianya/ruoyi-vue-pro) [![GitHub stars](https://img.shields.io/github/stars/YunaiV/ruoyi-vue-pro.svg?style=social&label=Stars)](https://github.com/YunaiV/ruoyi-vue-pro) | 基于 Spring Boot 多模块架构 |\n| [yudao-cloud](https://gitee.com/zhijiantianya/yudao-cloud) | [![Gitee star](https://gitee.com/zhijiantianya/yudao-cloud/badge/star.svg?theme=white)](https://gitee.com/zhijiantianya/yudao-cloud) [![GitHub stars](https://img.shields.io/github/stars/YunaiV/yudao-cloud.svg?style=social&label=Stars)](https://github.com/YunaiV/yudao-cloud) | 基于 Spring Cloud 微服务架构 |\n| [Spring-Boot-Labs](https://gitee.com/yudaocode/SpringBoot-Labs) | [![Gitee star](https://gitee.com/yudaocode/SpringBoot-Labs/badge/star.svg?theme=white)](https://gitee.com/zhijiantianya/yudao-cloud) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/SpringBoot-Labs.svg?style=social&label=Stars)](https://github.com/yudaocode/SpringBoot-Labs) | 系统学习 Spring Boot & Cloud 专栏 |\n\n### 前端项目\n\n| 项目 | Star | 简介 |\n|----------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------|\n| [yudao-ui-admin-vue3](https://gitee.com/yudaocode/yudao-ui-admin-vue3) | [![Gitee star](https://gitee.com/yudaocode/yudao-ui-admin-vue3/badge/star.svg?theme=white)](https://gitee.com/yudaocode/yudao-ui-admin-vue3) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/yudao-ui-admin-vue3.svg?style=social&label=Stars)](https://github.com/yudaocode/yudao-ui-admin-vue3) | 基于 Vue3 + element-plus 实现的管理后台 |\n| [yudao-ui-admin](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/yudao-ui-admin) | [![Gitee star](https://gitee.com/zhijiantianya/ruoyi-vue-pro/badge/star.svg?theme=white)](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/yudao-ui-admin) [![GitHub stars](https://img.shields.io/github/stars/YunaiV/ruoyi-vue-pro.svg?style=social&label=Stars)](https://github.com/YunaiV/ruoyi-vue-pro/tree/master/yudao-ui-admin) | 基于 Vue2 + element-ui 实现的管理后台 |\n| [yudao-ui-admin-uniapp](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/yudao-ui-admin-uniapp) | [![Gitee star](https://gitee.com/zhijiantianya/ruoyi-vue-pro/badge/star.svg?theme=white)](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/yudao-ui-admin-uniapp) [![GitHub stars](https://img.shields.io/github/stars/YunaiV/ruoyi-vue-pro.svg?style=social&label=Stars)](https://github.com/YunaiV/ruoyi-vue-pro/tree/master/yudao-ui-admin-uniapp) | 基于 uni-app + uni-ui 实现的管理后台的小程序 |\n| [yudao-ui-go-view](https://gitee.com/yudaocode/yudao-ui-go-view) | [![Gitee star](https://gitee.com/yudaocode/yudao-ui-go-view/badge/star.svg?theme=white)](https://gitee.com/yudaocode/yudao-ui-go-view) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/yudao-ui-go-view.svg?style=social&label=Stars)](https://github.com/yudaocode/yudao-ui-go-view) | 基于 Vue3 + naive-ui 实现的大屏报表 |\n| [yudao-ui-app](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/yudao-ui-app) | [![Gitee star](https://gitee.com/zhijiantianya/ruoyi-vue-pro/badge/star.svg?theme=white)](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/yudao-ui-app) [![GitHub stars](https://img.shields.io/github/stars/YunaiV/ruoyi-vue-pro.svg?style=social&label=Stars)](https://github.com/YunaiV/ruoyi-vue-pro/tree/master/yudao-ui-app) | 基于 uni-app + uview 实现的用户 App |\n\n## 😎 开源协议\n\n**为什么推荐使用本项目?**\n\n① 本项目采用比 Apache 2.0 更宽松的 [MIT License](https://gitee.com/zhijiantianya/ruoyi-vue-pro/blob/master/LICENSE) 开源协议,个人与企业可 100% 免费使用,不用保留类作者、Copyright 信息。\n\n② 代码全部开源,不会像其他项目一样,只开源部分代码,让你无法了解整个项目的架构设计。\n\n③ 代码整洁、架构整洁,遵循《阿里巴巴 Java 开发手册》规范,代码注释详细,57000 行 Java 代码,22000 行代码注释。\n\n## 🐼 内置功能\n\n系统内置多种多种业务功能,可以用于快速你的业务系统:\n\n![功能分层](https://static.iocoder.cn/ruoyi-vue-pro-biz.png)\n\n* 系统功能\n* 基础设施\n* 工作流程\n* 支付系统\n* 数据报表\n\n> 友情提示:本项目基于 RuoYi-Vue 修改,**重构优化**后端的代码,**美化**前端的界面。\n>\n> * 额外新增的功能,我们使用 🚀 标记。\n> * 重新实现的功能,我们使用 ⭐️ 标记。\n\n🙂 所有功能,都通过 **单元测试** 保证高质量。\n\n### 系统功能\n\n| | 功能 | 描述 |\n|-----|-------|---------------------------------|\n| | 用户管理 | 用户是系统操作者,该功能主要完成系统用户配置 |\n| ⭐️ | 在线用户 | 当前系统中活跃用户状态监控,支持手动踢下线 |\n| | 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分 |\n| | 菜单管理 | 配置系统菜单、操作权限、按钮权限标识等,本地缓存提供性能 |\n| | 部门管理 | 配置系统组织机构(公司、部门、小组),树结构展现支持数据权限 |\n| | 岗位管理 | 配置系统用户所属担任职务 |\n| 🚀 | 租户管理 | 配置系统租户,支持 SaaS 场景下的多租户功能 |\n| 🚀 | 租户套餐 | 配置租户套餐,自定每个租户的菜单、操作、按钮的权限 |\n| | 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 |\n| 🚀 | 短信管理 | 短信渠道、短息模板、短信日志,对接阿里云、腾讯云等主流短信平台 |\n| 🚀 | 操作日志 | 系统正常操作日志记录和查询,集成 Swagger 生成日志内容 |\n| ⭐️ | 登录日志 | 系统登录日志记录查询,包含登录异常 |\n| 🚀 | 错误码管理 | 系统所有错误码的管理,可在线修改错误提示,无需重启服务 |\n| | 通知公告 | 系统通知公告信息发布维护 |\n| 🚀 | 敏感词 | 配置系统敏感词,支持标签分组 |\n| 🚀 | 应用管理 | 管理 SSO 单点登录的应用,支持多种 OAuth2 授权方式 |\n\n### 工作流程\n\n| | 功能 | 描述 |\n|-----|-------|----------------------------------------|\n| 🚀 | 流程模型 | 配置工作流的流程模型,支持文件导入与在线设计流程图,提供 7 种任务分配规则 |\n| 🚀 | 流程表单 | 拖动表单元素生成相应的工作流表单,覆盖 Element UI 所有的表单组件 |\n| 🚀 | 用户分组 | 自定义用户分组,可用于工作流的审批分组 |\n| 🚀 | 我的流程 | 查看我发起的工作流程,支持新建、取消流程等操作,高亮流程图、审批时间线 |\n| 🚀 | 待办任务 | 查看自己【未】审批的工作任务,支持通过、不通过、转发、委派、退回等操作 |\n| 🚀 | 已办任务 | 查看自己【已】审批的工作任务,未来会支持回退操作 |\n| 🚀 | OA 请假 | 作为业务自定义接入工作流的使用示例,只需创建请求对应的工作流程,即可进行审批 |\n\n### 支付系统\n\n| | 功能 | 描述 |\n|-----|------|---------------------------|\n| 🚀 | 商户信息 | 管理商户信息,支持 Saas 场景下的多商户功能 |\n| 🚀 | 应用信息 | 配置商户的应用信息,对接支付宝、微信等多个支付渠道 |\n| 🚀 | 支付订单 | 查看用户发起的支付宝、微信等的【支付】订单 |\n| 🚀 | 退款订单 | 查看用户发起的支付宝、微信等的【退款】订单 |\n\nps:核心功能已经实现,正在对接微信小程序中...\n\n### 基础设施\n\n| | 功能 | 描述 |\n|-----|----------|----------------------------------------------|\n| 🚀 | 代码生成 | 前后端代码的生成(Java、Vue、SQL、单元测试),支持 CRUD 下载 |\n| 🚀 | 系统接口 | 基于 Swagger 自动生成相关的 RESTful API 接口文档 |\n| 🚀 | 数据库文档 | 基于 Screw 自动生成数据库文档,支持导出 Word、HTML、MD 格式 |\n| | 表单构建 | 拖动表单元素生成相应的 HTML 代码,支持导出 JSON、Vue 文件 |\n| 🚀 | 配置管理 | 对系统动态配置常用参数,支持 SpringBoot 加载 |\n| ⭐️ | 定时任务 | 在线(添加、修改、删除)任务调度包含执行结果日志 |\n| 🚀 | 文件服务 | 支持将文件存储到 S3(MinIO、阿里云、腾讯云、七牛云)、本地、FTP、数据库等 | \n| 🚀 | API 日志 | 包括 RESTful API 访问日志、异常日志两部分,方便排查 API 相关的问题 |\n| | MySQL 监控 | 监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈 |\n| | Redis 监控 | 监控 Redis 数据库的使用情况,使用的 Redis Key 管理 |\n| 🚀 | 消息队列 | 基于 Redis 实现消息队列,Stream 提供集群消费,Pub/Sub 提供广播消费 |\n| 🚀 | Java 监控 | 基于 Spring Boot Admin 实现 Java 应用的监控 |\n| 🚀 | 链路追踪 | 接入 SkyWalking 组件,实现链路追踪 |\n| 🚀 | 日志中心 | 接入 SkyWalking 组件,实现日志中心 |\n| 🚀 | 分布式锁 | 基于 Redis 实现分布式锁,满足并发场景 |\n| 🚀 | 幂等组件 | 基于 Redis 实现幂等组件,解决重复请求问题 |\n| 🚀 | 服务保障 | 基于 Resilience4j 实现服务的稳定性,包括限流、熔断等功能 |\n| 🚀 | 日志服务 | 轻量级日志中心,查看远程服务器的日志 |\n| 🚀 | 单元测试 | 基于 JUnit + Mockito 实现单元测试,保证功能的正确性、代码的质量等 |\n\n### 数据报表\n\n| | 功能 | 描述 |\n|-----|----------|----------------------------------------------|\n| 🚀 | 报表设计器 | 支持数据报表、图形报表、打印设计等 |\n| 🚀 | 大屏设计器 | 建设中... 拖拽式实现可视化数据大屏 |\n\n## 🐨 技术栈\n\n| 项目 | 说明 |\n|-------------------------|-----------------------|\n| `yudao-dependencies` | Maven 依赖版本管理 |\n| `yudao-framework` | Java 框架拓展 |\n| `yudao-server` | 管理后台 + 用户 APP 的服务端 |\n| `yudao-ui-admin` | 管理后台的 Vue2 前端项目 |\n| `yudao-ui-admin-vue3` | 管理后台的 Vue3 前端项目 |\n| `yudao-ui-admin-uniapp` | 管理后台的 uni-app 多端项目 |\n| `yudao-ui-app` | 用户 APP 的 UI 界面 |\n| `yudao-module-system` | 系统功能的 Module 模块 |\n| `yudao-module-member` | 会员中心的 Module 模块 |\n| `yudao-module-infra` | 基础设施的 Module 模块 |\n| `yudao-module-tool` | 研发工具的 Module 模块 |\n| `yudao-module-bpm` | 工作流程的 Module 模块 |\n| `yudao-module-pay` | 支付系统的 Module 模块 |\n\n### 后端\n\n| 框架 | 说明 | 版本 | 学习指南 |\n|---------------------------------------------------------------------------------------------|-----------------------|-------------|----------------------------------------------------------------|\n| [Spring Boot](https://spring.io/projects/spring-boot) | 应用开发框架 | 2.7.6 | [文档](https://github.com/YunaiV/SpringBoot-Labs) |\n| [MySQL](https://www.mysql.com/cn/) | 数据库服务器 | 5.7 / 8.0+ | |\n| [Druid](https://github.com/alibaba/druid) | JDBC 连接池、监控组件 | 1.2.15 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |\n| [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.5.2 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) |\n| [Dynamic Datasource](https://dynamic-datasource.com/) | 动态数据源 | 3.6.0 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |\n| [Redis](https://redis.io/) | key-value 数据库 | 5.0 / 6.0 | |\n| [Redisson](https://github.com/redisson/redisson) | Redis 客户端 | 3.18.0 | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao) |\n| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架 | 5.3.24 | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao) |\n| [Spring Security](https://github.com/spring-projects/spring-security) | Spring 安全框架 | 5.7.5 | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) |\n| [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 6.2.5 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) |\n| [Flowable](https://github.com/flowable/flowable-engine) | 工作流引擎 | 6.7.2 | [文档](https://doc.iocoder.cn/bpm/) |\n| [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) |\n| [Knife4j](https://gitee.com/xiaoym/knife4j) | Swagger 增强 UI 实现 | 3.0.3 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) |\n| [Resilience4j](https://github.com/resilience4j/resilience4j) | 服务保障组件 | 1.7.1 | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao) |\n| [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 8.12.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) |\n| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 监控平台 | 2.7.9 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) |\n| [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.13.3 | |\n| [MapStruct](https://mapstruct.org/) | Java Bean 转换 | 1.5.3.Final | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) |\n| [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.18.24 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) |\n| [JUnit](https://junit.org/junit5/) | Java 单元测试框架 | 5.8.2 | - |\n| [Mockito](https://github.com/mockito/mockito) | Java Mock 框架 | 4.8.0 | - |\n\n### [管理后台 Vue2 前端](./yudao-ui-admin)\n\n| 框架 | 说明 | 版本 |\n|------------------------------------------------------------------------------|---------------|--------|\n| [Vue](https://cn.vuejs.org/index.html) | JavaScript 框架 | 2.7.14 |\n| [Vue Element Admin](https://panjiachen.github.io/vue-element-admin-site/zh/) | 后台前端解决方案 | - |\n\n### [管理后台 Vue3 前端](./yudao-ui-admin-vue3)\n\n| 框架 | 说明 | 版本 |\n|----------------------------------------------------------------------|:------------:|:------:|\n| [Vue](https://staging-cn.vuejs.org/) | Vue 框架 | 3.2.45 |\n| [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 4.0.3 |\n| [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.2.27 |\n| [TypeScript](https://www.typescriptlang.org/docs/) | TypeScript | 4.9.4 |\n| [pinia](https://pinia.vuejs.org/) | vuex5 | 2.0.28 |\n| [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.2.2 |\n| [vxe-table](https://vxetable.cn/) | vue最强表单 | 4.3.7 |\n\n### [管理后台 uni-app 跨端](./yudao-ui-admin-uniapp)\n\n| 框架 | 说明 | 版本 |\n|----------------------------------------------------------------------|------------------|--------|\n| [uni-app](hhttps://github.com/dcloudio/uni-app) | 跨平台框架 | 2.0.0 |\n| [uni-ui](https://github.com/dcloudio/uni-ui) | 基于 uni-app 的 UI 框架 | 1.4.20 |\n\n## 🐷 演示图\n\n**效果预览** :\n\n![首页](https://mmbiz.qpic.cn/mmbiz/iaIdQfEric9Txw85YtbKNvl0ibKkgxeiahe5GYiamW2FAgbicPCzMAx37hy26WL8wtcgGqU8olicAYgAlDyGwIJtgsc6Q/640?wx_fmt=other&wxfrom=5&wx_lazy=1&wx_co=1)\n\n![令牌管理](https://mmbiz.qpic.cn/mmbiz/iaIdQfEric9Txw85YtbKNvl0ibKkgxeiahe5foMLJmVhW95QMKxkCricxPu107iboFGuN6XfVdTh7FrroB0fcX6SMFaw/640?wx_fmt=other&wxfrom=5&wx_lazy=1&wx_co=1)\n\n![流程模型-设计](https://mmbiz.qpic.cn/mmbiz/iaIdQfEric9Txw85YtbKNvl0ibKkgxeiahe5SiaibhtBlnP9OlOm5AsNE386jRpRAwHTgh0seL7tNiceNXCVhDOK72Xrg/640?wx_fmt=other&wxfrom=5&wx_lazy=1&wx_co=1)\n\n![大屏设计](https://gitee.com/yudaocode/yudao-ui-go-view/raw/master/readme/preview.png)\n', 18425, 6747, 500, 0, 0, '1', '2025-03-09 18:45:52', '1', '2025-03-09 18:45:52', b'0', 1); +INSERT INTO `ai_knowledge_document` VALUES (22, 2, '31.4k!这是我见过最强的后台管理系统 !!.md', 'http://test.yudao.iocoder.cn/530212386f51a33cb452e84599e341ca2f47adb7cfdaff6c99950993759158e4.md', '\n## 🐯 平台简介\n\n**芋道**,以开发者为中心,打造中国第一流的快速开发平台,全部开源,个人与企业可 100% 免费使用。\n\n![架构图](https://static.iocoder.cn/ruoyi-vue-pro-architecture.png)\n\n* 管理后台的 Vue3 版本采用 [vue-element-plus-admin](https://gitee.com/kailong110120130/vue-element-plus-admin) ,Vue2 版本采用 [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin) \n* 管理后台的移动端采用 [uni-app](https://github.com/dcloudio/uni-app) 方案,一份代码多终端适配,同时支持 APP、小程序、H5!\n* 后端采用 Spring Boot、MySQL + MyBatis Plus、Redis + Redisson\n* 数据库可使用 MySQL、Oracle、PostgreSQL、SQL Server、MariaDB、国产达梦 DM、TiDB 等\n* 权限认证使用 Spring Security & Token & Redis,支持多终端、多种用户的认证系统,支持 SSO 单点登录\n* 支持加载动态权限菜单,按钮级别权限控制,本地缓存提升性能\n* 支持 SaaS 多租户系统,可自定义每个租户的权限,提供透明化的多租户底层封装\n* 工作流使用 Flowable,支持动态表单、在线设计流程、会签 / 或签、多种任务分配方式\n* 高效率开发,使用代码生成器可以一键生成前后端代码 + 单元测试 + Swagger 接口文档 + Validator 参数校验\n* 集成微信小程序、微信公众号、企业微信、钉钉等三方登陆,集成支付宝、微信等支付与退款\n* 集成阿里云、腾讯云等短信渠道,集成 MinIO、阿里云、腾讯云、七牛云等云存储服务\n* 集成报表设计器,支持数据报表、图形报表、打印设计等\n\n## 🐳 项目关系\n\n![架构演进](https://static.iocoder.cn/yudao-roadmap.png?imageView2/2/format/webp)\n\n三个项目的功能对比,可见社区共同整理的 [国产开源项目对比](https://www.yuque.com/xiatian-bsgny/lm0ec1/wqf8mn) 表格。\n\n* 项目地址:\n* 官方文档:\n* 演示地址:\n* 视频教程:\n\n### 后端项目\n\n| 项目 | Star | 简介 |\n|-----------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------|\n| [ruoyi-vue-pro](https://gitee.com/zhijiantianya/ruoyi-vue-pro) | [![Gitee star](https://gitee.com/zhijiantianya/ruoyi-vue-pro/badge/star.svg?theme=white)](https://gitee.com/zhijiantianya/ruoyi-vue-pro) [![GitHub stars](https://img.shields.io/github/stars/YunaiV/ruoyi-vue-pro.svg?style=social&label=Stars)](https://github.com/YunaiV/ruoyi-vue-pro) | 基于 Spring Boot 多模块架构 |\n| [yudao-cloud](https://gitee.com/zhijiantianya/yudao-cloud) | [![Gitee star](https://gitee.com/zhijiantianya/yudao-cloud/badge/star.svg?theme=white)](https://gitee.com/zhijiantianya/yudao-cloud) [![GitHub stars](https://img.shields.io/github/stars/YunaiV/yudao-cloud.svg?style=social&label=Stars)](https://github.com/YunaiV/yudao-cloud) | 基于 Spring Cloud 微服务架构 |\n| [Spring-Boot-Labs](https://gitee.com/yudaocode/SpringBoot-Labs) | [![Gitee star](https://gitee.com/yudaocode/SpringBoot-Labs/badge/star.svg?theme=white)](https://gitee.com/zhijiantianya/yudao-cloud) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/SpringBoot-Labs.svg?style=social&label=Stars)](https://github.com/yudaocode/SpringBoot-Labs) | 系统学习 Spring Boot & Cloud 专栏 |\n\n### 前端项目\n\n| 项目 | Star | 简介 |\n|----------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------|\n| [yudao-ui-admin-vue3](https://gitee.com/yudaocode/yudao-ui-admin-vue3) | [![Gitee star](https://gitee.com/yudaocode/yudao-ui-admin-vue3/badge/star.svg?theme=white)](https://gitee.com/yudaocode/yudao-ui-admin-vue3) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/yudao-ui-admin-vue3.svg?style=social&label=Stars)](https://github.com/yudaocode/yudao-ui-admin-vue3) | 基于 Vue3 + element-plus 实现的管理后台 |\n| [yudao-ui-admin](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/yudao-ui-admin) | [![Gitee star](https://gitee.com/zhijiantianya/ruoyi-vue-pro/badge/star.svg?theme=white)](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/yudao-ui-admin) [![GitHub stars](https://img.shields.io/github/stars/YunaiV/ruoyi-vue-pro.svg?style=social&label=Stars)](https://github.com/YunaiV/ruoyi-vue-pro/tree/master/yudao-ui-admin) | 基于 Vue2 + element-ui 实现的管理后台 |\n| [yudao-ui-admin-uniapp](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/yudao-ui-admin-uniapp) | [![Gitee star](https://gitee.com/zhijiantianya/ruoyi-vue-pro/badge/star.svg?theme=white)](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/yudao-ui-admin-uniapp) [![GitHub stars](https://img.shields.io/github/stars/YunaiV/ruoyi-vue-pro.svg?style=social&label=Stars)](https://github.com/YunaiV/ruoyi-vue-pro/tree/master/yudao-ui-admin-uniapp) | 基于 uni-app + uni-ui 实现的管理后台的小程序 |\n| [yudao-ui-go-view](https://gitee.com/yudaocode/yudao-ui-go-view) | [![Gitee star](https://gitee.com/yudaocode/yudao-ui-go-view/badge/star.svg?theme=white)](https://gitee.com/yudaocode/yudao-ui-go-view) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/yudao-ui-go-view.svg?style=social&label=Stars)](https://github.com/yudaocode/yudao-ui-go-view) | 基于 Vue3 + naive-ui 实现的大屏报表 |\n| [yudao-ui-app](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/yudao-ui-app) | [![Gitee star](https://gitee.com/zhijiantianya/ruoyi-vue-pro/badge/star.svg?theme=white)](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/yudao-ui-app) [![GitHub stars](https://img.shields.io/github/stars/YunaiV/ruoyi-vue-pro.svg?style=social&label=Stars)](https://github.com/YunaiV/ruoyi-vue-pro/tree/master/yudao-ui-app) | 基于 uni-app + uview 实现的用户 App |\n\n## 😎 开源协议\n\n**为什么推荐使用本项目?**\n\n① 本项目采用比 Apache 2.0 更宽松的 [MIT License](https://gitee.com/zhijiantianya/ruoyi-vue-pro/blob/master/LICENSE) 开源协议,个人与企业可 100% 免费使用,不用保留类作者、Copyright 信息。\n\n② 代码全部开源,不会像其他项目一样,只开源部分代码,让你无法了解整个项目的架构设计。\n\n③ 代码整洁、架构整洁,遵循《阿里巴巴 Java 开发手册》规范,代码注释详细,57000 行 Java 代码,22000 行代码注释。\n\n## 🐼 内置功能\n\n系统内置多种多种业务功能,可以用于快速你的业务系统:\n\n![功能分层](https://static.iocoder.cn/ruoyi-vue-pro-biz.png)\n\n* 系统功能\n* 基础设施\n* 工作流程\n* 支付系统\n* 数据报表\n\n> 友情提示:本项目基于 RuoYi-Vue 修改,**重构优化**后端的代码,**美化**前端的界面。\n>\n> * 额外新增的功能,我们使用 🚀 标记。\n> * 重新实现的功能,我们使用 ⭐️ 标记。\n\n🙂 所有功能,都通过 **单元测试** 保证高质量。\n\n### 系统功能\n\n| | 功能 | 描述 |\n|-----|-------|---------------------------------|\n| | 用户管理 | 用户是系统操作者,该功能主要完成系统用户配置 |\n| ⭐️ | 在线用户 | 当前系统中活跃用户状态监控,支持手动踢下线 |\n| | 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分 |\n| | 菜单管理 | 配置系统菜单、操作权限、按钮权限标识等,本地缓存提供性能 |\n| | 部门管理 | 配置系统组织机构(公司、部门、小组),树结构展现支持数据权限 |\n| | 岗位管理 | 配置系统用户所属担任职务 |\n| 🚀 | 租户管理 | 配置系统租户,支持 SaaS 场景下的多租户功能 |\n| 🚀 | 租户套餐 | 配置租户套餐,自定每个租户的菜单、操作、按钮的权限 |\n| | 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 |\n| 🚀 | 短信管理 | 短信渠道、短息模板、短信日志,对接阿里云、腾讯云等主流短信平台 |\n| 🚀 | 操作日志 | 系统正常操作日志记录和查询,集成 Swagger 生成日志内容 |\n| ⭐️ | 登录日志 | 系统登录日志记录查询,包含登录异常 |\n| 🚀 | 错误码管理 | 系统所有错误码的管理,可在线修改错误提示,无需重启服务 |\n| | 通知公告 | 系统通知公告信息发布维护 |\n| 🚀 | 敏感词 | 配置系统敏感词,支持标签分组 |\n| 🚀 | 应用管理 | 管理 SSO 单点登录的应用,支持多种 OAuth2 授权方式 |\n\n### 工作流程\n\n| | 功能 | 描述 |\n|-----|-------|----------------------------------------|\n| 🚀 | 流程模型 | 配置工作流的流程模型,支持文件导入与在线设计流程图,提供 7 种任务分配规则 |\n| 🚀 | 流程表单 | 拖动表单元素生成相应的工作流表单,覆盖 Element UI 所有的表单组件 |\n| 🚀 | 用户分组 | 自定义用户分组,可用于工作流的审批分组 |\n| 🚀 | 我的流程 | 查看我发起的工作流程,支持新建、取消流程等操作,高亮流程图、审批时间线 |\n| 🚀 | 待办任务 | 查看自己【未】审批的工作任务,支持通过、不通过、转发、委派、退回等操作 |\n| 🚀 | 已办任务 | 查看自己【已】审批的工作任务,未来会支持回退操作 |\n| 🚀 | OA 请假 | 作为业务自定义接入工作流的使用示例,只需创建请求对应的工作流程,即可进行审批 |\n\n### 支付系统\n\n| | 功能 | 描述 |\n|-----|------|---------------------------|\n| 🚀 | 商户信息 | 管理商户信息,支持 Saas 场景下的多商户功能 |\n| 🚀 | 应用信息 | 配置商户的应用信息,对接支付宝、微信等多个支付渠道 |\n| 🚀 | 支付订单 | 查看用户发起的支付宝、微信等的【支付】订单 |\n| 🚀 | 退款订单 | 查看用户发起的支付宝、微信等的【退款】订单 |\n\nps:核心功能已经实现,正在对接微信小程序中...\n\n### 基础设施\n\n| | 功能 | 描述 |\n|-----|----------|----------------------------------------------|\n| 🚀 | 代码生成 | 前后端代码的生成(Java、Vue、SQL、单元测试),支持 CRUD 下载 |\n| 🚀 | 系统接口 | 基于 Swagger 自动生成相关的 RESTful API 接口文档 |\n| 🚀 | 数据库文档 | 基于 Screw 自动生成数据库文档,支持导出 Word、HTML、MD 格式 |\n| | 表单构建 | 拖动表单元素生成相应的 HTML 代码,支持导出 JSON、Vue 文件 |\n| 🚀 | 配置管理 | 对系统动态配置常用参数,支持 SpringBoot 加载 |\n| ⭐️ | 定时任务 | 在线(添加、修改、删除)任务调度包含执行结果日志 |\n| 🚀 | 文件服务 | 支持将文件存储到 S3(MinIO、阿里云、腾讯云、七牛云)、本地、FTP、数据库等 | \n| 🚀 | API 日志 | 包括 RESTful API 访问日志、异常日志两部分,方便排查 API 相关的问题 |\n| | MySQL 监控 | 监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈 |\n| | Redis 监控 | 监控 Redis 数据库的使用情况,使用的 Redis Key 管理 |\n| 🚀 | 消息队列 | 基于 Redis 实现消息队列,Stream 提供集群消费,Pub/Sub 提供广播消费 |\n| 🚀 | Java 监控 | 基于 Spring Boot Admin 实现 Java 应用的监控 |\n| 🚀 | 链路追踪 | 接入 SkyWalking 组件,实现链路追踪 |\n| 🚀 | 日志中心 | 接入 SkyWalking 组件,实现日志中心 |\n| 🚀 | 分布式锁 | 基于 Redis 实现分布式锁,满足并发场景 |\n| 🚀 | 幂等组件 | 基于 Redis 实现幂等组件,解决重复请求问题 |\n| 🚀 | 服务保障 | 基于 Resilience4j 实现服务的稳定性,包括限流、熔断等功能 |\n| 🚀 | 日志服务 | 轻量级日志中心,查看远程服务器的日志 |\n| 🚀 | 单元测试 | 基于 JUnit + Mockito 实现单元测试,保证功能的正确性、代码的质量等 |\n\n### 数据报表\n\n| | 功能 | 描述 |\n|-----|----------|----------------------------------------------|\n| 🚀 | 报表设计器 | 支持数据报表、图形报表、打印设计等 |\n| 🚀 | 大屏设计器 | 建设中... 拖拽式实现可视化数据大屏 |\n\n## 🐨 技术栈\n\n| 项目 | 说明 |\n|-------------------------|-----------------------|\n| `yudao-dependencies` | Maven 依赖版本管理 |\n| `yudao-framework` | Java 框架拓展 |\n| `yudao-server` | 管理后台 + 用户 APP 的服务端 |\n| `yudao-ui-admin` | 管理后台的 Vue2 前端项目 |\n| `yudao-ui-admin-vue3` | 管理后台的 Vue3 前端项目 |\n| `yudao-ui-admin-uniapp` | 管理后台的 uni-app 多端项目 |\n| `yudao-ui-app` | 用户 APP 的 UI 界面 |\n| `yudao-module-system` | 系统功能的 Module 模块 |\n| `yudao-module-member` | 会员中心的 Module 模块 |\n| `yudao-module-infra` | 基础设施的 Module 模块 |\n| `yudao-module-tool` | 研发工具的 Module 模块 |\n| `yudao-module-bpm` | 工作流程的 Module 模块 |\n| `yudao-module-pay` | 支付系统的 Module 模块 |\n\n### 后端\n\n| 框架 | 说明 | 版本 | 学习指南 |\n|---------------------------------------------------------------------------------------------|-----------------------|-------------|----------------------------------------------------------------|\n| [Spring Boot](https://spring.io/projects/spring-boot) | 应用开发框架 | 2.7.6 | [文档](https://github.com/YunaiV/SpringBoot-Labs) |\n| [MySQL](https://www.mysql.com/cn/) | 数据库服务器 | 5.7 / 8.0+ | |\n| [Druid](https://github.com/alibaba/druid) | JDBC 连接池、监控组件 | 1.2.15 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |\n| [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.5.2 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) |\n| [Dynamic Datasource](https://dynamic-datasource.com/) | 动态数据源 | 3.6.0 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |\n| [Redis](https://redis.io/) | key-value 数据库 | 5.0 / 6.0 | |\n| [Redisson](https://github.com/redisson/redisson) | Redis 客户端 | 3.18.0 | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao) |\n| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架 | 5.3.24 | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao) |\n| [Spring Security](https://github.com/spring-projects/spring-security) | Spring 安全框架 | 5.7.5 | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) |\n| [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 6.2.5 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) |\n| [Flowable](https://github.com/flowable/flowable-engine) | 工作流引擎 | 6.7.2 | [文档](https://doc.iocoder.cn/bpm/) |\n| [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) |\n| [Knife4j](https://gitee.com/xiaoym/knife4j) | Swagger 增强 UI 实现 | 3.0.3 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) |\n| [Resilience4j](https://github.com/resilience4j/resilience4j) | 服务保障组件 | 1.7.1 | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao) |\n| [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 8.12.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) |\n| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 监控平台 | 2.7.9 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) |\n| [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.13.3 | |\n| [MapStruct](https://mapstruct.org/) | Java Bean 转换 | 1.5.3.Final | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) |\n| [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.18.24 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) |\n| [JUnit](https://junit.org/junit5/) | Java 单元测试框架 | 5.8.2 | - |\n| [Mockito](https://github.com/mockito/mockito) | Java Mock 框架 | 4.8.0 | - |\n\n### [管理后台 Vue2 前端](./yudao-ui-admin)\n\n| 框架 | 说明 | 版本 |\n|------------------------------------------------------------------------------|---------------|--------|\n| [Vue](https://cn.vuejs.org/index.html) | JavaScript 框架 | 2.7.14 |\n| [Vue Element Admin](https://panjiachen.github.io/vue-element-admin-site/zh/) | 后台前端解决方案 | - |\n\n### [管理后台 Vue3 前端](./yudao-ui-admin-vue3)\n\n| 框架 | 说明 | 版本 |\n|----------------------------------------------------------------------|:------------:|:------:|\n| [Vue](https://staging-cn.vuejs.org/) | Vue 框架 | 3.2.45 |\n| [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 4.0.3 |\n| [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.2.27 |\n| [TypeScript](https://www.typescriptlang.org/docs/) | TypeScript | 4.9.4 |\n| [pinia](https://pinia.vuejs.org/) | vuex5 | 2.0.28 |\n| [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.2.2 |\n| [vxe-table](https://vxetable.cn/) | vue最强表单 | 4.3.7 |\n\n### [管理后台 uni-app 跨端](./yudao-ui-admin-uniapp)\n\n| 框架 | 说明 | 版本 |\n|----------------------------------------------------------------------|------------------|--------|\n| [uni-app](hhttps://github.com/dcloudio/uni-app) | 跨平台框架 | 2.0.0 |\n| [uni-ui](https://github.com/dcloudio/uni-ui) | 基于 uni-app 的 UI 框架 | 1.4.20 |\n\n## 🐷 演示图\n\n**效果预览** :\n\n![首页](https://mmbiz.qpic.cn/mmbiz/iaIdQfEric9Txw85YtbKNvl0ibKkgxeiahe5GYiamW2FAgbicPCzMAx37hy26WL8wtcgGqU8olicAYgAlDyGwIJtgsc6Q/640?wx_fmt=other&wxfrom=5&wx_lazy=1&wx_co=1)\n\n![令牌管理](https://mmbiz.qpic.cn/mmbiz/iaIdQfEric9Txw85YtbKNvl0ibKkgxeiahe5foMLJmVhW95QMKxkCricxPu107iboFGuN6XfVdTh7FrroB0fcX6SMFaw/640?wx_fmt=other&wxfrom=5&wx_lazy=1&wx_co=1)\n\n![流程模型-设计](https://mmbiz.qpic.cn/mmbiz/iaIdQfEric9Txw85YtbKNvl0ibKkgxeiahe5SiaibhtBlnP9OlOm5AsNE386jRpRAwHTgh0seL7tNiceNXCVhDOK72Xrg/640?wx_fmt=other&wxfrom=5&wx_lazy=1&wx_co=1)\n\n![大屏设计](https://gitee.com/yudaocode/yudao-ui-go-view/raw/master/readme/preview.png)\n', 18425, 6747, 500, 0, 0, '1', '2025-03-09 18:50:19', '1', '2025-03-09 18:50:19', b'0', 1); +INSERT INTO `ai_knowledge_document` VALUES (23, 2, 'MQ 分享.md', 'http://test.yudao.iocoder.cn/0963041be320795bf707da09da1062d3b8c237d974234e04bce0884eb3e84ab6.md', '---\nmarp: true\n---\n\n# 分享内容\n\n* 为什么推荐阅读 MQ 的源码\n* 对比 RocketMQ 与 PMQ 的整体架构\n* 有趣的 MQ 功能点实现\n\n---\n\n# 为什么推荐阅 MQ 的源码\n\n* 工作:[常用中间件](https://www.processon.com/view/link/60f3896a0791291daf481096)\n* 技术:[一通百通](https://www.processon.com/view/link/60f3bcc2e401fd4fe0542a0e)\n\n---\n\n# 整体架构\n\n[RocketMQ 与 PMQ 对比图](https://www.processon.com/diagraming/60eced2d7d9c08312720a8e3)\n\n\n\n* 存储\n* 高可用\n* 通信\n* 注册中心内嵌\n\n---\n\n# 消息队列的功能\n\n[功能导图](https://www.processon.com/view/link/60f3de381efad41bbea99334)\n\n---\n\n# 前置:消息模型\n\n~~JMS、AMQP、OpenMessaging 协议~~\n\n[Topic + Queue 模型](https://www.processon.com/view/link/60f3de381efad41bbea99334)\n\n\n\n---\n\n# RocketMQ 存储\n\n## 1. 整体\n\n![store 目录](https://static.iocoder.cn/rocketmq%E5%AD%98%E5%82%A8-%E6%95%B4%E4%BD%93.png)\n\n## 2. config 目录\n\n![config 目录](https://static.iocoder.cn/rocketmq%E5%AD%98%E5%82%A8-config.png)\n\n---\n\n# RocketMQ 存储(config)\n\n### 2.1 topics.json\n\n用途:Topic 定义\n\n![topics.json](https://static.iocoder.cn/rocketmq%E5%AD%98%E5%82%A8-topics.png)\n\n---\n\n# RocketMQ 存储(config)\n\n### 2.1 topics.json(有趣的参数)\n\n\n\n[有趣的参数](https://www.processon.com/diagraming/60f3eae4637689739c3bbbc5)\n\n\n\n---\n\n# RocketMQ 存储(config)\n\n### 2.2 subscriptionGroupTable.json\n\n用途:Consumer Group 定义\n\n![subscriptionGroupTable.json](https://static.iocoder.cn/rocketmq%E5%AD%98%E5%82%A8-subscriptionGroupTable.png)\n\n为什么没有订阅的 topic?\n\n---\n\n# RocketMQ 存储(config)\n\n### 2.3 offsetTable.json\n\n用途:每个消费组,针对每个 topic 的消费进度\n\n![offsetTable.json](https://static.iocoder.cn/rocketmq%E5%AD%98%E5%82%A8-offsetTable.png)\n\n---\n\n# RocketMQ 存储(commitlog)\n\n## 3. commitlog 目录\n\n用途:存储所有消息\n\n![commitlog 目录](https://static.iocoder.cn/rocketmq%E5%AD%98%E5%82%A8-commitlog.png)\n\n问题:为什么是 1G?\n* Memory-mapped files cannot be larger than 2GB on 32-bit systems.\n\n---\n\n# RocketMQ 存储(commitlog)\n\n## 3.1 消息分布\n\n![消息分布](https://static.iocoder.cn/rocketmq%E5%AD%98%E5%82%A8-commitlog2.png)\n\n---\n\n# RocketMQ 存储(commitlog)\n\n## 3.2 消息格式\n\n[![消息格式](https://static.iocoder.cn/rocketmq%E5%AD%98%E5%82%A8-commitlog3.png)](https://static.iocoder.cn/rocketmq%E5%AD%98%E5%82%A8-commitlog3.png)\n\n---\n\n# RocketMQ 存储(consumequeue)\n\n## 4. 存储(consumequeue)\n\n用途:每个 topic 的 queue,对 commitlog 的索引\n\n额外作用:计算每个 topic + queue 的 offset\n\n![关系](http://assets.processon.com/chart_image/60f3fbdf5653bb0b488a1a07.png)\n\n---\n\n## 4.1 分布\n\n![](https://static.iocoder.cn/rocketmq%E5%AD%98%E5%82%A8-consuequeue.png)\n\n和 commitlog 一样的命名方式,只是大小为 30w * 20B\n\n---\n\n## 4.2 内容\n\n![](https://static.iocoder.cn/rocketmq%E5%AD%98%E5%82%A8-consuequeue2.png)\n\n长度为 20B\n\n提问:为什么会有 Tag?\n\n---\n\n# PMQ 存储\n\n## 4.1 表关系\n\n[传送门](https://www.processon.com/diagraming/60f2b4f25653bb0b488947a4)\n\n\n\n---\n\n# 4.2 分库分表\n\n![分库分表](https://static.iocoder.cn/pmq%E5%AD%98%E5%82%A8-%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A8.png)\n\n---\n\n# 4.2 分库分表\n\n![查询演示](https://static.iocoder.cn/pmq%E5%AD%98%E5%82%A8-%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A82.png)\n\n----\n\n# 4.3 RocketMQ 文件 vs PMQ 表\n\n| 定义 | RocketMQ 文件 | PMQ 表 | 备注 |\n| ---- | ---- | ---- | ---- |\n| 主题 | `topics.json` | `topic` | |\n| 队列 | | `queue` | ① 分库分表 |\n| 消费者分组 | `subscriptionGroupTable.json` | `consumer_group` | |\n| 消费进度 | `offsetTable.json` | `queue_offset` | |\n| 消费者 | 内存 | `consumer` | ② 共享 |\n| 分组的消费者 | 内存 | `consumer_group_consumer` | ② 共享 |\n| 分组的主题 | 内存 | `consumer_group_topic` | ② 共享 |\n| 消息 | `commitlog` + `consumequeue` | `message` | ③ ??? |\n\n---\n\n# 4.4 是否可以每个队列的文件,直接存储消息?\n\nkafka 的设计如此。\n\nrocketmq 优点:\n* commitlog 消息的合并提交\n* 无法支撑海量 Topic + 队列 [《如何解决kafka topic数量过多带来的性能问题?》](https://www.zhihu.com/question/431131178/answer/1586855731)\n\nrocketmq 缺点:\n* commitlog 是顺序写,但是 commitlog 是随机读\n* 读取两次,先读 consumequeue,在读 commitlog\n\n\n\n推荐阅读:[《天池中间件大赛百万队列存储设计总结【复赛】》](https://mp.weixin.qq.com/s/aQtaDdnGxoGLvmXf7iuhLQ)\n\n---\n\n# RocketMQ 消息的写入\n\n需要写入 commitlog 和 consumequeue\n\n---\n\n## 4.1 写入 commitlog\n\n三种:\n* 同步写入\n* 异步写入 + mmap\n* 异步写入 + filechannel + buffer\n\n[传送门](https://www.processon.com/diagraming/60eced2d7d9c08312720a8e3)\n\n\n\nTODO 需要再思考下\n\n---\n\n## 4.2 写入 consumequeue\n\n![写入 consumequeue](http://assets.processon.com/chart_image/60f4590ae401fd4fe054d374.png)\n\n---\n\n# RocketMQ 消息的读取\n\n两种:\n* 堆内传输\n* 堆外传输 + 零拷贝\n\n[传送门](https://www.processon.com/diagraming/60f45b0d637689739c3c2faa)\n\n\n\nTODO 需要再思考下\n\n---\n\n# PMQ 消息的写入\n\nTopic、Queue 等元数据,缓存在内存中,通过定时任务每 3000 毫秒刷新一次。\n\n```Java\n // 设置使用的 DB 编号;该变量,是 ThreadLocal\n message01Service.setDbId(temp.getDbNodeId());\n```\n\n如下,是批量插入消息的 SQL:\n\n```SQL\n \n insert into ${tbName} (\n biz_id, tag, head, body, send_ip, race_id, retry_count\n )\n values\n \n (\n #{item.bizId}, #{item.tag}, #{item.body}, #{item.sendIp}, #{item.traceId} , #{item.retryCount}\n )\n \n \n```\n\n[《阿里云 MySQL 8.0测试结果》](https://help.aliyun.com/document_detail/150351.html)\n\n[MySQL 写入过程](https://www.processon.com/view/link/5f6eb0845653bb6013249557)\n\n---\n\n# PMQ 消息的读取\n\n```Java\n // 设置使用的 DB 编号;该变量,是 ThreadLocal\n message01Service.setDbId(temp.getDbNodeId());\n```\n\n如下,是批量查询消息的 SQL:\n\n```SQL\n \n```\n\n---\n\n# RocketMQ 高可用\n\n* 主从架构\n* [基于 Raft 协议的多副本架构](https://www.infoq.cn/article/7xejrpdzba9v*gdzofs6)\n\n---\n\n# 1. RocketMQ 高可用(主从架构)\n\n![](http://assets.processon.com/chart_image/60f434325653bb0b488a54c1.png)\n\n* 主从不支持切换\n* 多套 Broker 集群保证可用性\n* 需要同步的数据:1)commitlog;2)config\n\n---\n\n# 2. RocketMQ 高可用(主从同步 commitlog)\n\n同步类型:\n* 同步\n* 异步\n\n[流程图](https://www.processon.com/diagraming/60f43bbee401fd4fe054bb9a)\n\n\n\n---\n\n# 3. RocketMQ 高可用(主从同步 config)\n\n[流程图](https://www.processon.com/diagraming/60f445d10791291daf48df0e)\n\n\n\n---\n\n# PMQ 高可用\n\n[传送门](https://www.processon.com/diagraming/60f447f55653bb0b488a6a94)\n\n\n\n* Broker 无状态,集群\n* MySQL 主从集群\n\n---\n\n# RocketMQ 延迟消息(定义)\n\n延迟级别:\n\n| 延迟级别 | 时间 | 延迟级别 | 时间 |\n| :------- | :--- | ---- | :--- |\n| 1 | 1s | 10 | 6m |\n| 2 | 5s | 11 | 7m |\n| 3 | 10s | 12 | 8m |\n| 4 | 30s | 13 | 9m |\n| 5 | 1m | 14 | 10m |\n| 6 | 2m | 15 | 20m |\n| 7 | 3m | 16 | 30m |\n| 8 | 4m | 17 | 1h |\n| 9 | 5m | 18 | 2h |\n\n---\n\n# RocketMQ 延迟消息(实现)\n\n实现原理:[传送门](https://www.processon.com/diagraming/60f468067d9c087bac5cf13a)\n\n\n\n# 其它中间件的延迟消息\n\n* Mafka 支持任意维度的延迟消息\n* [QMQ 支持任意时间的延迟消息](https://github.com/qunarcorp/qmq/blob/master/docs/cn/arch.md#%E5%BB%B6%E6%97%B6%E5%AE%9A%E6%97%B6%E6%B6%88%E6%81%AF)\n* [rabbitmq 支持任务时间的延迟消息](https://blog.csdn.net/u013256816/article/details/55106401)\n* [滴滴开源分布式消息中间件产品 DDMQ](https://blog.didiyun.com/index.php/2019/01/18/ddmq/)\n\n---\n\n# MQ 事务消息\n\n* [为什么会有事务的问题?](https://www.processon.com/diagraming/60f4ce3d5653bb0b488a8c36)\n* 不同 MQ 提供的事务消息能力不同:\n * RabbitMQ 事务消息:多条消息的一致性,本地事务\n * Kafka 事务消息:实现 Exactly-Once 的特性\n * RocketMQ 事务消息:分布式事务,基于 MQ 协调\n * QMQ 事务消息:分布式事务,基于 MySQL 协调\n\n---\n\n# RocketMQ 事务消息\n\n![阿里云](https://static-aliyun-doc.oss-accelerate.aliyuncs.com/assets/img/zh-CN/1579264061/p177406.png)\n\n* 比较复杂,需要新增两个存储文件(`transaction/statetable` 和 `transaction/redolog` )。暂时不分享,[源码解析](https://www.iocoder.cn/RocketMQ/message-transaction/?vip)\n* [使用示例](https://github.com/YunaiV/SpringBoot-Labs/blob/master/lab-31/lab-31-rocketmq-demo/src/main/java/cn/iocoder/springboot/lab31/rocketmqdemo/producer/Demo07Producer.java)\n* 存在的问题:1)使用复杂 2)强依赖 MQ;3)强依赖 RocketMQ 的特性\n\n---\n\n# QMQ 事务消息\n\n```Java\nbegin transaction;\ncreateOrder();\nsaveMessageA(); // sendMessageA();\nsaveMessageB(); // snedMessageB();\ncommit transaction;\n\n// 监听事务提交,发送消息\nsendMessageA();\nsnedMessageB();\n\n// 如果提交失败,Job 重试\n```\n\n[官方文档](https://github.com/qunarcorp/qmq/blob/master/docs/cn/transaction.md)\n\n---\n\n# 推荐阅读文章\n\n* 《阿里二面:什么是mmap?》https://zhuanlan.zhihu.com/p/357820303\n* 《谈谈 RocketMQ 消息存储的设计与实现》https://juejin.cn/post/6844903893982248967\n* Linux中的零拷贝 https://www.cnblogs.com/rexcheny/p/12178014.html\n* pagecache与mmap https://www.jianshu.com/p/7044e0b9ab7a\n* 消息中间件—RocketMQ消息存储(一) https://www.jianshu.com/p/b73fdd893f98\n* 消息中间件—RocketMQ消息存储(二) https://www.jianshu.com/p/6d0c118c17de\n* 框架篇:小白也能秒懂的Linux零拷贝原理 https://juejin.cn/post/6887469050515947528\n* 面试官:RocketMQ 如何基于mmap+page cache实现磁盘文件的高性能读写? https://www.imooc.com/article/301624\n* 文件 IO 操作的一些最佳实践 https://www.cnkirito.moe/file-io-best-practise/\n* 零拷贝技术的原理与在java中应用 https://blog.csdn.net/u022812849/article/details/109805403\n* 论最强IO:MappedByteBuffer VS FileChannel https://blog.csdn.net/alex_xfboy/article/details/90174840\n* Page Cache是怎样产生和释放的? https://time.geekbang.org/column/article/274106\n\n---\n\n', 9406, 4308, 500, 0, 0, '1', '2025-03-10 12:54:21', '1', '2025-03-10 12:54:21', b'0', 1); +INSERT INTO `ai_knowledge_document` VALUES (24, 2, 'de30420d8e7e4824948096f81b08a50d.pdf', 'http://test.yudao.iocoder.cn/677871c92cea0aeeab6020e4bef713ff0b9bc1b340c7034141379a072635c6f1.pdf', '\n1 广州天凯信息科技有限公司 www.dbs-\nservice.com\n\n1\n\nOracle镜像使用说明\n\n一、 镜像背景\n\n广州天凯信息科技有限公司,是广州少数主打数据库技术服务的企业,主营服务:数据库优化,数据误删恢复,迁\n\n移升级,故障修复等运维服务。拥有资深专业的技术团队,数据库专家平均具备 10年以上大型企业数据库 DBA经验,\n\n具有 OCP,OCM,MySQL,LINUX等专家认证,服务行业涉及金融,税务,交通,电商等关键行业,长期与国内知名企业合\n\n作,累积客户 5000+。我们的服务宗旨是“专业,诚信,可靠”,我们将帮助中小企业低成本获得数据安全保障,为企\n\n业数据安全做长远规划,从企业的利益出发,给企业带来价值!欢迎各界企业客户咨询合作。\n\n为了提高客户 IT系统的上云效率,给客户环境部署带来便利,我方推出了镜像产品服务,而我们主要针对数据库集\n\n成方面,做了更专业更周到的部署集成服务,以下是我们的镜像产品说明。\n\n二、 镜像说明\n\n(一) 镜像简介\n\n本镜像系统预安装了 Oracle官方企业版,并升级更新最新发布补丁包程序,修复了安全漏洞同时,并对数据库配置\n\n做了调整优化,可当作数据库服务器可直接使用或上线。本镜像有以下亮点。\n\n● 官方企业版:镜像采用主流 Centos7.8系统,预安装官方 Oracle11gR2企业版数据库,功能完整,稳定性有保障;\n\n● 安全保障:在 Oracle11.2.0.4安装完成后,更新了 2020年 4月 20日最新发布的补丁包,修复了此版本以往所有\n\n安全漏洞与 BUG,可应对各种等保漏扫软件;\n\n● 配置优化:对 Oracle内存参数,性能参数,REDO成员,开机自启动等方面做了一系列优化,满足了上线的要求\n\n● 预安装了高版本 Oracle EM或 PLSQL Developer软件,方便数据库管理使用;\n\n● 技术支持:对镜像使用有任何疑问或技术问题,提供免费技术支持,售后无忧。\n\n2 广州天凯信息科技有限公司 www.dbs-\nservice.com\n\n2\n\n(二) 使用须知\n\n2.1 修改监听 IP地址\n\n当使用本镜像安装系统后,监听程序由于绑定了旧 IP所以无法正常启动,需要修改\n\n$ORACLE_HOME/network/admin下的 listener.ora文件,将里面 HOST=后面的主机名修改成服务器本身设置的主机\n\n名,同时检查/etc/hosts的主机记录,确保正确的对应关系,可参考下面条目:\n\n127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4\n\n::1 localhost localhost.localdomain localhost6 localhost6.localdomain6\n\n172.17.252.242 db-server db-server\n\n当修改完以上配置后,重启监听程序即可!\n\n2.2 修改 LOCAL_LISTENER参数\n\n若上面配置无法解决,需重新设置以下 LOCAL_LISTENER 参数,调整方法:\n\nSqlplus / as sysdba登陆执行:\n\nALTER SYSTEM SET LOCAL_LISTENER=\'(ADDRESS=(PROTOCOL=TCP)(HOST=新 IP 地址)(PORT=1521))\';\n\n最后再次重启监听程序即可解决!\n\n2.3 修改 TNSNAMES.ORA\n\n当监听程序启动正常后,若服务器内部需要引用 TNSNAMES.ORA文件连接数据库,还需要将此文件里的 HOST改\n\n成新主机名。\n\n2.4 数据库登陆方式\n\n本镜像还预安装了 Oracle EM数据库管理后台(地址:https://你的 IP:5500/em或 http://你的 IP:5500/em)和\n\nPLSQL Developer软件(已激活,主要针对 windows server环境),数据库登陆信息文件保存在桌面或 Linux环境的\n\n/home/oracle/Orapwd.txt;\n\n(三) 软件/平台\n\n本镜像系统采用 CentOS7.8 64位,预安装数据库版本 Oracle11.2.0.4 企业版 \n\n3 广州天凯信息科技有限公司 www.dbs-\nservice.com\n\n3\n\n(四) 最低配置\n\n本镜像环境:CPU:2核心 内存:4G 系统盘:100G\n\n注意:若低于此配置,需要修改内存参数才能启动.\n\n(五) 售后支持\n\n1,免费技术支持:对镜像部署有疑问或使用过程存在问题,欢迎咨询阿里旺旺、手机或工单方式与我们联系。\n\n2,收费人工支持:若涉及非镜像以外的数据库技术问题,如有数据库误删恢复,数据库故障排查,性能优化,代\n\n运维等技术服务需求,请在我方云市场购买我们服务,也可直接进入我方店铺找到 Oracle技术服务商品进行购\n\n买合作。\n\n\n', 2292, 1475, 500, 0, 0, '1', '2025-03-10 12:59:10', '1', '2025-03-10 12:59:10', b'0', 1); + +-- ---------------------------- +-- Table structure for ai_knowledge_segment +-- ---------------------------- +DROP TABLE IF EXISTS `ai_knowledge_segment`; +CREATE TABLE `ai_knowledge_segment` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `knowledge_id` bigint NOT NULL COMMENT '知识库编号', + `document_id` bigint NOT NULL COMMENT '文档编号', + `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '分段内容', + `content_length` int NOT NULL COMMENT '字符数', + `vector_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '向量库的编号', + `tokens` int NOT NULL COMMENT 'token 数量', + `retrieval_count` int NOT NULL DEFAULT 0 COMMENT '召回次数', + `status` tinyint NOT NULL COMMENT '是否启用', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 183 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'AI 知识库分段表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of ai_knowledge_segment +-- ---------------------------- +INSERT INTO `ai_knowledge_segment` VALUES (116, 2, 14, '# yunaiv.github.io 12343123\n2\n3\n\n3\n4\n5\n5\n\n4\n\n31232131232\n冯绍峰爽肤水\n\n饿332323', 18, '7b46241a-3cf7-4029-84ee-8636f16e1dbb', 6, 3, 0, NULL, '2025-03-02 18:36:44', '1', '2025-03-09 18:50:03', b'1', 1); +INSERT INTO `ai_knowledge_segment` VALUES (117, 2, 14, '测试一个', 4, '4b0b549e-73c3-4b7b-8c98-fd2b6765b46d', 2, 1, 0, '1', '2025-03-02 21:43:17', '1', '2025-03-09 18:50:03', b'1', 1); +INSERT INTO `ai_knowledge_segment` VALUES (118, 3, 16, 'AAAA', 4, 'd1b06aca-6051-4347-bb72-830a78129119', 1, 2, 0, '1', '2025-03-05 12:58:53', '1', '2025-03-09 18:31:21', b'1', 1); +INSERT INTO `ai_knowledge_segment` VALUES (119, 3, 16, 'BBBB', 4, 'ba5b8f1d-2ae4-4f76-a40f-ab6312d2156f', 1, 0, 0, '1', '2025-03-05 13:56:42', '1', '2025-03-09 18:31:21', b'1', 1); +INSERT INTO `ai_knowledge_segment` VALUES (120, 3, 16, 'CCCC', 4, '39fdc64b-b93d-4e02-b170-d7414e3954d0', 1, 0, 0, '1', '2025-03-06 21:46:36', '1', '2025-03-09 18:31:21', b'1', 1); +INSERT INTO `ai_knowledge_segment` VALUES (121, 3, 16, 'DDDD', 4, 'ff8f4ef2-06e6-42f6-81c2-d7a2c2b5c05b', 2, 0, 0, '1', '2025-03-06 21:51:50', '1', '2025-03-09 18:31:21', b'1', 1); +INSERT INTO `ai_knowledge_segment` VALUES (122, 3, 16, 'AAAA', 4, '02ccb87d-0288-4691-ad69-1191968c4d55', 2, 2, 0, '1', '2025-03-06 21:52:23', '1', '2025-03-09 18:31:21', b'1', 1); +INSERT INTO `ai_knowledge_segment` VALUES (123, 3, 16, 'DDDDEF沙发上放松放松', 5, '65269953-8879-4331-8368-5bd035058a1b', 2, 0, 0, '1', '2025-03-06 21:52:25', '1', '2025-03-09 18:31:21', b'1', 1); +INSERT INTO `ai_knowledge_segment` VALUES (124, 3, 17, '一,创建seata子模块\n在yudao-framework模块下新建子模块yudao-spring-boot-starter-seata,\n然后在这个yudao-spring-boot-starter-seata模块的pom文件中引入依赖,\n\n cn.iocoder.cloud\n yudao-common\n 2.3.0-SNAPSHOT\n \n \n com.alibaba.cloud\n spring-cloud-alibaba-seata\n 2023.0.1.2\n \n \n io.seata\n seata-spring-boot-starter\n \n 1.8.0\n \n \n io.seata\n seata-all\n \n 1.8.0\n \n \n log4j\n log4j\n \n \n \n \n io.seata\n seata-spring-autoconfigure-client\n \n 1.8.0\n \n \n com.caucho\n hessian\n 4.0.63\n \n \n io.protostuff', 1804, 'f23ddd5a-216e-4881-885d-98eb920e280f', 500, 0, 0, NULL, '2025-03-06 22:21:48', '1', '2025-03-09 18:31:07', b'1', 1); +INSERT INTO `ai_knowledge_segment` VALUES (125, 3, 17, 'protostuff-core\n 1.7.2\n \n \n io.protostuff\n protostuff-runtime\n 1.7.2\n \n\n二,部署seata服务端\nseata是用于分布式事务的,\n目前我用的是seata-server2.0.0版的windows版,nacos服务器版本我用的2.0.3\nseata\\conf\\application.yml配置文件中:\n\nserver:\n port: 7091\n\nspring:\n application:\n name: seata-server\n\nlogging:\n config: classpath:logback-spring.xml\n file:\n path: ${log.home:${user.home}/logs/seata}\n extend:\n logstash-appender:\n destination: 127.0.0.1:4560\n kafka-appender:\n bootstrap-servers: 127.0.0.1:9092\n topic: logback_to_logstash\n\nconsole:\n user:\n username: seata\n password: seata\nseata:\n config:\n # support: nacos, consul, apollo, zk, etcd3\n type: nacos\n nacos:\n server-addr: 192.168.1.146:8848\n namespace: zma-dev\n group: SEATA_GROUP\n username: nacos\n password: nacos\n context-path:\n ##if use MSE Nacos with auth, mutex with username/password attribute\n #access-key:\n #secret-key:\n data-id: seataServer.properties\n registry:\n # support: nacos, eureka, redis, zk, consul, etcd3, sofa\n type: nacos\n preferred-networks: 30.240.*\n nacos:\n application: seata-server\n server-addr: 192.168.1.146:8848\n group: SEATA_GROUP\n namespace: zma-dev\n cluster: default\n username: nacod\n password: nacos\n context-path:\n ##if use MSE Nacos with auth, mutex with username/password attribute\n #', 1604, '7d0460c7-0e53-46d7-a6c1-93be45547743', 499, 0, 0, NULL, '2025-03-06 22:21:48', '1', '2025-03-09 18:31:07', b'1', 1); +INSERT INTO `ai_knowledge_segment` VALUES (126, 3, 17, 'access-key:\n store:\n # support: file 、 db 、 redis 、 raft\n mode: file\n # server:\n # service-port: 8091 #If not configured, the default is \'${server.port} + 1000\'\n security:\n secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017\n tokenValidityInMilliseconds: 1800000\n ignore:\n urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.jpeg,/**/*.ico,/api/v1/auth/login,/metadata/v1/**\nnacos配置中心里面,建一个seataServer.properties配置文件,内容如下:\nData ID: seataServer.properties\nGroup: SEATA_GROUP\nservice.enableDegrade=false\nservice.disableGlobalTransaction=false\nservice.vgroupMapping.default-tx-group=default\nservice.vgroupMapping.order-service-group=default\n启动seata-server,\n在seata\\bin下,双击seata-server.bat文件启动,查看nacos中是否有seata-server的服务,如果有,证明启动成功。\n或者去访问seata的管理页面地址:http://localhost:7091,如果能正常打开,证明seata已经启动成功。\n二,微服务中配置seata\nspringcloud的微服务中配置seata\n先在微服务的pom.xml中添加依赖\n \n \n cn.iocoder.cloud\n yudao-spring-boot-starter-seata\n 2.3.0-SNAPSHOT\n \n然后在springboot微服务的yml中配置:\n# Seata 配置项,对应 SeataProperties 类\nseata:\n application-id: ${spring.application.name} # Seata 应用编号,默认为 ${spring.application.name}\n tx-service-group: default-tx-group # Seata 事务组编号,用于 TC 集群名\n # Seata 服务配置项,对应 ServiceProperties 类\n service:\n vgroup-mapping:\n default-tx-group: default\n data-source-proxy-mode:', 1476, 'c78b2fff-e639-434e-8e89-80b195920477', 500, 0, 0, NULL, '2025-03-06 22:21:48', '1', '2025-03-09 18:31:07', b'1', 1); + +-- ---------------------------- +-- Table structure for ai_mind_map +-- ---------------------------- +DROP TABLE IF EXISTS `ai_mind_map`; +CREATE TABLE `ai_mind_map` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `user_id` bigint NOT NULL COMMENT '用户编号', + `prompt` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '生成内容提示', + `generated_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '生成的思维导图内容', + `platform` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '平台', + `model_id` bigint NOT NULL COMMENT '模型编号', + `model` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模型', + `error_message` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '错误信息', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'AI 思维导图表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of ai_mind_map +-- ---------------------------- +INSERT INTO `ai_mind_map` VALUES (1, 1, '32132312', NULL, 'OpenAI', 0, 'gpt-3.5-turbo', '403 Forbidden from POST https://api.holdai.top/v1/chat/completions', '1', '2024-07-29 21:43:30', NULL, '2024-08-10 09:27:48', b'1', 1); +INSERT INTO `ai_mind_map` VALUES (2, 1, 'vue 技术栈!', '# Vue 技术栈\n## 核心框架\n### Vue.js\n### Vue Router\n### Vuex\n## 构建工具\n### Webpack\n### Vite\n## UI 框架\n### Element UI\n### Vuetify\n### Ant Design Vue\n## 状态管理\n### Pinia\n### Vuex\n## 测试工具\n### Vue Test Utils\n### Jest\n## 服务器端渲染\n### Nuxt.js\n## 静态站点生成\n### VuePress\n### VitePress', 'DeepSeek', 0, 'deepseek-chat', NULL, '1', '2024-07-29 21:48:11', NULL, '2024-07-29 21:48:18', b'0', 1); +INSERT INTO `ai_mind_map` VALUES (3, 1, '生成一个 Vue 核心关键点', '# Vue 核心关键点\n## 数据绑定\n### 单向数据绑定\n### 双向数据绑定\n## 组件系统\n### 组件定义\n### 组件通信\n#### 父子组件通信\n#### 非父子组件通信\n## 生命周期钩子\n### 创建阶段\n### 挂载阶段\n### 更新阶段\n### 销毁阶段\n## 指令\n### v-bind\n### v-model\n### v-on\n### v-for\n### v-if\n## 计算属性和侦听器\n### 计算属性\n### 侦听器\n## 插槽\n### 默认插槽\n### 具名插槽\n### 作用域插槽\n## 路由\n### Vue Router\n### 路由配置\n### 路由导航\n## 状态管理\n### Vuex\n### 状态\n### mutations\n### actions\n### getters', 'DeepSeek', 0, 'deepseek-chat', NULL, '1', '2024-07-29 21:56:45', NULL, '2024-07-29 21:56:56', b'0', 1); + +-- ---------------------------- +-- Table structure for ai_model +-- ---------------------------- +DROP TABLE IF EXISTS `ai_model`; +CREATE TABLE `ai_model` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `key_id` bigint NOT NULL COMMENT 'API 秘钥编号', + `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模型名字', + `model` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模型标识', + `platform` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模型平台', + `type` tinyint NOT NULL COMMENT '模型类型', + `sort` int NOT NULL COMMENT '排序', + `status` tinyint NOT NULL COMMENT '状态', + `temperature` double NULL DEFAULT NULL COMMENT '温度参数', + `max_tokens` int NULL DEFAULT NULL COMMENT '单条回复的最大 Token 数量', + `max_contexts` int NULL DEFAULT NULL COMMENT '上下文的最大 Message 数量', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 56 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'AI 模型表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of ai_model +-- ---------------------------- +INSERT INTO `ai_model` VALUES (9, 4, 'ernie-tiny-8k', 'ernie-tiny-8k', 'YiYan', 1, 100, 0, NULL, NULL, NULL, '', '2024-05-10 01:38:04', '1', '2025-03-03 01:26:22', b'0', 1); +INSERT INTO `ai_model` VALUES (10, 4, 'ERNIE 4.0', 'ERNIE 4.0', 'YiYan', 1, 100, 0, 1, 4096, 10, '', '2024-05-10 01:38:04', '1', '2025-03-03 01:26:22', b'1', 1); +INSERT INTO `ai_model` VALUES (11, 1, 'gpt-3.5-turbo', 'gpt-3.5-turbo', 'OpenAI', 1, 0, 0, 1, 4096, 20, '1', '2024-05-11 17:57:56', '1', '2025-03-03 01:26:22', b'0', 1); +INSERT INTO `ai_model` VALUES (12, 3, 'llama3', 'llama3', 'Ollama', 1, 1, 0, 1, 4096, 10, '1', '2024-05-17 23:16:38', '1', '2025-03-03 01:26:22', b'0', 1); +INSERT INTO `ai_model` VALUES (13, 5, '星火大模型3.5', 'generalv3.5', 'XingHuo', 1, 5, 0, NULL, NULL, NULL, '1', '2024-05-18 10:10:21', '1', '2025-03-03 01:26:22', b'0', 1); +INSERT INTO `ai_model` VALUES (14, 6, 'qwen-72b-chat', 'qwen-72b-chat', 'TongYi', 1, 6, 0, 1, 2000, 20, '1', '2024-05-18 10:33:47', '1', '2025-03-03 01:26:22', b'0', 1); +INSERT INTO `ai_model` VALUES (15, 6, 'Qwen-7B', 'Qwen-7B', 'TongYi', 1, 1000, 0, 1, 4096, 20, '1', '2024-06-01 20:05:14', '1', '2025-03-03 01:26:22', b'0', 1); +INSERT INTO `ai_model` VALUES (16, 4, 'ernie_speed', 'ernie_speed', 'YiYan', 1, 2000, 0, 1, 4096, 10, '1', '2024-06-02 09:00:21', '1', '2025-03-03 01:26:22', b'0', 1); +INSERT INTO `ai_model` VALUES (17, 11, 'deepseek-chat', 'deepseek-chat', 'DeepSeek', 1, 300, 0, 0.75, 4096, 20, '1', '2024-07-06 12:06:47', '1', '2025-03-03 01:26:22', b'0', 1); +INSERT INTO `ai_model` VALUES (18, 11, 'deepseek-reasoner', 'deepseek-reasoner', 'DeepSeek', 1, 301, 0, 1, 4096, 20, '1', '2024-07-06 12:07:25', '1', '2025-03-03 01:26:22', b'0', 1); +INSERT INTO `ai_model` VALUES (19, 12, 'GLM-4', 'GLM-4', 'ZhiPu', 1, 400, 0, 0.75, 2000, 20, '1', '2024-07-06 18:01:45', '1', '2025-03-03 01:26:22', b'0', 1); +INSERT INTO `ai_model` VALUES (20, 13, '【微软】gpt-35-turbo', 'gpt-35-turbo', 'AzureOpenAI', 1, 2000, 0, 1, 4096, 20, '1', '2024-08-10 14:10:07', '1', '2025-03-03 01:26:22', b'0', 1); +INSERT INTO `ai_model` VALUES (21, 8, 'qwen:4b', 'qwen:4b', 'Ollama', 1, 9999, 0, NULL, NULL, NULL, '1', '2025-02-23 19:05:00', '1', '2025-03-03 01:26:22', b'0', 1); +INSERT INTO `ai_model` VALUES (22, 14, 'doubao-1-5-lite-32k', 'doubao-1-5-lite-32k-250115', 'DouBao', 1, 350, 0, NULL, NULL, NULL, '1', '2025-02-23 19:53:24', '1', '2025-03-03 01:26:22', b'0', 1); +INSERT INTO `ai_model` VALUES (23, 14, 'deepseek-r1-zijie', 'deepseek-r1-250120', 'DouBao', 1, 351, 0, NULL, NULL, NULL, '1', '2025-02-23 19:58:32', '1', '2025-03-03 01:26:22', b'0', 1); +INSERT INTO `ai_model` VALUES (24, 15, 'hunyuan-turbo', 'hunyuan-turbo', 'HunYuan', 1, 380, 0, NULL, NULL, NULL, '1', '2025-02-23 21:00:37', '1', '2025-03-03 01:26:22', b'0', 1); +INSERT INTO `ai_model` VALUES (25, 16, 'deepseek-r1-tengxun', 'deepseek-r1', 'HunYuan', 1, 381, 0, NULL, NULL, NULL, '1', '2025-02-23 21:01:20', '1', '2025-03-03 01:26:22', b'0', 1); +INSERT INTO `ai_model` VALUES (26, 8, 'deepseek-r1-local', 'deepseek-r1', 'Ollama', 1, 10000, 0, NULL, NULL, NULL, '1', '2025-02-24 09:22:32', '1', '2025-03-03 01:26:22', b'0', 1); +INSERT INTO `ai_model` VALUES (27, 6, 'deepseek-r1-aliyun', 'deepseek-r1', 'TongYi', 1, 7, 0, NULL, NULL, NULL, '1', '2025-02-24 10:05:51', '1', '2025-03-03 01:26:22', b'0', 1); +INSERT INTO `ai_model` VALUES (28, 6, 'deepseek-v3-aliyun', 'deepseek-v3', 'TongYi', 1, 8, 0, NULL, NULL, NULL, '1', '2025-02-24 10:24:29', '1', '2025-03-03 01:26:22', b'0', 1); +INSERT INTO `ai_model` VALUES (29, 18, 'deepseek-r1-siliconflow', 'deepseek-ai/DeepSeek-R1', 'SiliconFlow', 1, 12000, 0, NULL, NULL, NULL, '1', '2025-02-24 20:35:18', '1', '2025-03-03 01:26:22', b'0', 1); +INSERT INTO `ai_model` VALUES (30, 8, 'nomic-embed-text', 'nomic-embed-text', 'Ollama', 5, 20000, 0, NULL, NULL, NULL, '1', '2025-02-24 20:35:18', '1', '2025-03-03 01:51:28', b'0', 1); +INSERT INTO `ai_model` VALUES (31, 6, 'wanx-v1', 'wanx-v1', 'TongYi', 2, 3005, 0, NULL, NULL, NULL, '1', '2025-03-03 20:08:49', '1', '2025-03-03 21:36:24', b'0', 1); +INSERT INTO `ai_model` VALUES (32, 6, 'wanx-sketch-to-image-v1', 'wanx-sketch-to-image-v1', 'TongYi', 2, 3005, 0, NULL, NULL, NULL, '1', '2025-03-03 20:09:05', '1', '2025-03-03 21:36:20', b'0', 1); +INSERT INTO `ai_model` VALUES (33, 4, 'sd_xl', 'sd_xl', 'YiYan', 2, 3004, 0, NULL, NULL, NULL, '1', '2025-03-03 20:30:49', '1', '2025-03-03 21:36:14', b'0', 1); +INSERT INTO `ai_model` VALUES (34, 12, 'cogview-3', 'cogview-3', 'ZhiPu', 2, 3003, 0, NULL, NULL, NULL, '1', '2025-03-03 20:31:40', '1', '2025-03-03 21:36:07', b'0', 1); +INSERT INTO `ai_model` VALUES (35, 1, 'dall-e-3', 'dall-e-3', 'OpenAI', 2, 3002, 0, NULL, NULL, NULL, '1', '2025-03-03 20:56:55', '1', '2025-03-03 21:36:02', b'0', 1); +INSERT INTO `ai_model` VALUES (36, 1, 'dall-e-2', 'dall-e-2', 'OpenAI', 2, 3002, 0, NULL, NULL, NULL, '1', '2025-03-03 20:57:57', '1', '2025-03-03 21:35:58', b'0', 1); +INSERT INTO `ai_model` VALUES (37, 7, 'stable-diffusion-v1-6', 'stable-diffusion-v1-6', 'StableDiffusion', 2, 3001, 0, NULL, NULL, NULL, '1', '2025-03-03 21:30:59', '1', '2025-03-03 21:35:48', b'0', 1); +INSERT INTO `ai_model` VALUES (38, 10, 'midjourney', 'midjourney', 'Midjourney', 2, 3000, 0, NULL, NULL, NULL, '1', '2025-03-03 21:35:01', '1', '2025-03-03 21:35:01', b'0', 1); +INSERT INTO `ai_model` VALUES (39, 10, 'niji', 'niji', 'Midjourney', 2, 3000, 0, NULL, NULL, NULL, '1', '2025-03-03 21:35:23', '1', '2025-03-03 21:35:23', b'0', 1); +INSERT INTO `ai_model` VALUES (40, 8, 'mxbai-embed-large', 'mxbai-embed-large', 'Ollama', 5, 20000, 0, NULL, NULL, NULL, '1', '2025-03-10 09:10:33', '1', '2025-03-10 09:10:33', b'0', 1); +INSERT INTO `ai_model` VALUES (41, 6, 'text-embedding-v3', 'text-embedding-v3', 'TongYi', 5, 20000, 0, NULL, NULL, NULL, '1', '2025-03-10 22:04:30', '1', '2025-03-10 22:04:30', b'0', 1); +INSERT INTO `ai_model` VALUES (42, 12, 'embedding-3', 'embedding-3', 'ZhiPu', 5, 20000, 0, NULL, NULL, NULL, '1', '2025-03-11 07:48:21', '1', '2025-03-11 07:48:21', b'0', 1); +INSERT INTO `ai_model` VALUES (43, 1, 'text-embedding-ada-002 ', 'text-embedding-ada-002 ', 'OpenAI', 5, 20000, 0, NULL, NULL, NULL, '1', '2025-03-11 09:38:09', '1', '2025-03-11 09:40:54', b'0', 1); +INSERT INTO `ai_model` VALUES (44, 19, 'abab6.5g-chat', 'abab6.5g-chat', 'MiniMax', 1, 500, 0, NULL, NULL, NULL, '1', '2025-03-11 20:08:03', '1', '2025-03-11 20:08:15', b'0', 1); +INSERT INTO `ai_model` VALUES (45, 19, 'embo-01', 'embo-01', 'MiniMax', 5, 20000, 0, NULL, NULL, NULL, '1', '2025-03-11 20:08:47', '1', '2025-03-11 20:15:17', b'0', 1); +INSERT INTO `ai_model` VALUES (46, 20, 'moonshot-v1-8k', 'moonshot-v1-8k', 'Moonshot', 1, 600, 0, NULL, NULL, NULL, '1', '2025-03-11 20:10:24', '1', '2025-03-11 20:10:24', b'0', 1); +INSERT INTO `ai_model` VALUES (47, 21, 'FastGPT', 'FastGPT', 'OpenAI', 1, 8888, 0, NULL, NULL, NULL, '1', '2025-03-12 13:51:46', '1', '2025-03-12 13:51:46', b'0', 1); +INSERT INTO `ai_model` VALUES (48, 22, 'Dify', 'Dify', 'OpenAI', 1, 8888, 0, NULL, NULL, NULL, '1', '2025-03-12 21:27:34', '1', '2025-03-12 21:27:34', b'0', 1); +INSERT INTO `ai_model` VALUES (49, 1, 'gpt-4o-mini', 'gpt-4o-mini', 'OpenAI', 1, 0, 0, 1, 4096, 20, '1', '2025-03-13 12:46:02', '1', '2025-03-13 12:47:02', b'0', 1); +INSERT INTO `ai_model` VALUES (50, 8, 'qwen2.5', 'qwen2.5', 'Ollama', 1, 9999, 0, NULL, NULL, NULL, '1', '2025-03-13 15:05:15', '1', '2025-03-13 20:38:28', b'0', 1); +INSERT INTO `ai_model` VALUES (51, 19, 'MiniMax-Text-01', 'MiniMax-Text-01', 'MiniMax', 1, 500, 0, NULL, NULL, NULL, '1', '2025-03-13 20:37:48', '1', '2025-03-13 20:38:06', b'0', 1); +INSERT INTO `ai_model` VALUES (52, 18, 'deepseek-v3-siliconflow-vip', 'Pro/deepseek-ai/DeepSeek-V3', 'SiliconFlow', 1, 12000, 0, NULL, NULL, NULL, '1', '2025-03-13 21:06:01', '1', '2025-03-13 21:06:01', b'0', 1); +INSERT INTO `ai_model` VALUES (53, 20, 'moonshot-v1-128k', 'moonshot-v1-128k', 'Moonshot', 1, 600, 0, NULL, NULL, NULL, '1', '2025-03-13 21:15:16', '1', '2025-03-13 21:15:16', b'0', 1); +INSERT INTO `ai_model` VALUES (54, 6, 'qwen-max-latest', 'qwen-max-latest', 'TongYi', 1, 6, 0, NULL, NULL, NULL, '1', '2025-03-13 21:32:27', '1', '2025-03-13 21:34:12', b'0', 1); +INSERT INTO `ai_model` VALUES (55, 5, '4.0Ultra', '4.0Ultra', 'XingHuo', 1, 5, 0, NULL, NULL, NULL, '1', '2025-03-14 11:24:14', '1', '2025-03-14 11:24:14', b'0', 1); + +-- ---------------------------- +-- Table structure for ai_music +-- ---------------------------- +DROP TABLE IF EXISTS `ai_music`; +CREATE TABLE `ai_music` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `user_id` bigint NOT NULL COMMENT '用户编号', + `title` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '音乐名称', + `lyric` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '歌词', + `image_url` varchar(600) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '图片地址', + `audio_url` varchar(600) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '音频地址', + `video_url` varchar(600) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '视频地址', + `status` tinyint NOT NULL COMMENT '音乐状态', + `description` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '描述词', + `prompt` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '提示词', + `platform` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模型平台', + `model_id` bigint NOT NULL COMMENT '模型编号', + `model` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模型', + `generate_mode` tinyint NOT NULL COMMENT '生成模式', + `tags` varchar(600) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '音乐风格标签', + `duration` double NULL DEFAULT NULL COMMENT '音乐时长', + `public_status` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否发布', + `task_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '任务编号', + `error_message` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '错误信息', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 37 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'AI 音乐表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of ai_music +-- ---------------------------- +INSERT INTO `ai_music` VALUES (1, 1, '幸福的旋律', '[Verse]\n阳光撒满了街道\n梦想在心中起跑\n[Verse 2]\n快乐随着风在笑\n青春在时光里跳\n[Chorus]\n哼着熟悉的歌谣\n幸福就在我怀抱\n奔向未来的征兆\n一起创造美好\n[Verse 3]\n花开在晨曦微笑\n心跳伴随音符跳\n[Bridge]\n让烦恼都退烧\n世界只剩心跳\n[Chorus]\n哼着熟悉的歌谣\n幸福就在我怀抱\n奔向未来的征兆\n一起创造美好', 'https://cdn1.suno.ai/image_73032eee-470e-46ff-a9bd-abb3e67b2934.png', 'http://test.yudao.iocoder.cn/12f3702f71bf3d1e7eadbc0d611afca58868b783fe9c8b30bf913b4aa74e3af1.mp3', 'https://cdn1.suno.ai/73032eee-470e-46ff-a9bd-abb3e67b2934.mp4', 20, '来一首快乐的歌曲', '[Verse]\n阳光撒满了街道\n梦想在心中起跑\n\n[Verse 2]\n快乐随着风在笑\n青春在时光里跳\n\n[Chorus]\n哼着熟悉的歌谣\n幸福就在我怀抱\n奔向未来的征兆\n一起创造美好\n\n[Verse 3]\n花开在晨曦微笑\n心跳伴随音符跳\n\n[Bridge]\n让烦恼都退烧\n世界只剩心跳\n\n[Chorus]\n哼着熟悉的歌谣\n幸福就在我怀抱\n奔向未来的征兆\n一起创造美好', 'Suno', 0, 'chirp-v3.5', 2, '[\"pop\"]', 145.96, b'0', '73032eee-470e-46ff-a9bd-abb3e67b2934', NULL, '1', '2024-06-27 21:08:42', '1', '2024-07-05 01:30:16', b'0', 1); +INSERT INTO `ai_music` VALUES (2, 1, '幸福的旋律', '[Verse]\n阳光撒满了街道\n梦想在心中起跑\n[Verse 2]\n快乐随着风在笑\n青春在时光里跳\n[Chorus]\n哼着熟悉的歌谣\n幸福就在我怀抱\n奔向未来的征兆\n一起创造美好\n[Verse 3]\n花开在晨曦微笑\n心跳伴随音符跳\n[Bridge]\n让烦恼都退烧\n世界只剩心跳\n[Chorus]\n哼着熟悉的歌谣\n幸福就在我怀抱\n奔向未来的征兆\n一起创造美好', 'http://test.yudao.iocoder.cn/e8e50a3fd176756069c7cd2117d32b3eddec58c2439d1e8faf8f08d23a7fd992.png', 'https://cdn1.suno.ai/727a5f9b-102d-438a-909a-13f31c433dbb.mp3', 'http://test.yudao.iocoder.cn/bb48fe2b19211d80f3522b2528b12dad6f72a95c674cff4a6b8c0396ed954a4b.mp4', 20, '来一首快乐的歌曲', '[Verse]\n阳光撒满了街道\n梦想在心中起跑\n\n[Verse 2]\n快乐随着风在笑\n青春在时光里跳\n\n[Chorus]\n哼着熟悉的歌谣\n幸福就在我怀抱\n奔向未来的征兆\n一起创造美好\n\n[Verse 3]\n花开在晨曦微笑\n心跳伴随音符跳\n\n[Bridge]\n让烦恼都退烧\n世界只剩心跳\n\n[Chorus]\n哼着熟悉的歌谣\n幸福就在我怀抱\n奔向未来的征兆\n一起创造美好', 'Suno', 0, 'chirp-v3.5', 2, '[\"pop\"]', 121.48, b'0', '727a5f9b-102d-438a-909a-13f31c433dbb', NULL, '1', '2024-06-27 21:08:42', '1', '2024-07-05 01:30:16', b'0', 1); +INSERT INTO `ai_music` VALUES (3, 1, '快乐的时光', '[Verse]\n阳光洒在天空下\n笑脸藏不住啊\n[Verse 2]\n伙伴们聚在一起\n欢笑声不停歇\n[Chorus]\n快乐就在眼前\n一起尽情欢笑\n跳舞不停的旋转\n快乐围绕着我们\n[Verse 3]\n时间在快乐中飞\n烦恼都忘掉了\n[Bridge]\n闭上眼用心感觉\n幸福在心中荡漾\n[Chorus]\n快乐就在眼前\n一起尽情欢笑\n跳舞不停的旋转\n快乐围绕着我们', 'https://cdn1.suno.ai/image_c300a71d-237d-4d82-a884-00ccab42f10e.png', 'https://cdn1.suno.ai/c300a71d-237d-4d82-a884-00ccab42f10e.mp3', 'https://cdn1.suno.ai/c300a71d-237d-4d82-a884-00ccab42f10e.mp4', 20, '来一首快乐的歌曲', '[Verse]\n阳光洒在天空下\n笑脸藏不住啊\n\n[Verse 2]\n伙伴们聚在一起\n欢笑声不停歇\n\n[Chorus]\n快乐就在眼前\n一起尽情欢笑\n跳舞不停的旋转\n快乐围绕着我们\n\n[Verse 3]\n时间在快乐中飞\n烦恼都忘掉了\n\n[Bridge]\n闭上眼用心感觉\n幸福在心中荡漾\n\n[Chorus]\n快乐就在眼前\n一起尽情欢笑\n跳舞不停的旋转\n快乐围绕着我们', 'Suno', 0, 'chirp-v3.5', 2, '[\"pop\"]', NULL, b'0', 'c300a71d-237d-4d82-a884-00ccab42f10e', NULL, '1', '2024-06-27 21:12:14', '1', '2024-07-05 01:30:16', b'0', 1); +INSERT INTO `ai_music` VALUES (4, 1, '快乐的时光', '[Verse]\n阳光洒在天空下\n笑脸藏不住啊\n[Verse 2]\n伙伴们聚在一起\n欢笑声不停歇\n[Chorus]\n快乐就在眼前\n一起尽情欢笑\n跳舞不停的旋转\n快乐围绕着我们\n[Verse 3]\n时间在快乐中飞\n烦恼都忘掉了\n[Bridge]\n闭上眼用心感觉\n幸福在心中荡漾\n[Chorus]\n快乐就在眼前\n一起尽情欢笑\n跳舞不停的旋转\n快乐围绕着我们', 'https://cdn1.suno.ai/image_bc9ed3f8-8666-4af4-99a0-8ffd4c78db89.png', 'https://cdn1.suno.ai/bc9ed3f8-8666-4af4-99a0-8ffd4c78db89.mp3', 'https://cdn1.suno.ai/bc9ed3f8-8666-4af4-99a0-8ffd4c78db89.mp4', 20, '来一首快乐的歌曲', '[Verse]\n阳光洒在天空下\n笑脸藏不住啊\n\n[Verse 2]\n伙伴们聚在一起\n欢笑声不停歇\n\n[Chorus]\n快乐就在眼前\n一起尽情欢笑\n跳舞不停的旋转\n快乐围绕着我们\n\n[Verse 3]\n时间在快乐中飞\n烦恼都忘掉了\n\n[Bridge]\n闭上眼用心感觉\n幸福在心中荡漾\n\n[Chorus]\n快乐就在眼前\n一起尽情欢笑\n跳舞不停的旋转\n快乐围绕着我们', 'Suno', 0, 'chirp-v3.5', 2, '[\"pop\", \"good\"]', NULL, b'1', 'bc9ed3f8-8666-4af4-99a0-8ffd4c78db89', NULL, '1', '2024-06-27 21:12:14', '1', '2024-07-05 01:30:16', b'0', 1); +INSERT INTO `ai_music` VALUES (33, 1, 'Happy Song', '创作一首带有轻松吉他旋律的流行歌曲,[verse] 描述夏日海滩的宁静,[chorus] 节奏加快,表达对自由的向往。', 'https://cdn1.suno.ai/image_57395779-d801-4b46-b502-11531268bf0c.png', 'https://cdn1.suno.ai/None.mp3', '', 30, NULL, NULL, 'Suno', 0, 'chirp-v3', 2, '[\"Happy\"]', NULL, b'0', '57395779-d801-4b46-b502-11531268bf0c', NULL, '1', '2024-07-04 23:26:12', '1', '2024-07-05 01:30:16', b'0', 1); +INSERT INTO `ai_music` VALUES (34, 1, 'Happy Song', '创作一首带有轻松吉他旋律的流行歌曲,[verse] 描述夏日海滩的宁静,[chorus] 节奏加快,表达对自由的向往。', 'https://cdn1.suno.ai/image_c0d6e94b-3388-44be-9591-9a5704de106a.png', '', '', 10, NULL, NULL, 'Suno', 0, 'chirp-v3', 2, '[\"Happy\"]', NULL, b'0', 'c0d6e94b-3388-44be-9591-9a5704de106a', NULL, '1', '2024-07-04 23:26:12', '1', '2024-07-05 01:30:16', b'0', 1); +INSERT INTO `ai_music` VALUES (35, 1, 'Sunshine in My Soul', '[Verse]\nSunny days no cloud in sight\nEvery step feels so light\nLaughter echoes all around\nFeet moving to the sound\n[Verse 2]\nColors bright like neon lights\nHeart\'s glowing with delight\nJoy fills every single street\nDancing to a happy beat\n[Chorus]\nSunshine in my soul today\nWorries all just float away\nLiving in this moment bright\nEverything\'s gonna be alright', 'https://cdn1.suno.ai/image_ce3e7d91-bce0-4163-a66d-f58dd41a695e.png', 'https://cdn1.suno.ai/None.mp3', '', 30, 'happy music', NULL, 'Suno', 0, 'chirp-v3', 1, '[\"pop feel-good\"]', NULL, b'0', 'ce3e7d91-bce0-4163-a66d-f58dd41a695e', NULL, '1', '2024-07-04 23:26:20', '1', '2024-07-05 01:30:16', b'0', 1); +INSERT INTO `ai_music` VALUES (36, 1, 'Sunshine in My Soul', '[Verse]\nSunny days no cloud in sight\nEvery step feels so light\nLaughter echoes all around\nFeet moving to the sound\n[Verse 2]\nColors bright like neon lights\nHeart\'s glowing with delight\nJoy fills every single street\nDancing to a happy beat\n[Chorus]\nSunshine in my soul today\nWorries all just float away\nLiving in this moment bright\nEverything\'s gonna be alright', 'https://cdn1.suno.ai/image_57e6d837-96c0-4b4f-b022-20c776d7ef4b.png', '', '', 10, 'happy music', NULL, 'Suno', 0, 'chirp-v3', 1, '[\"pop feel-good\"]', NULL, b'0', '57e6d837-96c0-4b4f-b022-20c776d7ef4b', NULL, '1', '2024-07-04 23:26:20', '1', '2024-07-05 01:30:16', b'0', 1); + +-- ---------------------------- +-- Table structure for ai_tool +-- ---------------------------- +DROP TABLE IF EXISTS `ai_tool`; +CREATE TABLE `ai_tool` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '工具编号', + `name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '工具名称', + `description` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '工具描述', + `status` tinyint NOT NULL COMMENT '状态', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 19 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'AI 工具表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of ai_tool +-- ---------------------------- +INSERT INTO `ai_tool` VALUES (17, 'directory_list', '列出指定目录的文件列表', 0, '1', '2025-03-14 19:28:41', '1', '2025-03-14 19:28:41', b'0', 1); +INSERT INTO `ai_tool` VALUES (18, 'weather_query', '查询指定城市的天气信息', 0, '1', '2025-03-14 19:28:59', '1', '2025-03-14 19:28:59', b'0', 1); + +-- ---------------------------- +-- Table structure for ai_write +-- ---------------------------- +DROP TABLE IF EXISTS `ai_write`; +CREATE TABLE `ai_write` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `user_id` bigint NOT NULL COMMENT '用户编号', + `type` int NULL DEFAULT NULL COMMENT '写作类型', + `platform` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '平台', + `model_id` bigint NOT NULL COMMENT '模型编号', + `model` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模型', + `prompt` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '生成内容提示', + `generated_content` varchar(5120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '生成的内容', + `original_content` varchar(5120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '原文', + `length` tinyint NULL DEFAULT NULL COMMENT '长度提示词', + `format` tinyint NULL DEFAULT NULL COMMENT '格式提示词', + `tone` tinyint NULL DEFAULT NULL COMMENT '语气提示词', + `language` tinyint NULL DEFAULT NULL COMMENT '语言提示词', + `error_message` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '错误信息', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 226 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'AI 写作表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of ai_write +-- ---------------------------- + -- ---------------------------- -- Table structure for base_com_appendix -- ---------------------------- @@ -1793,7 +2303,7 @@ CREATE TABLE `def_user` ( -- Records of def_user -- ---------------------------- INSERT INTO `def_user` VALUES (61170828519936, 2, 'bot', 'HuLa小管家', '', '022', NULL, NULL, '', NULL, b'0', '', '', '1', b'1', '', '2025-08-11 11:11:03.139', '{\"createIp\": \"206.237.119.215\", \"updateIp\": \"120.231.232.41\", \"createIpDetail\": null, \"updateIpDetail\": null}', '2025-08-19 10:05:05', 1, NULL, 'a4d5c225e6709ba025272a31c7e90e0121d5e5ba16695afe0b61370bedb677d0', 'Dawn', '2025-07-07 15:27:02', 1, '2025-03-27 04:23:08', NULL, '2025-07-16 12:26:15', 0, 1); -INSERT INTO `def_user` VALUES (61170828519937, 2, '2439646234', 'Dawn', '2439646234@qq.com', 'https://cdn.hulaspark.com/avatar/2439646234/6ec99d37b8ba1296c325d2d36b46a14d.webp', NULL, NULL, '', NULL, b'0', '', '', '1', b'1', '', '2025-08-11 11:11:03.189', '{\"createIp\": \"206.237.119.215\", \"updateIp\": \"192.168.1.26\", \"createIpDetail\": null, \"updateIpDetail\": {\"ip\": \"192.168.1.26\", \"isp\": \"内网IP\", \"area\": \"\", \"city\": \"内网IP\", \"isp_id\": \"local\", \"region\": \"\", \"city_id\": \"local\", \"country\": \"\", \"region_id\": \"\", \"country_id\": \"\"}}', NULL, 0, NULL, 'a4d5c225e6709ba025272a31c7e90e0121d5e5ba16695afe0b61370bedb677d0', 'Dawn', '2025-10-20 16:12:56', 1, '2025-03-27 04:23:08', NULL, '2025-10-20 16:25:36', 0, 1); +INSERT INTO `def_user` VALUES (61170828519937, 2, '2439646234', 'Dawn', '2439646234@qq.com', 'https://cdn.hulaspark.com/avatar/2439646234/6ec99d37b8ba1296c325d2d36b46a14d.webp', NULL, NULL, '', NULL, b'0', '', '', '1', b'1', '', '2025-08-11 11:11:03.189', '{\"createIp\": \"206.237.119.215\", \"updateIp\": \"183.15.179.234\", \"createIpDetail\": null, \"updateIpDetail\": {\"ip\": \"183.15.179.234\", \"isp\": \"电信\", \"area\": \"\", \"city\": \"深圳\", \"isp_id\": \"100017\", \"region\": \"广东\", \"city_id\": \"440300\", \"country\": \"中国\", \"region_id\": \"440000\", \"country_id\": \"CN\"}}', NULL, 0, NULL, 'a4d5c225e6709ba025272a31c7e90e0121d5e5ba16695afe0b61370bedb677d0', 'Dawn', '2025-10-28 16:38:01', 1, '2025-03-27 04:23:08', NULL, '2025-10-28 16:55:55', 0, 1); -- ---------------------------- -- Table structure for def_user_application @@ -1878,7 +2388,7 @@ CREATE TABLE `extend_interface_log` ( -- Records of extend_interface_log -- ---------------------------- INSERT INTO `extend_interface_log` VALUES (66567882983426, 244439130119864323, '阿里短信', 0, 1, '2025-08-26 16:37:01', '2025-08-26 16:37:00', NULL, '2025-08-26 16:37:00', NULL, 0, 0); -INSERT INTO `extend_interface_log` VALUES (655249535051914248, 244881451621810192, '腾讯邮件', 340, 51, '2025-10-20 12:13:08', '2025-07-16 18:41:01', NULL, '2025-07-16 18:41:01', NULL, 0, 0); +INSERT INTO `extend_interface_log` VALUES (655249535051914248, 244881451621810192, '腾讯邮件', 576, 56, '2025-10-28 16:44:42', '2025-07-16 18:41:01', NULL, '2025-07-16 18:41:01', NULL, 0, 0); -- ---------------------------- -- Table structure for extend_interface_logging @@ -2027,7 +2537,7 @@ CREATE TABLE `secure_invoke_record` ( -- ---------------------------- DROP TABLE IF EXISTS `sys_model`; CREATE TABLE `sys_model` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `id` bigint NOT NULL COMMENT '主键ID', `model_key` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模型唯一键', `model_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模型名称', `model_url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模型文件URL', @@ -2044,7 +2554,7 @@ CREATE TABLE `sys_model` ( UNIQUE INDEX `uk_model_key`(`model_key` ASC) USING BTREE, INDEX `idx_model_name`(`model_name` ASC) USING BTREE, INDEX `idx_status`(`status` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统模型表' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统模型表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of sys_model @@ -2092,7 +2602,7 @@ CREATE TABLE `worker_node` ( `created` timestamp NULL DEFAULT NULL COMMENT '创建时间', `is_del` tinyint(1) NOT NULL DEFAULT 0, PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 845 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = 'DB;WorkerID Assigner for UID Generator' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 891 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = 'DB;WorkerID Assigner for UID Generator' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of worker_node diff --git a/docs/install/sql/luohuo_im_01.sql b/docs/install/sql/luohuo_im_01.sql index fd8a6d5f..b37b5636 100644 --- a/docs/install/sql/luohuo_im_01.sql +++ b/docs/install/sql/luohuo_im_01.sql @@ -11,350 +11,12 @@ Target Server Version : 80030 (8.0.30) File Encoding : 65001 - Date: 20/10/2025 17:27:01 + Date: 28/10/2025 17:10:36 */ SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; --- ---------------------------- --- Table structure for ai_gpt_agreement --- ---------------------------- -DROP TABLE IF EXISTS `ai_gpt_agreement`; -CREATE TABLE `ai_gpt_agreement` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', - `title` varchar(250) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT '标题', - `type` smallint NULL DEFAULT 0 COMMENT '类型', - `status` smallint NULL DEFAULT 0 COMMENT '状态 0 禁用 1 启用', - `content` longtext CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '内容', - `remark` varchar(250) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '备注', - `created_by` bigint NOT NULL COMMENT '创建者', - `created_time` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间', - `updated_by` bigint NULL DEFAULT NULL COMMENT '更新者', - `updated_time` datetime NULL DEFAULT NULL COMMENT '更新时间', - `is_del` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除', - PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '内容管理' ROW_FORMAT = Dynamic; - --- ---------------------------- --- Records of ai_gpt_agreement --- ---------------------------- -INSERT INTO `ai_gpt_agreement` VALUES (1, '用户协议', 1, 1, '

欢迎使用“ChatAi”(以下简称“本产品”)。本协议是您(以下简称“用户”)与xxx公司(以下简称“本公司”)之间关于使用本产品的协议。本协议规定用户使用本产品的条件和限制,包括但不限于用户的权利和义务以及本公司的责任和义务。用户在使用本产品之前,请仔细阅读本协议的全部内容,特别是加粗部分。用户选择使用本产品即表示用户已经阅读、理解并接受本协议的全部内容。


一、服务内容


本产品是一款基于AI语言大模型技术,提供对话服务的产品,主要功能包括但不限于提供创作、游玩、学习、编程等方面的对话服务。用户可通过本产品获取有关创作、学习、编程等方面的信息,并根据自己的需要进行对话。


二、用户权利和义务


1.用户可以在遵守本协议及相关法律法规的前提下使用本产品,并享有相应的咨询服务。


2.用户不得利用本产品进行违法活动,不得利用本产品干扰或破坏本产品的正常运行。


3.用户应遵守网络道德,不得在使用本产品时发布、传播违反国家法律法规和社会公德的信息。


4.用户应妥善保管个人账号和密码,并承担因账号和密码泄露而导致的损失和后果。


5.用户应当遵守本公司对于使用本产品的其他规定。


三、本公司权利和义务


1.本公司有权对本产品的服务内容进行调整和变更,并及时通知用户。


2.本公司有权暂停或终止本产品的服务,并无需事先通知用户。


3.本公司有权根据相关法律法规和政策要求,在符合法律规定的前提下对用户的信息进行管理和使用。


4.本公司有义务采取必要的技术措施保护用户信息的安全。


四、免责声明


1.用户应当自行承担使用本产品所造成的风险和后果。


2.本公司不保证本产品能够满足用户的全部需求,不保证本产品的使用是不中断、及时、安全、准确、完整和可靠的。


3.本公司不对用户使用本产品而产生的任何直接、间接、附带的、特殊的、惩罚性或因使用本产品而引起的任何损失或损害负责,包括但不限于财产损失、利润损失、商业机会损失等。


五、知识产权


1.本产品所包含的所有内容,包括但不限于文字、图片、音频、视频、软件、程序、代码、数据等,均属于本公司或相关权利人的知识产权。


2.用户不得以任何形式将本产品的内容进行复制、转载、修改、传播或用于其他商业用途。


3.未经本公司或相关权利人书面同意,用户不得以任何形式使用、修改、复制或传播本产品的商标、标识等知识产权。


六、协议的变更和生效


1.本公司有权根据需要修改本协议,并在本产品上予以公布。用户应定期关注本协议的变更情况。


2.本协议的任何修改均在本公司公布之日生效。


3.如用户不同意本协议的修改内容,应立即停止使用本产品。


七、争议解决


1.本协议的签订、效力、履行和争议解决均适用中华人民共和国法律法规。


2.如发生本协议履行过程中的争议,应通过友好协商解决,协商不成的,任何一方有权向有管辖权的人民法院提起诉讼。


八、其他


1.本协议构成用户和本公司之间的全部协议,并取代所有先前的书面或口头协议。


2.如本协议中任何一条被认定为无效或不可执行,不影响其他条款的效力。


3.本公司未能行使或执行本协议规定的任何权利或规定,不构成对该权利或规定的放弃。


4.本协议中的标题仅为方便起见,不影响本协议的解释和执行。


 


本公司保留在法律允许范围内对本协议的最终解释权。用户在使用本产品时应遵守本协议及本公司的其他规定,以保证自身的合法权益。

', '', 0, '2025-03-29 22:30:16', NULL, NULL, 0); -INSERT INTO `ai_gpt_agreement` VALUES (2, '隐私政策', 2, 1, '

一、信息收集


为了为用户提供更好的服务,我们可能会收集用户的以下信息:


1.设备信息:我们可能会收集您使用HulaAi时所用的设备类型、设备号、操作系统版本、设备设置、应用程序版本号以及设备标识符等信息。


2.日志信息:当您使用HulaAi时,我们可能会自动收集您的浏览历史、IP地址、使用时间、访问页面、推出时间等信息。


3.用户信息:我们可能会收集您提供给我们的个人信息,如姓名、电话号码、电子邮件地址等。


4.交易信息:如果您使用HulaAi进行在线交易,我们可能会收集与该交易相关的信息,如购买的商品或服务、支付方式、交易金额等。


二、信息使用


我们可能会将收集到的用户信息用于以下用途:


1.为用户提供智能对话的服务。


2.为改进和优化对话的服务内容。


3.用于向用户推送HulaAi相关的信息和广告。


4.用于与用户进行交流,如回复用户的咨询、处理投诉等。


5.遵守法律法规的要求。


三、信息共享


我们承诺不会将用户的个人信息出售、交换或出租给任何第三方。但以下情况除外:


1.用户事先同意共享。


2.根据法律法规规定,需要与政府机构、执法机构共享用户信息的情况。


3.为了保护HulaAi的权益,需要与律师、会计师、评估师等专业人士共享用户信息的情况。


四、信息安全


我们会采取必要的技术手段和管理措施来保护用户的个人信息安全。但由于网络环境的不确定性,我们无法完全保证信息的绝对安全。如果用户发现自己的个人信息存在泄露或被盗用的情况,请立即联系我们,我们会采取必要的措施予以解决。


五、未成年人保护


HulaAi尤为重视未成年人的隐私保护。如果未成年人在未经监护人同意的情况下使用了我们的服务,我们会尽快采取必要的措施删除相关的个人信息。


六、隐私政策的修改和更新


我们可能会根据需要对本隐私政策进行修改和更新。修改和更新后的隐私政策将在HulaAi上公布,如用户继续使用本服务,即表示用户已同意修改后的隐私政策。


七、联系我们


如果您对本隐私政策有任何疑问、意见或建议,欢迎通过HulaAi内的联系方式与我们取得联系,我们会尽快回复您的问题。

', '', 0, '2025-03-29 22:30:56', NULL, NULL, 0); -INSERT INTO `ai_gpt_agreement` VALUES (3, '【知识扫盲】什么是GPT?它有什么特点?', 3, 0, '

一、什么是GPT

\n

GPT是一种基于人工智能技术的语言模型,它的全称是Generative Pre-trained Transformer。GPT的背景和发展历程可以追溯到2018年,由OpenAI公司提出,其目标是通过预先训练模型来增强自然语言处理(NLP)的性能。

\n

简单来说,他的实现方式是将海量的文本语料,直接喂给模型进行学习,在这其中模型对词性、句法的学习自然而然会沉淀在模型的参数当中……也就是经过预训练出一个这样的大语言模型后,AI理解了人类对语言的使用技巧(句法、语法、词性等),也理解了各种事实知识,甚至还懂得了代码编程,并最终在这样的一个大语言模型的基础上,直接降维作用于垂直领域的应用(例如闲聊对话,代码生成,文章生成等)。

\n

GPT模型的特点在于其使用了Transformer架构。Transformer是一种基于自注意力机制的深度学习模型,能够高效地学习输入序列之间的关系,因此在处理自然语言时非常有效。GPT模型通过大规模的预训练来提高其性能,这样可以在训练后对其进行微调,以适应特定的NLP任务。

\n

GPT模型被广泛用于各种自然语言处理任务,例如文本生成、文本分类、问答系统、机器翻译等等。GPT-3是目前最大的GPT模型,其参数量高达1750亿个,可以处理非常复杂的NLP任务。此外,GPT还可以用于文本自动摘要、文本纠错、情感分析等应用。

\n

在传统的自然语言处理技术中,我们需要手动设计和提取特征来让计算机理解和处理自然语言。但这种方法很难应对不同的语言和任务,并且需要大量的人工劳动和经验。因此,研究人员开始探索使用深度学习来解决自然语言处理的问题。

\n

Transformer是一种特殊的深度学习模型,它使用了自注意力机制来学习输入序列之间的关系。自注意力机制可以让模型高效地处理输入序列中的不同部分之间的相互作用,从而提高模型的性能。在自然语言处理任务中,Transformer模型可以很好地学习词汇之间的关系,从而更好地处理语言。

\n

GPT的特别之处在于,它使用了预训练技术来提高模型的性能。预训练是指在大规模数据上训练模型,以提高其性能和泛化能力。在GPT中,研究人员使用了大量的无标签文本数据来预训练模型,从而让它学习到更多的语言知识和规律。预训练后,GPT可以在各种自然语言处理任务上进行微调,以适应不同的应用场景。

\n

二、GPT的特点及如何应用

\n
    \n
  1. 大规模:GPT-3是目前最大的预训练语言生成模型,拥有超过175B参数。
  2. \n
  3. 高效:GPT-3使用了最先进的技术和硬件来进行训练,从而在生成高质量的文本的同时,保证了计算效率。
  4. \n
  5. 通用:GPT-3可以进行多种自然语言任务,如文本生成,语音识别,问答等,具有较强的通用性。
  6. \n
  7. 可扩展性:GPT-3可以通过训练来适应不同的应用场景,从而扩展其功能。
  8. \n
  9. 可靠性:GPT-3训练数据的质量和数量都比以往模型更高,因此其生成的文本质量也更高,具有更高的可靠性。
  10. \n
  11. \n

    常见的应用场景包括:

    \n

    1.聊天机器人:GPT-3可以作为客服助理,回答用户的查询和请求,并与用户进行对话。

    \n

    2.内容生成:GPT-3可以生成文字、图像和音频内容,如新闻报道、广告、博客帖子和诗歌。

    \n

    3.搜索引擎优化(SEO):GPT-3可以帮助网站管理者生成有价值的关键字和描述,以提高搜索引擎排名。

    \n

    4.语言翻译:GPT-3可以实现机器翻译,将文字从一种语言翻译成另一种语言。

    \n

    5.问题回答:GPT-3可以根据用户提出的问题,在已有的知识库中查找答案,并回答用户的问题。

    \n

    这些只是GPT-3的一些应用场景,随着技术的不断发展,GPT-3的应用场景还会有所增加。

    \n

    GPT-3,作为一个领先的大规模语言生成模型,具有广泛的应用前景。由于GPT-3具有高效的文本生成能力,它可以在许多领域中使用,如聊天机器人、语音识别、文本翻译等。同时,随着人工智能技术的不断提高,GPT-3的应用领域还将不断扩大,以适应更多的实际需求。因此,GPT-3的未来前景非常广阔。

    \n
  12. \n
', '', 0, '2025-03-05 20:44:01', NULL, NULL, 0); -INSERT INTO `ai_gpt_agreement` VALUES (4, '如何更好使用本产品?', 3, 1, '

首先需要转变一个认知,HulaAi不同于传统的搜索引擎,它更像是你的一个私人助理,可以帮你解决很多文本创意相关的问题,也可以帮你检索收集知识,对文本的理解、归纳、整理、发散才是他的优势,简而言之,搜索引擎只能检索存在的信息,HulaAi可以为你创造信息。


 


你如何使用他,他就有多大的威力,本产品的使用方式主要以问答形式进行,我们提的问题需要做到以下几点:


1.清晰明确:要让HulaAi明确你的问题或要求,确保你的问题表达清晰,简短明了。

2.具体细节:尽可能提供更多具体的信息,例如关键词、例子或特定场景,以帮助更好地理解你的问题或要求。

3.相关背景:如果你的问题或要求需要一些背景信息,提供一些相关背景,这将有助于系统更好地理解问题,并提供更有针对性的回答。

4.合理的期望: 你的问题应该合理,并符合产品的能力和限制。

例如,一个好的问题可能是:“有一张excel表格,需要将T列的值全部取出,并以“,”分隔,请给出实际的例子。\"这个问题是清晰明确的,提供了具体的要求和背暑信息,同时也是合理的期望,因为HulaAi可以提供相关的信息和例子来回答这个问题。

 


四个关键词:主题,细节,背景,期望


又例如:“我在处理公司税务时遇到了一些困难,希望能够获得关于如何避免公司税务风险的建议。我们是一家小型企业,我们需要了解如何在合规的情况下最大限度地降低税务负担。请提供建议和指导,包括如何选择最适合我们公司的税务方案,以及如何在税务申报和报告方面遵循最佳实践。此外,请提供一些税务规划的建议,以帮助我们最大化利润,并避免任何潜在的税务问题。”


此外,得到初版答案后,我们可以继续对话,使其根据我们的要求去完善细节


 

', '', 0, '2025-03-29 22:31:13', NULL, NULL, 0); -INSERT INTO `ai_gpt_agreement` VALUES (5, '如何提高GPT回答的逻辑性', 3, 0, '



本文适合对 ChatGPT 有复杂需求或想深入理解的用户阅读。简单的问题较少要用到本文提到的方法,而复杂问题,目前ChatGPT也不是最合适的工具。





人脑的系统1 在熟悉情境中采取的模式是精确的,所作出的短期预测是准确的,遇到挑战时做出的第一反应也是迅速且基本恰当的。然而,系统1存在成见,在很多特定的情况下,这一系统易犯系统性错误。你会发现这个系统有时候会将原本较难的问题作简单化处理,对于逻辑学和统计学问题,它几乎一无所知。


——《思考,快与慢》

目录



  1. 为何没有逻辑



  2. 增强逻辑的方法




  3. 思维链(Chain of Thought)



  4. 提出子问题(Self-Ask)



  5. 给出多种方案




  6. 向人类发起挑战




  7. 解决数理问题



  8. 机器的直觉



1 为何没有逻辑

众所周知,ChatGPT 回答的逻辑性不好


\"图片\"

正确答案是:7个偶数,3个奇数。ChatGPT甚至连数字都抄错了


然而,我们人类很多时候也是这样,当我们依赖于直觉判断,或是思维跳得太快,没有按部就班一步一步推理时,就很容易犯错,得出错误的答案。不过,当我们遇到一些问题时(如257*37=?),我们懂得不要着急给出答案(就算想也做不到啊),而是会在脑海里先计算推理一番,用「工作记忆」记住计算过程中的临时结果,对于更难的问题,我们会先做一下草稿或利用工具,由此来得到正确的答案。


注:人脑的「工作记忆」是一种记忆容量有限的认知系统,被用以暂时保存信息。工作记忆对于推理以及指导决策和行为有重要影响。


当我们让 ChatGPT 回答问题时,我们并没有给它思考的空间,它无法利用「工作记忆」,也无法用草稿纸,需要直接给出答案(可能是因为用于训练的数据,少有推理过程)。但如果我们可以让它像人类一样,把需要多步推理的问题,拆分成子问题,便可以帮助ChatGPT提高回答的逻辑性,这一点被证明是有效的。


我们可以通过改写 prompt 来达到这个目的,以下将介绍几种提高逻辑性的方法。




1.方法有很多,但并不需要一一记住,本质都是引导ChatGPT给出中间的推理步骤,不要直接给结果。



2.随着ChatGPT本身逻辑性的提高,在某些问题上,可以直接得到很好的答案,而不需要使用额外的方法。



3.这些方法源自无对话功能的GPT-3,而ChatGPT可以来回对话,在对话中修正答案,某些时候无需用到这些方法。




2 增强逻辑的方法

2.1 思维链(Chain of Thought)

CoT可是说是最重要的一种方法,因此有时候也把其它方法统称为CoT。这个方法利用GPT-3是一个文本预测器的特性,它需要尽量保持上下文的连贯性。


CoT 主要分为两种:





  1. Zero-shot-CoT:在 prompt 的后面加上 Let\'s think step by step(一步一步地思考)



  2. Chain of Thought:展示一个相似问题的推理过程,告诉ChatGPT应该这么来(推荐使用)。


区别是前者没有给出推理的示例(zero-shot表示0示例),后者给出至少一个示例。


我们用这 2 种方法,分别测试一下前面数奇数偶数的问题。



Zero-shot-CoT

在问题的最后加上 Let\'s think step by step\"图片\"


好吧,虽然列出的过程,可最后一步不知为什么失败了。


当然在这个问题中失败了并不意味着以后不能用了,GPT-3并不是一个确定的系统,在某些情况下也许可以得到正确的答案。但这个方法不稳定。


Zero-shot-CoT最大的用处或许是可以为我们的第二种方法 CoT 提供例子。



Chain of Thought

将上一个方法的结果,改写一下,在每一步当中加入当前步数的累计个数,然后给ChatGPT作为处理此类问题的示例。


现在我们得到了正确的答案。\"图片\"同样,尽管把这道题做对了,但改下数字或换个题目,可能就又不行了。


ChatGPT通常都很粗心,需要把推理的过程需要拆分得很细,否则很容易犯错,这样的错误可能只是抄错了数字,但一步错便步步错了。


这还只是很简单的问题,便需要写这么复杂的prompt才能解决,甚至还不能保证结果是对的,可见对待此类问题,我们应当另寻出路,除非是为了运用费曼学习法,将知识讲于它人听,以加深对知识的理解。


对这个特定的问题:实现一个自动数「奇偶个数」的功能。对大部分人来说,写prompt还是比写代码简单的,但就算如此,ChatGPT的效率是低下的,代码运算只要几毫秒就能得到结果,而ChatGPT要一个字一个字蹦出来,至少要花个十几秒。所以,在ChatGPT能够聪明高效地解决问题前,对于传统的计算问题,还是应该使用传统的方式。


这并不是说 ChatGPT 或 Chain of Thought 派不上用场。对于需要对语言有所理解才能处理的问题,传统的编程方式难以使用,这是ChatGPT施展手脚的地方。人类有大部分知识都是用语言记录,有很大的应用空间。


接下来的 2 种方法,是CoT的变种。



2.2 提出子问题(Self-Ask)

有些时候,中间的推理过程更为复杂一些,需要将问题分解成子问题。


Self-Ask 是一种让 GPT-3 根据问题自动提出子问题的方法,要求GPT-3判断一个问题是否提出子问题,先解决子问题后,再给出最后的答案。


\"图片\"我们总是可以用很简单的问题(小学算术)作为示例,然后让ChatGPT处理更难的问题\"图片\"



2.3 给出多种方案(Self Consistency)

要求GPT-3给出一个问题的多个解决方案,最后综合考虑几个方案,得出最终的答案。\"图片\"


对于搜索的计算问题,传统的编程有2种算法:深度搜索、广度搜索。如果我们将ChatGPT处理的问题类比到传统的计算问题上,那么Self Consistency可以类比成是广度搜索的组成部分,而Self Ask则是深度搜索的组成部分。


\"图片\"

该方法已被证明可以提高算术、常识和符号推理任务的结果。即使发现常规 CoT 无效,改方法仍然能够改善结果


除了以上方法外,GPT-3 还能够结合其他工具,例如将问题转成代码,或是从外部获取信息,以此来提高GPT-3回答的准确性,在此不做详细介绍。



3 向人类发起挑战

3.1 解决数理问题

Google利用上面提到的这些方法,做了一个叫Minerva的系统,提高了大语言模型在数理逻辑方面的表现。https://ai.googleblog.com/2022/06/minerva-solving-quantitative-reasoning.html




Minerva 结合了最新的 prompt 和评估技术,以更好地解决数学问题。这些包括 Chain of Thought 或 scratchpad (在提出新问题之前,Minerva 会使用几种step-by-step的方法解决现有问题),以及多数投票(也就是Self Consistency)。

注:scratchpad会将过程中的结果记录下来,和上面数奇偶的方法相似,也可以认为是一种CoT。


\"图片\"

Minerva在数理上的表现


当然,正如我们前面提到的,GPT-3在不借助其它工具时,对需要多步推理的问题,处理效率不高,因此解决数理问题,更好的方法可能是和Wolfram结合,取GPT-3理解语言之长,补其逻辑推理之短。



3.2 机器的直觉

最后我们来比较一下人类和ChatGPT谁的「直觉」比较厉害。




下面是一个相对简单的题目,别费力去分析它,凭直觉做做看:


「球拍」和「球」共花 1.10 美元,「球拍」比「球」贵 1 美元,问「球」多少钱?


 


你会马上想到一个数字,这个数字当然就是10,即10美分。这道简单的难题之所以与众不同,是因为它能引出一个直觉性的、吸引人的但却错误的答案。计算一下,你就会发现。如果球花费10美分的话,总共就要花1.20美元(球10美分,球拍1.10美元),而不是1.10美元。正确答案是5美分。


——《思考,快与慢》

\"图片\"好吧,这已经不是「直觉」了,ChatGPT开始使用「系统2」了

', '', 0, '2025-03-05 20:44:01', NULL, NULL, 0); - --- ---------------------------- --- Table structure for ai_gpt_assistant --- ---------------------------- -DROP TABLE IF EXISTS `ai_gpt_assistant`; -CREATE TABLE `ai_gpt_assistant` ( - `id` bigint NOT NULL AUTO_INCREMENT, - `avatar` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT '头像', - `icon` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '角色图标', - `title` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '角色名称', - `tag` varchar(250) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT '标签', - `main_model` smallint NULL DEFAULT 0 COMMENT '主模型', - `description` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '角色描述', - `first_message` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT 'AI打招呼', - `system_prompt` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '系统提示词', - `type_id` bigint NOT NULL DEFAULT 0 COMMENT '助手分类id', - `sort` int NOT NULL DEFAULT 1 COMMENT '排序', - `status` smallint NOT NULL DEFAULT 1 COMMENT '状态 0 禁用 1 启用', - `remark` varchar(250) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '备注', - `created_by` bigint NOT NULL COMMENT '创建者', - `created_time` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间', - `updated_by` bigint NULL DEFAULT NULL COMMENT '更新者', - `updated_time` datetime NULL DEFAULT NULL COMMENT '更新时间', - `is_del` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除', - PRIMARY KEY (`id`) USING BTREE, - INDEX `type_id`(`type_id` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'AI助理功能' ROW_FORMAT = Dynamic; - --- ---------------------------- --- Records of ai_gpt_assistant --- ---------------------------- -INSERT INTO `ai_gpt_assistant` VALUES (1, '', '💍', '婚礼请柬文案', '婚礼请柬文案', 0, '作为婚礼文案师,请为一对新人撰写以浪漫田园为主题的婚礼请柬。', '', '你是一名资深的婚礼文案师,需要为一对新人撰写一份婚礼请柬。\n主题:[浪漫田园]\n文案要点:[包含新人的名字、婚礼日期、地点、RSVP详情]', 1, 1, 1, '', 0, '2025-03-05 20:43:29', NULL, NULL, 0); -INSERT INTO `ai_gpt_assistant` VALUES (2, '', '🙇🏻‍♀️', '高效复习计划', '高效复习计划', 0, '线性代数95分冲刺:30天复习攻略', '', '你是一名面临重要考试的大学生,需要在最后一个月内高效复习。\n请根据以下要求制定你的复习计划:\n复习目标:[线性代数获得95分]\n复习时间:[每天1小时]\n要求:\n明确指出具体的复习目标,包括所有需要掌握的科目和知识点。\n将复习目标细化为每周或每天的具体任务,给出整个月都复习排期表,以便跟踪进度。', 2, 1, 1, '', 0, '2025-03-05 20:43:29', NULL, NULL, 0); -INSERT INTO `ai_gpt_assistant` VALUES (3, '', '🚀', '职业规划', '职业规划', 0, 'AI行业大爆发,快来定制专属职业发展路径,助你在AI获得高薪!', '', '你是一名职业规划师,专注于AI行业,请根据以下要求设计个性化职业规划:\n当前职业定位:[交友软件产品经理]\n未来职业目标:[成为AI行业资深产品经理]\n必备技能和知识:[请根据市面上的招聘要求告诉我达成我的目标必备的知识和技能]\n行动计划:[请提供具体可执行的计划]', 3, 1, 1, '', 0, '2025-03-05 20:43:29', NULL, NULL, 0); -INSERT INTO `ai_gpt_assistant` VALUES (4, '', '📕', '探店笔记', '探店笔记', 0, '快速记录店铺体验,分享你的发现与感受,吸引更多关注和互动!', '', '请根据以下要求撰写一篇探店笔记:\n餐厅名称:[老街角意式餐厅]\n特色菜品:[奶酪培根意面和烤羊排]\n顾客体验:[温馨的店内装饰和亲切的服务员]\n要求:[标题参照小红书爆款标题,要吸引人眼球,语言要生动活泼,像是和好朋友热情地分享]', 5, 1, 1, '', 0, '2025-03-05 20:43:29', NULL, NULL, 0); -INSERT INTO `ai_gpt_assistant` VALUES (5, '', '🏁', '秒杀神器代码', '秒杀神器代码', 0, '帮你写Python代码,轻松秒杀购物节', '', '你是一位擅长编写各种程序的资深工程师,我需要你根据以下需求,为我生成一段Python代码:\n代码目的:[设计一个双十一自动抢购脚本]\n代码功能:[在双十一当天自动登录购物网站,定时抢购预设商品]\n代码要求:[使用面向对象编程方式,使用selenium库进行网页操作]', 7, 1, 1, '', 0, '2025-03-05 20:43:29', NULL, NULL, 0); -INSERT INTO `ai_gpt_assistant` VALUES (6, '', '💌', '情感分析', '情感分析', 0, '男朋友长时间不回信息怎么办?一定要忍住', '', '你是一名情感分析师,请为以下要求分析情况并提供建议:\n问题描述:[男朋友回消息很慢]\n分析要求:[分析可能的情况,给出合理的建议和解决方法]', 8, 1, 1, '', 0, '2025-03-05 20:43:29', NULL, NULL, 0); -INSERT INTO `ai_gpt_assistant` VALUES (7, '', '💡', '创意广告软文', '创意广告软文', 0, '灵感涌现,助你轻松编写广告软文。', '', '你是一位出色的软文写手,请根据以下要求,为一个产品撰写软性广告文章:\n产品名称:[X品牌洗面奶]\n目标用户:[20-35岁的都市女性]\n内容要求:[自然融入产品参数和功能解读,结合用户故事或产品体验]\n创作要点:[隐蔽推广,文章主题与产品关联不明显]', 10, 1, 1, '', 0, '2025-03-05 20:43:29', NULL, NULL, 0); -INSERT INTO `ai_gpt_assistant` VALUES (8, '', '🤖', '钢铁侠', '钢铁侠', 0, '画出钢铁侠飞行在夜幕下的纽约', '', '画一个钢铁侠飞行在纽约上空的画面,夜景中建筑灯光闪烁,全景构图,平视视角。', 11, 1, 1, '', 0, '2025-03-05 20:43:29', NULL, NULL, 0); -INSERT INTO `ai_gpt_assistant` VALUES (9, '', '👨‍👩‍👧', '育儿活动策划', '育儿活动策划', 0, '请策划一项探索自然奥秘的育儿活动', '', '你是一名育儿顾问,请根据以下要求策划一项增添趣味的育儿活动:\n活动主题:[探索自然的奥秘]\n目标年龄段:[4-6岁的儿童]\n活动时长:[1小时]', 4, 1, 1, '', 0, '2025-03-05 20:43:29', NULL, NULL, 0); - --- ---------------------------- --- Table structure for ai_gpt_assistant_type --- ---------------------------- -DROP TABLE IF EXISTS `ai_gpt_assistant_type`; -CREATE TABLE `ai_gpt_assistant_type` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', - `name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT '分类名称', - `icon` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT 'icon图标', - `sort` int NOT NULL DEFAULT 0 COMMENT '排序', - `status` smallint NULL DEFAULT 1 COMMENT '状态 0 禁用 1 启用', - `remark` varchar(250) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '备注', - `created_by` bigint NOT NULL COMMENT '创建者', - `created_time` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间', - `updated_by` bigint NULL DEFAULT NULL COMMENT '更新者', - `updated_time` datetime NULL DEFAULT NULL COMMENT '更新时间', - `is_del` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除', - PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '助手分类' ROW_FORMAT = Dynamic; - --- ---------------------------- --- Records of ai_gpt_assistant_type --- ---------------------------- -INSERT INTO `ai_gpt_assistant_type` VALUES (1, '创意写作', 'icon-park-outline:picture', 97, 1, '', 0, '2025-03-05 20:42:37', NULL, NULL, 0); -INSERT INTO `ai_gpt_assistant_type` VALUES (2, '学生', 'ph:student-fill', 0, 1, '', 0, '2025-03-05 20:42:37', NULL, NULL, 0); -INSERT INTO `ai_gpt_assistant_type` VALUES (3, '职场', 'healthicons:city-worker', 0, 1, '', 0, '2025-03-05 20:42:37', NULL, NULL, 0); -INSERT INTO `ai_gpt_assistant_type` VALUES (4, '家长', 'material-symbols:family-home-outline', 0, 1, '', 0, '2025-03-05 20:42:37', NULL, NULL, 0); -INSERT INTO `ai_gpt_assistant_type` VALUES (5, '媒体', 'hugeicons:medium', 95, 1, '', 0, '2025-03-05 20:42:37', NULL, NULL, 0); -INSERT INTO `ai_gpt_assistant_type` VALUES (6, '老师', 'mdi:teacher', 0, 1, '', 0, '2025-03-05 20:42:37', NULL, NULL, 0); -INSERT INTO `ai_gpt_assistant_type` VALUES (7, '程序', 'ri:code-box-line', 96, 1, '', 0, '2025-03-05 20:42:37', NULL, NULL, 0); -INSERT INTO `ai_gpt_assistant_type` VALUES (8, '娱乐大师', 'material-symbols-light:family-star', 98, 1, '', 0, '2025-03-07 16:14:17', NULL, NULL, 0); -INSERT INTO `ai_gpt_assistant_type` VALUES (9, '生活', 'mdi:family', 99, 1, '', 0, '2025-03-05 20:42:37', NULL, NULL, 0); -INSERT INTO `ai_gpt_assistant_type` VALUES (10, '营销', 'mdi:cart-sale', 0, 1, '', 0, '2025-03-05 20:42:37', NULL, NULL, 0); -INSERT INTO `ai_gpt_assistant_type` VALUES (11, 'AI作画', 'icon-park-outline:picture', 0, 1, '', 0, '2025-03-05 20:42:37', NULL, NULL, 0); - --- ---------------------------- --- Table structure for ai_gpt_chat --- ---------------------------- -DROP TABLE IF EXISTS `ai_gpt_chat`; -CREATE TABLE `ai_gpt_chat` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', - `chat_number` varchar(32) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT '聊天编号', - `assistant_id` bigint NOT NULL DEFAULT 0 COMMENT '角色id', - `uid` bigint NOT NULL COMMENT '会员id', - `title` varchar(250) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '聊天摘要', - `remark` varchar(250) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '备注', - `created_by` bigint NOT NULL COMMENT '创建者', - `created_time` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间', - `updated_by` bigint NULL DEFAULT NULL COMMENT '更新者', - `updated_time` datetime NULL DEFAULT NULL COMMENT '更新时间', - `is_del` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除', - PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 83706726461169702 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '聊天摘要' ROW_FORMAT = Dynamic; - --- ---------------------------- --- Records of ai_gpt_chat --- ---------------------------- -INSERT INTO `ai_gpt_chat` VALUES (6, '1920746450749358080', 0, 10937855681024, '你好', '', 10937855681024, '2025-05-13 10:47:15', NULL, NULL, 1); - --- ---------------------------- --- Table structure for ai_gpt_chat_message --- ---------------------------- -DROP TABLE IF EXISTS `ai_gpt_chat_message`; -CREATE TABLE `ai_gpt_chat_message` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', - `chat_id` bigint NOT NULL DEFAULT 0 COMMENT 'chat_id', - `message_id` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT '消息id', - `parent_message_id` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT '回复消息id', - `model` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT '模型', - `model_version` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT '模型版本', - `content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '消息内容', - `content_type` varchar(32) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT '内容类型:text:文字 image : 图片', - `role` varchar(250) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT '角色', - `finish_reason` varchar(250) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '结束原因', - `status` smallint NULL DEFAULT 1 COMMENT '状态 1 回复中 2正常 3 失败', - `app_key` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT '使用的key', - `used_tokens` bigint NOT NULL DEFAULT 0 COMMENT '使用token', - `response` longtext CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '响应全文', - `remark` varchar(250) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '备注', - `created_by` bigint NOT NULL DEFAULT 0 COMMENT '创建者', - `created_time` datetime NOT NULL DEFAULT (now()) ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间', - `updated_by` bigint NULL DEFAULT NULL COMMENT '更新者', - `updated_time` datetime NULL DEFAULT NULL COMMENT '更新时间', - `is_del` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除', - PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 83706726461169735 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '对话消息' ROW_FORMAT = Dynamic; - --- ---------------------------- --- Records of ai_gpt_chat_message --- ---------------------------- - --- ---------------------------- --- Table structure for ai_gpt_comb --- ---------------------------- -DROP TABLE IF EXISTS `ai_gpt_comb`; -CREATE TABLE `ai_gpt_comb` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', - `title` varchar(250) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT '套餐名称', - `type` smallint NULL DEFAULT 1 COMMENT '套餐类型 1 次数 2 天数', - `num` int NULL DEFAULT 0 COMMENT '包含次数', - `origin_price` decimal(10, 2) NULL DEFAULT 0.00 COMMENT '原价', - `price` decimal(10, 2) NULL DEFAULT 0.00 COMMENT '价格', - `status` smallint NULL DEFAULT 1 COMMENT '状态 0 禁用 1 启用', - `remark` varchar(250) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '备注', - `created_by` bigint NOT NULL COMMENT '创建者', - `created_time` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间', - `updated_by` bigint NULL DEFAULT NULL COMMENT '更新者', - `updated_time` datetime NULL DEFAULT NULL COMMENT '更新时间', - `is_del` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除', - PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '会员套餐' ROW_FORMAT = Dynamic; - --- ---------------------------- --- Records of ai_gpt_comb --- ---------------------------- -INSERT INTO `ai_gpt_comb` VALUES (1, '体验套餐', 1, 20, 2.00, 0.01, 1, '', 0, '2025-03-05 20:39:52', NULL, NULL, 0); -INSERT INTO `ai_gpt_comb` VALUES (2, '20次包', 1, 20, 10.00, 5.00, 1, '', 0, '2025-03-05 20:39:52', NULL, NULL, 0); -INSERT INTO `ai_gpt_comb` VALUES (3, '100次30天包', 1, 100, 50.00, 20.00, 1, '', 0, '2025-03-05 20:39:52', NULL, NULL, 0); -INSERT INTO `ai_gpt_comb` VALUES (4, '200次季度包', 1, 200, 100.00, 39.90, 1, '', 0, '2025-03-05 20:39:52', NULL, NULL, 0); -INSERT INTO `ai_gpt_comb` VALUES (5, '500次全年包', 1, 5000, 199.99, 99.99, 1, '', 0, '2025-03-05 20:39:52', NULL, NULL, 0); - --- ---------------------------- --- Table structure for ai_gpt_model --- ---------------------------- -DROP TABLE IF EXISTS `ai_gpt_model`; -CREATE TABLE `ai_gpt_model` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', - `name` varchar(32) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT '模型名称', - `icon` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT '模型logo', - `model` varchar(32) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT '模型名称', - `local_model_type` int NOT NULL DEFAULT 0 COMMENT '本地模型类型:1、Langchian;2、ollama;3、Giteeai', - `model_url` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT '模型接口', - `knowledge` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT '知识库名称', - `version` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT '模型版本', - `sort` int NOT NULL DEFAULT 0 COMMENT '排序', - `status` smallint NOT NULL DEFAULT 1 COMMENT '状态 0 禁用 1 启用', - `remark` varchar(250) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '备注', - `created_by` bigint NOT NULL COMMENT '创建者', - `created_time` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间', - `updated_by` bigint NULL DEFAULT NULL COMMENT '更新者', - `updated_time` datetime NULL DEFAULT NULL COMMENT '更新时间', - `is_del` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除', - PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '大模型信息' ROW_FORMAT = Dynamic; - --- ---------------------------- --- Records of ai_gpt_model --- ---------------------------- -INSERT INTO `ai_gpt_model` VALUES (1, 'ChatGPT', 'back/model/gpt.png', 'ChatGPT', 0, '', '', 'gpt-3.5-turbo-0613', 0, 1, '', 0, '2025-03-12 10:36:52', NULL, NULL, 0); -INSERT INTO `ai_gpt_model` VALUES (2, '文心一言', 'back/model/wenxin.png', 'WENXIN', 0, '', '', 'ERNIE_Bot_turbo', 0, 1, '', 0, '2025-03-12 10:37:27', NULL, NULL, 0); -INSERT INTO `ai_gpt_model` VALUES (3, '通义千问', 'back/model/qianwen.png', 'QIANWEN', 0, '', '', 'qwen-turbo', 0, 1, '', 0, '2025-03-12 10:37:21', NULL, NULL, 0); -INSERT INTO `ai_gpt_model` VALUES (4, '讯飞星火', 'back/model/SPARK.png', 'SPARK', 0, '', '', 'v1.1', 0, 1, '', 0, '2025-03-12 10:35:27', NULL, NULL, 0); -INSERT INTO `ai_gpt_model` VALUES (5, '智谱清言', 'back/model/ChatGLM.png', 'ChatGLM', 0, '', '', 'chatGLM_6b_SSE', 0, 1, '', 0, '2025-03-12 10:39:04', NULL, NULL, 0); -INSERT INTO `ai_gpt_model` VALUES (6, '月之暗面', 'back/model/kimi-icon.png', 'Moonshot', 1, '', '', 'moonshot-v1-auto', 0, 1, '', 0, '2025-03-12 10:37:12', NULL, NULL, 0); -INSERT INTO `ai_gpt_model` VALUES (7, '书生·浦语', 'back/model/internlm.png', 'Internlm', 0, '', '', 'internlm2-latest', 0, 1, '', 0, '2025-03-12 10:37:03', NULL, NULL, 0); -INSERT INTO `ai_gpt_model` VALUES (8, '本地模型', 'back/model/GLM.png', 'LocalLM', 0, 'http://127.0.0.1:7861', '', 'chatglm3-6b', 0, 1, '', 0, '2025-03-12 10:35:26', NULL, NULL, 0); -INSERT INTO `ai_gpt_model` VALUES (9, 'deepseek', '\r\nback/model/deepseek.png', 'deepseek', 0, 'http://127.0.0.1:7861', '', 'DeepSeek-R1', 0, 1, '', 0, '2025-03-12 10:45:45', NULL, NULL, 0); -INSERT INTO `ai_gpt_model` VALUES (10, '豆包', 'back/model/doubao.png', 'doubao', 0, 'http://127.0.0.1:7861', '', 'Doubao-lite-32k', 0, 1, '', 0, '2025-03-12 10:45:32', NULL, NULL, 0); - --- ---------------------------- --- Table structure for ai_gpt_openkey --- ---------------------------- -DROP TABLE IF EXISTS `ai_gpt_openkey`; -CREATE TABLE `ai_gpt_openkey` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', - `model` varchar(32) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT '模型', - `app_id` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT 'appid', - `app_key` varchar(512) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT 'app key对应openai的token', - `app_secret` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT 'app密钥', - `total_tokens` bigint NOT NULL DEFAULT 0 COMMENT '总额度', - `used_tokens` bigint NOT NULL DEFAULT 0 COMMENT '已用额度', - `surplus_tokens` bigint NOT NULL DEFAULT 0 COMMENT '剩余token', - `status` int NOT NULL DEFAULT 1 COMMENT '状态 0 禁用 1 启用', - `remark` varchar(250) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '备注', - `created_by` bigint NOT NULL COMMENT '创建者', - `created_time` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间', - `updated_by` bigint NULL DEFAULT NULL COMMENT '更新者', - `updated_time` datetime NULL DEFAULT NULL COMMENT '更新时间', - `is_del` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除', - PRIMARY KEY (`id`) USING BTREE, - INDEX `app_key`(`app_key` ASC) USING BTREE, - INDEX `model`(`model` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = 'openai token' ROW_FORMAT = Dynamic; - --- ---------------------------- --- Records of ai_gpt_openkey --- ---------------------------- -INSERT INTO `ai_gpt_openkey` VALUES (1, 'ChatGPT', '', '', '', 100000, 0, 0, 1, '1046762075@qq.com', 0, '2025-03-07 18:17:46', NULL, NULL, 0); -INSERT INTO `ai_gpt_openkey` VALUES (2, 'WENXIN', '', '', '', 100000, 0, 0, 1, '', 0, '2025-03-05 20:33:20', NULL, NULL, 0); -INSERT INTO `ai_gpt_openkey` VALUES (3, 'QIANWEN', 'sk-cc182631c3244fcd8fc8856c321b4e07', 'sk-cc182631c3244fcd8fc8856c321b4e07', 'sk-cc182631c3244fcd8fc8856c321b4e07', 100000, 0, 0, 1, '', 0, '2025-05-11 20:30:23', NULL, NULL, 0); -INSERT INTO `ai_gpt_openkey` VALUES (4, 'SPARK', '0f1760da92baf6048056907115fc1ca0', '0f1760da92baf6048056907115fc1ca0', '0f1760da92baf6048056907115fc1ca0', 100000, 0, 0, 1, '', 0, '2025-05-11 21:01:31', NULL, NULL, 0); -INSERT INTO `ai_gpt_openkey` VALUES (5, 'ChatGLM', '', '', '', 100000, 0, 0, 1, '', 0, '2025-03-05 20:33:20', NULL, NULL, 0); -INSERT INTO `ai_gpt_openkey` VALUES (6, 'Moonshot', 'sk-iJRKZOS3oA8x9k1kB8xWSvTmecbpAue1qDsGTh8pc1p6I3x0', 'sk-iJRKZOS3oA8x9k1kB8xWSvTmecbpAue1qDsGTh8pc1p6I3x0', 'sk-iJRKZOS3oA8x9k1kB8xWSvTmecbpAue1qDsGTh8pc1p6I3x0', 100000, 0, 0, 1, '', 0, '2025-05-11 20:09:13', NULL, NULL, 0); -INSERT INTO `ai_gpt_openkey` VALUES (7, 'Internlm', '', '', '', 100000, 0, 0, 1, '', 0, '2025-03-05 20:33:20', NULL, NULL, 0); -INSERT INTO `ai_gpt_openkey` VALUES (8, 'LocalLM', '', '', '', 100000, 0, 0, 1, '', 0, '2025-03-05 20:33:20', NULL, NULL, 0); - --- ---------------------------- --- Table structure for ai_gpt_order --- ---------------------------- -DROP TABLE IF EXISTS `ai_gpt_order`; -CREATE TABLE `ai_gpt_order` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', - `success_time` datetime NULL DEFAULT NULL COMMENT '支付成功时间', - `trade_no` varchar(250) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT '订单号', - `transaction_id` varchar(250) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '渠道交易ID', - `uid` bigint NOT NULL DEFAULT 0 COMMENT '下单用户', - `comb_id` bigint NOT NULL DEFAULT 0 COMMENT '购买套餐', - `price` decimal(10, 2) NULL DEFAULT 0.00 COMMENT '价格', - `chanel` smallint NULL DEFAULT -1 COMMENT '支付渠道 1 微信小程序 2、微信公众号 3、微信h5 4、微信扫码', - `status` smallint NULL DEFAULT -1 COMMENT '订单状态 1 待支付 2 支付成功 3 支付超时 4 已退款', - `remark` varchar(250) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '备注', - `created_by` bigint NOT NULL COMMENT '创建者', - `created_time` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间', - `updated_by` bigint NULL DEFAULT NULL COMMENT '更新者', - `updated_time` datetime NULL DEFAULT NULL COMMENT '更新时间', - `is_del` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除', - PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '订单' ROW_FORMAT = Dynamic; - --- ---------------------------- --- Records of ai_gpt_order --- ---------------------------- - --- ---------------------------- --- Table structure for ai_gpt_redemption --- ---------------------------- -DROP TABLE IF EXISTS `ai_gpt_redemption`; -CREATE TABLE `ai_gpt_redemption` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', - `code` varchar(250) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '兑换码', - `num` int NULL DEFAULT 0 COMMENT '可兑次数', - `uid` bigint NULL DEFAULT 0 COMMENT '兑换人', - `recieve_time` int NULL DEFAULT NULL COMMENT '兑换时间', - `status` int NULL DEFAULT 0 COMMENT '状态 0 未兑换 1 已兑换', - `remark` varchar(250) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '备注', - `created_by` bigint NOT NULL COMMENT '创建者', - `created_time` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间', - `updated_by` bigint NULL DEFAULT NULL COMMENT '更新者', - `updated_time` datetime NULL DEFAULT NULL COMMENT '更新时间', - `is_del` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除', - PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '兑换码' ROW_FORMAT = Dynamic; - --- ---------------------------- --- Records of ai_gpt_redemption --- ---------------------------- - --- ---------------------------- --- Table structure for ai_oauth_client_details --- ---------------------------- -DROP TABLE IF EXISTS `ai_oauth_client_details`; -CREATE TABLE `ai_oauth_client_details` ( - `client_id` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '客户端id', - `client_secret` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '客户端密钥', - `resource_ids` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '可访问资源id', - `scope` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '权限范围', - `authorized_grant_types` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT 'password,refresh_token,authorization_code,implicit' COMMENT '授权模式 password,refresh_token,authorization_code,implicit', - `web_server_redirect_uri` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '授权回调地址', - `authorities` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '权限值', - `access_token_validity` int NULL DEFAULT 86400 COMMENT '令牌过期秒数 默认一天', - `refresh_token_validity` int NULL DEFAULT 604800 COMMENT '刷新令牌过期秒数 默认一星期', - `additional_information` varchar(4096) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '附加说明', - `autoapprove` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT 'false' COMMENT '自动授权', - `remark` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '备注', - PRIMARY KEY (`client_id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '认证授权表' ROW_FORMAT = Dynamic; - --- ---------------------------- --- Records of ai_oauth_client_details --- ---------------------------- - -- ---------------------------- -- Table structure for base_config -- ---------------------------- @@ -412,7 +74,7 @@ CREATE TABLE `im_announcements` ( `is_del` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除', `tenant_id` bigint NOT NULL DEFAULT 1, PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 84990645864449 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_as_ci COMMENT = '聊天公告表' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 89028498137601 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_as_ci COMMENT = '聊天公告表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of im_announcements @@ -489,7 +151,7 @@ CREATE TABLE `im_contact` ( INDEX `idx_create_time`(`create_time` ASC) USING BTREE, INDEX `idx_update_time`(`update_time` ASC) USING BTREE, INDEX `idx_contact_room_uid_hide`(`room_id` ASC, `uid` ASC, `hide` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 69082079587433 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '会话列表' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 69082079590943 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '会话列表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of im_contact @@ -504,16 +166,18 @@ INSERT INTO `im_contact` VALUES (10937855681526, 10937855681024, 11229133317122, DROP TABLE IF EXISTS `im_feed`; CREATE TABLE `im_feed` ( `id` bigint NOT NULL, - `u_id` bigint NOT NULL COMMENT '用户id', + `uid` bigint NOT NULL COMMENT '用户id', `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_ci NOT NULL COMMENT '朋友圈文案', `permission` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_ci NOT NULL DEFAULT '1' COMMENT 'privacy -> 私密 open -> 公开 partVisible -> 部分可见 notAnyone -> 不给谁看', `media_type` tinyint NULL DEFAULT NULL COMMENT '朋友圈内容类型(0: 纯文字 1: 图片, 2: 视频)', `create_time` datetime NOT NULL COMMENT '创建时间', `tenant_id` bigint NOT NULL DEFAULT 1, - `create_by` tinyint NOT NULL DEFAULT 1, + `create_by` bigint NOT NULL DEFAULT 1, `is_del` tinyint NOT NULL DEFAULT 0, + `update_by` bigint NOT NULL DEFAULT 1, + `update_time` datetime NULL DEFAULT NULL COMMENT '创建时间', PRIMARY KEY (`id`) USING BTREE, - INDEX `uid`(`u_id` ASC) USING BTREE + INDEX `uid`(`uid` ASC) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_as_ci COMMENT = '朋友圈表' ROW_FORMAT = Dynamic; -- ---------------------------- @@ -533,6 +197,8 @@ CREATE TABLE `im_feed_media` ( `create_by` bigint NOT NULL DEFAULT 0 COMMENT '创建者', `create_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', `is_del` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除', + `update_by` bigint NULL DEFAULT 0 COMMENT '更新者', + `update_time` datetime(3) NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_as_ci COMMENT = '朋友圈资源表' ROW_FORMAT = Dynamic; @@ -553,6 +219,8 @@ CREATE TABLE `im_feed_target` ( `create_by` bigint NOT NULL DEFAULT 0 COMMENT '创建者', `create_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', `is_del` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除', + `update_by` bigint NULL DEFAULT 0 COMMENT '更新者', + `update_time` datetime(3) NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_as_ci COMMENT = '朋友圈可见表' ROW_FORMAT = Dynamic; @@ -609,7 +277,7 @@ CREATE TABLE `im_group_member` ( INDEX `idx_create_time`(`create_time` ASC) USING BTREE, INDEX `idx_update_time`(`update_time` ASC) USING BTREE, INDEX `idx_group_member_uid_isdel_groupid`(`uid` ASC, `is_del` ASC, `group_id` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 86501702603272 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '群成员表' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 89400339964930 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '群成员表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of im_group_member @@ -672,7 +340,7 @@ CREATE TABLE `im_message` ( INDEX `idx_from_uid`(`from_uid` ASC) USING BTREE, INDEX `idx_create_time`(`create_time` ASC) USING BTREE, INDEX `idx_update_time`(`update_time` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 86500645638657 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '消息表' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 89403284366339 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '消息表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of im_message @@ -702,7 +370,7 @@ CREATE TABLE `im_message_mark` ( INDEX `idx_uid`(`uid` ASC) USING BTREE, INDEX `idx_create_time`(`create_time` ASC) USING BTREE, INDEX `idx_update_time`(`update_time` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 86186840395265 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '消息标记表' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 89397676581889 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '消息标记表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of im_message_mark @@ -734,7 +402,7 @@ CREATE TABLE `im_notice` ( INDEX `idx_receiver_type`(`receiver_id` ASC, `event_type` ASC) USING BTREE, INDEX `idx_sender`(`sender_id` ASC) USING BTREE, INDEX `idx_related`(`apply_id` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 86491313312259 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '统一通知表' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 89403246617603 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '统一通知表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of im_notice @@ -784,12 +452,12 @@ CREATE TABLE `im_room` ( PRIMARY KEY (`id`) USING BTREE, INDEX `idx_create_time`(`create_time` ASC) USING BTREE, INDEX `idx_update_time`(`update_time` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 86501702603265 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '房间表' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 89400339964931 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '房间表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of im_room -- ---------------------------- -INSERT INTO `im_room` VALUES (1, 1, 1, '2025-10-20 16:42:41.743', 86500645638656, NULL, '2024-07-10 11:17:15.521', '2025-10-20 08:42:41.629', 1, 1, NULL, 0); +INSERT INTO `im_room` VALUES (1, 1, 1, '2025-10-28 16:45:02.174', 89400339964935, NULL, '2024-07-10 11:17:15.521', '2025-10-28 08:45:02.398', 1, 1, NULL, 0); -- ---------------------------- -- Table structure for im_room_friend @@ -814,7 +482,7 @@ CREATE TABLE `im_room_friend` ( INDEX `idx_room_id`(`room_id` ASC) USING BTREE, INDEX `idx_create_time`(`create_time` ASC) USING BTREE, INDEX `idx_update_time`(`update_time` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 86432953765380 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '单聊房间表' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 89400339964932 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '单聊房间表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of im_room_friend @@ -843,7 +511,7 @@ CREATE TABLE `im_room_group` ( INDEX `idx_room_id`(`room_id` ASC) USING BTREE, INDEX `idx_create_time`(`create_time` ASC) USING BTREE, INDEX `idx_update_time`(`update_time` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 86501702603267 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '群聊房间表' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 89398838404099 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '群聊房间表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of im_room_group @@ -926,13 +594,13 @@ CREATE TABLE `im_user` ( INDEX `idx_update_time`(`update_time` ASC) USING BTREE, INDEX `idx_active_status_last_opt_time`(`last_opt_time` ASC) USING BTREE, INDEX `account_UNIQUE`(`account` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 86432953765377 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户表' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 89400339964929 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of im_user -- ---------------------------- INSERT INTO `im_user` VALUES (1, 61170828519936, 2, 'HuLa小管家', '022', '', 'bot', NULL, '', 0, '2025-07-07 15:27:01.711', '{\"createIp\": \"206.237.119.215\", \"updateIp\": \"120.231.232.41\", \"createIpDetail\": {\"ip\": \"206.237.119.215\", \"isp\": \"\", \"area\": \"\", \"city\": \"\", \"isp_id\": \"\", \"region\": \"\", \"city_id\": \"\", \"country\": \"美国\", \"region_id\": \"\", \"country_id\": \"US\"}, \"updateIpDetail\": {\"ip\": \"120.231.232.41\", \"isp\": \"移动\", \"area\": \"\", \"city\": \"\", \"isp_id\": \"100025\", \"region\": \"广东\", \"city_id\": \"\", \"country\": \"中国\", \"region_id\": \"440000\", \"country_id\": \"CN\"}}', 6, 0, '', '2025-03-27 04:23:08.393', '2025-10-11 10:14:24.150', 'k.23772439646234', 0, NULL, 0, '2025-05-09 18:24:37.089', 99978, 0, 1); -INSERT INTO `im_user` VALUES (10937855681024, 61170828519937, 3, 'Dawn', 'https://cdn.hulaspark.com/avatar/2439646234/97320189485dca88dcc7a70054445a56.webp', '2439646234@qq.com', '2439646234', NULL, '', 26, '2025-07-30 15:31:57.651', '{\"createIp\": \"206.237.119.215\", \"updateIp\": \"192.168.1.26\", \"createIpDetail\": null, \"updateIpDetail\": {\"ip\": \"192.168.1.26\", \"isp\": \"内网IP\", \"area\": \"\", \"city\": \"内网IP\", \"isp_id\": \"local\", \"region\": \"\", \"city_id\": \"local\", \"country\": \"\", \"region_id\": \"\", \"country_id\": \"\"}}', 6, 0, '', '2025-03-27 04:23:08.393', '2025-10-20 14:27:30.170', 'k.2439646234', 0, NULL, 0, '2025-09-20 21:35:31.415', 99978, 0, 1); +INSERT INTO `im_user` VALUES (10937855681024, 61170828519937, 3, 'Dawn', 'https://cdn.hulaspark.com/avatar/2439646234/97320189485dca88dcc7a70054445a56.webp', '2439646234@qq.com', '2439646234', NULL, '', 15, '2025-07-30 15:31:57.651', '{\"createIp\": \"206.237.119.215\", \"updateIp\": \"183.15.179.234\", \"createIpDetail\": null, \"updateIpDetail\": {\"ip\": \"183.15.179.234\", \"isp\": \"电信\", \"area\": \"\", \"city\": \"深圳\", \"isp_id\": \"100017\", \"region\": \"广东\", \"city_id\": \"440300\", \"country\": \"中国\", \"region_id\": \"440000\", \"country_id\": \"CN\"}}', 6, 0, '', '2025-03-27 04:23:08.393', '2025-10-28 16:08:55.831', 'k.2439646234', 0, NULL, 0, '2025-09-20 21:35:31.415', 99978, 0, 1); -- ---------------------------- -- Table structure for im_user_apply @@ -961,7 +629,7 @@ CREATE TABLE `im_user_apply` ( INDEX `idx_target_id`(`target_id` ASC) USING BTREE, INDEX `idx_create_time`(`create_time` ASC) USING BTREE, INDEX `idx_update_time`(`update_time` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 86491313312257 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户申请表' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 89403246617601 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户申请表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of im_user_apply @@ -988,7 +656,7 @@ CREATE TABLE `im_user_backpack` ( INDEX `idx_uid`(`uid` ASC) USING BTREE, INDEX `idx_create_time`(`create_time` ASC) USING BTREE, INDEX `idx_update_time`(`update_time` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 86432953765387 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户背包表' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 89400339964939 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户背包表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of im_user_backpack @@ -1031,7 +699,7 @@ CREATE TABLE `im_user_emoji` ( `update_by` bigint NULL DEFAULT NULL COMMENT '更新者', PRIMARY KEY (`id`) USING BTREE, INDEX `IDX_USER_EMOJIS_UID`(`uid` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 85336302651905 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户表情包' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 86588445005313 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户表情包' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of im_user_emoji @@ -1064,7 +732,7 @@ CREATE TABLE `im_user_friend` ( INDEX `idx_uid_friend_uid`(`uid` ASC, `friend_uid` ASC) USING BTREE, INDEX `idx_create_time`(`create_time` ASC) USING BTREE, INDEX `idx_update_time`(`update_time` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 86489446846978 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户联系人表' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 89403284366338 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户联系人表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of im_user_friend @@ -1242,7 +910,7 @@ CREATE TABLE `secure_invoke_record` ( `is_del` tinyint NOT NULL DEFAULT 0 COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE, INDEX `idx_next_retry_time`(`next_retry_time` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 86500645638658 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '本地消息表' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 89403284366340 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '本地消息表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of secure_invoke_record @@ -1261,7 +929,7 @@ CREATE TABLE `worker_node` ( `modified` timestamp NULL DEFAULT NULL COMMENT '修改时间', `created` timestamp NULL DEFAULT NULL COMMENT '创建时间', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 202 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = 'DB;WorkerID Assigner for UID Generator' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 211 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = 'DB;WorkerID Assigner for UID Generator' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of worker_node diff --git a/luohuo-cloud/luohuo-ai/luohuo-ai-biz/pom.xml b/luohuo-cloud/luohuo-ai/luohuo-ai-biz/pom.xml index 61d3755f..514c470e 100644 --- a/luohuo-cloud/luohuo-ai/luohuo-ai-biz/pom.xml +++ b/luohuo-cloud/luohuo-ai/luohuo-ai-biz/pom.xml @@ -34,7 +34,14 @@ luohuo-database-mode ${luohuo-project.version}
- + + com.luohuo.flex + luohuo-sa-token-ext + + + com.luohuo.basic + luohuo-tenant + com.luohuo.basic luohuo-all diff --git a/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/config/AiAutoConfiguration.java b/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/config/AiAutoConfiguration.java index 1739319a..e5db97a3 100644 --- a/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/config/AiAutoConfiguration.java +++ b/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/config/AiAutoConfiguration.java @@ -2,6 +2,13 @@ package com.luohuo.flex.ai.config; import cn.hutool.core.util.StrUtil; import cn.hutool.extra.spring.SpringUtil; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.json.JsonReadFeature; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.luohuo.basic.jackson.LuohuoJacksonModule; +import com.luohuo.basic.utils.SpringUtils; import com.luohuo.flex.ai.core.AiModelFactory; import com.luohuo.flex.ai.core.AiModelFactoryImpl; import com.luohuo.flex.ai.core.model.BaiChuanChatModel; @@ -26,10 +33,22 @@ import org.springframework.ai.openai.OpenAiChatOptions; import org.springframework.ai.openai.api.OpenAiApi; import org.springframework.ai.tokenizer.JTokkitTokenCountEstimator; import org.springframework.ai.tokenizer.TokenCountEstimator; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; + +import java.text.SimpleDateFormat; +import java.time.ZoneId; +import java.util.Locale; +import java.util.TimeZone; + +import static com.luohuo.basic.utils.DateUtils.DEFAULT_DATE_TIME_FORMAT; @Configuration @EnableConfigurationProperties({HulaAiProperties.class, @@ -242,4 +261,47 @@ public class AiAutoConfiguration { private static ToolCallingManager getToolCallingManager() { return SpringUtil.getBean(ToolCallingManager.class); } + + /** + * Spring 工具类 + * + * @param applicationContext 上下文 + */ + @Bean + public SpringUtils getSpringUtils(ApplicationContext applicationContext) { + SpringUtils instance = SpringUtils.getInstance(); + SpringUtils.setApplicationContext(applicationContext); + return instance; + } + + @Bean + @Primary + @ConditionalOnClass(ObjectMapper.class) + @ConditionalOnMissingBean + public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) { + ObjectMapper objectMapper = builder.createXmlMapper(false).build(); + objectMapper + .setLocale(Locale.CHINA) + //去掉默认的时间戳格式 + .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) + // 时区 + .setTimeZone(TimeZone.getTimeZone(ZoneId.systemDefault())) + //Date参数日期格式 + .setDateFormat(new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT, Locale.CHINA)) + + //该特性决定parser是否允许JSON字符串包含非引号控制字符(值小于32的ASCII字符,包含制表符和换行符)。 如果该属性关闭,则如果遇到这些字符,则会抛出异常。JSON标准说明书要求所有控制符必须使用引号,因此这是一个非标准的特性 + .configure(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature(), true) + // 忽略不能转义的字符 + .configure(JsonReadFeature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER.mappedFeature(), true) + //在使用spring boot + jpa/hibernate,如果实体字段上加有FetchType.LAZY,并使用jackson序列化为json串时,会遇到SerializationFeature.FAIL_ON_EMPTY_BEANS异常 + .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false) + //忽略未知字段 + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + //单引号处理 + .configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); + // 注册自定义模块 + objectMapper.registerModule(new LuohuoJacksonModule()).findAndRegisterModules(); + + return objectMapper; + } } diff --git a/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/controller/chat/AiChatConversationController.java b/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/controller/chat/AiChatConversationController.java index 1ec636ed..d189b6a8 100644 --- a/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/controller/chat/AiChatConversationController.java +++ b/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/controller/chat/AiChatConversationController.java @@ -85,10 +85,12 @@ public class AiChatConversationController { } // ========== 对话管理 ========== - @GetMapping("/page") @Operation(summary = "获得对话分页", description = "用于【对话管理】菜单") public R> getChatConversationPage(AiChatConversationPageReqVO pageReqVO) { + if(ObjUtil.isNull(pageReqVO.getUid())){ + pageReqVO.setUid(ContextUtil.getUid()); + } PageResult pageResult = chatConversationService.getChatConversationPage(pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return success(PageResult.empty()); diff --git a/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/controller/chat/vo/conversation/AiChatConversationPageReqVO.java b/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/controller/chat/vo/conversation/AiChatConversationPageReqVO.java index 1163bbd7..777a9564 100644 --- a/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/controller/chat/vo/conversation/AiChatConversationPageReqVO.java +++ b/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/controller/chat/vo/conversation/AiChatConversationPageReqVO.java @@ -14,7 +14,7 @@ import static com.luohuo.basic.utils.TimeUtils.DEFAULT_YEAR_FORMAT; public class AiChatConversationPageReqVO extends PageParam { @Schema(description = "用户编号", example = "1024") - private Long userId; + private Long uid; @Schema(description = "对话标题", example = "你好") private String title; diff --git a/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/dal/chat/AiChatConversationDO.java b/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/dal/chat/AiChatConversationDO.java index 7cc3a8e9..c599340e 100644 --- a/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/dal/chat/AiChatConversationDO.java +++ b/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/dal/chat/AiChatConversationDO.java @@ -98,5 +98,8 @@ public class AiChatConversationDO extends BaseDO { * 上下文的最大 Message 数量 */ private Integer maxContexts; - + /** + * 租户id + */ + private Long tenantId; } diff --git a/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/dal/chat/AiChatMessageDO.java b/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/dal/chat/AiChatMessageDO.java index 4d715b46..ab471926 100644 --- a/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/dal/chat/AiChatMessageDO.java +++ b/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/dal/chat/AiChatMessageDO.java @@ -103,4 +103,8 @@ public class AiChatMessageDO extends BaseDO { @TableField(typeHandler = LongListTypeHandler.class) private List segmentIds; + /** + * 租户id + */ + private Long tenantId; } diff --git a/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/mapper/chat/AiChatConversationMapper.java b/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/mapper/chat/AiChatConversationMapper.java index 6ef0ea5f..36fa9630 100644 --- a/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/mapper/chat/AiChatConversationMapper.java +++ b/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/mapper/chat/AiChatConversationMapper.java @@ -27,7 +27,7 @@ public interface AiChatConversationMapper extends BaseMapperX selectChatConversationPage(AiChatConversationPageReqVO pageReqVO) { return selectPage(pageReqVO, new LambdaQueryWrapperX() - .eqIfPresent(AiChatConversationDO::getUserId, pageReqVO.getUserId()) + .eq(AiChatConversationDO::getUserId, pageReqVO.getUid()) .likeIfPresent(AiChatConversationDO::getTitle, pageReqVO.getTitle()) .betweenIfPresent(AiChatConversationDO::getCreateTime, pageReqVO.getCreateTime()) .orderByDesc(AiChatConversationDO::getId)); diff --git a/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/service/chat/AiChatMessageServiceImpl.java b/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/service/chat/AiChatMessageServiceImpl.java index 9e683ef0..1a2517d8 100644 --- a/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/service/chat/AiChatMessageServiceImpl.java +++ b/luohuo-cloud/luohuo-ai/luohuo-ai-biz/src/main/java/com/luohuo/flex/ai/service/chat/AiChatMessageServiceImpl.java @@ -3,6 +3,8 @@ package com.luohuo.flex.ai.service.chat; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.StrUtil; +import com.luohuo.basic.context.ContextUtil; +import com.luohuo.basic.tenant.core.aop.TenantIgnore; import com.luohuo.flex.ai.common.pojo.PageResult; import com.luohuo.flex.ai.controller.chat.vo.message.AiChatMessagePageReqVO; import com.luohuo.flex.ai.controller.chat.vo.message.AiChatMessageRespVO; @@ -139,8 +141,9 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { } @Override - public Flux> sendChatMessageStream(AiChatMessageSendReqVO sendReqVO, - Long userId) { + public Flux> sendChatMessageStream(AiChatMessageSendReqVO sendReqVO, Long userId) { + ContextUtil.setIgnore(true); + // 1.1 校验对话存在 AiChatConversationDO conversation = chatConversationService .validateChatConversationExists(sendReqVO.getConversationId()); @@ -195,10 +198,15 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { // 忽略租户,因为 Flux 异步无法透传租户 String content = contentBuffer.toString(); chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId()).setContent(content)); + ContextUtil.setIgnore(false); }).doOnError(throwable -> { log.error("[sendChatMessageStream][userId({}) sendReqVO({}) 发生异常]", userId, sendReqVO, throwable); // 忽略租户,因为 Flux 异步无法透传租户 - }).onErrorResume(error -> Flux.just(error(ErrorCodeConstants.CHAT_STREAM_ERROR))); + ContextUtil.setIgnore(false); + }).onErrorResume(error -> { + ContextUtil.setIgnore(false); + return Flux.just(error(ErrorCodeConstants.CHAT_STREAM_ERROR)); + }); } private List recallKnowledgeSegment(String content, diff --git a/luohuo-cloud/luohuo-ai/luohuo-ai-controller/pom.xml b/luohuo-cloud/luohuo-ai/luohuo-ai-controller/pom.xml deleted file mode 100644 index 5afaf65f..00000000 --- a/luohuo-cloud/luohuo-ai/luohuo-ai-controller/pom.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - 4.0.0 - - com.luohuo.flex - luohuo-ai - 3.0.0 - - - luohuo-ai-controller - - - 21 - 21 - UTF-8 - - - - - com.luohuo.flex - luohuo-ai-biz - ${luohuo-project.version} - - - - \ No newline at end of file diff --git a/luohuo-cloud/luohuo-ai/luohuo-ai-server/pom.xml b/luohuo-cloud/luohuo-ai/luohuo-ai-server/pom.xml index 9eddb61f..74d2c066 100644 --- a/luohuo-cloud/luohuo-ai/luohuo-ai-server/pom.xml +++ b/luohuo-cloud/luohuo-ai/luohuo-ai-server/pom.xml @@ -17,7 +17,7 @@ com.luohuo.flex - luohuo-ai-controller + luohuo-ai-biz ${luohuo-project.version} diff --git a/luohuo-cloud/luohuo-ai/luohuo-ai-server/src/main/resources/bootstrap.yml b/luohuo-cloud/luohuo-ai/luohuo-ai-server/src/main/resources/bootstrap.yml index 1fc1ac5d..51af5ecb 100644 --- a/luohuo-cloud/luohuo-ai/luohuo-ai-server/src/main/resources/bootstrap.yml +++ b/luohuo-cloud/luohuo-ai/luohuo-ai-server/src/main/resources/bootstrap.yml @@ -8,6 +8,7 @@ luohuo: username: ${NACOS_USERNAME:@nacos.username@} password: ${NACOS_PASSWORD:@nacos.password@} web-port: ${NACOS_WEB_PORT:@nacos.web-port@} + local-ip: ${NACOS_LOCAL_IP:@nacos.local-ip@} seata: ip: ${SEATA_IP:@seata.ip@} port: ${SEATA_PORT:@seata.port@} @@ -53,6 +54,7 @@ spring: username: ${luohuo.nacos.username} password: ${luohuo.nacos.password} server-addr: ${luohuo.nacos.ip}:${luohuo.nacos.port} + ip: ${luohuo.nacos.local-ip} namespace: ${luohuo.nacos.namespace} metadata: # 元数据,用于权限服务实时获取各个服务的所有接口 management.context-path: ${server.servlet.context-path:}${spring.mvc.servlet.path:}${management.endpoints.web.base-path:} diff --git a/luohuo-cloud/luohuo-ai/pom.xml b/luohuo-cloud/luohuo-ai/pom.xml index 85e891d9..268046da 100644 --- a/luohuo-cloud/luohuo-ai/pom.xml +++ b/luohuo-cloud/luohuo-ai/pom.xml @@ -20,7 +20,6 @@ - luohuo-ai-controller luohuo-ai-entity luohuo-ai-facade luohuo-ai-server diff --git a/luohuo-cloud/luohuo-base/luohuo-base-biz/src/main/java/com/luohuo/flex/base/service/tenant/impl/DefUserServiceImpl.java b/luohuo-cloud/luohuo-base/luohuo-base-biz/src/main/java/com/luohuo/flex/base/service/tenant/impl/DefUserServiceImpl.java index 1938149a..d8cb6a3a 100644 --- a/luohuo-cloud/luohuo-base/luohuo-base-biz/src/main/java/com/luohuo/flex/base/service/tenant/impl/DefUserServiceImpl.java +++ b/luohuo-cloud/luohuo-base/luohuo-base-biz/src/main/java/com/luohuo/flex/base/service/tenant/impl/DefUserServiceImpl.java @@ -2,7 +2,6 @@ package com.luohuo.flex.base.service.tenant.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.convert.Convert; -import cn.hutool.core.lang.UUID; import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SecureUtil; @@ -216,10 +215,9 @@ public class DefUserServiceImpl extends SuperCacheServiceImpl { .one(); } + public GroupResp getByRoomIdIgnoreDel(Long roomId) { + return baseMapper.getByRoomIdIgnoreDel(roomId); + } + public boolean checkUser(Long uid, Long roomId) { return baseMapper.checkUser(uid,roomId); } diff --git a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/chat/mapper/RoomGroupMapper.java b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/chat/mapper/RoomGroupMapper.java index ace7642e..26c0b7b2 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/chat/mapper/RoomGroupMapper.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/chat/mapper/RoomGroupMapper.java @@ -1,6 +1,7 @@ package com.luohuo.flex.im.core.chat.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.luohuo.flex.im.domain.vo.response.GroupResp; import org.springframework.stereotype.Repository; import com.luohuo.flex.im.domain.entity.RoomGroup; @@ -15,4 +16,6 @@ import com.luohuo.flex.im.domain.entity.RoomGroup; public interface RoomGroupMapper extends BaseMapper { boolean checkUser(Long uid, Long roomId); + + GroupResp getByRoomIdIgnoreDel(Long roomId); } diff --git a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/chat/service/RoomAppService.java b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/chat/service/RoomAppService.java index d591f581..2bc7c908 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/chat/service/RoomAppService.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/chat/service/RoomAppService.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.luohuo.flex.im.domain.vo.request.admin.AdminSetReq; import com.luohuo.flex.im.domain.vo.request.contact.ContactAddReq; import com.luohuo.flex.im.domain.vo.request.member.MemberExitReq; +import com.luohuo.flex.im.domain.vo.response.GroupResp; import jakarta.validation.Valid; import com.luohuo.flex.im.domain.vo.req.CursorPageBaseReq; import com.luohuo.flex.im.domain.vo.res.CursorPageBaseResp; @@ -30,6 +31,7 @@ import com.luohuo.flex.im.domain.vo.response.ChatRoomResp; import com.luohuo.flex.im.domain.vo.response.MemberResp; import com.luohuo.flex.im.domain.vo.req.MergeMessageReq; import com.luohuo.flex.model.entity.ws.ChatMemberResp; + import java.util.List; /** @@ -55,7 +57,12 @@ public interface RoomAppService { /** * 获取群组信息 */ - MemberResp getGroupDetail(Long uid, long roomId); + MemberResp getGroupDetail(Long uid, Long roomId); + + /** + * 获取群组基础信息 + */ + GroupResp getGroupInfo(Long uid, Long roomId); /** * 获取群成员 diff --git a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/chat/service/impl/ChatServiceImpl.java b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/chat/service/impl/ChatServiceImpl.java index 110ee956..a9ce33ec 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/chat/service/impl/ChatServiceImpl.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/chat/service/impl/ChatServiceImpl.java @@ -239,7 +239,7 @@ public class ChatServiceImpl implements ChatService { } // 2. 如果开启同步功能,那么把最近N天的消息拉回去, 否则获取所有未ack的消息 [要排除屏蔽的房间的消息] - if(msgReq.getAsync()){ + if(true || msgReq.getAsync()){ LocalDateTime effectiveStartTime = calculateStartTime(TimeUtils.getTime(LocalDateTime.now().minusDays(14))); messages = messageDao.list(new LambdaQueryWrapper().in(Message::getRoomId, roomIds) .between(Message::getCreateTime, effectiveStartTime, LocalDateTime.now())); diff --git a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/chat/service/impl/RoomAppServiceImpl.java b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/chat/service/impl/RoomAppServiceImpl.java index 45669aa1..394cb268 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/chat/service/impl/RoomAppServiceImpl.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/chat/service/impl/RoomAppServiceImpl.java @@ -31,6 +31,7 @@ import com.luohuo.flex.im.domain.vo.request.ChatMessageReq; import com.luohuo.flex.im.domain.vo.request.admin.AdminSetReq; import com.luohuo.flex.im.domain.vo.request.member.MemberExitReq; import com.luohuo.flex.im.domain.entity.msg.TextMsgReq; +import com.luohuo.flex.im.domain.vo.response.GroupResp; import com.luohuo.flex.model.entity.ws.AdminChangeDTO; import com.luohuo.flex.model.enums.ChatActiveStatusEnum; import com.luohuo.flex.im.domain.vo.request.contact.ContactAddReq; @@ -39,6 +40,7 @@ import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Triple; import org.springframework.beans.factory.InitializingBean; import org.springframework.data.redis.core.ZSetOperations; import org.springframework.stereotype.Service; @@ -104,6 +106,7 @@ import com.luohuo.flex.im.core.user.service.impl.PushService; import java.time.LocalDateTime; import java.util.*; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; import java.util.stream.Collectors; @@ -453,24 +456,6 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean { } } - /** - * 校验用户在群里的权限 - * - * @param uid - * @return - */ - public GroupMember verifyGroupPermissions(Long uid, RoomGroup roomGroup) { - if (ObjectUtil.isNull(roomGroup)) { - throw new RuntimeException("群聊不存在!"); - } - - GroupMember groupMember = groupMemberDao.getMemberByGroupId(roomGroup.getId(), uid); - if (ObjectUtil.isNull(groupMember)) { - throw new RuntimeException(StrUtil.format("您不是{}的群成员!", roomGroup.getName())); - } - return groupMember; - } - /** * 群主,管理员才可以修改 * @@ -481,34 +466,55 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean { @Override public Boolean updateRoomInfo(Long uid, RoomInfoReq request) { // 1.校验修改权限 - RoomGroup roomGroup = roomGroupCache.get(request.getId()); - GroupMember groupMember = verifyGroupPermissions(uid, roomGroup); - - if (GroupRoleEnum.MEMBER.getType().equals(groupMember.getRoleId())) { + Triple permissionCheck = checkGroupPermission(uid, request.getId()); + if (!permissionCheck.getRight()) { + log.warn("用户无权限修改群信息,uid:{}, roomId:{}", uid, request.getId()); return false; } + RoomGroup roomGroup = permissionCheck.getLeft(); // 2.修改群信息 roomGroup.setAvatar(request.getAvatar()); roomGroup.setName(request.getName()); roomGroup.setAllowScanEnter(request.getAllowScanEnter()); - Boolean success = roomService.updateRoomInfo(roomGroup); - // 3.通知群里所有人群信息修改了 - if (success) { - roomGroupCache.delete(roomGroup.getId()); - roomGroupCache.evictGroup(roomGroup.getAccount()); - List memberUidList = groupMemberCache.getMemberExceptUidList(roomGroup.getRoomId()); - pushService.sendPushMsg(RoomAdapter.buildRoomGroupChangeWS(roomGroup.getRoomId(), roomGroup.getName(), roomGroup.getAvatar()), memberUidList, uid); - } + // 3. 通知群里所有人群信息修改了 + Boolean success = transactionTemplate.execute(status -> { + try { + boolean updateResult = roomService.updateRoomInfo(roomGroup); + if (!updateResult) { + status.setRollbackOnly(); + return false; + } + + // 4. 异步清理缓存 + CompletableFuture.runAsync(() -> { + roomGroupCache.delete(roomGroup.getId()); + roomGroupCache.evictGroup(roomGroup.getAccount()); + }); + + List memberUidList = groupMemberCache.getMemberExceptUidList(roomGroup.getRoomId()); + pushService.sendPushMsg(RoomAdapter.buildRoomGroupChangeWS(roomGroup.getRoomId(), roomGroup.getName(), roomGroup.getAvatar()), memberUidList, uid); + return true; + } catch (Exception e) { + status.setRollbackOnly(); + throw e; + } + }); + return success; } @Override public Boolean updateMyRoomInfo(Long uid, RoomMyInfoReq request) { // 1.校验修改权限 - RoomGroup roomGroup = roomGroupCache.get(request.getId()); - GroupMember member = verifyGroupPermissions(uid, roomGroup); + Triple permissionCheck = checkGroupPermission(uid, request.getId()); + if (!permissionCheck.getRight()) { + return false; + } + + RoomGroup roomGroup = permissionCheck.getLeft(); + GroupMember member = permissionCheck.getMiddle(); // 2.修改我的信息 boolean equals = member.getMyName().equals(StrUtil.isEmpty(request.getMyName()) ? "" : request.getMyName()); @@ -540,11 +546,36 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean { return contactDao.updateById(contact); } + /** + * 统一权限校验方法 + * @return 返回三元组(roomGroup, groupMember, hasPermission) + */ + private Triple checkGroupPermission(Long uid, Long roomId) { + RoomGroup roomGroup = roomGroupCache.get(roomId); + if (roomGroup == null) { + return Triple.of(null, null, false); + } + + GroupMember groupMember = groupMemberCache.getMemberDetail(roomId, uid); + if (groupMember == null) { + return Triple.of(roomGroup, null, false); + } + + boolean hasPermission = !GroupRoleEnum.MEMBER.getType().equals(groupMember.getRoleId()); + return Triple.of(roomGroup, groupMember, hasPermission); + } + @Override @Transactional public Boolean pushAnnouncement(Long uid, AnnouncementsParam param) { - RoomGroup roomGroup = roomGroupCache.get(param.getRoomId()); - List uids = roomService.getGroupUsers(roomGroup.getId(), false); + // 1. 权限校验 + Triple permissionCheck = checkGroupPermission(uid, param.getRoomId()); + if (!permissionCheck.getRight()) { + return false; + } + + // 2. 保存公告 + List uids = roomService.getGroupUsers(permissionCheck.getLeft().getId(), false); if (CollUtil.isNotEmpty(uids)) { LocalDateTime now = LocalDateTime.now(); Announcements announcements = new Announcements(); @@ -579,7 +610,14 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean { @Override public Boolean announcementEdit(Long uid, AnnouncementsParam param) { - RoomGroup roomGroup = roomGroupCache.get(param.getRoomId()); + // 1. 鉴权 + Triple permissionCheck = checkGroupPermission(uid, param.getRoomId()); + if (!permissionCheck.getRight()) { + return false; + } + RoomGroup roomGroup = permissionCheck.getLeft(); + + // 2. 置顶公告 List uids = roomService.getGroupUsers(roomGroup.getId(), false); if (CollUtil.isNotEmpty(uids)) { AnnouncementsResp announcement = roomService.getAnnouncement(param.getId()); @@ -642,15 +680,14 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean { } @Override + @RedissonLock(prefixKey = "announceDel:", key = "#id") public Boolean announcementDelete(Long uid, Long id) { // 1. 鉴权 AnnouncementsResp resp = roomService.getAnnouncement(id); + Triple validation = checkGroupPermission(uid, resp.getRoomId()); + GroupMember groupMember = validation.getMiddle(); - RoomGroup roomGroup = roomGroupCache.get(resp.getRoomId()); - GroupMember groupMember = verifyGroupPermissions(uid, roomGroup); - - long count = userBackpackDao.countByUidAndItemId(uid, "HuLa项目贡献者专属徽章"); - + long count = userBackpackDao.countByUidAndItemId(uid, DefValConstants.CONTRIBUTOR_ID); if (count == 0 && GroupRoleEnum.MEMBER.getType().equals(groupMember.getRoleId())) { return false; } @@ -716,8 +753,10 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean { } if (room.getType().equals(RoomTypeEnum.GROUP.getType())) { - RoomGroup sourceRoomGroup = roomGroupCache.get(req.getFromRoomId()); - verifyGroupPermissions(uid, sourceRoomGroup); + Triple permissionCheck = checkGroupPermission(uid, req.getFromRoomId()); + if(ObjectUtil.isNull(permissionCheck.getMiddle())) { + throw new BizException("您不是群成员"); + } } else { RoomFriend roomFriend = roomFriendCache.get(req.getFromRoomId()); if (ObjectUtil.isNull(roomFriend) || !roomFriend.getUid1().equals(uid) && !roomFriend.getUid1().equals(uid)) { @@ -781,7 +820,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean { } @Override - public MemberResp getGroupDetail(Long uid, long roomId) { + public MemberResp getGroupDetail(Long uid, Long roomId) { RoomGroup roomGroup = roomGroupCache.get(roomId); Room room = roomCache.get(roomId); AssertUtil.isNotEmpty(roomGroup, "roomId有误"); @@ -807,6 +846,11 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean { .build(); } + @Override + public GroupResp getGroupInfo(Long uid, Long roomId) { + return roomGroupDao.getByRoomIdIgnoreDel(roomId); + } + @Override public List listMember(MemberReq request) { // 1. 基础校验 @@ -870,6 +914,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean { public void delMember(Long uid, MemberDelReq request) { Room room = roomCache.get(request.getRoomId()); AssertUtil.isNotEmpty(room, "房间号有误"); + AssertUtil.isFalse(DefValConstants.DEF_ROOM_ID.equals(request.getRoomId()), "官方群聊无法移除"); RoomGroup roomGroup = roomGroupCache.get(request.getRoomId()); AssertUtil.isNotEmpty(roomGroup, "房间号有误"); GroupMember self = groupMemberDao.getMemberByGroupId(roomGroup.getId(), uid); @@ -887,74 +932,77 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean { } // 1. 判断被移除的人是否是群主或者管理员 (群主不可以被移除,管理员只能被群主移除) - Long removedUid = request.getUid(); - // 1.1 群主 非法操作 - AssertUtil.isFalse(groupMemberDao.isLord(roomGroup.getId(), removedUid), GroupErrorEnum.NOT_ALLOWED_FOR_REMOVE, ""); - // 1.2 管理员 判断是否是群主操作 - if (groupMemberDao.isManager(roomGroup.getId(), removedUid)) { - Boolean isLord = groupMemberDao.isLord(roomGroup.getId(), uid); - AssertUtil.isTrue(isLord, GroupErrorEnum.NOT_ALLOWED_FOR_REMOVE); - } - // 1.3 普通成员 判断是否有权限操作 - AssertUtil.isTrue(hasPower(self), GroupErrorEnum.NOT_ALLOWED_FOR_REMOVE); - GroupMember member = groupMemberDao.getMemberByGroupId(roomGroup.getId(), removedUid); - AssertUtil.isNotEmpty(member, "用户已经移除"); - - // 发送移除事件告知群成员 - if (transactionTemplate.execute(e -> { - groupMemberDao.removeById(member.getId()); - // 1.5 移除会话 - contactDao.removeByRoomId(room.getId(), Collections.singletonList(request.getUid())); - return true; - })) { - // 移除群聊缓存 - CacheKey uKey = PresenceCacheKeyBuilder.userGroupsKey(request.getUid()); - cachePlusOps.sRem(membersKey, request.getUid()); - cachePlusOps.sRem(uKey, room.getId()); - asyncOnline(Arrays.asList(request.getUid()), room.getId(), false); - - // 推送状态到前端 - List memberUidList = groupMemberCache.getMemberExceptUidList(roomGroup.getRoomId()); - if (!memberUidList.contains(request.getUid())) { - memberUidList.add(request.getUid()); + request.getUidList().forEach(removedUid -> { + // 1.1 群主 非法操作 + AssertUtil.isFalse(groupMemberDao.isLord(roomGroup.getId(), removedUid), GroupErrorEnum.NOT_ALLOWED_FOR_REMOVE, ""); + // 1.2 管理员 判断是否是群主操作 + if (groupMemberDao.isManager(roomGroup.getId(), removedUid)) { + Boolean isLord = groupMemberDao.isLord(roomGroup.getId(), uid); + AssertUtil.isTrue(isLord, GroupErrorEnum.NOT_ALLOWED_FOR_REMOVE); } - WsBaseResp ws = MemberAdapter.buildMemberRemoveWS(roomGroup.getRoomId(), (int) (memberNum - 1), Math.toIntExact(cachePlusOps.sCard(PresenceCacheKeyBuilder.onlineGroupMembersKey(room.getId()))), Arrays.asList(member.getUid()), WSMemberChange.CHANGE_TYPE_REMOVE); - pushService.sendPushMsg(ws, memberUidList, uid); - groupMemberCache.evictMemberList(room.getId()); - groupMemberCache.evictExceptMemberList(room.getId()); - groupMemberCache.evictMemberDetail(room.getId(), removedUid); + // 1.3 普通成员 判断是否有权限操作 + AssertUtil.isTrue(hasPower(self), GroupErrorEnum.NOT_ALLOWED_FOR_REMOVE); + GroupMember member = groupMemberDao.getMemberByGroupId(roomGroup.getId(), removedUid); + AssertUtil.isNotEmpty(member, "用户已经移除"); - long uuid = uidGenerator.getUid(); - // 保存被删除人的通知 - noticeService.createNotice( - RoomTypeEnum.GROUP, - NoticeTypeEnum.GROUP_MEMBER_DELETE, - uid, - removedUid, - uuid, - removedUid, - roomGroup.getRoomId(), - roomGroup.getName() - ); + // 发送移除事件告知群成员 + if (transactionTemplate.execute(e -> { + groupMemberDao.removeById(member.getId()); + // 1.5 移除会话 + contactDao.removeByRoomId(room.getId(), Collections.singletonList(removedUid)); + return true; + })) { + // 移除群聊缓存 + CacheKey uKey = PresenceCacheKeyBuilder.userGroupsKey(removedUid); + cachePlusOps.sRem(membersKey, removedUid); + cachePlusOps.sRem(uKey, room.getId()); + asyncOnline(Arrays.asList(removedUid), room.getId(), false); - // 获取所有管理员 - List managerIds = groupMemberDao.getGroupUsers(roomGroup.getId(), true); - managerIds.forEach(managerId -> noticeService.createNotice( - RoomTypeEnum.GROUP, - NoticeTypeEnum.GROUP_MEMBER_DELETE, - uid, - managerId, - uuid, - removedUid, - roomGroup.getRoomId(), - roomGroup.getName() - )); - } + // 推送状态到前端 + List memberUidList = groupMemberCache.getMemberExceptUidList(roomGroup.getRoomId()); + if (!memberUidList.contains(removedUid)) { + memberUidList.add(removedUid); + } + WsBaseResp ws = MemberAdapter.buildMemberRemoveWS(roomGroup.getRoomId(), (int) (memberNum - 1), Math.toIntExact(cachePlusOps.sCard(PresenceCacheKeyBuilder.onlineGroupMembersKey(room.getId()))), Arrays.asList(member.getUid()), WSMemberChange.CHANGE_TYPE_REMOVE); + pushService.sendPushMsg(ws, memberUidList, uid); + groupMemberCache.evictMemberList(room.getId()); + groupMemberCache.evictExceptMemberList(room.getId()); + groupMemberCache.evictMemberDetail(room.getId(), removedUid); + + long uuid = uidGenerator.getUid(); + // 保存被删除人的通知 + noticeService.createNotice( + RoomTypeEnum.GROUP, + NoticeTypeEnum.GROUP_MEMBER_DELETE, + uid, + removedUid, + uuid, + removedUid, + roomGroup.getRoomId(), + roomGroup.getName() + ); + + // 获取所有管理员 + List managerIds = groupMemberDao.getGroupUsers(roomGroup.getId(),true); + managerIds.forEach(managerId -> noticeService.createNotice( + RoomTypeEnum.GROUP, + NoticeTypeEnum.GROUP_MEMBER_DELETE, + uid, + managerId, + uuid, + removedUid, + roomGroup.getRoomId(), + roomGroup.getName() + )); + } + }); } @Override @RedissonLock(key = "#request.roomId") public void addMember(Long uid, MemberAddReq request) { + HashSet inviteUidList = request.getUidList(); + AssertUtil.isNotEmpty(inviteUidList.contains(DefValConstants.DEF_BOT_ID), "不能拉小管家进群!"); // 1. 校验数据 Room room = roomCache.get(request.getRoomId()); AssertUtil.isNotEmpty(room, "房间号有误"); @@ -963,20 +1011,19 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean { GroupMember self = groupMemberDao.getMemberByGroupId(roomGroup.getId(), uid); AssertUtil.isNotEmpty(self, "您不是群成员"); // 已经进群了的 - List memberBatch = groupMemberDao.getMemberBatch(roomGroup.getId(), request.getUidList()).stream().map(GroupMember::getUid).toList(); + List memberBatch = groupMemberDao.getMemberBatch(roomGroup.getId(), inviteUidList).stream().map(GroupMember::getUid).toList(); // 已经邀请过的数据 - List existingUsers = userApplyDao.getExistingUsers(request.getRoomId(), request.getUidList()); - HashSet validUidSet = request.getUidList(); - validUidSet.removeAll(memberBatch); - validUidSet.removeAll(existingUsers); + List existingUsers = userApplyDao.getExistingUsers(request.getRoomId(), inviteUidList); + inviteUidList.removeAll(memberBatch); + inviteUidList.removeAll(existingUsers); - List validUids = new ArrayList<>(validUidSet); + List validUids = new ArrayList<>(inviteUidList); if (CollectionUtils.isEmpty(validUids)) { return; } // 2. 创建邀请记录 - List invites = validUids.stream().map(inviteeUid -> new UserApply(uid, RoomTypeEnum.GROUP.getType(), roomGroup.getRoomId(), inviteeUid, StrUtil.format("{}邀请你加入{}", userSummaryCache.get(uid).getName(), roomGroup.getName()), ApplyStatusEnum.WAIT_APPROVAL.getCode(), UNREAD.getCode(), 0, false)).collect(Collectors.toList()); + List invites = validUids.stream().map(inviteeUid -> new UserApply(uid, RoomTypeEnum.GROUP.getType(), roomGroup.getRoomId(), inviteeUid, StrUtil.format("{}邀请你加入{}", userSummaryCache.get(uid).getName(), roomGroup.getName()), NoticeStatusEnum.UNTREATED.getStatus(), UNREAD.getCode(), 0, false)).collect(Collectors.toList()); transactionTemplate.execute(e -> userApplyDao.saveBatch(invites)); // 3. 通知被邀请的人进群, 通知时绑定通知id @@ -1122,23 +1169,23 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean { @Override @RedissonLock(prefixKey = "addGroup:", key = "#uid") public Long addGroup(Long uid, GroupAddReq request) { - Map userMap = userSummaryCache.getBatch(request.getUidList()); - AssertUtil.isTrue(userMap.size() > 1, "群聊人数应大于2人"); + Map inviteUserMap = userSummaryCache.getBatch(request.getUidList()); + inviteUserMap.remove(DefValConstants.DEF_BOT_ID); + AssertUtil.isTrue(inviteUserMap.size() > 1, "群聊人数应大于2人"); - userMap.remove(DefValConstants.DEF_BOT_ID); - List uidList = new ArrayList<>(userMap.keySet()); + List inviteUidList = new ArrayList<>(inviteUserMap.keySet()); AtomicReference roomIdAtomic = new AtomicReference(0L); // 创建群组数据并推送数据到前端 if (transactionTemplate.execute(e -> { RoomGroup roomGroup = roomService.createGroupRoom(uid, request); // 批量保存群成员 - List groupMembers = RoomAdapter.buildGroupMemberBatch(uidList, roomGroup.getId()); + List groupMembers = RoomAdapter.buildGroupMemberBatch(inviteUidList, roomGroup.getId()); groupMemberDao.saveBatch(groupMembers); // 添加所有人的会话 - uidList.add(uid); - for (Long memberId : uidList) { + inviteUidList.add(uid); + for (Long memberId : inviteUidList) { contactDao.refreshOrCreate(roomGroup.getRoomId(), memberId); } @@ -1154,11 +1201,11 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean { // 更新在线缓存 CacheKey onlineGroupMembersKey = PresenceCacheKeyBuilder.onlineGroupMembersKey(roomIdAtomic.get()); CacheKey gKey = PresenceCacheKeyBuilder.groupMembersKey(roomIdAtomic.get()); - uidList.forEach(id -> { + inviteUidList.forEach(id -> { cachePlusOps.sAdd(gKey, id); cachePlusOps.sAdd(PresenceCacheKeyBuilder.userGroupsKey(id), roomIdAtomic.get()); }); - asyncOnline(uidList, roomIdAtomic.get(), true); + asyncOnline(inviteUidList, roomIdAtomic.get(), true); SpringUtils.publishEvent(new GroupMemberAddEvent(this, roomIdAtomic.get(), Math.toIntExact(cachePlusOps.sCard(gKey)), Math.toIntExact(cachePlusOps.sCard(onlineGroupMembersKey)), request.getUidList(), uid)); } return roomIdAtomic.get(); diff --git a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/chat/service/impl/RoomServiceImpl.java b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/chat/service/impl/RoomServiceImpl.java index ad1652aa..dfd4e6cf 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/chat/service/impl/RoomServiceImpl.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/chat/service/impl/RoomServiceImpl.java @@ -131,9 +131,13 @@ public class RoomServiceImpl implements RoomService { @Override public AnnouncementsResp getAnnouncement(Long id) { AnnouncementsResp resp = new AnnouncementsResp(); - BeanUtils.copyProperties(announcementsDao.getById(id), resp); - User user = userCache.get(resp.getUid()); - resp.setUName(user.getName()); + Announcements announcements = announcementsDao.getById(id); + resp.setUid(announcements.getUid()); + resp.setRoomId(announcements.getRoomId()); + resp.setTop(announcements.getTop()); + resp.setContent(announcements.getContent()); + resp.setCreateTime(announcements.getCreateTime()); + resp.setId(announcements.getId()); return resp; } diff --git a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/chat/service/strategy/msg/RecallMsgHandler.java b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/chat/service/strategy/msg/RecallMsgHandler.java index 78c8c30b..5e971cc9 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/chat/service/strategy/msg/RecallMsgHandler.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/chat/service/strategy/msg/RecallMsgHandler.java @@ -4,10 +4,13 @@ import com.luohuo.basic.context.ContextUtil; import com.luohuo.basic.utils.SpringUtils; import com.luohuo.basic.utils.TimeUtils; import com.luohuo.flex.im.core.chat.service.cache.GroupMemberCache; +import com.luohuo.flex.im.core.chat.service.cache.RoomCache; import com.luohuo.flex.im.core.user.service.cache.UserSummaryCache; import com.luohuo.flex.im.domain.dto.SummeryInfoDTO; import com.luohuo.flex.im.domain.entity.GroupMember; +import com.luohuo.flex.im.domain.entity.Room; import com.luohuo.flex.im.domain.enums.GroupRoleEnum; +import com.luohuo.flex.im.domain.enums.RoomTypeEnum; import com.luohuo.flex.im.vo.result.tenant.MsgRecallVo; import lombok.AllArgsConstructor; import org.springframework.stereotype.Component; @@ -31,6 +34,7 @@ import java.util.Objects; @AllArgsConstructor public class RecallMsgHandler extends AbstractMsgHandler { + private RoomCache roomCache; private MessageDao messageDao; private UserSummaryCache userSummaryCache; private GroupMemberCache groupMemberCache; @@ -52,8 +56,14 @@ public class RecallMsgHandler extends AbstractMsgHandler { Long senderUid = msg.getFromUid(); Long currentUserUid = ContextUtil.getUid(); + String roleName = ""; + Room room = roomCache.get(msg.getRoomId()); + if(room.getType().equals(RoomTypeEnum.GROUP.getType())){ + GroupMember recallerMember = groupMemberCache.getMemberDetail(msg.getRoomId(), recallerUid); + roleName = GroupRoleEnum.get(recallerMember.getRoleId()); + } + // 获取撤回者的群成员信息和用户信息 - GroupMember recallerMember = groupMemberCache.getMemberDetail(msg.getRoomId(), recallerUid); SummeryInfoDTO recallerUserInfo = userSummaryCache.get(recallerUid); // 获取被撤回消息发送者的用户信息(用于显示成员名称) @@ -63,7 +73,7 @@ public class RecallMsgHandler extends AbstractMsgHandler { boolean isRecallerCurrentUser = Objects.equals(recallerUid, currentUserUid); boolean isSenderCurrentUser = Objects.equals(senderUid, currentUserUid); - String roleName = GroupRoleEnum.get(recallerMember.getRoleId()); + String messageText; if (isRecallerCurrentUser) { diff --git a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/dao/FeedMediaDao.java b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/dao/FeedMediaDao.java index d0430cec..0118fc82 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/dao/FeedMediaDao.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/dao/FeedMediaDao.java @@ -18,13 +18,13 @@ public class FeedMediaDao extends ServiceImpl { /** * 批量添加朋友圈的资源的数据 * @param feedId 朋友圈id - * @param urls 素材地址 + * @param images 素材地址 * @param type 0 纯文字 1 图片 2 视频 */ - public List batchSaveMedia(Long feedId, List urls, Integer type){ + public List batchSaveMedia(Long feedId, List images, Integer type){ List feedMediaList = new ArrayList<>(); - for (int i = 0; i < urls.size(); i++) { - String url = urls.get(i); + for (int i = 0; i < images.size(); i++) { + String url = images.get(i); FeedMedia feedMedia = new FeedMedia(); feedMedia.setSort(i); feedMedia.setFeedId(feedId); diff --git a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/dao/ItemConfigDao.java b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/dao/ItemConfigDao.java index c2e117e3..db70d5c2 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/dao/ItemConfigDao.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/dao/ItemConfigDao.java @@ -1,6 +1,5 @@ package com.luohuo.flex.im.core.user.dao; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.luohuo.flex.im.domain.entity.ItemConfig; import com.luohuo.flex.im.core.user.mapper.ItemConfigMapper; @@ -23,9 +22,4 @@ public class ItemConfigDao extends ServiceImpl { .eq(ItemConfig::getType, type) .list(); } - - public ItemConfig getByDesc(String desc) { - return baseMapper.selectOne(new LambdaQueryWrapper() - .eq(ItemConfig::getDescribe, desc)); - } } diff --git a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/dao/NoticeDao.java b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/dao/NoticeDao.java index 3d4b2a08..c8fbfebe 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/dao/NoticeDao.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/dao/NoticeDao.java @@ -62,10 +62,11 @@ public class NoticeDao extends ServiceImpl { return wsNotice; } - public void readNotices(Long uid, List notices) { + public void readNotices(Long uid, Integer type, List notices) { lambdaUpdate() .set(Notice::getIsRead, READ.getCode()) .eq(Notice::getIsRead, UNREAD.getCode()) + .eq(Notice::getType, type) .in(Notice::getId, notices) .eq(Notice::getReceiverId, uid) .update(); diff --git a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/dao/UserApplyDao.java b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/dao/UserApplyDao.java index 7b23ddb3..1432bc52 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/dao/UserApplyDao.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/dao/UserApplyDao.java @@ -3,7 +3,7 @@ package com.luohuo.flex.im.core.user.dao; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.luohuo.flex.im.domain.entity.UserApply; import com.luohuo.flex.im.domain.enums.ApplyDeletedEnum; -import com.luohuo.flex.im.domain.enums.ApplyStatusEnum; +import com.luohuo.flex.im.domain.enums.NoticeStatusEnum; import com.luohuo.flex.im.core.user.mapper.UserApplyMapper; import com.luohuo.flex.im.domain.enums.RoomTypeEnum; import org.springframework.stereotype.Service; @@ -13,7 +13,7 @@ import java.util.HashSet; import java.util.List; import java.util.stream.Collectors; -import static com.luohuo.flex.im.domain.enums.ApplyStatusEnum.AGREE; +import static com.luohuo.flex.im.domain.enums.NoticeStatusEnum.ACCEPTED; /** *

@@ -35,7 +35,7 @@ public class UserApplyDao extends ServiceImpl { public UserApply getFriendApproving(Long uid, Long targetUid, boolean initiator) { return lambdaQuery().eq(UserApply::getUid, uid) .eq(UserApply::getTargetId, targetUid) - .eq(UserApply::getStatus, ApplyStatusEnum.WAIT_APPROVAL.getCode()) + .eq(UserApply::getStatus, NoticeStatusEnum.UNTREATED.getStatus()) .eq(UserApply::getType, RoomTypeEnum.FRIEND.getType()) .notIn(initiator,UserApply::getDeleted, ApplyDeletedEnum.applyDeleted()) .notIn(!initiator,UserApply::getDeleted, ApplyDeletedEnum.targetDeleted()) @@ -45,13 +45,13 @@ public class UserApplyDao extends ServiceImpl { public void agree(Long applyId) { lambdaUpdate() .eq(UserApply::getId, applyId) - .set(UserApply::getStatus, AGREE.getCode()) + .set(UserApply::getStatus, ACCEPTED.getStatus()) .set(UserApply::getUpdateTime, LocalDateTime.now()) .update(); } - public void updateStatus(Long applyId, ApplyStatusEnum statusEnum) { - lambdaUpdate().set(UserApply::getStatus, statusEnum.getCode()) + public void updateStatus(Long applyId, NoticeStatusEnum statusEnum) { + lambdaUpdate().set(UserApply::getStatus, statusEnum.getStatus()) .set(UserApply::getUpdateTime, LocalDateTime.now()) .eq(UserApply::getId,applyId) .update(); @@ -67,7 +67,7 @@ public class UserApplyDao extends ServiceImpl { public List getExistingUsers(Long roomId, HashSet uidList) { return lambdaQuery() .eq(UserApply::getRoomId, roomId) - .eq(UserApply::getStatus, ApplyStatusEnum.WAIT_APPROVAL.getCode()) + .eq(UserApply::getStatus, NoticeStatusEnum.UNTREATED.getStatus()) .in(UserApply::getTargetId, uidList) .list().stream().map(UserApply::getTargetId).collect(Collectors.toList()); } diff --git a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/dao/UserBackpackDao.java b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/dao/UserBackpackDao.java index af046a4d..d1078a3d 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/dao/UserBackpackDao.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/dao/UserBackpackDao.java @@ -3,7 +3,6 @@ package com.luohuo.flex.im.core.user.dao; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.luohuo.flex.im.domain.entity.ItemConfig; import org.springframework.stereotype.Service; import com.luohuo.flex.im.common.enums.YesOrNoEnum; import com.luohuo.flex.im.domain.entity.UserBackpack; @@ -67,11 +66,10 @@ public class UserBackpackDao extends ServiceImpl() .eq(UserBackpack::getUid, uid) - .eq(UserBackpack::getItemId, itemConfig.getId()) + .eq(UserBackpack::getItemId, itemId) ); } } diff --git a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/service/NoticeService.java b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/service/NoticeService.java index 9e5f8e5e..f2d2d4a4 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/service/NoticeService.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/service/NoticeService.java @@ -3,7 +3,7 @@ package com.luohuo.flex.im.core.user.service; import com.luohuo.flex.im.domain.entity.Notice; import com.luohuo.flex.im.domain.enums.NoticeTypeEnum; import com.luohuo.flex.im.domain.enums.RoomTypeEnum; -import com.luohuo.flex.im.domain.vo.req.PageBaseReq; +import com.luohuo.flex.im.domain.vo.req.NoticeReq; import com.luohuo.flex.im.domain.vo.res.NoticeVO; import com.luohuo.flex.im.domain.vo.res.PageBaseResp; import com.luohuo.flex.model.entity.ws.WSNotice; @@ -44,7 +44,7 @@ public interface NoticeService { /** * 获取用户通知 */ - PageBaseResp getUserNotices(Long userId, PageBaseReq request); + PageBaseResp getUserNotices(Long userId, NoticeReq request); /** * 标记为已读 diff --git a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/service/adapter/FriendAdapter.java b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/service/adapter/FriendAdapter.java index 77ed985b..766d0644 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/service/adapter/FriendAdapter.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/service/adapter/FriendAdapter.java @@ -12,7 +12,7 @@ import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; import static com.luohuo.flex.im.domain.enums.ApplyReadStatusEnum.UNREAD; -import static com.luohuo.flex.im.domain.enums.ApplyStatusEnum.WAIT_APPROVAL; +import static com.luohuo.flex.im.domain.enums.NoticeStatusEnum.UNTREATED; /** @@ -28,7 +28,7 @@ public class FriendAdapter { userApplyNew.setMsg(request.getMsg()); userApplyNew.setType(RoomTypeEnum.FRIEND.getType()); userApplyNew.setTargetId(request.getTargetUid()); - userApplyNew.setStatus(WAIT_APPROVAL.getCode()); + userApplyNew.setStatus(UNTREATED.getStatus()); userApplyNew.setReadStatus(UNREAD.getCode()); return userApplyNew; } diff --git a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/service/impl/ApplyServiceImpl.java b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/service/impl/ApplyServiceImpl.java index ac453a5f..885a5cf3 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/service/impl/ApplyServiceImpl.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/service/impl/ApplyServiceImpl.java @@ -40,9 +40,8 @@ import com.luohuo.flex.im.domain.entity.RoomGroup; import com.luohuo.flex.im.domain.entity.UserApply; import com.luohuo.flex.im.domain.entity.UserFriend; import com.luohuo.flex.im.domain.enums.ApplyDeletedEnum; -import com.luohuo.flex.im.domain.enums.ApplyStatusEnum; -import com.luohuo.flex.im.domain.enums.GroupRoleEnum; import com.luohuo.flex.im.domain.enums.NoticeStatusEnum; +import com.luohuo.flex.im.domain.enums.GroupRoleEnum; import com.luohuo.flex.im.domain.enums.NoticeTypeEnum; import com.luohuo.flex.im.domain.enums.RoomTypeEnum; import com.luohuo.flex.im.domain.vo.req.friend.FriendApplyReq; @@ -59,8 +58,7 @@ import java.util.List; import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; -import static com.luohuo.flex.im.domain.enums.ApplyStatusEnum.AGREE; -import static com.luohuo.flex.im.domain.enums.ApplyStatusEnum.WAIT_APPROVAL; +import static com.luohuo.flex.im.domain.enums.NoticeStatusEnum.*; /** * 好友申请、群聊邀请 @@ -107,7 +105,7 @@ public class ApplyServiceImpl implements ApplyService { // 是否有待审批的申请记录(别人请求自己的) UserApply friendApproving = userApplyDao.getFriendApproving(request.getTargetUid(), uid, false); if (Objects.nonNull(friendApproving)) { - handlerApply(uid, new ApplyReq(friendApproving.getId(), AGREE.getCode())); + handlerApply(uid, new ApplyReq(friendApproving.getId(), ACCEPTED.getStatus())); return null; } // 申请入库 @@ -204,11 +202,11 @@ public class ApplyServiceImpl implements ApplyService { throw new BizException("无效的邀请"); } - if (request.getState().equals(WAIT_APPROVAL.getCode())) { + if (request.getState().equals(UNTREATED.getStatus())) { throw new BizException("无效的审批状态"); } - if (!invite.getStatus().equals(WAIT_APPROVAL.getCode())) { + if (!invite.getStatus().equals(UNTREATED.getStatus())) { throw new BizException("无效的审批"); } @@ -217,18 +215,18 @@ public class ApplyServiceImpl implements ApplyService { throw new BizException("通知无法处理"); } - switch (request.getState()){ - case 0 -> { - userApplyDao.updateStatus(request.getApplyId(), ApplyStatusEnum.REJECT); + switch (NoticeStatusEnum.get(request.getState())){ + case REJECTED -> { + userApplyDao.updateStatus(request.getApplyId(), NoticeStatusEnum.REJECTED); // 发送通知 notice.setStatus(NoticeStatusEnum.REJECTED.getStatus()); noticeService.updateNotice(notice); } - case 2 -> { + case ACCEPTED -> { // 处理加好友 invite.setStatus(request.getState()); if(invite.getType().equals(RoomTypeEnum.FRIEND.getType())){ - AssertUtil.equal(invite.getStatus(), AGREE.getCode(), "已同意好友申请"); + AssertUtil.equal(invite.getStatus(), ACCEPTED.getStatus(), "已同意好友申请"); // 同意申请 AtomicReference atomicRoomId = new AtomicReference(0L); AtomicReference atomicIsFromTempSession = new AtomicReference(false); @@ -320,10 +318,10 @@ public class ApplyServiceImpl implements ApplyService { SpringUtils.publishEvent(new GroupMemberAddEvent(this, room.getId(), Math.toIntExact(cachePlusOps.sCard(gKey)), Math.toIntExact(cachePlusOps.sCard(onlineGroupMembersKey)), Arrays.asList(infoUid), uid)); } } - case 3 -> { + case IGNORE -> { checkRecord(request); - userApplyDao.updateStatus(request.getApplyId(), ApplyStatusEnum.IGNORE); - notice.setStatus(NoticeStatusEnum.IGNORE.getStatus()); + userApplyDao.updateStatus(request.getApplyId(), IGNORE); + notice.setStatus(IGNORE.getStatus()); noticeService.updateNotice(notice); } } @@ -354,7 +352,7 @@ public class ApplyServiceImpl implements ApplyService { private UserApply checkRecord(ApplyReq request) { UserApply userApply = userApplyDao.getById(request.getApplyId()); AssertUtil.isNotEmpty(userApply, "不存在申请记录"); - AssertUtil.equal(userApply.getStatus(), WAIT_APPROVAL.getCode(), "对方已是您的好友"); + AssertUtil.equal(userApply.getStatus(), UNTREATED.getStatus(), "对方已是您的好友"); return userApply; } } diff --git a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/service/impl/FeedServiceImpl.java b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/service/impl/FeedServiceImpl.java index bff36b7f..983de264 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/service/impl/FeedServiceImpl.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/service/impl/FeedServiceImpl.java @@ -8,7 +8,7 @@ import com.luohuo.basic.cache.repository.CachePlusOps; import com.luohuo.basic.exception.BizException; import com.luohuo.basic.model.cache.CacheHashKey; import com.luohuo.flex.common.cache.common.FeedMediaRelCacheKeyBuilder; -import com.luohuo.flex.im.common.constant.RedisKey; +import com.luohuo.flex.common.cache.common.FeedTargetRelCacheKeyBuilder; import com.luohuo.flex.im.domain.vo.req.CursorPageBaseReq; import com.luohuo.flex.im.domain.vo.res.CursorPageBaseResp; import com.luohuo.flex.im.core.chat.service.adapter.MemberAdapter; @@ -68,12 +68,9 @@ public class FeedServiceImpl implements FeedService { CacheHashKey hashKey = FeedMediaRelCacheKeyBuilder.build(feed.getId()); CacheResult> result = cachePlusOps.get(hashKey, t -> feedMediaDao.getMediaByFeedId(feed.getId())); List mediaList = result.getValue(); - - if(CollUtil.isEmpty(mediaList)){ - mediaList = feedMediaDao.getMediaByFeedId(feed.getId()); - cachePlusOps.hSet(hashKey, mediaList); + if(CollUtil.isNotEmpty(mediaList)){ + feedVo.setUrls(mediaList.stream().sorted(Comparator.comparingInt(FeedMedia::getSort)).map(FeedMedia::getUrl).collect(Collectors.toList())); } - feedVo.setUrls(mediaList.stream().sorted(Comparator.comparingInt(FeedMedia::getSort)).map(FeedMedia::getUrl).collect(Collectors.toList())); } feedVos.add(feedVo); } @@ -122,7 +119,6 @@ public class FeedServiceImpl implements FeedService { public void saveFeed(FeedParam param, Long uid, Feed feed) { List pushList = new ArrayList<>(); List feedTargets = new ArrayList<>(); - List mediaList = new ArrayList<>(); switch (FeedPermissionEnum.get(param.getPermission())){ case open -> { // 1. 查询所有好友,排除【不让他看我, 他不看我】的好友 @@ -169,19 +165,17 @@ public class FeedServiceImpl implements FeedService { switch (FeedEnum.get(param.getMediaType())){ case WORD -> log.info("发布了一条纯文字朋友圈~~"); case IMAGE, VIDEO -> { - List urls = param.getUrls(); - if (CollUtil.isEmpty(urls)){ + List images = param.getImages(); + if (CollUtil.isEmpty(images)){ throw new RuntimeException("请至少上传一条素材!"); } - mediaList = feedMediaDao.batchSaveMedia(feed.getId(), urls, param.getMediaType()); + feedMediaDao.batchSaveMedia(feed.getId(), images, param.getMediaType()); } } // 3. 缓存权限+素材 告知 pushList 我发布了朋友圈 - cachePlusOps.hDel(RedisKey.FEED_MEDIA, feed.getId()); - cachePlusOps.hDel(RedisKey.FEED_TARGET, feed.getId()); - cachePlusOps.hDel(RedisKey.FEED_MEDIA, feed.getId().toString(), mediaList); - cachePlusOps.hDel(RedisKey.FEED_TARGET, feed.getId().toString(), feedTargets); +// cachePlusOps.hDel(FeedMediaRelCacheKeyBuilder.build(feed.getId())); +// cachePlusOps.hDel(FeedTargetRelCacheKeyBuilder.build(feed.getId())); pushService.sendPushMsg(MemberAdapter.buildFeedPushWS(uid), pushList, uid); } @@ -236,8 +230,8 @@ public class FeedServiceImpl implements FeedService { feedDao.removeById(feedId); // 2. 清空缓存 - cachePlusOps.hDel(RedisKey.FEED_TARGET, feedId); - cachePlusOps.hDel(RedisKey.FEED_MEDIA, feedId); + cachePlusOps.hDel(FeedTargetRelCacheKeyBuilder.build(feedId)); + cachePlusOps.hDel(FeedMediaRelCacheKeyBuilder.build(feedId)); return true; } @@ -284,11 +278,8 @@ public class FeedServiceImpl implements FeedService { // 处理朋友圈权限 if(feedVo.getPermission().equals(FeedPermissionEnum.partVisible.getType()) || feedVo.getPermission().equals(FeedPermissionEnum.notAnyone.getType())){ - CacheResult cacheResult = cachePlusOps.hGet(FeedMediaRelCacheKeyBuilder.build(feedId)); + CacheResult cacheResult = cachePlusOps.hGet(FeedTargetRelCacheKeyBuilder.build(feedId), t -> feedTargetDao.selectFeedTargets(feedId)); List feedTargets = cacheResult.asList(); - if(CollUtil.isEmpty(feedTargets)){ - feedTargets = feedTargetDao.selectFeedTargets(feedId); - } List taggetList = feedTargets.stream().filter(item -> item.getType().equals(1)).map(FeedTarget::getTargetId).collect(Collectors.toUnmodifiableList()); List userList = feedTargets.stream().filter(item -> item.getType().equals(2)).map(FeedTarget::getTargetId).collect(Collectors.toUnmodifiableList()); diff --git a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/service/impl/FriendServiceImpl.java b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/service/impl/FriendServiceImpl.java index e1fd7509..8600475f 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/service/impl/FriendServiceImpl.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/service/impl/FriendServiceImpl.java @@ -13,7 +13,7 @@ import com.luohuo.flex.common.constant.DefValConstants; import com.luohuo.flex.im.core.user.service.cache.UserSummaryCache; import com.luohuo.flex.im.domain.dto.SummeryInfoDTO; import com.luohuo.flex.im.domain.enums.ApplyReadStatusEnum; -import com.luohuo.flex.im.domain.enums.ApplyStatusEnum; +import com.luohuo.flex.im.domain.enums.NoticeStatusEnum; import com.luohuo.flex.model.entity.WSRespTypeEnum; import com.luohuo.flex.model.entity.WsBaseResp; import jakarta.annotation.PostConstruct; @@ -137,7 +137,7 @@ public class FriendServiceImpl implements FriendService, InitializingBean { userApply.setType(type); userApply.setRoomId(roomId); userApply.setTargetId(targetId); - userApply.setStatus(ApplyStatusEnum.WAIT_APPROVAL.getCode()); + userApply.setStatus(NoticeStatusEnum.UNTREATED.getStatus()); userApply.setReadStatus(ApplyReadStatusEnum.UNREAD.getCode()); userApply.setApplyFor(true); userApplyDao.save(userApply); diff --git a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/service/impl/NoticeServiceImpl.java b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/service/impl/NoticeServiceImpl.java index f54a006c..b07315a9 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/service/impl/NoticeServiceImpl.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/java/com/luohuo/flex/im/core/user/service/impl/NoticeServiceImpl.java @@ -12,7 +12,7 @@ import com.luohuo.flex.im.domain.entity.Notice; import com.luohuo.flex.im.domain.enums.NoticeStatusEnum; import com.luohuo.flex.im.domain.enums.NoticeTypeEnum; import com.luohuo.flex.im.domain.enums.RoomTypeEnum; -import com.luohuo.flex.im.domain.vo.req.PageBaseReq; +import com.luohuo.flex.im.domain.vo.req.NoticeReq; import com.luohuo.flex.im.domain.vo.res.NoticeVO; import com.luohuo.flex.im.domain.vo.res.PageBaseResp; import com.luohuo.flex.model.entity.WSRespTypeEnum; @@ -89,21 +89,21 @@ public class NoticeServiceImpl implements NoticeService { } } - private void readNotices(Long uid, IPage noticeIPage) { + private void readNotices(Long uid, String applyType, IPage noticeIPage) { List notices = noticeIPage.getRecords() .stream().map(Notice::getId) .collect(Collectors.toList()); if(CollUtil.isNotEmpty(notices)){ - noticeDao.readNotices(uid, notices); + noticeDao.readNotices(uid, "friend".equals(applyType)? 2: 1, notices); } } @Override - public PageBaseResp getUserNotices(Long uid, PageBaseReq request) { + public PageBaseResp getUserNotices(Long uid, NoticeReq request) { IPage noticeIPage = noticeDao.getUserNotices(uid, true, request.plusPage()); // 将这些通知设为已读 if(request.getClick()){ - readNotices(uid, noticeIPage); + readNotices(uid, request.getApplyType(), noticeIPage); } return PageBaseResp.init(noticeIPage, noticeIPage.getRecords().stream().map(notice -> convertToVO(notice)).collect(Collectors.toList())); } diff --git a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/resources/mapper/chat/RoomGroupMapper.xml b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/resources/mapper/chat/RoomGroupMapper.xml index a13d23bf..10f9aadc 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/resources/mapper/chat/RoomGroupMapper.xml +++ b/luohuo-cloud/luohuo-im/luohuo-im-biz/src/main/resources/mapper/chat/RoomGroupMapper.xml @@ -9,6 +9,10 @@ on g.id = m.group_id and g.room_id = #{roomId} and m.uid = #{uid} - limit 1 + where g.is_del = 0 limit 1 + + + diff --git a/luohuo-cloud/luohuo-im/luohuo-im-controller/src/main/java/com/luohuo/flex/im/controller/NoticeController.java b/luohuo-cloud/luohuo-im/luohuo-im-controller/src/main/java/com/luohuo/flex/im/controller/NoticeController.java index 4f479c2f..74073092 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-controller/src/main/java/com/luohuo/flex/im/controller/NoticeController.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-controller/src/main/java/com/luohuo/flex/im/controller/NoticeController.java @@ -4,7 +4,7 @@ import com.luohuo.basic.base.R; import com.luohuo.basic.context.ContextUtil; import com.luohuo.flex.im.core.user.service.NoticeService; import com.luohuo.flex.im.domain.vo.req.NoticeReadReq; -import com.luohuo.flex.im.domain.vo.req.PageBaseReq; +import com.luohuo.flex.im.domain.vo.req.NoticeReq; import com.luohuo.flex.im.domain.vo.res.NoticeVO; import com.luohuo.flex.im.domain.vo.res.PageBaseResp; import com.luohuo.flex.model.entity.ws.WSNotice; @@ -24,7 +24,7 @@ public class NoticeController { private NoticeService noticeService; @GetMapping("/page") - public R> getNotices(@Valid PageBaseReq request) { + public R> getNotices(@Valid NoticeReq request) { Long uid = ContextUtil.getUid(); return R.success(noticeService.getUserNotices(uid, request)); } diff --git a/luohuo-cloud/luohuo-im/luohuo-im-controller/src/main/java/com/luohuo/flex/im/controller/chat/RoomController.java b/luohuo-cloud/luohuo-im/luohuo-im-controller/src/main/java/com/luohuo/flex/im/controller/chat/RoomController.java index 36eeee92..1f29ca00 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-controller/src/main/java/com/luohuo/flex/im/controller/chat/RoomController.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-controller/src/main/java/com/luohuo/flex/im/controller/chat/RoomController.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.luohuo.flex.im.domain.vo.req.IdReqVO; import com.luohuo.flex.im.domain.vo.res.IdRespVO; +import com.luohuo.flex.im.domain.vo.response.GroupResp; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; @@ -47,13 +48,20 @@ public class RoomController { @Resource private RoomAppService roomService; - @GetMapping("/group") + @GetMapping("/group/detail") @Operation(summary ="群组详情") public R groupDetail(@Valid IdReqVO request) { Long uid = ContextUtil.getUid(); return R.success(roomService.getGroupDetail(uid, request.getId())); } + @GetMapping("/group/info") + @Operation(summary ="群组基础信息[没加群的人也可以查]") + public R groupInfo(@Valid IdReqVO request) { + Long uid = ContextUtil.getUid(); + return R.success(roomService.getGroupInfo(uid, request.getId())); + } + @GetMapping("search") @Operation(summary = "查找群聊") public R> searchGroup(@Valid RoomGroupReq req) { diff --git a/luohuo-cloud/luohuo-im/luohuo-im-controller/src/main/java/com/luohuo/flex/im/controller/user/FeedController.java b/luohuo-cloud/luohuo-im/luohuo-im-controller/src/main/java/com/luohuo/flex/im/controller/user/FeedController.java index cfab8d30..6da03da9 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-controller/src/main/java/com/luohuo/flex/im/controller/user/FeedController.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-controller/src/main/java/com/luohuo/flex/im/controller/user/FeedController.java @@ -1,5 +1,6 @@ package com.luohuo.flex.im.controller.user; +import com.luohuo.flex.im.domain.vo.req.feed.FeedReq; import io.swagger.v3.oas.annotations.tags.Tag; import com.luohuo.basic.base.R; import com.luohuo.basic.context.ContextUtil; @@ -16,7 +17,6 @@ import jakarta.validation.Valid; import jakarta.validation.groups.Default; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -45,10 +45,10 @@ public class FeedController { return R.success(feedService.pushFeed(ContextUtil.getUid(), param)); } - @GetMapping("getFeedPermission/{feedId}") + @GetMapping("getFeedPermission") @Operation(summary = "查看朋友圈权限") - public R getFeedPermission(@PathVariable("feedId") Long feedId) { - return R.success(feedService.getFeedPermission(ContextUtil.getUid(), feedId)); + public R getFeedPermission(FeedReq feedReq) { + return R.success(feedService.getFeedPermission(ContextUtil.getUid(), feedReq.getFeedId())); } @PostMapping("edit") @@ -57,15 +57,15 @@ public class FeedController { return R.success(feedService.editFeed(ContextUtil.getUid(), param)); } - @PostMapping("del/{feedId}") + @PostMapping("del") @Operation(summary = "删除朋友圈") - public R delFeed(@PathVariable("feedId") Long feedId) { - return R.success(feedService.delFeed(feedId)); + public R delFeed(@RequestBody FeedReq feedReq) { + return R.success(feedService.delFeed(feedReq.getFeedId())); } - @GetMapping("detail/{feedId}") + @GetMapping("detail") @Operation(summary = "用户查看详情") - public R feedDetail(@PathVariable("feedId") Long feedId) { - return R.success(feedService.feedDetail(feedId)); + public R feedDetail(FeedReq feedReq) { + return R.success(feedService.feedDetail(feedReq.getFeedId())); } } diff --git a/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/entity/UserApply.java b/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/entity/UserApply.java index 0f0eaf0f..353f917d 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/entity/UserApply.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/entity/UserApply.java @@ -3,7 +3,7 @@ package com.luohuo.flex.im.domain.entity; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableField; import com.luohuo.basic.base.entity.Entity; -import com.luohuo.flex.im.domain.enums.ApplyStatusEnum; +import com.luohuo.flex.im.domain.enums.NoticeStatusEnum; import com.luohuo.flex.im.domain.enums.RoomTypeEnum; import lombok.AllArgsConstructor; import lombok.Data; @@ -59,7 +59,7 @@ public class UserApply extends Entity { /** * 申请状态 - * @see ApplyStatusEnum + * @see NoticeStatusEnum */ @TableField("status") private Integer status; diff --git a/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/enums/ApplyStatusEnum.java b/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/enums/ApplyStatusEnum.java deleted file mode 100644 index fe650c99..00000000 --- a/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/enums/ApplyStatusEnum.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.luohuo.flex.im.domain.enums; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -/** - * @author nyh - * 申请状态枚举 - */ -@Getter -@AllArgsConstructor -public enum ApplyStatusEnum { - - WAIT_APPROVAL(1, "待审批"), - - AGREE(2, "同意"), - - REJECT(3, "拒绝"), - - IGNORE(4, "忽略"); - private final Integer code; - - private final String desc; -} diff --git a/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/req/feed/FeedParam.java b/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/req/feed/FeedParam.java index c676061f..bc9b89a7 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/req/feed/FeedParam.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/req/feed/FeedParam.java @@ -7,6 +7,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Size; import lombok.Data; @@ -34,7 +35,7 @@ public class FeedParam extends OperParam { private Integer mediaType; @Schema(description = "发布的图片的url") - private List urls; + private List images; @Schema(description = "发布视频的url") private String videoUrl; @@ -43,7 +44,7 @@ public class FeedParam extends OperParam { * @see FeedPermissionEnum */ @Schema(description = "privacy -> 私密 open -> 公开 partVisible -> 部分可见 notAnyone -> 不给谁看") - @Min(value = 0, message = "请选择正确的可见类型") + @Pattern(regexp = "^(privacy|open|partVisible|notAnyone)$", message = "请选择正确的可见类型(privacy/open/partVisible/notAnyone)") private String permission; @Schema(description = "permission 限制的用户id") diff --git a/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/request/member/ApplyReq.java b/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/request/member/ApplyReq.java index 3af65aae..ecfc1701 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/request/member/ApplyReq.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/request/member/ApplyReq.java @@ -1,5 +1,6 @@ package com.luohuo.flex.im.domain.vo.request.member; +import com.luohuo.flex.im.domain.enums.NoticeStatusEnum; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; @@ -20,7 +21,9 @@ public class ApplyReq { @Schema(description ="邀请的id") private Long applyId; - @NotNull(message = "请选择邀请记录") - @Schema(description ="0 = 拒绝 2 = 同意 3 = 忽略") + /** + * @see NoticeStatusEnum + */ + @NotNull(message = "请选择审批类型") private Integer state; } diff --git a/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/request/member/MemberDelReq.java b/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/request/member/MemberDelReq.java index b3974991..ae4b9761 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/request/member/MemberDelReq.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/request/member/MemberDelReq.java @@ -7,6 +7,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import jakarta.validation.constraints.NotNull; +import java.util.List; /** * 移除群成员 @@ -23,5 +24,5 @@ public class MemberDelReq { @NotNull @Schema(description ="被移除的uid(主动退群填自己)") - private Long uid; + private List uidList; } diff --git a/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/response/AnnouncementsResp.java b/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/response/AnnouncementsResp.java index c3a04a82..f9180ddd 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/response/AnnouncementsResp.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/response/AnnouncementsResp.java @@ -21,9 +21,6 @@ public class AnnouncementsResp implements Serializable { @Schema(description = "公告发布人id") private Long uid; - @Schema(description = "公告发布人") - private String uName; - @Schema(description = "发布内容") private String content; diff --git a/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/response/ChatMemberListResp.java b/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/response/ChatMemberListResp.java index 05ce944f..4f931c2c 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/response/ChatMemberListResp.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/response/ChatMemberListResp.java @@ -6,6 +6,8 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import java.io.Serializable; + /** * 群成员列表的成员信息 * @author nyh @@ -14,7 +16,7 @@ import lombok.NoArgsConstructor; @Builder @AllArgsConstructor @NoArgsConstructor -public class ChatMemberListResp { +public class ChatMemberListResp implements Serializable { @Schema(description ="uid") private Long uid; @Schema(description ="用户名称") diff --git a/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/response/ChatMessageReadResp.java b/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/response/ChatMessageReadResp.java index b1a650ce..d85ac5c5 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/response/ChatMessageReadResp.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/response/ChatMessageReadResp.java @@ -6,6 +6,8 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import java.io.Serializable; + /** * @author nyh */ @@ -13,7 +15,7 @@ import lombok.NoArgsConstructor; @Builder @AllArgsConstructor @NoArgsConstructor -public class ChatMessageReadResp { +public class ChatMessageReadResp implements Serializable { @Schema(description ="已读或者未读的用户uid") private Long uid; } diff --git a/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/response/ChatRoomResp.java b/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/response/ChatRoomResp.java index c0249ddf..9ebd70c5 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/response/ChatRoomResp.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/response/ChatRoomResp.java @@ -6,6 +6,7 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import java.io.Serializable; import java.time.LocalDateTime; /** @@ -16,7 +17,7 @@ import java.time.LocalDateTime; @Builder @AllArgsConstructor @NoArgsConstructor -public class ChatRoomResp { +public class ChatRoomResp implements Serializable { @Schema(description ="会话id") private Long id; @Schema(description ="单聊时对方的id,群聊是groupId") diff --git a/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/response/MemberResp.java b/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/response/MemberResp.java index 67a6a376..c47aacef 100644 --- a/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/response/MemberResp.java +++ b/luohuo-cloud/luohuo-im/luohuo-im-entity/src/main/java/com/luohuo/flex/im/domain/vo/response/MemberResp.java @@ -6,6 +6,8 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import java.io.Serializable; + /** * @author nyh */ @@ -13,7 +15,7 @@ import lombok.NoArgsConstructor; @Builder @AllArgsConstructor @NoArgsConstructor -public class MemberResp { +public class MemberResp implements Serializable { @Schema(description ="群聊id") private Long groupId; @Schema(description ="房间id") diff --git a/luohuo-cloud/luohuo-oauth/luohuo-oauth-biz/src/main/java/com/luohuo/flex/oauth/service/impl/CaptchaServiceImpl.java b/luohuo-cloud/luohuo-oauth/luohuo-oauth-biz/src/main/java/com/luohuo/flex/oauth/service/impl/CaptchaServiceImpl.java index 6cc9a8d7..2fff614d 100644 --- a/luohuo-cloud/luohuo-oauth/luohuo-oauth-biz/src/main/java/com/luohuo/flex/oauth/service/impl/CaptchaServiceImpl.java +++ b/luohuo-cloud/luohuo-oauth/luohuo-oauth-biz/src/main/java/com/luohuo/flex/oauth/service/impl/CaptchaServiceImpl.java @@ -145,7 +145,7 @@ public class CaptchaServiceImpl implements CaptchaService { String code = RandomUtil.randomNumbers(6); CacheKey cacheKey = CaptchaCacheKeyBuilder.build(bindEmailReq.getEmail(), bindEmailReq.getTemplateCode()); if(cachePlusOps.exists(cacheKey)){ - return R.success(cachePlusOps.ttl(cacheKey)); + ArgumentAssert.isFalse(true, "验证码还剩"+cachePlusOps.ttl(cacheKey)+"秒过期,可以继续使用"); } cachePlusOps.set(cacheKey, code); diff --git a/luohuo-cloud/luohuo-public/luohuo-common/src/main/java/com/luohuo/flex/common/constant/DefValConstants.java b/luohuo-cloud/luohuo-public/luohuo-common/src/main/java/com/luohuo/flex/common/constant/DefValConstants.java index 8bf85b86..65ecff59 100644 --- a/luohuo-cloud/luohuo-public/luohuo-common/src/main/java/com/luohuo/flex/common/constant/DefValConstants.java +++ b/luohuo-cloud/luohuo-public/luohuo-common/src/main/java/com/luohuo/flex/common/constant/DefValConstants.java @@ -17,6 +17,8 @@ public interface DefValConstants { Long DEF_ROOM_ID = 1L; /** 内置的群组id */ Long DEF_GROUP_ID = 1L; + /** 贡献者id */ + Long CONTRIBUTOR_ID = 6L; /** * 默认的树节点 分隔符 */ diff --git a/luohuo-cloud/luohuo-ws/luohuo-ws-biz/src/main/java/com/luohuo/flex/ws/websocket/SessionManager.java b/luohuo-cloud/luohuo-ws/luohuo-ws-biz/src/main/java/com/luohuo/flex/ws/websocket/SessionManager.java index a664f9b7..1a79ba41 100644 --- a/luohuo-cloud/luohuo-ws/luohuo-ws-biz/src/main/java/com/luohuo/flex/ws/websocket/SessionManager.java +++ b/luohuo-cloud/luohuo-ws/luohuo-ws-biz/src/main/java/com/luohuo/flex/ws/websocket/SessionManager.java @@ -365,8 +365,10 @@ public class SessionManager { * 清空所有会话 */ public void clean() { - // 1. 标记服务不可用状态 + // 0. 标记服务不可用状态 setAcceptingNewConnections(false); + nacosSessionRegistry.deregisterNode(); + // 1. 收集所有设备信息 Map> offlineDevices = new HashMap<>(); USER_DEVICE_SESSION_MAP.forEach((uid, deviceMap) -> offlineDevices.put(uid, new HashSet<>(deviceMap.keySet()))); @@ -397,8 +399,7 @@ public class SessionManager { USER_DEVICE_SESSION_MAP.clear(); // 6. 清理路由与节点 - nacosSessionRegistry.cleanupNodeRoutes(); - nacosSessionRegistry.deregisterNode(); + nacosSessionRegistry.cleanupNodeRoutes(""); } /** diff --git a/luohuo-cloud/luohuo-ws/luohuo-ws-biz/src/main/java/com/luohuo/flex/ws/websocket/nacos/NacosSessionRegistry.java b/luohuo-cloud/luohuo-ws/luohuo-ws-biz/src/main/java/com/luohuo/flex/ws/websocket/nacos/NacosSessionRegistry.java index c4839df0..2308faa5 100644 --- a/luohuo-cloud/luohuo-ws/luohuo-ws-biz/src/main/java/com/luohuo/flex/ws/websocket/nacos/NacosSessionRegistry.java +++ b/luohuo-cloud/luohuo-ws/luohuo-ws-biz/src/main/java/com/luohuo/flex/ws/websocket/nacos/NacosSessionRegistry.java @@ -1,5 +1,6 @@ package com.luohuo.flex.ws.websocket.nacos; +import cn.hutool.core.util.StrUtil; import com.alibaba.cloud.nacos.NacosDiscoveryProperties; import com.alibaba.cloud.nacos.NacosServiceManager; import com.alibaba.nacos.api.exception.NacosException; @@ -9,6 +10,7 @@ import com.alibaba.nacos.client.naming.utils.CollectionUtils; import com.luohuo.basic.cache.repository.CachePlusOps; import com.luohuo.basic.model.cache.CacheHashKey; import com.luohuo.basic.model.cache.CacheKey; +import com.luohuo.flex.common.cache.PresenceCacheKeyBuilder; import com.luohuo.flex.router.RouterCacheKeyBuilder; import com.luohuo.flex.ws.websocket.SessionManager; import jakarta.annotation.PostConstruct; @@ -17,17 +19,24 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Lazy; +import org.springframework.data.redis.core.Cursor; +import org.springframework.data.redis.core.RedisOperations; import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.ScanOptions; +import org.springframework.data.redis.core.SessionCallback; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import java.net.InetAddress; import java.time.Instant; +import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; /** * Nacos会话注册中心 @@ -156,9 +165,10 @@ public class NacosSessionRegistry { /** * 清理节点在Redis中的所有路由信息 */ - public void cleanupNodeRoutes() { + public void cleanupNodeRoutes(String cleanNodeId) { + cleanNodeId = StrUtil.isEmpty(cleanNodeId) ? nodeId : cleanNodeId; // 1. 清理节点→设备映射 - CacheKey cacheKey = RouterCacheKeyBuilder.buildNodeDevices(nodeId); + CacheKey cacheKey = RouterCacheKeyBuilder.buildNodeDevices(cleanNodeId); Set deviceFields = redisTemplate.opsForSet().members(cacheKey.getKey()); if (!CollectionUtils.isEmpty(deviceFields)) { @@ -169,7 +179,7 @@ public class NacosSessionRegistry { // 清理节点本地映射 redisTemplate.delete(cacheKey.getKey()); } - log.info("节点路由清理完成: nodeId={}, 清理设备数={}", nodeId, deviceFields != null ? deviceFields.size() : 0); + log.info("节点路由清理完成: nodeId={}, 清理设备数={}", cleanNodeId, deviceFields != null ? deviceFields.size() : 0); } public void deregisterNode() { @@ -202,4 +212,92 @@ public class NacosSessionRegistry { log.error("心跳更新失败", e); } } + + public Set getAllActiveNodeIds() { + try { + List instances = namingService.getAllInstances("ws-cluster", "WS_GROUP"); + return instances.stream() + .filter(Instance::isHealthy) + .map(instance -> instance.getMetadata().get("nodeId")) + .collect(Collectors.toSet()); + } catch (NacosException e) { + log.error("获取活跃节点失败", e); + return Collections.emptySet(); + } + } + + public Set getAllRedisNodeIds() { + // 1. 获取基础key模式 + String baseKey = RouterCacheKeyBuilder.buildNodeDevices("").getKey(); + String pattern = baseKey + "*"; + + // 2. 使用SCAN命令安全遍历 + ScanOptions options = ScanOptions.scanOptions() + .match(pattern) + .count(100) + .build(); + + Set nodeIds = new HashSet<>(); + try (Cursor cursor = redisTemplate.scan(options)) { + while (cursor.hasNext()) { + String key = cursor.next(); + // 3. 提取纯节点ID + if(key.startsWith(baseKey)) { + String[] parts = key.split(":"); + nodeIds.add(parts[parts.length - 1]); + } + } + } + return nodeIds; + } + + @Scheduled(fixedDelay = 30000) + public void cleanStaleRoutes() { + // 1. 获取所有需要对比的ID集合 + Set activeNodes = getAllActiveNodeIds(); + Set redisNodes = getAllRedisNodeIds(); + + // 2. 计算需要清理的节点ID + Set staleNodes = redisNodes.stream() + .filter(node -> !activeNodes.contains(node)) + .collect(Collectors.toSet()); + + // 3. 批量清理 + staleNodes.forEach(node -> { + log.info("发现残留节点数据,开始清理: {}", node); + try { + cleanupNodeRoutes(node); + cleanNodeCompletely(node); + } catch (Exception e) { + log.error("节点清理失败: {}", node, e); + } + }); + } + + private void cleanNodeCompletely(String nodeId) { + // 1. 获取节点所有设备 + CacheKey nodeDevicesKey = RouterCacheKeyBuilder.buildNodeDevices(nodeId); + Set deviceFields = redisTemplate.opsForSet() + .members(nodeDevicesKey.getKey()) + .stream() + .map(Object::toString) + .collect(Collectors.toSet()); + + if (CollectionUtils.isEmpty(deviceFields)) { + return; + } + + // 2. 准备在线状态清理数据 + Map> uidToClients = deviceFields.stream() + .map(field -> field.split(":")) + .filter(parts -> parts.length == 2) + .collect(Collectors.groupingBy( + parts -> Long.parseLong(parts[0]), + Collectors.mapping(parts -> parts[1], Collectors.toSet()) + )); + + // 3. 执行原子化清理 + uidToClients.forEach((uid, clients) -> clients.forEach(client -> sessionManager.syncOnline(uid, client, false))); + log.info("节点完全清理完成: node={}, 设备数={}", nodeId, deviceFields.size()); + } } \ No newline at end of file