diff --git a/urbanLifelineServ/.bin/database/postgres/sql/createTableAI.sql b/urbanLifelineServ/.bin/database/postgres/sql/createTableAI.sql
index 845e53e5..6e5c68a0 100644
--- a/urbanLifelineServ/.bin/database/postgres/sql/createTableAI.sql
+++ b/urbanLifelineServ/.bin/database/postgres/sql/createTableAI.sql
@@ -9,6 +9,7 @@ CREATE TABLE ai.tb_agent(
description VARCHAR(500) DEFAULT NULL, -- 智能体描述
link VARCHAR(500) DEFAULT NULL, -- 智能体url
api_key VARCHAR(500) NOT NULL, -- dify智能体APIKEY
+ outer BOOLEAN DEFAULT false, -- 是否是对外智能体,未登录可用
introduce VARCHAR(500) NOT NULL, -- 引导词
prompt_cards JSONB DEFAULT '[]'::jsonb, -- 提示卡片数组 [{file_id:'', prompt:''}]
category VARCHAR(50) NOT NULL, -- 分类
@@ -45,8 +46,9 @@ DROP TABLE IF EXISTS ai.tb_chat_message CASCADE;
CREATE TABLE ai.tb_chat_message(
optsn VARCHAR(50) NOT NULL, -- 流水号
message_id VARCHAR(50) NOT NULL, -- 消息ID
+ dify_message_id VARCHAR(100) DEFAULT NULL, -- Dify消息ID
chat_id VARCHAR(50) NOT NULL, -- 对话ID
- role VARCHAR(50) NOT NULL, -- 角色:user-用户/assistant-智能体/recipient-来客
+ role VARCHAR(50) NOT NULL, -- 角色:user-用户/ai-智能体/recipient-来客
content TEXT NOT NULL, -- 消息内容
files VARCHAR(50)[] DEFAULT NULL, -- 文件id数组
comment VARCHAR(50) DEFAULT NULL, -- 评价
@@ -144,7 +146,7 @@ CREATE TABLE ai.tb_knowledge_file(
file_root_id VARCHAR(50) NOT NULL, -- 文件根ID
file_id VARCHAR(50) NOT NULL, -- 文件ID
dify_file_id VARCHAR(50) NOT NULL, -- dify文件ID
- version VARCHAR(50) NOT NULL, -- 文件版本
+ version INTEGER NOT NULL DEFAULT 1, -- 文件版本
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
diff --git a/urbanLifelineServ/.bin/database/postgres/sql/createTableBidding.sql b/urbanLifelineServ/.bin/database/postgres/sql/createTableBidding.sql
index 533724a0..4818df60 100644
--- a/urbanLifelineServ/.bin/database/postgres/sql/createTableBidding.sql
+++ b/urbanLifelineServ/.bin/database/postgres/sql/createTableBidding.sql
@@ -64,7 +64,7 @@ CREATE TABLE bidding.tb_bidding_document (
file_path VARCHAR(500), -- 文件路径
file_size BIGINT, -- 文件大小
mime_type VARCHAR(100), -- MIME类型
- version VARCHAR(20) DEFAULT '1.0', -- 版本号
+ version INTEGER DEFAULT 1, -- 版本号
language VARCHAR(20) DEFAULT 'zh-CN', -- 语言
page_count INTEGER, -- 页数
parse_status VARCHAR(30) DEFAULT 'pending', -- 解析状态:pending-待解析/parsing-解析中/completed-已完成/failed-失败
@@ -145,7 +145,7 @@ CREATE TABLE bidding.tb_bid_response (
generation_status VARCHAR(30) DEFAULT 'draft', -- 生成状态:draft-草稿/reviewing-审核中/approved-已批准/rejected-已拒绝/submitted-已提交
file_id VARCHAR(50), -- 生成的文件ID
file_path VARCHAR(500), -- 文件路径
- version VARCHAR(20) DEFAULT '1.0', -- 版本号
+ version INTEGER DEFAULT 1, -- 版本号
parent_version_id VARCHAR(50), -- 父版本ID
review_comments TEXT, -- 审核意见
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
diff --git a/urbanLifelineServ/.bin/database/postgres/sql/createTableFile.sql b/urbanLifelineServ/.bin/database/postgres/sql/createTableFile.sql
index b1bc95ac..28d46ebb 100644
--- a/urbanLifelineServ/.bin/database/postgres/sql/createTableFile.sql
+++ b/urbanLifelineServ/.bin/database/postgres/sql/createTableFile.sql
@@ -16,7 +16,7 @@ CREATE TABLE file.tb_sys_file (
-- TbSysFileDTO 特有字段
file_id VARCHAR(50) NOT NULL, -- 文件ID (主键)
file_root_id VARCHAR(50) DEFAULT NULL, -- 文件根ID
- version VARCHAR(50) DEFAULT NULL, -- 文件版本
+ version INTEGER DEFAULT 1, -- 文件版本
name VARCHAR(255) NOT NULL, -- 文件名
path VARCHAR(500) NOT NULL, -- 文件路径
size BIGINT NOT NULL, -- 文件大小(字节)
diff --git a/urbanLifelineServ/.bin/database/postgres/sql/createTableWorkcase.sql b/urbanLifelineServ/.bin/database/postgres/sql/createTableWorkcase.sql
index 4ccdb093..6c7c7de8 100644
--- a/urbanLifelineServ/.bin/database/postgres/sql/createTableWorkcase.sql
+++ b/urbanLifelineServ/.bin/database/postgres/sql/createTableWorkcase.sql
@@ -1,15 +1,16 @@
CREATE SCHEMA IF NOT EXISTS workcase;
-- 系统外部人员(来客)管理 用于给系统外人员创建id
-DROP TABLE IF EXISTS workcase.tb_receptionist CASCADE;
-CREATE TABLE workcase.tb_receptionist(
+DROP TABLE IF EXISTS sys.tb_guest CASCADE;
+CREATE TABLE sys.tb_guest(
optsn VARCHAR(50) NOT NULL, -- 流水号
user_id VARCHAR(50) NOT NULL, -- 来客ID
name VARCHAR(50) NOT NULL, -- 姓名
- phone VARCHAR(50) NOT NULL, -- 电话
- email VARCHAR(50) NOT NULL, -- 邮箱
- wechat_id VARCHAR(50) NOT NULL, -- 微信号
+ phone VARCHAR(50) DEFAULT NULL, -- 电话
+ email VARCHAR(50) DEFAULT NULL, -- 邮箱
+ wechat_id VARCHAR(50) DEFAULT NULL, -- 微信号
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
+ update_time TIMESTAMPTZ DEFAULT NULL, -- 创建时间
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
PRIMARY KEY (user_id),
diff --git a/urbanLifelineServ/.bin/database/postgres/sql/initDataPermission.sql b/urbanLifelineServ/.bin/database/postgres/sql/initDataPermission.sql
index bb8f42f0..3c17047f 100644
--- a/urbanLifelineServ/.bin/database/postgres/sql/initDataPermission.sql
+++ b/urbanLifelineServ/.bin/database/postgres/sql/initDataPermission.sql
@@ -38,158 +38,107 @@ INSERT INTO sys.tb_sys_role (
-- 3. 初始化系统模块
-- =============================
INSERT INTO sys.tb_sys_module (
- optsn, module_id, name, description,
- creator, dept_path, create_time, deleted
+ optsn, module_id, name, description, creator, dept_path, create_time, deleted
) VALUES
-('MODULE-0001', 'module_system', '系统管理', '用户、角色、权限、部门管理',
- 'system', NULL, now(), false),
-
-('MODULE-0002', 'module_file', '文件管理', '文件上传、下载、关联管理',
- 'system', NULL, now(), false),
-
-('MODULE-0003', 'module_message', '消息通知', '消息发送、接收、模板管理',
- 'system', NULL, now(), false),
-
-('MODULE-0004', 'module_config', '配置管理', '系统配置参数管理',
- 'system', NULL, now(), false),
-
-('MODULE-0005', 'module_knowledge', '知识库', '知识文档管理',
- 'system', NULL, now(), false),
-
-('MODULE-0006', 'module_bidding', '招投标', '招投标业务管理',
- 'system', NULL, now(), false),
-
-('MODULE-0007', 'module_workcase', '智能客服', '客服工单管理',
- 'system', NULL, now(), false);
+('MODULE-0001', 'module_system', '系统管理', '用户、角色、权限、部门管理', 'system', NULL, now(), false),
+('MODULE-0002', 'module_file', '文件管理', '文件上传、下载、关联管理', 'system', NULL, now(), false),
+('MODULE-0003', 'module_message', '消息通知', '消息发送、接收、模板管理', 'system', NULL, now(), false),
+('MODULE-0004', 'module_config', '配置管理', '系统配置参数管理', 'system', NULL, now(), false),
+('MODULE-0008', 'module_agent', '智能体', '智能体管理', 'system', NULL, now(), false),
+('MODULE-0005', 'module_knowledge', '知识库', '知识文档管理', 'system', NULL, now(), false),
+('MODULE-0006', 'module_bidding', '招投标', '招投标业务管理', 'system', NULL, now(), false),
+('MODULE-0007', 'module_workcase', '智能客服', '客服工单管理', 'system', NULL, now(), false);
-- =============================
-- 4. 初始化系统权限
-- =============================
INSERT INTO sys.tb_sys_permission (
- optsn, permission_id, name, code, description, module_id,
- status, creator, dept_path, create_time, deleted
+ optsn, permission_id, name, code, description, module_id, status, creator, dept_path, create_time, deleted
) VALUES
-- 系统管理模块权限
-('PERM-0001', 'perm_user_view', '用户查看', 'system:user:view', '查看用户列表和详情', 'module_system',
- true, 'system', NULL, now(), false),
-('PERM-0002', 'perm_user_create', '用户创建', 'system:user:create', '创建新用户', 'module_system',
- true, 'system', NULL, now(), false),
-('PERM-0003', 'perm_user_edit', '用户编辑', 'system:user:edit', '编辑用户信息', 'module_system',
- true, 'system', NULL, now(), false),
-('PERM-0004', 'perm_user_delete', '用户删除', 'system:user:delete', '删除用户', 'module_system',
- true, 'system', NULL, now(), false),
-
-('PERM-0011', 'perm_role_view', '角色查看', 'system:role:view', '查看角色列表和详情', 'module_system',
- true, 'system', NULL, now(), false),
-('PERM-0012', 'perm_role_create', '角色创建', 'system:role:create', '创建新角色', 'module_system',
- true, 'system', NULL, now(), false),
-('PERM-0013', 'perm_role_edit', '角色编辑', 'system:role:edit', '编辑角色信息', 'module_system',
- true, 'system', NULL, now(), false),
-('PERM-0014', 'perm_role_delete', '角色删除', 'system:role:delete', '删除角色', 'module_system',
- true, 'system', NULL, now(), false),
-
-('PERM-0021', 'perm_dept_view', '部门查看', 'system:dept:view', '查看部门列表和详情', 'module_system',
- true, 'system', NULL, now(), false),
-('PERM-0022', 'perm_dept_create', '部门创建', 'system:dept:create', '创建新部门', 'module_system',
- true, 'system', NULL, now(), false),
-('PERM-0023', 'perm_dept_edit', '部门编辑', 'system:dept:edit', '编辑部门信息', 'module_system',
- true, 'system', NULL, now(), false),
-('PERM-0024', 'perm_dept_delete', '部门删除', 'system:dept:delete', '删除部门', 'module_system',
- true, 'system', NULL, now(), false),
-
-('PERM-0031', 'perm_permission_view', '权限查看', 'system:permission:view', '查看权限列表', 'module_system',
- true, 'system', NULL, now(), false),
-('PERM-0032', 'perm_permission_manage', '权限管理', 'system:permission:manage', '管理权限配置', 'module_system',
- true, 'system', NULL, now(), false),
+('PERM-0001', 'perm_user_view', '用户查看', 'system:user:view', '查看用户列表和详情', 'module_system', true, 'system', NULL, now(), false),
+('PERM-0002', 'perm_user_create', '用户创建', 'system:user:create', '创建新用户', 'module_system', true, 'system', NULL, now(), false),
+('PERM-0003', 'perm_user_edit', '用户编辑', 'system:user:edit', '编辑用户信息', 'module_system', true, 'system', NULL, now(), false),
+('PERM-0004', 'perm_user_delete', '用户删除', 'system:user:delete', '删除用户', 'module_system', true, 'system', NULL, now(), false),
+('PERM-0011', 'perm_role_view', '角色查看', 'system:role:view', '查看角色列表和详情', 'module_system', true, 'system', NULL, now(), false),
+('PERM-0012', 'perm_role_create', '角色创建', 'system:role:create', '创建新角色', 'module_system', true, 'system', NULL, now(), false),
+('PERM-0013', 'perm_role_edit', '角色编辑', 'system:role:edit', '编辑角色信息', 'module_system', true, 'system', NULL, now(), false),
+('PERM-0014', 'perm_role_delete', '角色删除', 'system:role:delete', '删除角色', 'module_system', true, 'system', NULL, now(), false),
+('PERM-0021', 'perm_dept_view', '部门查看', 'system:dept:view', '查看部门列表和详情', 'module_system', true, 'system', NULL, now(), false),
+('PERM-0022', 'perm_dept_create', '部门创建', 'system:dept:create', '创建新部门', 'module_system', true, 'system', NULL, now(), false),
+('PERM-0023', 'perm_dept_edit', '部门编辑', 'system:dept:edit', '编辑部门信息', 'module_system', true, 'system', NULL, now(), false),
+('PERM-0024', 'perm_dept_delete', '部门删除', 'system:dept:delete', '删除部门', 'module_system', true, 'system', NULL, now(), false),
+('PERM-0031', 'perm_permission_view', '权限查看', 'system:permission:view', '查看权限列表', 'module_system', true, 'system', NULL, now(), false),
+('PERM-0032', 'perm_permission_manage', '权限管理', 'system:permission:manage', '管理权限配置', 'module_system', true, 'system', NULL, now(), false),
-- 系统管理模块导出权限
-('PERM-0041', 'perm_user_export', '用户导出', 'system:user:export', '导出用户数据', 'module_system',
- true, 'system', NULL, now(), false),
-('PERM-0042', 'perm_role_export', '角色导出', 'system:role:export', '导出角色数据', 'module_system',
- true, 'system', NULL, now(), false),
-('PERM-0043', 'perm_dept_export', '部门导出', 'system:dept:export', '导出部门数据', 'module_system',
- true, 'system', NULL, now(), false),
+('PERM-0041', 'perm_user_export', '用户导出', 'system:user:export', '导出用户数据', 'module_system', true, 'system', NULL, now(), false),
+('PERM-0042', 'perm_role_export', '角色导出', 'system:role:export', '导出角色数据', 'module_system', true, 'system', NULL, now(), false),
+('PERM-0043', 'perm_dept_export', '部门导出', 'system:dept:export', '导出部门数据', 'module_system', true, 'system', NULL, now(), false),
-- 文件管理模块权限
-('PERM-0101', 'perm_file_view', '文件查看', 'file:file:view', '查看文件列表', 'module_file',
- true, 'system', NULL, now(), false),
-('PERM-0102', 'perm_file_upload', '文件上传', 'file:file:upload', '上传文件', 'module_file',
- true, 'system', NULL, now(), false),
-('PERM-0103', 'perm_file_download', '文件下载', 'file:file:download', '下载文件', 'module_file',
- true, 'system', NULL, now(), false),
-('PERM-0104', 'perm_file_delete', '文件删除', 'file:file:delete', '删除文件', 'module_file',
- true, 'system', NULL, now(), false),
-('PERM-0105', 'perm_file_export', '文件导出', 'file:file:export', '导出文件列表数据', 'module_file',
- true, 'system', NULL, now(), false),
+('PERM-0101', 'perm_file_view', '文件查看', 'file:file:view', '查看文件列表', 'module_file', true, 'system', NULL, now(), false),
+('PERM-0102', 'perm_file_upload', '文件上传', 'file:file:upload', '上传文件', 'module_file', true, 'system', NULL, now(), false),
+('PERM-0103', 'perm_file_download', '文件下载', 'file:file:download', '下载文件', 'module_file', true, 'system', NULL, now(), false),
+('PERM-0104', 'perm_file_delete', '文件删除', 'file:file:delete', '删除文件', 'module_file', true, 'system', NULL, now(), false),
+('PERM-0105', 'perm_file_export', '文件导出', 'file:file:export', '导出文件列表数据', 'module_file', true, 'system', NULL, now(), false),
+-- 智能体权限
+('PERM-0120', 'perm_ai_create', '智能体创建', 'ai:agent:create', '创建智能体', 'module_agent', true, 'system', NULL, now(), false),
+('PERM-0121', 'perm_ai_update', '智能体更新', 'ai:agent:update', '更新智能体', 'module_agent', true, 'system', NULL, now(), false),
+('PERM-0122', 'perm_ai_delete', '智能体删除', 'ai:agent:delete', '删除智能体', 'module_agent', true, 'system', NULL, now(), false),
+('PERM-0123', 'perm_ai_view', '智能体查询', 'ai:agent:view', '查询智能体', 'module_agent', true, 'system', NULL, now(), false),
+-- 智能体对话权限 没有,因为所有人都可以
+-- Dify代理功能权限(知识库分段管理)
+('PERM-0130', 'perm_dify_segment_view', '分段查看', 'ai:dify:segment:view', '查看文档分段列表', 'module_knowledge', true, 'system', NULL, now(), false),
+('PERM-0131', 'perm_dify_segment_create', '分段创建', 'ai:dify:segment:create', '创建文档分段', 'module_knowledge', true, 'system', NULL, now(), false),
+('PERM-0132', 'perm_dify_segment_update', '分段更新', 'ai:dify:segment:update', '更新文档分段', 'module_knowledge', true, 'system', NULL, now(), false),
+('PERM-0133', 'perm_dify_segment_delete', '分段删除', 'ai:dify:segment:delete', '删除文档分段', 'module_knowledge', true, 'system', NULL, now(), false),
+('PERM-0134', 'perm_dify_document_status', '文档状态管理', 'ai:dify:document:status', '更新文档状态(启用/禁用/归档)', 'module_knowledge', true, 'system', NULL, now(), false),
+-- 知识库管理权限
+('PERM-0140', 'perm_knowledge_create', '知识库创建', 'ai:knowledge:create', '创建知识库', 'module_knowledge', true, 'system', NULL, now(), false),
+('PERM-0141', 'perm_knowledge_update', '知识库更新', 'ai:knowledge:update', '更新知识库', 'module_knowledge', true, 'system', NULL, now(), false),
+('PERM-0142', 'perm_knowledge_delete', '知识库删除', 'ai:knowledge:delete', '删除知识库', 'module_knowledge', true, 'system', NULL, now(), false),
+('PERM-0143', 'perm_knowledge_view', '知识库查看', 'ai:knowledge:view', '查看知识库列表和详情', 'module_knowledge', true, 'system', NULL, now(), false),
+-- 知识库文件管理权限
+('PERM-0150', 'perm_knowledge_file_upload', '知识库文件上传', 'ai:knowledge:file:upload', '上传文件到知识库', 'module_knowledge', true, 'system', NULL, now(), false),
+('PERM-0151', 'perm_knowledge_file_update', '知识库文件更新', 'ai:knowledge:file:update', '更新知识库文件信息', 'module_knowledge', true, 'system', NULL, now(), false),
+('PERM-0152', 'perm_knowledge_file_delete', '知识库文件删除', 'ai:knowledge:file:delete', '删除知识库文件', 'module_knowledge', true, 'system', NULL, now(), false),
+('PERM-0153', 'perm_knowledge_file_view', '知识库文件查看', 'ai:knowledge:file:view', '查看知识库文件历史', 'module_knowledge', true, 'system', NULL, now(), false),
-- 消息通知模块权限
-('PERM-0201', 'perm_message_view', '消息查看', 'message:message:view', '查看消息列表', 'module_message',
- true, 'system', NULL, now(), false),
-('PERM-0202', 'perm_message_send', '消息发送', 'message:message:send', '发送消息通知', 'module_message',
- true, 'system', NULL, now(), false),
-('PERM-0203', 'perm_message_manage', '消息管理', 'message:message:manage', '管理消息模板和配置', 'module_message',
- true, 'system', NULL, now(), false),
-('PERM-0204', 'perm_message_export', '消息导出', 'message:message:export', '导出消息数据', 'module_message',
- true, 'system', NULL, now(), false),
-
+('PERM-0201', 'perm_message_view', '消息查看', 'message:message:view', '查看消息列表', 'module_message', true, 'system', NULL, now(), false),
+('PERM-0202', 'perm_message_send', '消息发送', 'message:message:send', '发送消息通知', 'module_message', true, 'system', NULL, now(), false),
+('PERM-0203', 'perm_message_manage', '消息管理', 'message:message:manage', '管理消息模板和配置', 'module_message', true, 'system', NULL, now(), false),
+('PERM-0204', 'perm_message_export', '消息导出', 'message:message:export', '导出消息数据', 'module_message', true, 'system', NULL, now(), false),
-- 配置管理模块权限
-('PERM-0301', 'perm_config_view', '配置查看', 'config:config:view', '查看系统配置', 'module_config',
- true, 'system', NULL, now(), false),
-('PERM-0302', 'perm_config_edit', '配置编辑', 'config:config:edit', '修改系统配置', 'module_config',
- true, 'system', NULL, now(), false),
-('PERM-0303', 'perm_config_export', '配置导出', 'config:config:export', '导出系统配置数据', 'module_config',
- true, 'system', NULL, now(), false),
-
+('PERM-0301', 'perm_config_view', '配置查看', 'config:config:view', '查看系统配置', 'module_config', true, 'system', NULL, now(), false),
+('PERM-0302', 'perm_config_edit', '配置编辑', 'config:config:edit', '修改系统配置', 'module_config', true, 'system', NULL, now(), false),
+('PERM-0303', 'perm_config_export', '配置导出', 'config:config:export', '导出系统配置数据', 'module_config', true, 'system', NULL, now(), false),
-- 日志模块权限
-('PERM-0401', 'perm_log_view', '日志查看', 'log:log:view', '查看系统日志', 'module_system',
- true, 'system', NULL, now(), false),
-('PERM-0402', 'perm_log_export', '日志导出', 'log:log:export', '导出系统日志数据', 'module_system',
- true, 'system', NULL, now(), false),
-
+('PERM-0401', 'perm_log_view', '日志查看', 'log:log:view', '查看系统日志', 'module_system', true, 'system', NULL, now(), false),
+('PERM-0402', 'perm_log_export', '日志导出', 'log:log:export', '导出系统日志数据', 'module_system', true, 'system', NULL, now(), false),
-- 平台基础菜单访问权限(所有登录用户都有)
-('PERM-0501', 'perm_platform_home', '工作台访问', 'platform:home:view', '访问平台工作台', 'module_system',
- true, 'system', NULL, now(), false),
-('PERM-0502', 'perm_platform_chat', 'AI助手访问', 'platform:chat:view', '访问AI助手', 'module_system',
- true, 'system', NULL, now(), false),
-('PERM-0503', 'perm_platform_bidding', '招标助手访问', 'platform:bidding:view', '访问招标助手(iframe)', 'module_bidding',
- true, 'system', NULL, now(), false),
-('PERM-0504', 'perm_platform_workcase', '泰豪小电访问', 'platform:workcase:view', '访问泰豪小电客服(iframe)', 'module_workcase',
- true, 'system', NULL, now(), false),
-('PERM-0505', 'perm_platform_workflow', '智能体编排访问', 'platform:workflow:view', '访问智能体编排(iframe)', 'module_system',
- true, 'system', NULL, now(), false),
-
+('PERM-0501', 'perm_platform_home', '工作台访问', 'platform:home:view', '访问平台工作台', 'module_system', true, 'system', NULL, now(), false),
+('PERM-0502', 'perm_platform_chat', 'AI助手访问', 'platform:chat:view', '访问AI助手', 'module_system', true, 'system', NULL, now(), false),
+('PERM-0503', 'perm_platform_bidding', '招标助手访问', 'platform:bidding:view', '访问招标助手(iframe)', 'module_bidding', true, 'system', NULL, now(), false),
+('PERM-0504', 'perm_platform_workcase', '泰豪小电访问', 'platform:workcase:view', '访问泰豪小电客服(iframe)', 'module_workcase', true, 'system', NULL, now(), false),
+('PERM-0505', 'perm_platform_workflow', '智能体编排访问', 'platform:workflow:view', '访问智能体编排(iframe)', 'module_system', true, 'system', NULL, now(), false),
-- Platform 管理后台功能权限
-('PERM-0601', 'perm_platform_admin', '平台管理后台', 'platform:admin:view', '访问平台管理后台', 'module_system',
- true, 'system', NULL, now(), false),
-('PERM-0602', 'perm_platform_admin_overview', '平台数据概览', 'platform:admin:overview', '访问平台数据概览', 'module_system',
- true, 'system', NULL, now(), false),
-('PERM-0603', 'perm_platform_admin_user', '平台用户管理', 'platform:admin:user', '访问平台用户管理', 'module_system',
- true, 'system', NULL, now(), false),
-('PERM-0604', 'perm_platform_admin_knowledge', '平台知识库', 'platform:admin:knowledge', '访问平台知识库', 'module_knowledge',
- true, 'system', NULL, now(), false),
-('PERM-0605', 'perm_platform_admin_config', '平台系统配置', 'platform:admin:config', '访问平台系统配置', 'module_config',
- true, 'system', NULL, now(), false),
-
+('PERM-0601', 'perm_platform_admin', '平台管理后台', 'platform:admin:view', '访问平台管理后台', 'module_system', true, 'system', NULL, now(), false),
+('PERM-0602', 'perm_platform_admin_overview', '平台数据概览', 'platform:admin:overview', '访问平台数据概览', 'module_system', true, 'system', NULL, now(), false),
+('PERM-0603', 'perm_platform_admin_user', '平台用户管理', 'platform:admin:user', '访问平台用户管理', 'module_system', true, 'system', NULL, now(), false),
+('PERM-0604', 'perm_platform_admin_knowledge', '平台知识库', 'platform:admin:knowledge', '访问平台知识库', 'module_knowledge', true, 'system', NULL, now(), false),
+('PERM-0605', 'perm_platform_admin_config', '平台系统配置', 'platform:admin:config', '访问平台系统配置', 'module_config', true, 'system', NULL, now(), false),
-- Bidding 管理后台功能权限
-('PERM-0611', 'perm_bidding_admin', '招标管理后台', 'bidding:admin:view', '访问招标管理后台', 'module_bidding',
- true, 'system', NULL, now(), false),
-
+('PERM-0611', 'perm_bidding_admin', '招标管理后台', 'bidding:admin:view', '访问招标管理后台', 'module_bidding', true, 'system', NULL, now(), false),
-- Workcase 管理后台功能权限
-('PERM-0621', 'perm_workcase_admin', '客服管理后台', 'workcase:admin:view', '访问客服管理后台', 'module_workcase',
- true, 'system', NULL, now(), false),
-('PERM-0622', 'perm_workcase_overview', '数据概览', 'workcase:overview:view', '访问泰豪小电数据概览', 'module_workcase',
- true, 'system', NULL, now(), false),
-('PERM-0623', 'perm_workcase_knowledge', '知识库管理', 'workcase:knowledge:view', '访问知识库管理', 'module_workcase',
- true, 'system', NULL, now(), false),
-('PERM-0624', 'perm_workcase_tickets', '工单管理', 'workcase:tickets:view', '访问工单管理', 'module_workcase',
- true, 'system', NULL, now(), false),
-('PERM-0625', 'perm_workcase_conversation', '对话数据', 'workcase:conversation:view', '访问对话数据管理', 'module_workcase',
- true, 'system', NULL, now(), false),
-('PERM-0626', 'perm_workcase_agent', '智能体管理', 'workcase:agent:view', '访问智能体管理', 'module_workcase',
- true, 'system', NULL, now(), false),
-('PERM-0627', 'perm_workcase_log', '日志管理', 'workcase:log:view', '访问日志管理', 'module_workcase',
- true, 'system', NULL, now(), false);
-
+('PERM-0621', 'perm_workcase_admin', '客服管理后台', 'workcase:admin:view', '访问客服管理后台', 'module_workcase', true, 'system', NULL, now(), false),
+('PERM-0622', 'perm_workcase_overview', '数据概览', 'workcase:overview:view', '访问泰豪小电数据概览', 'module_workcase', true, 'system', NULL, now(), false),
+('PERM-0623', 'perm_workcase_knowledge', '知识库管理', 'workcase:knowledge:view', '访问知识库管理', 'module_workcase', true, 'system', NULL, now(), false),
+('PERM-0624', 'perm_workcase_tickets', '工单管理', 'workcase:tickets:view', '访问工单管理', 'module_workcase', true, 'system', NULL, now(), false),
+('PERM-0625', 'perm_workcase_conversation', '对话数据', 'workcase:conversation:view', '访问对话数据管理', 'module_workcase', true, 'system', NULL, now(), false),
+('PERM-0626', 'perm_workcase_agent', '智能体管理', 'workcase:agent:view', '访问智能体管理', 'module_workcase', true, 'system', NULL, now(), false),
+('PERM-0627', 'perm_workcase_log', '日志管理', 'workcase:log:view', '访问日志管理', 'module_workcase', true, 'system', NULL, now(), false);
-- =============================
-- 5. 初始化视图(菜单)
-- =============================
diff --git a/urbanLifelineServ/.gitignore b/urbanLifelineServ/.gitignore
index 0f5aef70..1bfb4993 100644
--- a/urbanLifelineServ/.gitignore
+++ b/urbanLifelineServ/.gitignore
@@ -24,4 +24,5 @@ hs_err_pid*
.data
.idea
*/target
-*/*/target
\ No newline at end of file
+*/*/target
+# example/*
\ No newline at end of file
diff --git a/urbanLifelineServ/.windsurf/rules/urbanlife.md b/urbanLifelineServ/.windsurf/rules/urbanlife.md
index 3c0148e1..83137f98 100644
--- a/urbanLifelineServ/.windsurf/rules/urbanlife.md
+++ b/urbanLifelineServ/.windsurf/rules/urbanlife.md
@@ -3,4 +3,5 @@ trigger: manual
---
1. 有BaseDTO基类,DTO\VO在api模块下面
-2. 用Dubbo注册和,引用服务
\ No newline at end of file
+2. 用Dubbo注册和,引用服务
+3. 当个端Insert语句,对应sql表的必填项才生成(有默认值也是if生成),其他应该if条件生成
diff --git a/urbanLifelineServ/ai/AI模块功能说明.md b/urbanLifelineServ/ai/AI模块功能说明.md
new file mode 100644
index 00000000..48f91a9e
--- /dev/null
+++ b/urbanLifelineServ/ai/AI模块功能说明.md
@@ -0,0 +1,51 @@
+# 智能体创建
+
+说明: 本服务只对智能体进行对话的转发,不能对dify智能体进行修改
+1. 智能体创建,用户上传tb_agent需要的字段进行智能体创建
+
+# 智能体更新
+1. 更新数据库和redis缓存
+2. 注意加锁,避免并发时,其他线程用了错误数据
+
+# 智能体删除
+软删除本服务的智能体数据
+
+# 智能体对话
+1. 校验智能体是否可以用
+2. 用户会先对1个智能体创建一个会话
+3. 用户先发起对话预处理请求,传入会话携带的对象数据到redis中,产生一个临时的消息id
+4. 真正发起对话数据请求时,会传入3个必须参数,1智能体id,2会话id,3本次消息id
+5. 优先从redis缓存中获取agentid对应的agent配置,没有找数据库。这里要进行双检加锁,避免智能体修改、重复加载等问题
+6. 从redis中获取消息id真正的数据,包含各种数据对象和fileid等等内容
+7. 和dify构建sse流式对话,并回应前端的sse流式对话。 不要乱生成无用的data事件,直接返回dify的事件和数据
+8. 前端会自动处理dify的事件
+
+# 对话评价
+1. 用户对对话进行评价,评价会存储到tb_chat_message的comment字段中
+2. 调用dify代理服务,更新dify智能体本消息的评价
+
+# 知识库创建
+1. 用户上传tb_knowledge需要的字段进行知识库创建
+
+# 知识库文件上传
+1. 用户上传文件到本服务,存储到文件表和minio中,并生成version版本
+2. 上传文件到dify知识库,dify返回上传成功后插入tb_knowledge_file表,并更新version版本,否则提示用户
+
+# 知识库更新文件
+1. 用户上传文件到本服务,并生成version版本,存储到文件表和minio中
+2. 上传文件到dify知识库,dify返回上传成功后插入tb_knowledge_file表,并更新version版本,否则提示用户
+3. 删除dify旧的version的文件document,来控制版本
+4. 本服务中,旧的文件对象不会删除,本条新的file对象会有file_root_id指向原始第一个file对象的file_id,用来进行版本展示,但dify知识库实际只有1个最新的文件
+
+# 知识库删除文件
+1. 软删除本服务服务中tb_knowledge_file的该文件所有版本
+2. 真删除dify本文件
+
+
+# 知识库创建、更新、删除文件分段
+1. 直接调用dify代理服务实现,不存储到本服务,也不生成新的version版本
+
+# 知识库删除
+1. 软删除本服务服务中tb_knowledge的该知识库
+2. 真删除dify知识库
+
diff --git a/urbanLifelineServ/ai/pom.xml b/urbanLifelineServ/ai/pom.xml
index 7f1f1db1..370b25af 100644
--- a/urbanLifelineServ/ai/pom.xml
+++ b/urbanLifelineServ/ai/pom.xml
@@ -28,7 +28,51 @@
api-system
${urban-lifeline.version}
-
+
+ org.xyzh.apis
+ api-file
+ ${urban-lifeline.version}
+
+
+ org.xyzh.common
+ common-redis
+
+
+ org.xyzh.common
+ common-auth
+
+
+ org.xyzh.common
+ common-utils
+
+
+ org.xyzh.common
+ common-exception
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.apache.dubbo
+ dubbo-spring-boot-starter
+
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+
+
+ com.squareup.okhttp3
+ okhttp
+
+
+ com.squareup.okhttp3
+ okhttp-sse
+
\ No newline at end of file
diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/DifyApiClient.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/DifyApiClient.java
index ee62b8e3..c0cb735f 100644
--- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/DifyApiClient.java
+++ b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/DifyApiClient.java
@@ -13,7 +13,6 @@ import org.xyzh.ai.client.dto.*;
import org.xyzh.ai.client.callback.StreamCallback;
import org.xyzh.ai.config.DifyConfig;
import org.xyzh.ai.exception.DifyException;
-import org.xyzh.api.ai.dto.DifyFileInfo;
import java.io.BufferedReader;
import java.io.File;
@@ -483,11 +482,11 @@ public class DifyApiClient {
}
if (!data.isEmpty()) {
- // 使用Fastjson2解析SSE数据
+ // 解析SSE数据
JSONObject jsonNode = JSON.parseObject(data);
String event = jsonNode.containsKey("event") ? jsonNode.getString("event") : "";
- // 转发所有事件到回调(包含完整数据)
+ // 转发事件给回调(用于前端SSE转发)
callback.onEvent(event, data);
switch (event) {
diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DifyFileInfo.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DifyFileInfo.java
new file mode 100644
index 00000000..956232c2
--- /dev/null
+++ b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DifyFileInfo.java
@@ -0,0 +1,97 @@
+package org.xyzh.ai.client.dto;
+
+import com.alibaba.fastjson2.annotation.JSONField;
+
+import lombok.Data;
+
+/**
+ * Dify文件上传响应DTO
+ * 对应 Dify API /files/upload 的响应结构
+ */
+@Data
+public class DifyFileInfo {
+
+ /**
+ * 文件ID(Dify返回)
+ */
+ private String id;
+
+ /**
+ * 文件名
+ */
+ private String name;
+
+ /**
+ * 文件大小(字节)
+ */
+ private Integer size;
+
+ /**
+ * 文件扩展名
+ */
+ private String extension;
+
+ /**
+ * 文件MIME类型
+ */
+ @JSONField(name="mime_type")
+ private String mimeType;
+
+ /**
+ * 上传人ID
+ */
+ @JSONField(name="created_by")
+ private String createdBy;
+
+ /**
+ * 上传时间(时间戳)
+ */
+ @JSONField(name="created_at")
+ private Long createdAt;
+
+ /**
+ * 预览URL
+ */
+ @JSONField(name="preview_url")
+ private String previewUrl;
+
+ /**
+ * 源文件URL
+ */
+ @JSONField(name="source_url")
+ private String sourceUrl;
+
+ /**
+ * 文件类型:image、document、audio、video、file
+ */
+ private String type;
+
+ /**
+ * 传输方式:remote_url、local_file
+ */
+ @JSONField(name="transfer_method")
+ private String transferMethod;
+
+ /**
+ * 文件URL或ID
+ */
+ private String url;
+
+ /**
+ * 本地文件上传ID
+ */
+ @JSONField(name="upload_file_id")
+ private String uploadFileId;
+
+ /**
+ * 系统文件ID
+ */
+ @JSONField(name="sys_file_id")
+ private String sysFileId;
+
+ /**
+ * 文件路径(从系统文件表获取)
+ */
+ @JSONField(name="file_path")
+ private String filePath;
+}
diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/controller/AgentController.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/controller/AgentController.java
new file mode 100644
index 00000000..31230884
--- /dev/null
+++ b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/controller/AgentController.java
@@ -0,0 +1,147 @@
+package org.xyzh.ai.controller;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.xyzh.ai.service.impl.AgentServiceImpl;
+import org.xyzh.api.ai.dto.TbAgent;
+import org.xyzh.common.core.domain.ResultDomain;
+import org.xyzh.common.core.page.PageRequest;
+import org.xyzh.common.utils.validation.ValidationResult;
+import org.xyzh.common.utils.validation.ValidationParam;
+import org.xyzh.common.utils.validation.ValidationUtils;
+
+import jakarta.validation.constraints.NotNull;
+
+import java.util.Arrays;
+
+/**
+ * @description 智能体控制器
+ * @filename AgentController.java
+ * @author yslg
+ * @copyright xyzh
+ * @since 2025-12-17
+ */
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("/ai/agent")
+public class AgentController {
+
+ @Autowired
+ private AgentServiceImpl agentService;
+
+ /**
+ * @description 创建智能体
+ * @param agent
+ * @author yslg
+ * @since 2025-12-17
+ */
+ @PostMapping
+ @PreAuthorize("@ss.hasPermi('ai:agent:create')")
+ public ResultDomain createAgent(@RequestBody TbAgent agent) {
+ log.info("创建智能体: name={}", agent.getName());
+ // 参数校验
+ ValidationResult result = ValidationUtils.validate(agent, Arrays.asList(
+ ValidationUtils.requiredString("name", "智能体名称", 1, 100),
+ ValidationUtils.requiredString("apiKey", "API密钥", 1, 100),
+ ValidationUtils.requiredString("link", "智能体url",10,500)
+ ));
+ if (!result.isValid()) {
+ return ResultDomain.failure(result.getAllErrors());
+ }
+ return agentService.addAgent(agent);
+ }
+
+ /**
+ * @description 更新智能体
+ * @param agent
+ * @author yslg
+ * @since 2025-12-17
+ */
+ @PutMapping
+ @PreAuthorize("@ss.hasPermi('ai:agent:update')")
+ public ResultDomain updateAgent(@RequestBody TbAgent agent) {
+ log.info("更新智能体: agentId={}", agent.getAgentId());
+ // 参数校验
+ ValidationResult result = ValidationUtils.validate(agent, Arrays.asList(
+ ValidationUtils.requiredString("agentId", "智能体ID"),
+ ValidationUtils.requiredString("name", "智能体名称", 1, 100),
+ ValidationUtils.requiredString("apiKey", "API密钥", 1, 100),
+ ValidationUtils.requiredString("link", "智能体url",10,500)
+ ));
+ if (!result.isValid()) {
+ return ResultDomain.failure(result.getAllErrors());
+ }
+ return agentService.updateAgent(agent);
+ }
+
+ /**
+ * @description 删除智能体
+ * @param agentId
+ * @author yslg
+ * @since 2025-12-17
+ */
+ @DeleteMapping("/{agentId}")
+ @PreAuthorize("@ss.hasPermi('ai:agent:delete')")
+ public ResultDomain deleteAgent(@PathVariable("agentId") @NotNull String agentId) {
+ log.info("删除智能体: agentId={}", agentId);
+ TbAgent agent = new TbAgent();
+ agent.setAgentId(agentId);
+ return agentService.deleteAgent(agent);
+ }
+
+ /**
+ * @description 获取智能体详情
+ * @param agentId
+ * @author yslg
+ * @since 2025-12-17
+ */
+ @GetMapping("/{agentId}")
+ @PreAuthorize("@ss.hasPermi('ai:agent:view')")
+ public ResultDomain getAgent(@PathVariable("agentId") @NotNull String agentId) {
+ log.info("获取智能体: agentId={}", agentId);
+ ResultDomain agentResult = agentService.selectAgentById(agentId);
+ if (agentResult.getSuccess() && agentResult.getData() != null) {
+ return ResultDomain.success("查询成功", agentResult.getData());
+ }
+ return ResultDomain.failure("智能体不存在"+agentResult.getMessage());
+ }
+
+ /**
+ * @description 分页查询智能体
+ * @param pageRequest
+ * @author yslg
+ * @since 2025-12-17
+ */
+ @PostMapping("/page")
+ @PreAuthorize("@ss.hasPermi('ai:agent:view')")
+ public ResultDomain getAgentPage(@RequestBody PageRequest pageRequest) {
+ log.info("分页查询智能体");
+ // 参数校验(支持嵌套属性路径)
+ ValidationResult result = ValidationUtils.validate(pageRequest, Arrays.asList(
+ ValidationParam.builder().fieldName("pageParam").fieldLabel("分页参数").required().build(),
+ ValidationUtils.requiredNumber("pageParam.page", "页码", 1, null),
+ ValidationUtils.requiredNumber("pageParam.pageSize", "每页条数", 1, 100)
+ ));
+ if (!result.isValid()) {
+ return ResultDomain.failure(result.getAllErrors());
+ }
+ return agentService.getAgentPage(pageRequest);
+ }
+
+ /**
+ * @description 获取智能体列表
+ * @param tbAgent
+ * @author yslg
+ * @since 2025-12-17
+ */
+ @GetMapping("/list")
+ @PreAuthorize("@ss.hasPermi('ai:agent:view')")
+ public ResultDomain getAgentList(TbAgent tbAgent) {
+ log.info("获取智能体列表");
+ return agentService.getAgentList(tbAgent);
+ }
+}
diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/controller/ChatController.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/controller/ChatController.java
new file mode 100644
index 00000000..0e028785
--- /dev/null
+++ b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/controller/ChatController.java
@@ -0,0 +1,305 @@
+package org.xyzh.ai.controller;
+
+import jakarta.validation.constraints.NotNull;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+import org.xyzh.api.ai.dto.ChatPrepareData;
+import org.xyzh.api.ai.dto.TbChat;
+import org.xyzh.api.ai.dto.TbChatMessage;
+import org.xyzh.api.ai.service.AIFileUploadService;
+import org.xyzh.api.ai.service.AgentChatService;
+import org.xyzh.common.auth.utils.LoginUtil;
+import org.xyzh.common.core.domain.LoginDomain;
+import org.xyzh.common.core.domain.ResultDomain;
+import org.xyzh.common.utils.NonUtils;
+import org.xyzh.common.utils.validation.ValidationParam;
+import org.xyzh.common.utils.validation.ValidationResult;
+import org.xyzh.common.utils.validation.ValidationUtils;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Map;
+
+/**
+ * @description 智能体对话控制器 所有接口开放
+ * @filename ChatController.java
+ * @author yslg
+ * @copyright xyzh
+ * @since 2025-12-17
+ */
+@Slf4j
+@RestController
+@Validated
+@RequestMapping("/ai/chat")
+public class ChatController {
+
+ @Autowired
+ private AgentChatService chatService;
+
+ @Autowired
+ private AIFileUploadService fileUploadService;
+
+ // ====================== 会话管理 ======================
+
+ /**
+ * @description 创建会话
+ * @param
+ * @author yslg
+ * @since 2025-12-17
+ */
+ @PostMapping("/conversation")
+ public ResultDomain createChat(@RequestBody TbChat chat, @RequestHeader("Authorization") String token) {
+ ValidationResult result = ValidationUtils.validate(chat, Arrays.asList(
+ ValidationUtils.requiredString("agentId", "智能体id", 1, 100),
+ ValidationUtils.requiredString("title", "对话标题", 1, 100),
+ ValidationUtils.requiredString("userId", "用户id", 1, 100)
+ ));
+ if (!result.isValid()) {
+ return ResultDomain.failure(result.getAllErrors());
+ }
+ // 默认来客,如果token不为空且token对应的用户存在,说明是员工
+ chat.setUserType(false);
+ if(NonUtils.isNotEmpty(token)){
+ LoginDomain loginDomain = LoginUtil.getCurrentLogin();
+ if (NonUtils.isNotEmpty(loginDomain)) {
+ chat.setUserType(true);
+ }
+ }
+
+ log.info("创建会话: agentId={}, title={}, userId={}, userType={}", chat.getAgentId(), chat.getTitle(), chat.getUserId());
+ return chatService.createChat(chat);
+ }
+
+ /**
+ * @description 更新对话
+ * @param
+ * @author yslg
+ * @since 2025-12-17
+ */
+ @PutMapping("/conversation")
+ public ResultDomain updateChat(@RequestBody TbChat chat, @RequestHeader("Authorization") String token) {
+ ValidationResult result = ValidationUtils.validate(chat, Arrays.asList(
+ ValidationUtils.requiredString("agentId", "智能体id", 1, 100),
+ ValidationUtils.requiredString("title", "对话标题", 1, 100),
+ ValidationUtils.requiredString("userId", "用户id", 1, 100),
+ ValidationParam.builder().fieldName("userType").fieldLabel("用户类型").required().fieldType(Boolean.class).build()
+ ));
+ if (!result.isValid()) {
+ return ResultDomain.failure(result.getAllErrors());
+ }
+ chat.setUserType(false);
+ if(NonUtils.isNotEmpty(token)){
+ LoginDomain loginDomain = LoginUtil.getCurrentLogin();
+ if (NonUtils.isNotEmpty(loginDomain)) {
+ chat.setUserType(true);
+ }
+ }
+ log.info("更新会话: chatId={}", chat.getChatId());
+ return chatService.updateChat(chat);
+ }
+
+ /**
+ * @description 删除对话
+ * @param
+ * @author yslg
+ * @since 2025-12-17
+ */
+ @DeleteMapping("/conversation")
+ public ResultDomain deleteChat(@RequestBody TbChat chat, @RequestHeader("Authorization") String token) {
+ chat.setUserType(false);
+ if(NonUtils.isNotEmpty(token)){
+ LoginDomain loginDomain = LoginUtil.getCurrentLogin();
+ if (NonUtils.isNotEmpty(loginDomain)) {
+ chat.setUserType(true);
+ }
+ }
+ log.info("删除会话: chatId={}", chat.getChatId());
+ return chatService.deleteChat(chat);
+ }
+
+ /**
+ * @description 获取对话列表
+ * @param
+ * @author yslg
+ * @since 2025-12-17
+ */
+ @GetMapping("/conversations")
+ public ResultDomain getChatList(@RequestBody TbChat filter, @RequestHeader("Authorization") String token) {
+ log.info("获取会话列表: agentId={}", filter.getAgentId());
+
+ filter.setUserType(false);
+ if(NonUtils.isNotEmpty(token)){
+ LoginDomain loginDomain = LoginUtil.getCurrentLogin();
+ if (NonUtils.isNotEmpty(loginDomain)) {
+ filter.setUserType(true);
+ }
+ }
+ return chatService.getChatList(filter);
+ }
+
+ // ====================== 消息管理 ======================
+
+ /**
+ * @description 获取对话消息列表
+ * @param
+ * @author yslg
+ * @since 2025-12-17
+ */
+ @PostMapping("/messages")
+ public ResultDomain getMessageList(@RequestBody TbChat filter, @RequestHeader("Authorization") String token) {
+ ValidationResult result = ValidationUtils.validate(filter, Arrays.asList(
+ ValidationUtils.requiredString("agentId", "智能体id",10,50),
+ ValidationUtils.requiredString("chatId", "对话Id", 10, 50),
+ ValidationUtils.requiredString("userId", "用户Id")
+ ));
+
+ filter.setUserType(false);
+ if(NonUtils.isNotEmpty(token)){
+ LoginDomain loginDomain = LoginUtil.getCurrentLogin();
+ if (NonUtils.isNotEmpty(loginDomain)) {
+ filter.setUserType(true);
+ }
+ }
+ log.info("获取消息列表: chatId={}", filter.getChatId());
+ return chatService.getChatMessageList(filter);
+ }
+
+ // ====================== 流式对话 ======================
+
+ /**
+ * @description 准备流式对话会话数据
+ * @param chatPrepareData
+ * @author yslg
+ * @since 2025-12-17
+ */
+ @PostMapping("/stream/prepare")
+ public ResultDomain prepareStreamChat(@RequestBody ChatPrepareData chatPrepareData, @RequestHeader("Authorization") String token) {
+ ValidationResult result = ValidationUtils.validate(chatPrepareData, Arrays.asList(
+ ValidationUtils.requiredString("agentId", "智能体Id", 1, 50),
+ ValidationUtils.requiredString("chatId", "会话Id", 1, 50),
+ ValidationUtils.requiredString("query", "用户问题"),
+ ValidationUtils.requiredString("userId", "用户Id", 1, 100)
+ ));
+ if(!result.isValid()){
+ return ResultDomain.failure(result.getAllErrors());
+ }
+ // 设置用户类型
+ chatPrepareData.setUserType(false);
+ if(NonUtils.isNotEmpty(token)){
+ LoginDomain loginDomain = LoginUtil.getCurrentLogin();
+ if (NonUtils.isNotEmpty(loginDomain)) {
+ chatPrepareData.setUserType(true);
+ }
+ }
+ log.info("准备流式对话: agentId={}, chatId={}, query={}", chatPrepareData.getAgentId(), chatPrepareData.getChatId(), chatPrepareData.getQuery());
+ return chatService.prepareChatMessageSession(chatPrepareData);
+ }
+
+ /**
+ * @description 进行流式对话
+ * @param
+ * @author yslg
+ * @since 2025-12-17
+ */
+ @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
+ public SseEmitter streamChat(@RequestParam("sessionId") String sessionId) {
+ if(NonUtils.isEmpty(sessionId)){
+ SseEmitter emitter = new SseEmitter(300000L);
+ try {
+ emitter.send(SseEmitter.event().name("error").data("{\"message\":\"会话不存在\"}"));
+ } catch (IOException e) {
+ log.error("发送错误事件失败", e);
+ }finally {
+ emitter.complete();
+ }
+ return emitter;
+ }
+ log.info("建立SSE连接: sessionId={}", sessionId);
+ return chatService.streamChatMessageWithSse(sessionId);
+ }
+
+ /**
+ * @description 停止会话
+ * @param
+ * @author yslg
+ * @since 2025-12-17
+ */
+ @PostMapping("/stop")
+ public ResultDomain stopChat(@RequestBody Map params, @RequestHeader("Authorization") String token) {
+ ValidationResult result = ValidationUtils.validateMap(params, Arrays.asList(
+ ValidationUtils.requiredString("taskId", "任务ID"),
+ ValidationUtils.requiredString("agentId", "智能体ID"),
+ ValidationUtils.requiredString("userId", "用户ID")
+ ));
+ if (!result.isValid()) {
+ return ResultDomain.failure(result.getAllErrors());
+ }
+ TbChat filter = new TbChat();
+ filter.setAgentId(params.get("agentId"));
+ filter.setUserId(params.get("userId"));
+ filter.setUserType(false);
+ if(NonUtils.isNotEmpty(token)){
+ LoginDomain loginDomain = LoginUtil.getCurrentLogin();
+ if (NonUtils.isNotEmpty(loginDomain)) {
+ filter.setUserType(true);
+ }
+ }
+ log.info("停止对话: taskId={}", params.get("taskId"));
+ return chatService.stopChatMessageByTaskId(filter, params.get("taskId"));
+ }
+
+ /**
+ * @description 评价消息
+ * @param
+ * @author yslg
+ * @since 2025-12-17
+ */
+ @PostMapping("/comment")
+ public ResultDomain commentMessage(@RequestBody Map params, @RequestHeader("Authorization") String token) {
+ ValidationResult result = ValidationUtils.validateMap(params, Arrays.asList(
+ ValidationUtils.requiredString("agentId", "智能体ID"),
+ ValidationUtils.requiredString("chatId", "对话ID"),
+ ValidationUtils.requiredString("messageId", "消息ID"),
+ ValidationUtils.requiredString("comment", "评价"),
+ ValidationUtils.requiredString("userId", "用户ID")
+ ));
+ if (!result.isValid()) {
+ return ResultDomain.failure(result.getAllErrors());
+ }
+ TbChat filter = new TbChat();
+ filter.setAgentId(params.get("agentId"));
+ filter.setChatId(params.get("chatId"));
+ filter.setUserId(params.get("userId"));
+ filter.setUserType(false);
+ if(NonUtils.isNotEmpty(token)){
+ LoginDomain loginDomain = LoginUtil.getCurrentLogin();
+ if (NonUtils.isNotEmpty(loginDomain)) {
+ filter.setUserType(true);
+ }
+ }
+ log.info("评价消息: messageId={}, comment={}", params.get("messageId"), params.get("comment"));
+ return chatService.commentChatMessage(filter, params.get("messageId"), params.get("comment"));
+ }
+
+ // ====================== 文件上传 ======================
+
+ /**
+ * @description 上传文件用于对话(图文多模态)
+ * @param file 文件
+ * @param agentId 智能体ID
+ * @author yslg
+ * @since 2025-12-17
+ */
+ @PostMapping(value = "/file/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+ public ResultDomain