Merge branch 'codex/personal-assistant-phase2' into codex/multi-tenant-knowledge-platform

# Conflicts:
#	backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/domain/AihrSopDto.java
#	backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrModelSeedService.java
#	backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java
#	backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/service/AihrModelSeedServiceTest.java
#	backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/service/AihrSopSeedServiceTest.java
#	docs/API_INTEGRATION.md
#	docs/个人AI助理阶段二专项TechSpec.md
#	docs/个人AI助理阶段二开发推进计划.md
#	frontend/src/views/knowledge/processing.vue
#	mobile-uni/src/pages/user/sop/index.vue
#	mobile-uni/src/services/api.ts
#	mobile-uni/src/services/personal-assistant.ts
#	mobile-uni/tests/personal-assistant.test.mjs
#	scripts/demo-check.sh
#	scripts/personal-assistant-smoke.sh
This commit is contained in:
2026-07-22 08:54:04 +08:00
72 changed files with 13883 additions and 61 deletions
@@ -73,6 +73,26 @@ CREATE TABLE IF NOT EXISTS `aihr_knowledge_fragment` (
FULLTEXT KEY `ft_aihr_knowledge_fragment_content` (`content`) WITH PARSER ngram
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='AI HR 知识片段';
CREATE TABLE IF NOT EXISTS `aihr_knowledge_acl` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`tenant_id` varchar(20) NOT NULL COMMENT '租户编号',
`knowledge_id` bigint NOT NULL COMMENT '企业知识库ID',
`access_scope` varchar(20) NOT NULL COMMENT '授权范围:TENANT/PROJECT/POSITION',
`project_code` varchar(50) DEFAULT NULL COMMENT '项目编码,PROJECT必填,POSITION可选',
`position_name` varchar(100) DEFAULT NULL COMMENT '规范岗位名称,POSITION必填',
`position_level` varchar(30) DEFAULT NULL COMMENT '岗位层级,POSITION可选',
`classification` varchar(20) NOT NULL DEFAULT 'INTERNAL' COMMENT '知识密级:INTERNAL/RESTRICTED',
`enabled` tinyint(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
`rule_key` varchar(220) GENERATED ALWAYS AS
(concat(`access_scope`, '|', ifnull(`project_code`, ''), '|', ifnull(`position_name`, ''), '|', ifnull(`position_level`, ''))) STORED,
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_aihr_knowledge_acl_rule` (`tenant_id`, `knowledge_id`, `rule_key`),
KEY `idx_aihr_knowledge_acl_lookup` (`tenant_id`, `enabled`, `access_scope`),
KEY `idx_aihr_knowledge_acl_knowledge` (`tenant_id`, `knowledge_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='企业知识访问控制,默认无ACL不可见';
CREATE TABLE IF NOT EXISTS `aihr_knowledge_import_task` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`tenant_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '000000' COMMENT '租户编号',
@@ -140,6 +160,17 @@ ON DUPLICATE KEY UPDATE
`content` = VALUES(`content`),
`update_time` = NOW();
INSERT INTO `aihr_knowledge_acl`
(`tenant_id`, `knowledge_id`, `access_scope`, `project_code`, `position_name`, `position_level`, `classification`, `enabled`, `create_time`, `update_time`)
VALUES
('000000', 1001, 'POSITION', NULL, '生活顾问', '一线', 'INTERNAL', 1, NOW(), NOW()),
('000000', 1002, 'POSITION', NULL, '生活顾问', '一线', 'INTERNAL', 1, NOW(), NOW()),
('000000', 1003, 'POSITION', NULL, '生活顾问', '一线', 'INTERNAL', 1, NOW(), NOW())
ON DUPLICATE KEY UPDATE
`classification` = VALUES(`classification`),
`enabled` = VALUES(`enabled`),
`update_time` = NOW();
-- 知识库批量上传队列:上传秒回后由后台 worker 加工,支持单文件重试
CREATE TABLE IF NOT EXISTS `aihr_knowledge_upload_item` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
@@ -0,0 +1,208 @@
-- 个人 AI 助理独立知识空间。
-- 个人知识仅按 tenant_id + owner_user_id 隔离,不修改或复用企业 aihr_knowledge_* 表。
-- 个人资料使用独立私有桶;不得修改企业知识使用的默认 MinIO 配置。
INSERT INTO `sys_oss_config`
(`oss_config_id`, `tenant_id`, `config_key`, `access_key`, `secret_key`, `bucket_name`, `prefix`,
`endpoint`, `domain`, `is_https`, `region`, `access_policy`, `status`, `ext1`, `create_dept`,
`create_by`, `create_time`, `update_by`, `update_time`, `remark`)
SELECT 9001, source.`tenant_id`, 'personal-minio', source.`access_key`, source.`secret_key`,
'ruoyi-personal', '', source.`endpoint`, source.`domain`, source.`is_https`, source.`region`,
'0', '1', '', source.`create_dept`, source.`create_by`, CURRENT_TIMESTAMP,
source.`update_by`, CURRENT_TIMESTAMP, '个人AI助理专用私有对象存储'
FROM `sys_oss_config` source
WHERE source.`tenant_id` = '000000' AND source.`config_key` = 'minio'
AND NOT EXISTS (
SELECT 1 FROM `sys_oss_config` target
WHERE target.`tenant_id` = source.`tenant_id` AND target.`config_key` = 'personal-minio'
);
CREATE TABLE IF NOT EXISTS `aihr_personal_space` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`tenant_id` varchar(20) NOT NULL DEFAULT '000000' COMMENT '租户编号',
`owner_user_id` bigint NOT NULL COMMENT '个人空间所属用户ID',
`owner_ext_party_id` varchar(100) DEFAULT NULL COMMENT '外部组织主体ID',
`status` varchar(20) NOT NULL DEFAULT 'ACTIVE' COMMENT '空间状态',
`quota_bytes` bigint NOT NULL DEFAULT 524288000 COMMENT '空间配额,默认500MB',
`used_bytes` bigint NOT NULL DEFAULT 0 COMMENT '已使用字节数',
`item_count` int NOT NULL DEFAULT 0 COMMENT '资料数量',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_personal_space_owner` (`tenant_id`, `owner_user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='个人AI助理知识空间';
CREATE TABLE IF NOT EXISTS `aihr_personal_item` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`tenant_id` varchar(20) NOT NULL DEFAULT '000000' COMMENT '租户编号',
`space_id` bigint NOT NULL COMMENT '个人空间ID',
`owner_user_id` bigint NOT NULL COMMENT '资料所属用户ID',
`source_type` varchar(20) NOT NULL COMMENT '来源类型: text/file/url',
`title` varchar(500) NOT NULL COMMENT '资料标题',
`original_url` varchar(2000) DEFAULT NULL COMMENT '原始网址',
`oss_id` bigint DEFAULT NULL COMMENT '对象存储ID',
`mime_type` varchar(100) DEFAULT NULL COMMENT 'MIME类型',
`size_bytes` bigint NOT NULL DEFAULT 0 COMMENT '资料大小',
`content_hash` varchar(64) NOT NULL COMMENT '内容摘要哈希',
`status` varchar(20) NOT NULL DEFAULT 'QUEUED' COMMENT '处理状态',
`attempt_count` int NOT NULL DEFAULT 0 COMMENT '处理尝试次数',
`error_code` varchar(80) DEFAULT NULL COMMENT '错误代码',
`error_message` varchar(500) DEFAULT NULL COMMENT '错误信息',
`summary` text COMMENT '资料摘要',
`tags_json` json COMMENT '标签JSON',
`captured_at` datetime NOT NULL COMMENT '采集完成时间',
`parsed_at` datetime DEFAULT NULL COMMENT '解析完成时间',
`deleted_at` datetime DEFAULT NULL COMMENT '软删除时间',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_personal_item_owner` (`tenant_id`, `owner_user_id`, `status`, `create_time`),
KEY `idx_personal_item_date` (`tenant_id`, `owner_user_id`, `captured_at`),
KEY `idx_personal_item_hash` (`space_id`, `content_hash`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='个人AI助理资料';
CREATE TABLE IF NOT EXISTS `aihr_personal_fragment` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`tenant_id` varchar(20) NOT NULL DEFAULT '000000' COMMENT '租户编号',
`space_id` bigint NOT NULL COMMENT '个人空间ID',
`owner_user_id` bigint NOT NULL COMMENT '片段所属用户ID',
`item_id` bigint NOT NULL COMMENT '个人资料ID',
`idx` int NOT NULL COMMENT '片段序号',
`content` text NOT NULL COMMENT '片段内容',
`token_count` int NOT NULL DEFAULT 0 COMMENT '估算Token数',
`embedding_json` longtext COMMENT '向量JSON',
`embedding_model` varchar(100) DEFAULT NULL COMMENT '向量模型',
`embedding_time` datetime DEFAULT NULL COMMENT '向量生成时间',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_personal_fragment_idx` (`item_id`, `idx`),
KEY `idx_personal_fragment_owner` (`tenant_id`, `owner_user_id`, `item_id`),
FULLTEXT KEY `ft_personal_fragment_content` (`content`) WITH PARSER ngram
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='个人AI助理知识片段';
CREATE TABLE IF NOT EXISTS `aihr_personal_chat_session` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`tenant_id` varchar(20) NOT NULL DEFAULT '000000' COMMENT '租户编号',
`owner_user_id` bigint NOT NULL COMMENT '会话所属用户ID',
`title` varchar(200) NOT NULL COMMENT '会话标题',
`status` varchar(20) NOT NULL DEFAULT 'ACTIVE' COMMENT '会话状态',
`default_scope` varchar(50) NOT NULL DEFAULT 'PERSONAL' COMMENT '默认问答范围',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_personal_session_owner` (`tenant_id`, `owner_user_id`, `update_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='个人AI助理对话会话';
CREATE TABLE IF NOT EXISTS `aihr_personal_chat_message` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`tenant_id` varchar(20) NOT NULL DEFAULT '000000' COMMENT '租户编号',
`owner_user_id` bigint NOT NULL COMMENT '消息所属用户ID',
`session_id` bigint NOT NULL COMMENT '对话会话ID',
`role` varchar(20) NOT NULL COMMENT '消息角色: user/assistant/system',
`content` longtext NOT NULL COMMENT '消息内容',
`scope_json` json COMMENT '本轮检索范围JSON',
`citations_json` json COMMENT '引用来源JSON',
`model_name` varchar(100) DEFAULT NULL COMMENT '模型名称',
`prompt_version` varchar(100) DEFAULT NULL COMMENT '提示词版本',
`input_tokens` int NOT NULL DEFAULT 0 COMMENT '输入Token数',
`output_tokens` int NOT NULL DEFAULT 0 COMMENT '输出Token数',
`latency_ms` bigint NOT NULL DEFAULT 0 COMMENT '响应耗时毫秒',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_personal_message_session` (`session_id`, `create_time`),
KEY `idx_personal_message_owner` (`tenant_id`, `owner_user_id`, `session_id`, `create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='个人AI助理对话消息';
CREATE TABLE IF NOT EXISTS `aihr_personal_cleanup_job` (
`id` bigint NOT NULL COMMENT '清理任务ID',
`tenant_id` varchar(20) NOT NULL COMMENT '租户编号',
`owner_user_id` bigint NOT NULL COMMENT '资料所属用户ID',
`item_id` bigint NOT NULL COMMENT '资料ID',
`status` varchar(20) NOT NULL DEFAULT 'PENDING' COMMENT 'PENDING/RETRY/DONE',
`attempt_count` int NOT NULL DEFAULT 0 COMMENT '执行次数',
`last_error` varchar(100) DEFAULT NULL COMMENT '脱敏后的错误类型',
`completed_at` datetime DEFAULT NULL COMMENT '完成时间',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_personal_cleanup_item` (`tenant_id`, `owner_user_id`, `item_id`),
KEY `idx_personal_cleanup_status` (`status`, `update_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='个人AI助理资料清理任务';
CREATE TABLE IF NOT EXISTS `aihr_personal_ocr_job` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'OCR任务ID',
`tenant_id` varchar(20) NOT NULL COMMENT '租户编号',
`owner_user_id` bigint NOT NULL COMMENT '资料所属用户ID',
`item_id` bigint NOT NULL COMMENT '资料ID',
`status` varchar(20) NOT NULL DEFAULT 'PENDING' COMMENT 'PENDING/RUNNING/RETRY/COMPLETED/FAILED',
`total_pages` int NOT NULL COMMENT 'PDF总页数',
`processed_pages` int NOT NULL DEFAULT 0 COMMENT '已处理页数',
`success_pages` int NOT NULL DEFAULT 0 COMMENT '识别成功页数',
`failed_pages` int NOT NULL DEFAULT 0 COMMENT '识别失败页数',
`failed_page_numbers_json` json COMMENT '识别失败页码JSON',
`next_page` int NOT NULL DEFAULT 1 COMMENT '下一待处理页码,从1开始',
`attempt_count` int NOT NULL DEFAULT 0 COMMENT '任务领取次数',
`last_error_code` varchar(80) DEFAULT NULL COMMENT '脱敏后的错误码',
`lease_until` datetime DEFAULT NULL COMMENT '任务租约截止时间',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_personal_ocr_job_item` (`tenant_id`, `owner_user_id`, `item_id`),
KEY `idx_personal_ocr_job_status` (`status`, `update_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='个人AI助理扫描PDF OCR任务';
CREATE TABLE IF NOT EXISTS `aihr_personal_ocr_page` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'OCR页记录ID',
`tenant_id` varchar(20) NOT NULL COMMENT '租户编号',
`owner_user_id` bigint NOT NULL COMMENT '资料所属用户ID',
`item_id` bigint NOT NULL COMMENT '资料ID',
`page_number` int NOT NULL COMMENT '页码,从1开始',
`status` varchar(20) NOT NULL DEFAULT 'PENDING' COMMENT 'PENDING/RUNNING/SUCCESS/FAILED',
`ocr_text` longtext COMMENT '页级OCR文本',
`attempt_count` int NOT NULL DEFAULT 0 COMMENT '识别尝试次数',
`last_error_code` varchar(80) DEFAULT NULL COMMENT '脱敏后的错误码',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_personal_ocr_page_number` (`tenant_id`, `owner_user_id`, `item_id`, `page_number`),
KEY `idx_personal_ocr_page_status` (`status`, `update_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='个人AI助理扫描PDF OCR页结果';
CREATE TABLE IF NOT EXISTS `aihr_personal_export_task` (
`id` bigint NOT NULL COMMENT '导出任务ID',
`tenant_id` varchar(20) NOT NULL COMMENT '租户编号',
`owner_user_id` bigint NOT NULL COMMENT '任务所属用户ID',
`session_id` bigint NOT NULL COMMENT '来源会话ID',
`outline_json` json NOT NULL COMMENT '可编辑大纲及不可变来源JSON',
`outline_confirmed` tinyint(1) NOT NULL DEFAULT 0 COMMENT '大纲是否已确认',
`template_code` varchar(50) NOT NULL DEFAULT 'standard' COMMENT 'PPT模板代码',
`status` varchar(20) NOT NULL DEFAULT 'DRAFT' COMMENT 'DRAFT/CONFIRMED/PENDING/RUNNING/READY/FAILED',
`oss_id` bigint DEFAULT NULL COMMENT '生成PPTX的私有OSS ID',
`error_message` varchar(500) DEFAULT NULL COMMENT '公开错误信息',
`confirmed_at` datetime DEFAULT NULL COMMENT '大纲确认时间',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_personal_export_owner` (`tenant_id`, `owner_user_id`, `update_time`),
KEY `idx_personal_export_status` (`status`, `update_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='个人AI助理汇报导出任务';
CREATE TABLE IF NOT EXISTS `aihr_personal_publish_request` (
`id` bigint NOT NULL COMMENT '发布申请ID',
`tenant_id` varchar(20) NOT NULL COMMENT '租户编号',
`item_id` bigint NOT NULL COMMENT '个人资料ID',
`applicant_user_id` bigint NOT NULL COMMENT '申请人用户ID',
`target_scope` varchar(100) NOT NULL COMMENT '目标范围,阶段二仅POSITION:生活顾问',
`reason` varchar(500) NOT NULL COMMENT '申请原因',
`status` varchar(20) NOT NULL DEFAULT 'PENDING' COMMENT 'PENDING/APPROVED/REJECTED',
`reviewer_user_id` bigint DEFAULT NULL COMMENT '审核人用户ID',
`review_comment` varchar(500) DEFAULT NULL COMMENT '审核意见',
`review_time` datetime DEFAULT NULL COMMENT '审核时间',
`published_knowledge_id` bigint DEFAULT NULL COMMENT '企业知识库副本ID',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_personal_publish_applicant` (`tenant_id`, `applicant_user_id`, `create_time`),
KEY `idx_personal_publish_status` (`tenant_id`, `status`, `update_time`),
KEY `idx_personal_publish_item` (`tenant_id`, `item_id`, `status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='个人知识申请沉淀企业知识审核';