feat(aihr): close functional checklist gaps

This commit is contained in:
key
2026-08-02 12:15:45 +08:00
parent 699cc08050
commit 6ad8a017a4
80 changed files with 4930 additions and 430 deletions
@@ -0,0 +1,93 @@
-- Broadcast delivery controls: strict audience visibility, controlled downloads,
-- evidence-backed topic tags, and attachment access audit.
-- Idempotent; run after aihr_20260724_broadcast_attachment_mysql8.sql.
SET @has_broadcast_visibility_mode := (
SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE table_schema = DATABASE() AND table_name = 'aihr_broadcast_message'
AND column_name = 'visibility_mode'
);
SET @broadcast_delivery_ddl := IF(
@has_broadcast_visibility_mode = 0,
'ALTER TABLE aihr_broadcast_message ADD COLUMN visibility_mode varchar(20) NOT NULL DEFAULT ''ALL'' COMMENT ''ALL/TARGET_ONLY'' AFTER required_read',
'SELECT 1'
);
PREPARE aihr_broadcast_delivery_stmt FROM @broadcast_delivery_ddl; EXECUTE aihr_broadcast_delivery_stmt; DEALLOCATE PREPARE aihr_broadcast_delivery_stmt;
SET @has_broadcast_allow_download := (
SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE table_schema = DATABASE() AND table_name = 'aihr_broadcast_message'
AND column_name = 'allow_download'
);
SET @broadcast_delivery_ddl := IF(
@has_broadcast_allow_download = 0,
'ALTER TABLE aihr_broadcast_message ADD COLUMN allow_download tinyint(1) NOT NULL DEFAULT 1 COMMENT ''附件是否允许下载'' AFTER visibility_mode',
'SELECT 1'
);
PREPARE aihr_broadcast_delivery_stmt FROM @broadcast_delivery_ddl; EXECUTE aihr_broadcast_delivery_stmt; DEALLOCATE PREPARE aihr_broadcast_delivery_stmt;
CREATE TABLE IF NOT EXISTS `aihr_broadcast_attachment_topic_tag` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主题标签ID',
`tenant_id` varchar(20) NOT NULL COMMENT '租户编号',
`attachment_id` bigint NOT NULL COMMENT '公司文件ID',
`tag_name` varchar(30) NOT NULL COMMENT '主题标签',
`source_type` varchar(20) NOT NULL COMMENT 'AUTO/MANUAL',
`evidence_quote` varchar(200) NOT NULL COMMENT '经原文校验的短引用',
`created_by` bigint DEFAULT NULL COMMENT '人工修正账号;自动标签为空',
`create_time` datetime NOT NULL COMMENT '创建时间',
`update_time` datetime NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_aihr_broadcast_attachment_topic_tag` (`tenant_id`, `attachment_id`, `tag_name`),
KEY `idx_aihr_broadcast_attachment_topic_tag_attachment` (`tenant_id`, `attachment_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='公司文件主题标签及原文依据';
CREATE TABLE IF NOT EXISTS `aihr_broadcast_attachment_access_audit` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '访问审计ID',
`tenant_id` varchar(20) NOT NULL COMMENT '租户编号',
`message_id` bigint NOT NULL COMMENT '消息ID',
`attachment_id` bigint NOT NULL COMMENT '公司文件ID',
`user_id` bigint NOT NULL COMMENT 'APP账号ID',
`access_type` varchar(20) NOT NULL COMMENT 'VIEW/DOWNLOAD',
`access_time` datetime NOT NULL COMMENT '访问时间',
PRIMARY KEY (`id`),
KEY `idx_aihr_broadcast_attachment_access_user` (`tenant_id`, `user_id`, `access_time`),
KEY `idx_aihr_broadcast_attachment_access_file` (`tenant_id`, `attachment_id`, `access_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='公司文件在线查看与下载审计';
SET @broadcast_delivery_target_collation := (
SELECT collation_name FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_knowledge_info' AND column_name = 'tenant_id'
LIMIT 1
);
SET @broadcast_delivery_target_collation := COALESCE(@broadcast_delivery_target_collation, @@collation_database);
SET @broadcast_topic_tag_collation := (
SELECT table_collation FROM information_schema.tables
WHERE table_schema = DATABASE() AND table_name = 'aihr_broadcast_attachment_topic_tag'
LIMIT 1
);
SET @broadcast_delivery_ddl := IF(
@broadcast_topic_tag_collation = @broadcast_delivery_target_collation,
'SELECT 1',
CONCAT('ALTER TABLE aihr_broadcast_attachment_topic_tag CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @broadcast_delivery_target_collation)
);
PREPARE aihr_broadcast_delivery_stmt FROM @broadcast_delivery_ddl; EXECUTE aihr_broadcast_delivery_stmt; DEALLOCATE PREPARE aihr_broadcast_delivery_stmt;
SET @broadcast_access_audit_collation := (
SELECT table_collation FROM information_schema.tables
WHERE table_schema = DATABASE() AND table_name = 'aihr_broadcast_attachment_access_audit'
LIMIT 1
);
SET @broadcast_delivery_ddl := IF(
@broadcast_access_audit_collation = @broadcast_delivery_target_collation,
'SELECT 1',
CONCAT('ALTER TABLE aihr_broadcast_attachment_access_audit CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @broadcast_delivery_target_collation)
);
PREPARE aihr_broadcast_delivery_stmt FROM @broadcast_delivery_ddl; EXECUTE aihr_broadcast_delivery_stmt; DEALLOCATE PREPARE aihr_broadcast_delivery_stmt;
SET @has_broadcast_visibility_mode := NULL;
SET @has_broadcast_allow_download := NULL;
SET @broadcast_delivery_target_collation := NULL;
SET @broadcast_topic_tag_collation := NULL;
SET @broadcast_access_audit_collation := NULL;
SET @broadcast_delivery_ddl := NULL;
@@ -0,0 +1,95 @@
-- Separate reviewed experience candidates from the formal employee-visible library.
-- This migration adds metadata only; it does not approve or publish existing rows.
SET @aihr_case_governance_ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE()
AND table_name = 'aihr_case_record' AND column_name = 'knowledge_status'),
'ALTER TABLE `aihr_case_record` ADD COLUMN `knowledge_status` varchar(20) NOT NULL DEFAULT ''CANDIDATE'' COMMENT ''CANDIDATE/PUBLISHED/OFFLINE'' AFTER `summary`', 'SELECT 1');
PREPARE aihr_case_governance_stmt FROM @aihr_case_governance_ddl; EXECUTE aihr_case_governance_stmt; DEALLOCATE PREPARE aihr_case_governance_stmt;
SET @aihr_case_governance_ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE()
AND table_name = 'aihr_case_record' AND column_name = 'source_type'),
'ALTER TABLE `aihr_case_record` ADD COLUMN `source_type` varchar(40) DEFAULT NULL COMMENT ''经验来源类型'' AFTER `knowledge_status`', 'SELECT 1');
PREPARE aihr_case_governance_stmt FROM @aihr_case_governance_ddl; EXECUTE aihr_case_governance_stmt; DEALLOCATE PREPARE aihr_case_governance_stmt;
SET @aihr_case_governance_ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE()
AND table_name = 'aihr_case_record' AND column_name = 'applicable_positions'),
'ALTER TABLE `aihr_case_record` ADD COLUMN `applicable_positions` varchar(500) DEFAULT NULL COMMENT ''适用岗位'' AFTER `source_type`', 'SELECT 1');
PREPARE aihr_case_governance_stmt FROM @aihr_case_governance_ddl; EXECUTE aihr_case_governance_stmt; DEALLOCATE PREPARE aihr_case_governance_stmt;
SET @aihr_case_governance_ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE()
AND table_name = 'aihr_case_record' AND column_name = 'content_version'),
'ALTER TABLE `aihr_case_record` ADD COLUMN `content_version` varchar(50) DEFAULT NULL COMMENT ''正式经验版本'' AFTER `applicable_positions`', 'SELECT 1');
PREPARE aihr_case_governance_stmt FROM @aihr_case_governance_ddl; EXECUTE aihr_case_governance_stmt; DEALLOCATE PREPARE aihr_case_governance_stmt;
SET @aihr_case_governance_ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE()
AND table_name = 'aihr_case_record' AND column_name = 'source_authorized'),
'ALTER TABLE `aihr_case_record` ADD COLUMN `source_authorized` tinyint(1) NOT NULL DEFAULT 0 COMMENT ''来源已授权'' AFTER `content_version`', 'SELECT 1');
PREPARE aihr_case_governance_stmt FROM @aihr_case_governance_ddl; EXECUTE aihr_case_governance_stmt; DEALLOCATE PREPARE aihr_case_governance_stmt;
SET @aihr_case_governance_ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE()
AND table_name = 'aihr_case_record' AND column_name = 'deidentified'),
'ALTER TABLE `aihr_case_record` ADD COLUMN `deidentified` tinyint(1) NOT NULL DEFAULT 0 COMMENT ''内容已脱敏'' AFTER `source_authorized`', 'SELECT 1');
PREPARE aihr_case_governance_stmt FROM @aihr_case_governance_ddl; EXECUTE aihr_case_governance_stmt; DEALLOCATE PREPARE aihr_case_governance_stmt;
SET @aihr_case_governance_ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE()
AND table_name = 'aihr_case_record' AND column_name = 'effective_from'),
'ALTER TABLE `aihr_case_record` ADD COLUMN `effective_from` date DEFAULT NULL COMMENT ''生效日期'' AFTER `deidentified`', 'SELECT 1');
PREPARE aihr_case_governance_stmt FROM @aihr_case_governance_ddl; EXECUTE aihr_case_governance_stmt; DEALLOCATE PREPARE aihr_case_governance_stmt;
SET @aihr_case_governance_ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE()
AND table_name = 'aihr_case_record' AND column_name = 'effective_to'),
'ALTER TABLE `aihr_case_record` ADD COLUMN `effective_to` date DEFAULT NULL COMMENT ''失效日期'' AFTER `effective_from`', 'SELECT 1');
PREPARE aihr_case_governance_stmt FROM @aihr_case_governance_ddl; EXECUTE aihr_case_governance_stmt; DEALLOCATE PREPARE aihr_case_governance_stmt;
SET @aihr_case_governance_ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE()
AND table_name = 'aihr_case_record' AND column_name = 'release_owner'),
'ALTER TABLE `aihr_case_record` ADD COLUMN `release_owner` varchar(80) DEFAULT NULL COMMENT ''正式发布负责人'' AFTER `effective_to`', 'SELECT 1');
PREPARE aihr_case_governance_stmt FROM @aihr_case_governance_ddl; EXECUTE aihr_case_governance_stmt; DEALLOCATE PREPARE aihr_case_governance_stmt;
SET @aihr_case_governance_ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE()
AND table_name = 'aihr_case_record' AND column_name = 'release_note'),
'ALTER TABLE `aihr_case_record` ADD COLUMN `release_note` varchar(1000) DEFAULT NULL COMMENT ''正式发布说明'' AFTER `release_owner`', 'SELECT 1');
PREPARE aihr_case_governance_stmt FROM @aihr_case_governance_ddl; EXECUTE aihr_case_governance_stmt; DEALLOCATE PREPARE aihr_case_governance_stmt;
SET @aihr_case_governance_ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE()
AND table_name = 'aihr_case_record' AND column_name = 'released_by'),
'ALTER TABLE `aihr_case_record` ADD COLUMN `released_by` bigint DEFAULT NULL COMMENT ''正式发布操作人'' AFTER `release_note`', 'SELECT 1');
PREPARE aihr_case_governance_stmt FROM @aihr_case_governance_ddl; EXECUTE aihr_case_governance_stmt; DEALLOCATE PREPARE aihr_case_governance_stmt;
SET @aihr_case_governance_ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE()
AND table_name = 'aihr_case_record' AND column_name = 'released_time'),
'ALTER TABLE `aihr_case_record` ADD COLUMN `released_time` datetime DEFAULT NULL COMMENT ''正式发布时间'' AFTER `released_by`', 'SELECT 1');
PREPARE aihr_case_governance_stmt FROM @aihr_case_governance_ddl; EXECUTE aihr_case_governance_stmt; DEALLOCATE PREPARE aihr_case_governance_stmt;
SET @aihr_case_governance_ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE()
AND table_name = 'aihr_case_record' AND column_name = 'retire_reason'),
'ALTER TABLE `aihr_case_record` ADD COLUMN `retire_reason` varchar(500) DEFAULT NULL COMMENT ''下线原因'' AFTER `released_time`', 'SELECT 1');
PREPARE aihr_case_governance_stmt FROM @aihr_case_governance_ddl; EXECUTE aihr_case_governance_stmt; DEALLOCATE PREPARE aihr_case_governance_stmt;
SET @aihr_case_governance_index_exists := (
SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = 'aihr_case_record'
AND index_name = 'idx_aihr_case_knowledge_status'
);
SET @aihr_case_governance_ddl := IF(@aihr_case_governance_index_exists = 0,
'ALTER TABLE `aihr_case_record` ADD KEY `idx_aihr_case_knowledge_status` (`tenant_id`, `knowledge_status`, `effective_from`, `effective_to`)',
'SELECT 1');
PREPARE aihr_case_governance_stmt FROM @aihr_case_governance_ddl;
EXECUTE aihr_case_governance_stmt;
DEALLOCATE PREPARE aihr_case_governance_stmt;
SET @aihr_case_governance_index_exists := NULL;
SET @aihr_case_governance_ddl := NULL;
@@ -0,0 +1,114 @@
-- Link an authenticated negative knowledge-answer feedback to one moderated question-board item.
-- Additive and idempotent; existing questions keep no source linkage.
SET @aihr_column_exists := (
SELECT COUNT(*) FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_knowledge_answer_feedback'
AND column_name = 'request_id'
);
SET @aihr_ddl := IF(@aihr_column_exists = 0,
'ALTER TABLE `aihr_knowledge_answer_feedback` ADD COLUMN `request_id` varchar(64) DEFAULT NULL COMMENT ''知识查询请求ID'' AFTER `review_id`',
'SELECT 1');
PREPARE aihr_stmt FROM @aihr_ddl;
EXECUTE aihr_stmt;
DEALLOCATE PREPARE aihr_stmt;
SET @aihr_column_exists := (
SELECT COUNT(*) FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_knowledge_answer_feedback'
AND column_name = 'submitter_user_id'
);
SET @aihr_ddl := IF(@aihr_column_exists = 0,
'ALTER TABLE `aihr_knowledge_answer_feedback` ADD COLUMN `submitter_user_id` bigint DEFAULT NULL COMMENT ''反馈提交用户ID;历史记录为空'' AFTER `tenant_id`',
'SELECT 1');
PREPARE aihr_stmt FROM @aihr_ddl;
EXECUTE aihr_stmt;
DEALLOCATE PREPARE aihr_stmt;
SET @aihr_index_exists := (
SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = 'aihr_knowledge_answer_feedback'
AND index_name = 'uk_aihr_answer_feedback_pair'
);
SET @aihr_ddl := IF(@aihr_index_exists > 0,
'ALTER TABLE `aihr_knowledge_answer_feedback` DROP INDEX `uk_aihr_answer_feedback_pair`',
'SELECT 1');
PREPARE aihr_stmt FROM @aihr_ddl;
EXECUTE aihr_stmt;
DEALLOCATE PREPARE aihr_stmt;
SET @aihr_index_exists := (
SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = 'aihr_knowledge_answer_feedback'
AND index_name = 'uk_aihr_answer_feedback_user_request'
);
SET @aihr_ddl := IF(@aihr_index_exists = 0,
'ALTER TABLE `aihr_knowledge_answer_feedback` ADD UNIQUE KEY `uk_aihr_answer_feedback_user_request` (`tenant_id`, `submitter_user_id`, `request_id`, `fragment_id`)',
'SELECT 1');
PREPARE aihr_stmt FROM @aihr_ddl;
EXECUTE aihr_stmt;
DEALLOCATE PREPARE aihr_stmt;
SET @aihr_column_exists := (
SELECT COUNT(*) FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_community_question'
AND column_name = 'source_type'
);
SET @aihr_ddl := IF(@aihr_column_exists = 0,
'ALTER TABLE `aihr_community_question` ADD COLUMN `source_type` varchar(32) DEFAULT NULL COMMENT ''可信来源类型'' AFTER `question_type`',
'SELECT 1');
PREPARE aihr_stmt FROM @aihr_ddl;
EXECUTE aihr_stmt;
DEALLOCATE PREPARE aihr_stmt;
SET @aihr_column_exists := (
SELECT COUNT(*) FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_community_question'
AND column_name = 'source_request_id'
);
SET @aihr_ddl := IF(@aihr_column_exists = 0,
'ALTER TABLE `aihr_community_question` ADD COLUMN `source_request_id` varchar(64) DEFAULT NULL COMMENT ''知识查询请求ID'' AFTER `source_type`',
'SELECT 1');
PREPARE aihr_stmt FROM @aihr_ddl;
EXECUTE aihr_stmt;
DEALLOCATE PREPARE aihr_stmt;
SET @aihr_column_exists := (
SELECT COUNT(*) FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_community_question'
AND column_name = 'submit_idempotency_key'
);
SET @aihr_ddl := IF(@aihr_column_exists = 0,
'ALTER TABLE `aihr_community_question` ADD COLUMN `submit_idempotency_key` varchar(80) DEFAULT NULL COMMENT ''提交幂等键'' AFTER `source_request_id`',
'SELECT 1');
PREPARE aihr_stmt FROM @aihr_ddl;
EXECUTE aihr_stmt;
DEALLOCATE PREPARE aihr_stmt;
SET @aihr_index_exists := (
SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = 'aihr_community_question'
AND index_name = 'uk_aihr_community_question_source'
);
SET @aihr_ddl := IF(@aihr_index_exists = 0,
'ALTER TABLE `aihr_community_question` ADD UNIQUE KEY `uk_aihr_community_question_source` (`tenant_id`, `author_user_id`, `source_type`, `source_request_id`)',
'SELECT 1');
PREPARE aihr_stmt FROM @aihr_ddl;
EXECUTE aihr_stmt;
DEALLOCATE PREPARE aihr_stmt;
SET @aihr_index_exists := (
SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = 'aihr_community_question'
AND index_name = 'uk_aihr_community_question_submit_key'
);
SET @aihr_ddl := IF(@aihr_index_exists = 0,
'ALTER TABLE `aihr_community_question` ADD UNIQUE KEY `uk_aihr_community_question_submit_key` (`tenant_id`, `author_user_id`, `submit_idempotency_key`)',
'SELECT 1');
PREPARE aihr_stmt FROM @aihr_ddl;
EXECUTE aihr_stmt;
DEALLOCATE PREPARE aihr_stmt;
SET @aihr_column_exists := NULL;
SET @aihr_index_exists := NULL;
SET @aihr_ddl := NULL;
@@ -0,0 +1,113 @@
-- Learning task traceability and approved question-bank exam assembly.
-- Existing questions remain DRAFT and exam_disabled; migration never fabricates approval.
SET @aihr_schema := DATABASE();
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=@aihr_schema AND table_name='aihr_learning_question' AND column_name='exam_format')=0,
'ALTER TABLE aihr_learning_question ADD COLUMN exam_format varchar(20) DEFAULT NULL COMMENT ''single/multiple/judge/short'' AFTER sort_order', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=@aihr_schema AND table_name='aihr_learning_question' AND column_name='exam_options_json')=0,
'ALTER TABLE aihr_learning_question ADD COLUMN exam_options_json text COMMENT ''考试选项JSON'' AFTER exam_format', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=@aihr_schema AND table_name='aihr_learning_question' AND column_name='exam_answers_json')=0,
'ALTER TABLE aihr_learning_question ADD COLUMN exam_answers_json text COMMENT ''考试答案JSON'' AFTER exam_options_json', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=@aihr_schema AND table_name='aihr_learning_question' AND column_name='exam_explanation')=0,
'ALTER TABLE aihr_learning_question ADD COLUMN exam_explanation varchar(1000) DEFAULT NULL COMMENT ''考试解析'' AFTER exam_answers_json', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=@aihr_schema AND table_name='aihr_learning_question' AND column_name='exam_enabled')=0,
'ALTER TABLE aihr_learning_question ADD COLUMN exam_enabled tinyint NOT NULL DEFAULT 0 COMMENT ''是否可用于考试组卷'' AFTER exam_explanation', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=@aihr_schema AND table_name='aihr_learning_question' AND column_name='review_status')=0,
'ALTER TABLE aihr_learning_question ADD COLUMN review_status varchar(20) NOT NULL DEFAULT ''DRAFT'' COMMENT ''DRAFT/APPROVED/REJECTED'' AFTER exam_enabled', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=@aihr_schema AND table_name='aihr_learning_question' AND column_name='review_note')=0,
'ALTER TABLE aihr_learning_question ADD COLUMN review_note varchar(500) DEFAULT NULL COMMENT ''审核说明'' AFTER review_status', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=@aihr_schema AND table_name='aihr_learning_question' AND column_name='reviewed_by')=0,
'ALTER TABLE aihr_learning_question ADD COLUMN reviewed_by varchar(100) DEFAULT NULL COMMENT ''审核人'' AFTER review_note', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=@aihr_schema AND table_name='aihr_learning_question' AND column_name='reviewed_time')=0,
'ALTER TABLE aihr_learning_question ADD COLUMN reviewed_time datetime DEFAULT NULL COMMENT ''审核时间'' AFTER reviewed_by', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema=@aihr_schema AND table_name='aihr_learning_question' AND index_name='idx_aihr_learning_question_exam_pick')=0,
'ALTER TABLE aihr_learning_question ADD KEY idx_aihr_learning_question_exam_pick (tenant_id, position_code, review_status, exam_enabled, enabled, id)', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
CREATE TABLE IF NOT EXISTS aihr_exam_question_draw (
id bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
tenant_id varchar(20) NOT NULL DEFAULT '000000' COMMENT '租户编号',
owner_ext_party_id varchar(100) NOT NULL COMMENT '主管组织身份',
request_key varchar(100) NOT NULL COMMENT '抽题幂等键',
config_hash char(64) NOT NULL COMMENT '岗位、题型和题数配置哈希',
question_snapshot_json longtext NOT NULL COMMENT '审核题目完整快照',
create_time datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (id),
UNIQUE KEY uk_aihr_exam_question_draw_request (tenant_id, owner_ext_party_id, request_key)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='已审核题库随机组卷快照';
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=@aihr_schema AND table_name='aihr_onboard_exam_question' AND column_name='source_question_id')=0,
'ALTER TABLE aihr_onboard_exam_question ADD COLUMN source_question_id bigint DEFAULT NULL COMMENT ''题库来源主键'' AFTER sort_order', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=@aihr_schema AND table_name='aihr_onboard_exam_question' AND column_name='source_question_code')=0,
'ALTER TABLE aihr_onboard_exam_question ADD COLUMN source_question_code varchar(120) DEFAULT NULL COMMENT ''题库来源编码'' AFTER source_question_id', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=@aihr_schema AND table_name='aihr_onboard_exam_question' AND column_name='source_content_version')=0,
'ALTER TABLE aihr_onboard_exam_question ADD COLUMN source_content_version varchar(30) DEFAULT NULL COMMENT ''题库来源版本'' AFTER source_question_code', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=@aihr_schema AND table_name='aihr_onboard_exam_question' AND column_name='source_content_hash')=0,
'ALTER TABLE aihr_onboard_exam_question ADD COLUMN source_content_hash char(64) DEFAULT NULL COMMENT ''题库来源哈希'' AFTER source_content_version', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=@aihr_schema AND table_name='aihr_onboard_task' AND column_name='material_type')=0,
'ALTER TABLE aihr_onboard_task ADD COLUMN material_type varchar(20) DEFAULT NULL COMMENT ''DOCUMENT/VIDEO/COURSE/SOP'' AFTER course_id', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=@aihr_schema AND table_name='aihr_onboard_task' AND column_name='material_attachment_id')=0,
'ALTER TABLE aihr_onboard_task ADD COLUMN material_attachment_id bigint DEFAULT NULL COMMENT ''知识附件ID,受控读取'' AFTER material_type', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=@aihr_schema AND table_name='aihr_onboard_task' AND column_name='material_title')=0,
'ALTER TABLE aihr_onboard_task ADD COLUMN material_title varchar(200) DEFAULT NULL COMMENT ''材料标题快照'' AFTER material_attachment_id', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=@aihr_schema AND table_name='aihr_onboard_task' AND column_name='material_version')=0,
'ALTER TABLE aihr_onboard_task ADD COLUMN material_version varchar(50) DEFAULT NULL COMMENT ''材料版本快照'' AFTER material_title', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=@aihr_schema AND table_name='aihr_onboard_task' AND column_name='progress_percent')=0,
'ALTER TABLE aihr_onboard_task ADD COLUMN progress_percent int NOT NULL DEFAULT 0 COMMENT ''0-100学习进度'' AFTER material_version', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=@aihr_schema AND table_name='aihr_onboard_task' AND column_name='completion_rule')=0,
'ALTER TABLE aihr_onboard_task ADD COLUMN completion_rule varchar(30) NOT NULL DEFAULT ''MANUAL_CONFIRM'' COMMENT ''MANUAL_CONFIRM/EXAM_PASS'' AFTER progress_percent', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=@aihr_schema AND table_name='aihr_onboard_task' AND column_name='exam_id')=0,
'ALTER TABLE aihr_onboard_task ADD COLUMN exam_id bigint DEFAULT NULL COMMENT ''完成学习后关联考试'' AFTER completion_rule', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=@aihr_schema AND table_name='aihr_onboard_task' AND column_name='recurrence_type')=0,
'ALTER TABLE aihr_onboard_task ADD COLUMN recurrence_type varchar(20) NOT NULL DEFAULT ''ONCE'' COMMENT ''ONCE/DAILY/WEEKLY/MONTHLY'' AFTER exam_id', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=@aihr_schema AND table_name='aihr_onboard_task' AND column_name='dispatch_request_key')=0,
'ALTER TABLE aihr_onboard_task ADD COLUMN dispatch_request_key varchar(100) DEFAULT NULL COMMENT ''派发幂等键'' AFTER recurrence_type', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=@aihr_schema AND table_name='aihr_onboard_task' AND column_name='recurrence_series_key')=0,
'ALTER TABLE aihr_onboard_task ADD COLUMN recurrence_series_key varchar(100) DEFAULT NULL COMMENT ''周期任务系列键'' AFTER recurrence_type', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema=@aihr_schema AND table_name='aihr_onboard_task' AND index_name='uk_aihr_onboard_task_dispatch')=0,
'ALTER TABLE aihr_onboard_task ADD UNIQUE KEY uk_aihr_onboard_task_dispatch (tenant_id, ext_party_id, dispatch_request_key)', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema=@aihr_schema AND table_name='aihr_onboard_task' AND index_name='idx_aihr_onboard_task_due')=0,
'ALTER TABLE aihr_onboard_task ADD KEY idx_aihr_onboard_task_due (tenant_id, ext_party_id, status, due_time)', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-- Learning material viewing must be auditable and monotonic. These fields are
-- server-owned; the client only reports observed playback/read progress.
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=@aihr_schema AND table_name='aihr_onboard_task' AND column_name='started_time')=0,
'ALTER TABLE aihr_onboard_task ADD COLUMN started_time datetime DEFAULT NULL COMMENT ''材料首次打开时间'' AFTER progress_percent', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=@aihr_schema AND table_name='aihr_onboard_task' AND column_name='last_viewed_time')=0,
'ALTER TABLE aihr_onboard_task ADD COLUMN last_viewed_time datetime DEFAULT NULL COMMENT ''材料最近查看时间'' AFTER started_time', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=@aihr_schema AND table_name='aihr_onboard_task' AND column_name='last_position_seconds')=0,
'ALTER TABLE aihr_onboard_task ADD COLUMN last_position_seconds int NOT NULL DEFAULT 0 COMMENT ''视频最近播放位置'' AFTER last_viewed_time', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=@aihr_schema AND table_name='aihr_onboard_task' AND column_name='media_duration_seconds')=0,
'ALTER TABLE aihr_onboard_task ADD COLUMN media_duration_seconds int DEFAULT NULL COMMENT ''视频时长快照'' AFTER last_position_seconds', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;