Files
ruoyi-vue-pro/sql/mysql/education/004-education-submit-report.sql

165 lines
10 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- =============================================
-- Education 模块 — 交卷提交与成绩报告 DDL
-- Ticket #8: 交卷 CAS、保护性答案快照、评分与报告
-- Migration: 004
-- Prerequisites: 003-education-answer-idempotency.sql
-- =============================================
-- =============================================
-- Preconditions
-- =============================================
-- Operator is expected to verify:
-- SELECT COUNT(*) FROM information_schema.tables
-- WHERE table_schema = DATABASE()
-- AND table_name IN ('education_submit_idempotency',
-- 'education_practice_report',
-- 'education_practice_report_detail');
-- Result MUST be 0 before executing this migration.
--
-- Verify prerequisite tables exist:
-- SELECT COUNT(*) FROM information_schema.tables
-- WHERE table_schema = DATABASE()
-- AND table_name IN ('education_practice_session',
-- 'education_practice_question',
-- 'education_answer_idempotency');
-- Result MUST be 3.
-- =============================================
-- PracticeQuestionDO: add protected answer snapshot columns
-- =============================================
-- Purpose: At session creation, snapshot correct_answer and explanation
-- from the full CatalogQuestionDTO. These fields are NEVER exposed
-- before submission (enforced by SafeQuestionRespVO allow-list and
-- PracticeQuestionRespVO which does not include them).
ALTER TABLE `education_practice_question`
ADD COLUMN `correct_answer` TEXT DEFAULT NULL COMMENT '正确答案快照(不可在交卷前暴露)',
ADD COLUMN `explanation` TEXT DEFAULT NULL COMMENT '解析快照(不可在交卷前暴露)';
-- =============================================
-- 交卷幂等表
-- =============================================
-- Purpose: Provide durable idempotency for submit-session commands.
-- Same (tenant, user, operation, idempotency_key) + same request_hash → replay original report.
-- Same key + different request_hash → conflict.
-- Concurrent same-key inserts resolved by unique constraint race handling.
--
-- Indexes:
-- uk_submit_idempotency — per-tenant, per-actor, per-operation uniqueness for idempotency key.
-- INSERT during submit. DuplicateKeyException catch for concurrent-create race resolution.
-- idx_submit_session — covers lookup by session for audit/debug.
CREATE TABLE `education_submit_idempotency` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
`tenant_id` BIGINT NOT NULL COMMENT '租户编号',
`user_id` BIGINT NOT NULL COMMENT '交卷用户编号',
`operation` VARCHAR(32) NOT NULL DEFAULT 'SUBMIT_SESSION'
COMMENT '操作类型SUBMIT_SESSION',
`idempotency_key` VARCHAR(64) NOT NULL COMMENT '客户端幂等键UUID',
`request_hash` VARCHAR(64) NOT NULL COMMENT '请求载荷 SHA-256 哈希',
`session_id` BIGINT NOT NULL COMMENT '会话 ID',
`report_id` BIGINT DEFAULT NULL COMMENT '关联的报告 ID成功时有值',
`status` VARCHAR(20) NOT NULL DEFAULT 'ACCEPTED'
COMMENT '状态ACCEPTED-已接受, CONFLICT-冲突',
`response_json` TEXT NOT NULL COMMENT '首次成功响应 JSON用于重试重放',
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_submit_idempotency` (`tenant_id`, `user_id`, `operation`, `idempotency_key`),
KEY `idx_submit_session` (`tenant_id`, `session_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='教育-交卷幂等记录';
-- =============================================
-- 练习报告表(会话级)
-- =============================================
-- Purpose: Store the computed scoring result for a submitted session.
-- One report per session. Immutable after creation.
-- Question snapshots (stem, selectedAnswer, correctAnswer, explanation)
-- are stored in report_details so source question edits don't affect history.
--
-- Indexes:
-- uk_report_session — one report per session (unique).
-- idx_report_tenant_user — covers paginated history queries for current tenant+user.
-- idx_report_create_time — covers time-sorted listing.
CREATE TABLE `education_practice_report` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
`tenant_id` BIGINT NOT NULL COMMENT '租户编号',
`user_id` BIGINT NOT NULL COMMENT '用户编号',
`session_id` BIGINT NOT NULL COMMENT '会话 ID',
`question_count` INT NOT NULL COMMENT '题目总数',
`answered_count` INT NOT NULL DEFAULT 0 COMMENT '已答题数',
`unanswered_count` INT NOT NULL DEFAULT 0 COMMENT '未答题数',
`correct_count` INT NOT NULL DEFAULT 0 COMMENT '正确题数',
`incorrect_count` INT NOT NULL DEFAULT 0 COMMENT '错误题数',
`score` INT NOT NULL DEFAULT 0 COMMENT '得分(整数,满分 100 为基准)',
`status` VARCHAR(20) NOT NULL DEFAULT 'SUBMITTED'
COMMENT '报告状态SUBMITTED',
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_report_session` (`session_id`),
KEY `idx_report_tenant_user` (`tenant_id`, `user_id`),
KEY `idx_report_create_time` (`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='教育-练习报告';
-- =============================================
-- 练习报告明细表(逐题结果)
-- =============================================
-- Purpose: Store per-question scoring results at submission time.
-- Includes snapshot of stem, selectedAnswer, correctAnswer, and explanation
-- so that history is stable even if source questions are later edited.
--
-- Indexes:
-- uk_report_sequence — per-report uniqueness for question sequence.
-- idx_detail_session — covers lookup by session for report assembly.
CREATE TABLE `education_practice_report_detail` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
`tenant_id` BIGINT NOT NULL COMMENT '租户编号',
`user_id` BIGINT NOT NULL COMMENT '用户编号',
`report_id` BIGINT NOT NULL COMMENT '报告 ID',
`session_id` BIGINT NOT NULL COMMENT '会话 ID',
`question_id` VARCHAR(64) NOT NULL COMMENT '原始题目 ID',
`sequence` INT NOT NULL COMMENT '题目序号1-based',
`stem` TEXT NOT NULL COMMENT '题干快照',
`type` VARCHAR(32) NOT NULL COMMENT '题型快照',
`difficulty` VARCHAR(32) DEFAULT NULL COMMENT '难度快照',
`selected_answer` TEXT DEFAULT NULL COMMENT '学生已选答案',
`correct_answer` TEXT DEFAULT NULL COMMENT '正确答案快照',
`is_correct` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否正确',
`explanation` TEXT DEFAULT NULL COMMENT '解析快照',
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_report_sequence` (`report_id`, `sequence`),
KEY `idx_detail_session` (`session_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='教育-练习报告明细';
-- =============================================
-- Post-migration verification queries
-- =============================================
-- Verify new tables exist:
-- SHOW CREATE TABLE education_submit_idempotency;
-- SHOW CREATE TABLE education_practice_report;
-- SHOW CREATE TABLE education_practice_report_detail;
-- Verify columns added to question table:
-- SELECT COLUMN_NAME, DATA_TYPE, COLUMN_DEFAULT
-- FROM information_schema.COLUMNS
-- WHERE TABLE_SCHEMA = DATABASE()
-- AND TABLE_NAME = 'education_practice_question'
-- AND COLUMN_NAME IN ('correct_answer', 'explanation');
-- Verify unique keys are enforced:
-- SHOW INDEX FROM education_submit_idempotency WHERE Key_name = 'uk_submit_idempotency';
-- SHOW INDEX FROM education_practice_report WHERE Key_name = 'uk_report_session';
-- SHOW INDEX FROM education_practice_report_detail WHERE Key_name = 'uk_report_sequence';
-- Verify no orphan data (should be 0 after fresh migration):
-- SELECT COUNT(*) FROM education_submit_idempotency;
-- SELECT COUNT(*) FROM education_practice_report;
-- SELECT COUNT(*) FROM education_practice_report_detail;