DROP SCHEMA IF EXISTS course CASCADE; CREATE SCHEMA IF NOT EXISTS course; DROP TABLE IF EXISTS course.cl_course CASCADE; CREATE TABLE IF NOT EXISTS course.cl_course ( course_id VARCHAR(64) PRIMARY KEY, title VARCHAR(256) NOT NULL, subject_code VARCHAR(32) NOT NULL, grade_code VARCHAR(32) NOT NULL, difficulty_level VARCHAR(16), status VARCHAR(32) NOT NULL DEFAULT 'DRAFT', adcode VARCHAR(12) NOT NULL, tenant_id VARCHAR(64) NOT NULL, tenant_path VARCHAR(255) NOT NULL, dept_id VARCHAR(64), dept_path VARCHAR(255), created_by VARCHAR(64), created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ); COMMENT ON TABLE course.cl_course IS '课程主表'; COMMENT ON COLUMN course.cl_course.course_id IS '课程ID'; COMMENT ON COLUMN course.cl_course.title IS '课程标题'; COMMENT ON COLUMN course.cl_course.subject_code IS '学科编码'; COMMENT ON COLUMN course.cl_course.grade_code IS '年级编码'; COMMENT ON COLUMN course.cl_course.difficulty_level IS '难度等级'; COMMENT ON COLUMN course.cl_course.status IS '状态(DRAFT/PUBLISHED/ARCHIVED)'; COMMENT ON COLUMN course.cl_course.adcode IS '行政区划编码'; COMMENT ON COLUMN course.cl_course.tenant_id IS '租户ID'; COMMENT ON COLUMN course.cl_course.tenant_path IS '租户路径'; COMMENT ON COLUMN course.cl_course.dept_id IS '部门ID'; COMMENT ON COLUMN course.cl_course.dept_path IS '部门路径'; COMMENT ON COLUMN course.cl_course.created_by IS '创建人ID'; COMMENT ON COLUMN course.cl_course.created_at IS '创建时间'; DROP TABLE IF EXISTS course.cl_course_chapter CASCADE; CREATE TABLE IF NOT EXISTS course.cl_course_chapter ( chapter_id VARCHAR(64) PRIMARY KEY, course_id VARCHAR(64) NOT NULL, chapter_no INTEGER NOT NULL, chapter_title VARCHAR(256) NOT NULL, adcode VARCHAR(12) NOT NULL, tenant_id VARCHAR(64) NOT NULL, tenant_path VARCHAR(255) NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_cl_course_chapter_course FOREIGN KEY (course_id) REFERENCES course.cl_course(course_id) ); COMMENT ON TABLE course.cl_course_chapter IS '课程章节表'; COMMENT ON COLUMN course.cl_course_chapter.chapter_id IS '章节ID'; COMMENT ON COLUMN course.cl_course_chapter.course_id IS '课程ID'; COMMENT ON COLUMN course.cl_course_chapter.chapter_no IS '章节序号'; COMMENT ON COLUMN course.cl_course_chapter.chapter_title IS '章节标题'; COMMENT ON COLUMN course.cl_course_chapter.adcode IS '行政区划编码'; COMMENT ON COLUMN course.cl_course_chapter.tenant_id IS '租户ID'; COMMENT ON COLUMN course.cl_course_chapter.tenant_path IS '租户路径'; COMMENT ON COLUMN course.cl_course_chapter.created_at IS '创建时间'; DROP TABLE IF EXISTS course.cl_course_node CASCADE; CREATE TABLE IF NOT EXISTS course.cl_course_node ( node_id VARCHAR(64) PRIMARY KEY, chapter_id VARCHAR(64) NOT NULL, node_no INTEGER NOT NULL, node_title VARCHAR(256) NOT NULL, node_type VARCHAR(32) NOT NULL DEFAULT 'LESSON', class_type VARCHAR(32), duration_sec INTEGER, adcode VARCHAR(12) NOT NULL, tenant_id VARCHAR(64) NOT NULL, tenant_path VARCHAR(255) NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT chk_cl_course_node_type CHECK (node_type IN ('LESSON', 'IN_CLASS_ACTIVITY', 'AFTER_CLASS_TASK', 'MATERIAL', 'OTHER')), CONSTRAINT fk_cl_course_node_chapter FOREIGN KEY (chapter_id) REFERENCES course.cl_course_chapter(chapter_id) ); COMMENT ON TABLE course.cl_course_node IS '课程学习节点表'; COMMENT ON COLUMN course.cl_course_node.node_id IS '学习节点ID'; COMMENT ON COLUMN course.cl_course_node.chapter_id IS '章节ID'; COMMENT ON COLUMN course.cl_course_node.node_no IS '节点序号'; COMMENT ON COLUMN course.cl_course_node.node_title IS '节点标题'; COMMENT ON COLUMN course.cl_course_node.node_type IS '节点类型(LESSON/IN_CLASS_ACTIVITY/AFTER_CLASS_TASK/MATERIAL/OTHER)'; COMMENT ON COLUMN course.cl_course_node.class_type IS '课堂类型(如讲授/讨论/测验)'; COMMENT ON COLUMN course.cl_course_node.duration_sec IS '时长(秒)'; COMMENT ON COLUMN course.cl_course_node.adcode IS '行政区划编码'; COMMENT ON COLUMN course.cl_course_node.tenant_id IS '租户ID'; COMMENT ON COLUMN course.cl_course_node.tenant_path IS '租户路径'; COMMENT ON COLUMN course.cl_course_node.created_at IS '创建时间'; DROP TABLE IF EXISTS course.cl_knowledge_point CASCADE; CREATE TABLE IF NOT EXISTS course.cl_knowledge_point ( kp_id VARCHAR(64) PRIMARY KEY, kp_code VARCHAR(64) NOT NULL, kp_name VARCHAR(256) NOT NULL, kp_alias VARCHAR(256), kp_type VARCHAR(32) NOT NULL DEFAULT 'ATOMIC', parent_kp_id VARCHAR(64), kp_path VARCHAR(512), kp_desc TEXT, subject_code VARCHAR(32) NOT NULL, grade_code VARCHAR(32) NOT NULL, difficulty_level VARCHAR(16), importance_level NUMERIC(6,4) NOT NULL DEFAULT 1.0000, graph_entity_id VARCHAR(64), source_db VARCHAR(64) NOT NULL DEFAULT 'postgresql', source_table VARCHAR(128) NOT NULL DEFAULT 'course.cl_knowledge_point', source_pk VARCHAR(128), metadata_json JSONB NOT NULL DEFAULT '{}'::JSONB, status VARCHAR(32) NOT NULL DEFAULT 'ACTIVE', adcode VARCHAR(12) NOT NULL, tenant_id VARCHAR(64) NOT NULL, tenant_path VARCHAR(255) NOT NULL, dept_id VARCHAR(64), dept_path VARCHAR(255), created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT uq_cl_knowledge_point_tenant_code UNIQUE (tenant_id, kp_code), CONSTRAINT uq_cl_knowledge_point_tenant_graph_entity UNIQUE (tenant_id, graph_entity_id), CONSTRAINT chk_cl_knowledge_point_type CHECK (kp_type IN ('DOMAIN', 'TOPIC', 'ATOMIC')), CONSTRAINT chk_cl_knowledge_point_importance CHECK (importance_level > 0 AND importance_level <= 1), CONSTRAINT chk_cl_knowledge_point_metadata_json CHECK (jsonb_typeof(metadata_json) = 'object'), CONSTRAINT fk_cl_knowledge_point_parent FOREIGN KEY (parent_kp_id) REFERENCES course.cl_knowledge_point(kp_id) ON DELETE SET NULL ); COMMENT ON TABLE course.cl_knowledge_point IS '知识点表'; COMMENT ON COLUMN course.cl_knowledge_point.kp_id IS '知识点ID'; COMMENT ON COLUMN course.cl_knowledge_point.kp_code IS '知识点编码'; COMMENT ON COLUMN course.cl_knowledge_point.kp_name IS '知识点名称'; COMMENT ON COLUMN course.cl_knowledge_point.kp_alias IS '知识点别名'; COMMENT ON COLUMN course.cl_knowledge_point.kp_type IS '知识点类型(DOMAIN/TOPIC/ATOMIC)'; COMMENT ON COLUMN course.cl_knowledge_point.parent_kp_id IS '父知识点ID'; COMMENT ON COLUMN course.cl_knowledge_point.kp_path IS '知识点树路径'; COMMENT ON COLUMN course.cl_knowledge_point.kp_desc IS '知识点描述'; COMMENT ON COLUMN course.cl_knowledge_point.subject_code IS '学科编码'; COMMENT ON COLUMN course.cl_knowledge_point.grade_code IS '年级编码'; COMMENT ON COLUMN course.cl_knowledge_point.difficulty_level IS '难度等级'; COMMENT ON COLUMN course.cl_knowledge_point.importance_level IS '重要性权重(0,1]'; COMMENT ON COLUMN course.cl_knowledge_point.graph_entity_id IS '图谱实体ID(Nebula/Neo4j 映射)'; COMMENT ON COLUMN course.cl_knowledge_point.source_db IS '来源数据库'; COMMENT ON COLUMN course.cl_knowledge_point.source_table IS '来源表'; COMMENT ON COLUMN course.cl_knowledge_point.source_pk IS '来源主键'; COMMENT ON COLUMN course.cl_knowledge_point.metadata_json IS '扩展元数据JSON'; COMMENT ON COLUMN course.cl_knowledge_point.status IS '状态(ACTIVE/DISABLED)'; COMMENT ON COLUMN course.cl_knowledge_point.adcode IS '行政区划编码'; COMMENT ON COLUMN course.cl_knowledge_point.tenant_id IS '租户ID'; COMMENT ON COLUMN course.cl_knowledge_point.tenant_path IS '租户路径'; COMMENT ON COLUMN course.cl_knowledge_point.dept_id IS '部门ID'; COMMENT ON COLUMN course.cl_knowledge_point.dept_path IS '部门路径'; COMMENT ON COLUMN course.cl_knowledge_point.created_at IS '创建时间'; COMMENT ON COLUMN course.cl_knowledge_point.updated_at IS '更新时间'; DROP TABLE IF EXISTS course.cl_chapter_kp_rel CASCADE; CREATE TABLE IF NOT EXISTS course.cl_chapter_kp_rel ( chapter_id VARCHAR(64) NOT NULL, kp_id VARCHAR(64) NOT NULL, relation_type VARCHAR(32) NOT NULL DEFAULT 'TEACHES', weight NUMERIC(6,4) NOT NULL DEFAULT 1.0000, is_core BOOLEAN NOT NULL DEFAULT FALSE, tenant_id VARCHAR(64) NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (chapter_id, kp_id), CONSTRAINT chk_cl_chapter_kp_rel_type CHECK (relation_type IN ('TEACHES', 'REVIEWS', 'EXTENDS')), CONSTRAINT chk_cl_chapter_kp_rel_weight CHECK (weight > 0 AND weight <= 1), CONSTRAINT fk_cl_chapter_kp_rel_chapter FOREIGN KEY (chapter_id) REFERENCES course.cl_course_chapter(chapter_id), CONSTRAINT fk_cl_chapter_kp_rel_kp FOREIGN KEY (kp_id) REFERENCES course.cl_knowledge_point(kp_id) ); COMMENT ON TABLE course.cl_chapter_kp_rel IS '章节-知识点关联表'; COMMENT ON COLUMN course.cl_chapter_kp_rel.chapter_id IS '章节ID'; COMMENT ON COLUMN course.cl_chapter_kp_rel.kp_id IS '知识点ID'; COMMENT ON COLUMN course.cl_chapter_kp_rel.relation_type IS '关系类型(TEACHES/REVIEWS/EXTENDS)'; COMMENT ON COLUMN course.cl_chapter_kp_rel.weight IS '关联权重(0,1]'; COMMENT ON COLUMN course.cl_chapter_kp_rel.is_core IS '是否核心知识点'; COMMENT ON COLUMN course.cl_chapter_kp_rel.tenant_id IS '租户ID'; COMMENT ON COLUMN course.cl_chapter_kp_rel.created_at IS '创建时间'; COMMENT ON COLUMN course.cl_chapter_kp_rel.updated_at IS '更新时间'; DROP TABLE IF EXISTS course.cl_student_kp_mastery CASCADE; CREATE TABLE IF NOT EXISTS course.cl_student_kp_mastery ( mastery_id VARCHAR(64) PRIMARY KEY, student_id VARCHAR(64) NOT NULL, kp_id VARCHAR(64) NOT NULL, mastery_score NUMERIC(6,4) NOT NULL DEFAULT 0, mastery_level VARCHAR(16) NOT NULL DEFAULT 'UNKNOWN', mastery_status VARCHAR(16) NOT NULL DEFAULT 'LEARNING', evidence_json JSONB NOT NULL DEFAULT '{}'::JSONB, last_source_type VARCHAR(32), last_source_id VARCHAR(64), last_assessed_at TIMESTAMP, adcode VARCHAR(12) NOT NULL, tenant_id VARCHAR(64) NOT NULL, tenant_path VARCHAR(255) NOT NULL, dept_id VARCHAR(64), dept_path VARCHAR(255), created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT uq_cl_student_kp_mastery_student_kp UNIQUE (student_id, kp_id), CONSTRAINT chk_cl_student_kp_mastery_score CHECK (mastery_score >= 0 AND mastery_score <= 1), CONSTRAINT chk_cl_student_kp_mastery_level CHECK (mastery_level IN ('UNKNOWN', 'LOW', 'MEDIUM', 'HIGH', 'MASTERED')), CONSTRAINT chk_cl_student_kp_mastery_status CHECK (mastery_status IN ('LEARNING', 'STABLE', 'FORGOTTEN')), CONSTRAINT chk_cl_student_kp_mastery_evidence_json CHECK (jsonb_typeof(evidence_json) = 'object'), CONSTRAINT fk_cl_student_kp_mastery_student FOREIGN KEY (student_id) REFERENCES upms.tb_sys_user(user_id), CONSTRAINT fk_cl_student_kp_mastery_kp FOREIGN KEY (kp_id) REFERENCES course.cl_knowledge_point(kp_id) ); COMMENT ON TABLE course.cl_student_kp_mastery IS '学生知识点掌握度表'; COMMENT ON COLUMN course.cl_student_kp_mastery.mastery_id IS '掌握度记录ID'; COMMENT ON COLUMN course.cl_student_kp_mastery.student_id IS '学生ID'; COMMENT ON COLUMN course.cl_student_kp_mastery.kp_id IS '知识点ID'; COMMENT ON COLUMN course.cl_student_kp_mastery.mastery_score IS '掌握度分值(0-1)'; COMMENT ON COLUMN course.cl_student_kp_mastery.mastery_level IS '掌握等级'; COMMENT ON COLUMN course.cl_student_kp_mastery.mastery_status IS '掌握状态(LEARNING/STABLE/FORGOTTEN)'; COMMENT ON COLUMN course.cl_student_kp_mastery.evidence_json IS '证据数据JSON(错题、批改、学习行为等)'; COMMENT ON COLUMN course.cl_student_kp_mastery.last_source_type IS '最近更新来源类型'; COMMENT ON COLUMN course.cl_student_kp_mastery.last_source_id IS '最近更新来源ID'; COMMENT ON COLUMN course.cl_student_kp_mastery.last_assessed_at IS '最近评估时间'; COMMENT ON COLUMN course.cl_student_kp_mastery.adcode IS '行政区划编码'; COMMENT ON COLUMN course.cl_student_kp_mastery.tenant_id IS '租户ID'; COMMENT ON COLUMN course.cl_student_kp_mastery.tenant_path IS '租户路径'; COMMENT ON COLUMN course.cl_student_kp_mastery.dept_id IS '部门ID'; COMMENT ON COLUMN course.cl_student_kp_mastery.dept_path IS '部门路径'; COMMENT ON COLUMN course.cl_student_kp_mastery.created_at IS '创建时间'; COMMENT ON COLUMN course.cl_student_kp_mastery.updated_at IS '更新时间'; DROP TABLE IF EXISTS course.cl_kp_material_rel CASCADE; CREATE TABLE IF NOT EXISTS course.cl_kp_material_rel ( rel_id VARCHAR(64) PRIMARY KEY, kp_id VARCHAR(64) NOT NULL, material_type VARCHAR(32) NOT NULL, material_ref_id VARCHAR(64) NOT NULL, material_uri VARCHAR(512), weight NUMERIC(6,4) NOT NULL DEFAULT 1.0000, source_table VARCHAR(128), source_pk VARCHAR(128), tenant_id VARCHAR(64) NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT chk_cl_kp_material_rel_type CHECK (material_type IN ('VECTOR_DOCUMENT', 'VECTOR_CHUNK', 'COURSE_RESOURCE', 'EXTERNAL_URI')), CONSTRAINT chk_cl_kp_material_rel_weight CHECK (weight > 0 AND weight <= 1), CONSTRAINT fk_cl_kp_material_rel_kp FOREIGN KEY (kp_id) REFERENCES course.cl_knowledge_point(kp_id) ); COMMENT ON TABLE course.cl_kp_material_rel IS '知识点-学习资料关联表'; COMMENT ON COLUMN course.cl_kp_material_rel.rel_id IS '关联ID'; COMMENT ON COLUMN course.cl_kp_material_rel.kp_id IS '知识点ID'; COMMENT ON COLUMN course.cl_kp_material_rel.material_type IS '资料类型(VECTOR_DOCUMENT/VECTOR_CHUNK/COURSE_RESOURCE/EXTERNAL_URI)'; COMMENT ON COLUMN course.cl_kp_material_rel.material_ref_id IS '资料对象ID'; COMMENT ON COLUMN course.cl_kp_material_rel.material_uri IS '资料URI'; COMMENT ON COLUMN course.cl_kp_material_rel.weight IS '关联权重(0,1]'; COMMENT ON COLUMN course.cl_kp_material_rel.source_table IS '来源表'; COMMENT ON COLUMN course.cl_kp_material_rel.source_pk IS '来源主键'; COMMENT ON COLUMN course.cl_kp_material_rel.tenant_id IS '租户ID'; COMMENT ON COLUMN course.cl_kp_material_rel.created_at IS '创建时间'; COMMENT ON COLUMN course.cl_kp_material_rel.updated_at IS '更新时间'; DROP TABLE IF EXISTS course.cl_course_knowledge_rel CASCADE; CREATE TABLE IF NOT EXISTS course.cl_course_knowledge_rel ( course_id VARCHAR(64) NOT NULL, kp_id VARCHAR(64) NOT NULL, weight NUMERIC(6,4) NOT NULL DEFAULT 1.0000, tenant_id VARCHAR(64) NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (course_id, kp_id), CONSTRAINT chk_cl_course_knowledge_rel_weight CHECK (weight > 0 AND weight <= 1), CONSTRAINT fk_cl_course_knowledge_rel_course FOREIGN KEY (course_id) REFERENCES course.cl_course(course_id), CONSTRAINT fk_cl_course_knowledge_rel_kp FOREIGN KEY (kp_id) REFERENCES course.cl_knowledge_point(kp_id) ); COMMENT ON TABLE course.cl_course_knowledge_rel IS '课程-知识点关联表'; COMMENT ON COLUMN course.cl_course_knowledge_rel.course_id IS '课程ID'; COMMENT ON COLUMN course.cl_course_knowledge_rel.kp_id IS '知识点ID'; COMMENT ON COLUMN course.cl_course_knowledge_rel.weight IS '关联权重(0,1])'; COMMENT ON COLUMN course.cl_course_knowledge_rel.tenant_id IS '租户ID'; COMMENT ON COLUMN course.cl_course_knowledge_rel.created_at IS '创建时间'; DROP TABLE IF EXISTS course.cl_course_tag CASCADE; CREATE TABLE IF NOT EXISTS course.cl_course_tag ( tag_id VARCHAR(64) PRIMARY KEY, tag_name VARCHAR(128) NOT NULL, tag_type VARCHAR(32) NOT NULL, tenant_id VARCHAR(64) NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ); COMMENT ON TABLE course.cl_course_tag IS '课程标签表'; COMMENT ON COLUMN course.cl_course_tag.tag_id IS '标签ID'; COMMENT ON COLUMN course.cl_course_tag.tag_name IS '标签名称'; COMMENT ON COLUMN course.cl_course_tag.tag_type IS '标签类型'; COMMENT ON COLUMN course.cl_course_tag.tenant_id IS '租户ID'; COMMENT ON COLUMN course.cl_course_tag.created_at IS '创建时间'; DROP TABLE IF EXISTS course.cl_course_tag_rel CASCADE; CREATE TABLE IF NOT EXISTS course.cl_course_tag_rel ( course_id VARCHAR(64) NOT NULL, tag_id VARCHAR(64) NOT NULL, tenant_id VARCHAR(64) NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (course_id, tag_id), CONSTRAINT fk_cl_course_tag_rel_course FOREIGN KEY (course_id) REFERENCES course.cl_course(course_id), CONSTRAINT fk_cl_course_tag_rel_tag FOREIGN KEY (tag_id) REFERENCES course.cl_course_tag(tag_id) ); COMMENT ON TABLE course.cl_course_tag_rel IS '课程-标签关联表'; COMMENT ON COLUMN course.cl_course_tag_rel.course_id IS '课程ID'; COMMENT ON COLUMN course.cl_course_tag_rel.tag_id IS '标签ID'; COMMENT ON COLUMN course.cl_course_tag_rel.tenant_id IS '租户ID'; COMMENT ON COLUMN course.cl_course_tag_rel.created_at IS '创建时间'; DROP TABLE IF EXISTS course.cl_node_resource CASCADE; CREATE TABLE IF NOT EXISTS course.cl_node_resource ( resource_id VARCHAR(64) PRIMARY KEY, node_id VARCHAR(64) NOT NULL, resource_type VARCHAR(32) NOT NULL, file_id VARCHAR(64), resource_url VARCHAR(512), resource_title VARCHAR(256), tenant_id VARCHAR(64) NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT chk_cl_node_resource_type CHECK (resource_type IN ('PDF', 'VIDEO', 'DOC', 'IMAGE', 'LINK', 'OTHER')), CONSTRAINT chk_cl_node_resource_ref CHECK (file_id IS NOT NULL OR resource_url IS NOT NULL), CONSTRAINT fk_cl_node_resource_node FOREIGN KEY (node_id) REFERENCES course.cl_course_node(node_id), CONSTRAINT fk_cl_node_resource_file FOREIGN KEY (file_id) REFERENCES upms.tb_sys_file(file_id) ); COMMENT ON TABLE course.cl_node_resource IS '学习节点资源表'; COMMENT ON COLUMN course.cl_node_resource.resource_id IS '资源ID'; COMMENT ON COLUMN course.cl_node_resource.node_id IS '学习节点ID'; COMMENT ON COLUMN course.cl_node_resource.resource_type IS '资源类型(PDF/VIDEO/DOC/IMAGE/LINK/OTHER)'; COMMENT ON COLUMN course.cl_node_resource.file_id IS '资源文件ID'; COMMENT ON COLUMN course.cl_node_resource.resource_url IS '资源地址'; COMMENT ON COLUMN course.cl_node_resource.resource_title IS '资源标题'; COMMENT ON COLUMN course.cl_node_resource.tenant_id IS '租户ID'; COMMENT ON COLUMN course.cl_node_resource.created_at IS '创建时间'; DROP TABLE IF EXISTS course.cl_node_kp_rel CASCADE; CREATE TABLE IF NOT EXISTS course.cl_node_kp_rel ( node_id VARCHAR(64) NOT NULL, kp_id VARCHAR(64) NOT NULL, relation_type VARCHAR(32) NOT NULL DEFAULT 'TEACHES', weight NUMERIC(6,4) NOT NULL DEFAULT 1.0000, tenant_id VARCHAR(64) NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (node_id, kp_id), CONSTRAINT chk_cl_node_kp_rel_type CHECK (relation_type IN ('TEACHES', 'PRACTICES', 'REVIEWS')), CONSTRAINT chk_cl_node_kp_rel_weight CHECK (weight > 0 AND weight <= 1), CONSTRAINT fk_cl_node_kp_rel_node FOREIGN KEY (node_id) REFERENCES course.cl_course_node(node_id), CONSTRAINT fk_cl_node_kp_rel_kp FOREIGN KEY (kp_id) REFERENCES course.cl_knowledge_point(kp_id) ); COMMENT ON TABLE course.cl_node_kp_rel IS '学习节点-知识点关联表'; COMMENT ON COLUMN course.cl_node_kp_rel.node_id IS '学习节点ID'; COMMENT ON COLUMN course.cl_node_kp_rel.kp_id IS '知识点ID'; COMMENT ON COLUMN course.cl_node_kp_rel.relation_type IS '关系类型(TEACHES/PRACTICES/REVIEWS)'; COMMENT ON COLUMN course.cl_node_kp_rel.weight IS '关联权重(0,1]'; COMMENT ON COLUMN course.cl_node_kp_rel.tenant_id IS '租户ID'; COMMENT ON COLUMN course.cl_node_kp_rel.created_at IS '创建时间'; DROP TABLE IF EXISTS course.cl_node_homework_rel CASCADE; CREATE TABLE IF NOT EXISTS course.cl_node_homework_rel ( node_id VARCHAR(64) NOT NULL, assignment_id VARCHAR(64) NOT NULL, relation_type VARCHAR(32) NOT NULL DEFAULT 'AFTER_CLASS', tenant_id VARCHAR(64) NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (node_id, assignment_id), CONSTRAINT chk_cl_node_homework_rel_type CHECK (relation_type IN ('IN_CLASS', 'AFTER_CLASS')), CONSTRAINT fk_cl_node_homework_rel_node FOREIGN KEY (node_id) REFERENCES course.cl_course_node(node_id) ); COMMENT ON TABLE course.cl_node_homework_rel IS '学习节点-作业关联表'; COMMENT ON COLUMN course.cl_node_homework_rel.node_id IS '学习节点ID'; COMMENT ON COLUMN course.cl_node_homework_rel.assignment_id IS '作业ID(question.hw_assignment.assignment_id)'; COMMENT ON COLUMN course.cl_node_homework_rel.relation_type IS '关系类型(IN_CLASS/AFTER_CLASS)'; COMMENT ON COLUMN course.cl_node_homework_rel.tenant_id IS '租户ID'; COMMENT ON COLUMN course.cl_node_homework_rel.created_at IS '创建时间'; DROP TABLE IF EXISTS course.cl_learning_session CASCADE; CREATE TABLE IF NOT EXISTS course.cl_learning_session ( session_id VARCHAR(64) PRIMARY KEY, user_id VARCHAR(64) NOT NULL, course_id VARCHAR(64) NOT NULL, status VARCHAR(32) NOT NULL DEFAULT 'STARTED', started_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, ended_at TIMESTAMP, adcode VARCHAR(12) NOT NULL, tenant_id VARCHAR(64) NOT NULL, tenant_path VARCHAR(255) NOT NULL, dept_id VARCHAR(64), dept_path VARCHAR(255), CONSTRAINT fk_cl_learning_session_user FOREIGN KEY (user_id) REFERENCES upms.tb_sys_user(user_id), CONSTRAINT fk_cl_learning_session_course FOREIGN KEY (course_id) REFERENCES course.cl_course(course_id) ); COMMENT ON TABLE course.cl_learning_session IS '学习会话表'; COMMENT ON COLUMN course.cl_learning_session.session_id IS '会话ID'; COMMENT ON COLUMN course.cl_learning_session.user_id IS '学员ID'; COMMENT ON COLUMN course.cl_learning_session.course_id IS '课程ID'; COMMENT ON COLUMN course.cl_learning_session.status IS '会话状态(STARTED/PAUSED/COMPLETED)'; COMMENT ON COLUMN course.cl_learning_session.started_at IS '开始时间'; COMMENT ON COLUMN course.cl_learning_session.ended_at IS '结束时间'; COMMENT ON COLUMN course.cl_learning_session.adcode IS '行政区划编码'; COMMENT ON COLUMN course.cl_learning_session.tenant_id IS '租户ID'; COMMENT ON COLUMN course.cl_learning_session.tenant_path IS '租户路径'; COMMENT ON COLUMN course.cl_learning_session.dept_id IS '部门ID'; COMMENT ON COLUMN course.cl_learning_session.dept_path IS '部门路径'; DROP TABLE IF EXISTS course.cl_learning_progress CASCADE; CREATE TABLE IF NOT EXISTS course.cl_learning_progress ( progress_id VARCHAR(64) PRIMARY KEY, session_id VARCHAR(64) NOT NULL, node_id VARCHAR(64) NOT NULL, progress_pct NUMERIC(5,2) NOT NULL DEFAULT 0, last_position_sec INTEGER NOT NULL DEFAULT 0, mastery_level VARCHAR(16), tenant_id VARCHAR(64) NOT NULL, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_cl_learning_progress_session FOREIGN KEY (session_id) REFERENCES course.cl_learning_session(session_id), CONSTRAINT fk_cl_learning_progress_node FOREIGN KEY (node_id) REFERENCES course.cl_course_node(node_id) ); COMMENT ON TABLE course.cl_learning_progress IS '学习进度表'; COMMENT ON COLUMN course.cl_learning_progress.progress_id IS '进度ID'; COMMENT ON COLUMN course.cl_learning_progress.session_id IS '学习会话ID'; COMMENT ON COLUMN course.cl_learning_progress.node_id IS '学习节点ID'; COMMENT ON COLUMN course.cl_learning_progress.progress_pct IS '进度百分比'; COMMENT ON COLUMN course.cl_learning_progress.last_position_sec IS '最后学习位置(秒)'; COMMENT ON COLUMN course.cl_learning_progress.mastery_level IS '掌握等级'; COMMENT ON COLUMN course.cl_learning_progress.tenant_id IS '租户ID'; COMMENT ON COLUMN course.cl_learning_progress.updated_at IS '更新时间'; DROP TABLE IF EXISTS course.cl_learning_event CASCADE; CREATE TABLE IF NOT EXISTS course.cl_learning_event ( event_id VARCHAR(64) PRIMARY KEY, session_id VARCHAR(64) NOT NULL, event_type VARCHAR(32) NOT NULL, event_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, payload_json JSONB, tenant_id VARCHAR(64) NOT NULL, CONSTRAINT fk_cl_learning_event_session FOREIGN KEY (session_id) REFERENCES course.cl_learning_session(session_id) ); COMMENT ON TABLE course.cl_learning_event IS '学习行为事件表'; COMMENT ON COLUMN course.cl_learning_event.event_id IS '事件ID'; COMMENT ON COLUMN course.cl_learning_event.session_id IS '会话ID'; COMMENT ON COLUMN course.cl_learning_event.event_type IS '事件类型(start/pause/seek/finish)'; COMMENT ON COLUMN course.cl_learning_event.event_time IS '事件时间'; COMMENT ON COLUMN course.cl_learning_event.payload_json IS '事件扩展信息'; COMMENT ON COLUMN course.cl_learning_event.tenant_id IS '租户ID'; CREATE INDEX IF NOT EXISTS idx_cl_course_tenant_subject_grade ON course.cl_course(tenant_id, subject_code, grade_code); CREATE INDEX IF NOT EXISTS idx_cl_course_chapter_course_no ON course.cl_course_chapter(course_id, chapter_no); CREATE INDEX IF NOT EXISTS idx_cl_course_node_chapter_no ON course.cl_course_node(chapter_id, node_no); CREATE INDEX IF NOT EXISTS idx_cl_knowledge_point_subject_grade ON course.cl_knowledge_point(tenant_id, subject_code, grade_code); CREATE INDEX IF NOT EXISTS idx_cl_knowledge_point_parent ON course.cl_knowledge_point(tenant_id, parent_kp_id); CREATE INDEX IF NOT EXISTS idx_cl_knowledge_point_graph_entity ON course.cl_knowledge_point(tenant_id, graph_entity_id); CREATE INDEX IF NOT EXISTS idx_cl_chapter_kp_rel_chapter ON course.cl_chapter_kp_rel(tenant_id, chapter_id, relation_type); CREATE INDEX IF NOT EXISTS idx_cl_chapter_kp_rel_kp ON course.cl_chapter_kp_rel(tenant_id, kp_id, relation_type); CREATE INDEX IF NOT EXISTS idx_cl_student_kp_mastery_student ON course.cl_student_kp_mastery(tenant_id, student_id, mastery_score DESC); CREATE INDEX IF NOT EXISTS idx_cl_student_kp_mastery_kp ON course.cl_student_kp_mastery(tenant_id, kp_id, mastery_score DESC); CREATE INDEX IF NOT EXISTS idx_cl_kp_material_rel_kp ON course.cl_kp_material_rel(tenant_id, kp_id, material_type); CREATE INDEX IF NOT EXISTS idx_cl_node_resource_node ON course.cl_node_resource(node_id, resource_type); CREATE INDEX IF NOT EXISTS idx_cl_node_kp_rel_node ON course.cl_node_kp_rel(tenant_id, node_id, relation_type); CREATE INDEX IF NOT EXISTS idx_cl_node_kp_rel_kp ON course.cl_node_kp_rel(tenant_id, kp_id, relation_type); CREATE INDEX IF NOT EXISTS idx_cl_node_homework_rel_node ON course.cl_node_homework_rel(tenant_id, node_id, relation_type); CREATE INDEX IF NOT EXISTS idx_cl_learning_session_user_course ON course.cl_learning_session(tenant_id, user_id, course_id); CREATE INDEX IF NOT EXISTS idx_cl_learning_progress_session_node ON course.cl_learning_progress(session_id, node_id); CREATE INDEX IF NOT EXISTS idx_cl_learning_event_session_time ON course.cl_learning_event(session_id, event_time DESC);