DROP SCHEMA IF EXISTS achievement CASCADE; CREATE SCHEMA IF NOT EXISTS achievement; DROP TABLE IF EXISTS achievement.ac_achievement CASCADE; CREATE TABLE IF NOT EXISTS achievement.ac_achievement ( achievement_id VARCHAR(64) PRIMARY KEY, achievement_code VARCHAR(64) UNIQUE NOT NULL, achievement_name VARCHAR(128) NOT NULL, achievement_desc TEXT, achievement_category VARCHAR(32) NOT NULL DEFAULT 'SCORE', trigger_event VARCHAR(32) NOT NULL DEFAULT 'GRADE_PUBLISHED', trigger_rule_json JSONB NOT NULL DEFAULT '{}'::JSONB, badge_level VARCHAR(16) NOT NULL DEFAULT 'BRONZE', badge_icon_url VARCHAR(512), status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE', tenant_id VARCHAR(64) NOT NULL, created_by VARCHAR(64), created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT chk_ac_achievement_category CHECK (achievement_category IN ('SCORE', 'PROGRESS', 'TEACHING', 'ENGAGEMENT', 'MANUAL')), CONSTRAINT chk_ac_achievement_trigger_event CHECK (trigger_event IN ('GRADE_PUBLISHED', 'WRONG_QUESTION_MASTERED', 'TASK_COMPLETED', 'REVIEW_COMPLETED', 'MANUAL')), CONSTRAINT chk_ac_achievement_badge_level CHECK (badge_level IN ('BRONZE', 'SILVER', 'GOLD', 'PLATINUM')), CONSTRAINT chk_ac_achievement_status CHECK (status IN ('ACTIVE', 'DISABLED')), CONSTRAINT chk_ac_achievement_trigger_rule_json CHECK (jsonb_typeof(trigger_rule_json) = 'object'), CONSTRAINT fk_ac_achievement_created_by FOREIGN KEY (created_by) REFERENCES upms.tb_sys_user(user_id) ); COMMENT ON TABLE achievement.ac_achievement IS '成就定义表'; COMMENT ON COLUMN achievement.ac_achievement.achievement_id IS '成就ID'; COMMENT ON COLUMN achievement.ac_achievement.achievement_code IS '成就编码'; COMMENT ON COLUMN achievement.ac_achievement.achievement_name IS '成就名称'; COMMENT ON COLUMN achievement.ac_achievement.achievement_desc IS '成就描述'; COMMENT ON COLUMN achievement.ac_achievement.achievement_category IS '成就类别(SCORE/PROGRESS/TEACHING/ENGAGEMENT/MANUAL)'; COMMENT ON COLUMN achievement.ac_achievement.trigger_event IS '触发事件(GRADE_PUBLISHED/WRONG_QUESTION_MASTERED/TASK_COMPLETED/REVIEW_COMPLETED/MANUAL)'; COMMENT ON COLUMN achievement.ac_achievement.trigger_rule_json IS '触发规则JSON(可配置成绩阈值、次数阈值等)'; COMMENT ON COLUMN achievement.ac_achievement.badge_level IS '徽章等级(BRONZE/SILVER/GOLD/PLATINUM)'; COMMENT ON COLUMN achievement.ac_achievement.badge_icon_url IS '徽章图标URL'; COMMENT ON COLUMN achievement.ac_achievement.status IS '状态(ACTIVE/DISABLED)'; COMMENT ON COLUMN achievement.ac_achievement.tenant_id IS '租户ID'; COMMENT ON COLUMN achievement.ac_achievement.created_by IS '创建人ID'; COMMENT ON COLUMN achievement.ac_achievement.created_at IS '创建时间'; COMMENT ON COLUMN achievement.ac_achievement.updated_at IS '更新时间'; DROP TABLE IF EXISTS achievement.ac_achievement_role_rel CASCADE; CREATE TABLE IF NOT EXISTS achievement.ac_achievement_role_rel ( achievement_id VARCHAR(64) NOT NULL, role_id VARCHAR(64) NOT NULL, tenant_id VARCHAR(64) NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (achievement_id, role_id), CONSTRAINT fk_ac_achievement_role_rel_achievement FOREIGN KEY (achievement_id) REFERENCES achievement.ac_achievement(achievement_id) ON DELETE CASCADE, CONSTRAINT fk_ac_achievement_role_rel_role FOREIGN KEY (role_id) REFERENCES upms.tb_sys_role(role_id) ); COMMENT ON TABLE achievement.ac_achievement_role_rel IS '成就-角色绑定表'; COMMENT ON COLUMN achievement.ac_achievement_role_rel.achievement_id IS '成就ID'; COMMENT ON COLUMN achievement.ac_achievement_role_rel.role_id IS '角色ID'; COMMENT ON COLUMN achievement.ac_achievement_role_rel.tenant_id IS '租户ID'; COMMENT ON COLUMN achievement.ac_achievement_role_rel.created_at IS '创建时间'; DROP TABLE IF EXISTS achievement.ac_user_achievement CASCADE; CREATE TABLE IF NOT EXISTS achievement.ac_user_achievement ( user_achievement_id VARCHAR(64) PRIMARY KEY, user_id VARCHAR(64) NOT NULL, achievement_id VARCHAR(64) NOT NULL, role_id VARCHAR(64) NOT NULL, summary_id VARCHAR(64), grading_task_id VARCHAR(64), score_snapshot NUMERIC(8,2), grade_level VARCHAR(8), surpass_ratio NUMERIC(5,2), used_seconds INTEGER, award_source VARCHAR(32) NOT NULL DEFAULT 'RULE_ENGINE', award_reason VARCHAR(256), evidence_json JSONB NOT NULL DEFAULT '{}'::JSONB, achieved_count INTEGER NOT NULL DEFAULT 1, first_achieved_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, last_achieved_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, tenant_id VARCHAR(64) NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT uq_ac_user_achievement_user_achievement_role UNIQUE (user_id, achievement_id, role_id), CONSTRAINT chk_ac_user_achievement_award_source CHECK (award_source IN ('RULE_ENGINE', 'MANUAL', 'SYSTEM')), CONSTRAINT chk_ac_user_achievement_evidence_json CHECK (jsonb_typeof(evidence_json) = 'object'), CONSTRAINT chk_ac_user_achievement_achieved_count CHECK (achieved_count > 0), CONSTRAINT fk_ac_user_achievement_user FOREIGN KEY (user_id) REFERENCES upms.tb_sys_user(user_id), CONSTRAINT fk_ac_user_achievement_role_binding FOREIGN KEY (achievement_id, role_id) REFERENCES achievement.ac_achievement_role_rel(achievement_id, role_id), CONSTRAINT fk_ac_user_achievement_summary FOREIGN KEY (summary_id) REFERENCES question.gd_score_summary(summary_id), CONSTRAINT fk_ac_user_achievement_task FOREIGN KEY (grading_task_id) REFERENCES question.gd_grading_task(grading_task_id) ); COMMENT ON TABLE achievement.ac_user_achievement IS '用户成就记录表'; COMMENT ON COLUMN achievement.ac_user_achievement.user_achievement_id IS '用户成就记录ID'; COMMENT ON COLUMN achievement.ac_user_achievement.user_id IS '用户ID'; COMMENT ON COLUMN achievement.ac_user_achievement.achievement_id IS '成就ID'; COMMENT ON COLUMN achievement.ac_user_achievement.role_id IS '获奖时角色ID'; COMMENT ON COLUMN achievement.ac_user_achievement.summary_id IS '成绩汇总ID(来源于question.gd_score_summary)'; COMMENT ON COLUMN achievement.ac_user_achievement.grading_task_id IS '批改任务ID(来源于question.gd_grading_task)'; COMMENT ON COLUMN achievement.ac_user_achievement.score_snapshot IS '成绩快照分数'; COMMENT ON COLUMN achievement.ac_user_achievement.grade_level IS '成绩快照等级'; COMMENT ON COLUMN achievement.ac_user_achievement.surpass_ratio IS '成绩快照超越比例'; COMMENT ON COLUMN achievement.ac_user_achievement.used_seconds IS '成绩快照耗时(秒)'; COMMENT ON COLUMN achievement.ac_user_achievement.award_source IS '发放来源(RULE_ENGINE/MANUAL/SYSTEM)'; COMMENT ON COLUMN achievement.ac_user_achievement.award_reason IS '发放原因'; COMMENT ON COLUMN achievement.ac_user_achievement.evidence_json IS '发放证据JSON(可存规则命中明细)'; COMMENT ON COLUMN achievement.ac_user_achievement.achieved_count IS '累计达成次数'; COMMENT ON COLUMN achievement.ac_user_achievement.first_achieved_at IS '首次达成时间'; COMMENT ON COLUMN achievement.ac_user_achievement.last_achieved_at IS '最近达成时间'; COMMENT ON COLUMN achievement.ac_user_achievement.tenant_id IS '租户ID'; COMMENT ON COLUMN achievement.ac_user_achievement.created_at IS '创建时间'; COMMENT ON COLUMN achievement.ac_user_achievement.updated_at IS '更新时间'; DROP TABLE IF EXISTS achievement.ac_user_achievement_progress CASCADE; CREATE TABLE IF NOT EXISTS achievement.ac_user_achievement_progress ( progress_id VARCHAR(64) PRIMARY KEY, user_id VARCHAR(64) NOT NULL, achievement_id VARCHAR(64) NOT NULL, role_id VARCHAR(64) NOT NULL, current_value NUMERIC(12,2) NOT NULL DEFAULT 0, target_value NUMERIC(12,2) NOT NULL, progress_rate NUMERIC(5,2) NOT NULL DEFAULT 0, effort_index NUMERIC(6,2) NOT NULL DEFAULT 0, improvement_rate NUMERIC(6,2) NOT NULL DEFAULT 0, resilience_index NUMERIC(6,2) NOT NULL DEFAULT 0, streak_days INTEGER NOT NULL DEFAULT 0, last_checkin_date DATE, progress_status VARCHAR(16) NOT NULL DEFAULT 'IN_PROGRESS', progress_snapshot_json JSONB NOT NULL DEFAULT '{}'::JSONB, last_evaluated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, achieved_at TIMESTAMP, tenant_id VARCHAR(64) NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT uq_ac_user_achievement_progress_user_achievement_role UNIQUE (user_id, achievement_id, role_id), CONSTRAINT chk_ac_user_achievement_progress_current CHECK (current_value >= 0), CONSTRAINT chk_ac_user_achievement_progress_target CHECK (target_value > 0), CONSTRAINT chk_ac_user_achievement_progress_rate CHECK (progress_rate >= 0 AND progress_rate <= 100), CONSTRAINT chk_ac_user_achievement_progress_effort_index CHECK (effort_index >= 0 AND effort_index <= 100), CONSTRAINT chk_ac_user_achievement_progress_improvement_rate CHECK (improvement_rate >= -100 AND improvement_rate <= 1000), CONSTRAINT chk_ac_user_achievement_progress_resilience_index CHECK (resilience_index >= 0 AND resilience_index <= 100), CONSTRAINT chk_ac_user_achievement_progress_streak_days CHECK (streak_days >= 0), CONSTRAINT chk_ac_user_achievement_progress_status CHECK (progress_status IN ('IN_PROGRESS', 'ACHIEVED', 'EXPIRED')), CONSTRAINT chk_ac_user_achievement_progress_snapshot_json CHECK (jsonb_typeof(progress_snapshot_json) = 'object'), CONSTRAINT chk_ac_user_achievement_progress_achieved_at CHECK ( (progress_status = 'ACHIEVED' AND achieved_at IS NOT NULL) OR (progress_status IN ('IN_PROGRESS', 'EXPIRED') AND achieved_at IS NULL) ), CONSTRAINT fk_ac_user_achievement_progress_user FOREIGN KEY (user_id) REFERENCES upms.tb_sys_user(user_id), CONSTRAINT fk_ac_user_achievement_progress_role_binding FOREIGN KEY (achievement_id, role_id) REFERENCES achievement.ac_achievement_role_rel(achievement_id, role_id) ); COMMENT ON TABLE achievement.ac_user_achievement_progress IS '用户成就进度表(含未达成记录)'; COMMENT ON COLUMN achievement.ac_user_achievement_progress.progress_id IS '成就进度ID'; COMMENT ON COLUMN achievement.ac_user_achievement_progress.user_id IS '用户ID'; COMMENT ON COLUMN achievement.ac_user_achievement_progress.achievement_id IS '成就ID'; COMMENT ON COLUMN achievement.ac_user_achievement_progress.role_id IS '角色ID(学生/教师)'; COMMENT ON COLUMN achievement.ac_user_achievement_progress.current_value IS '当前进度值'; COMMENT ON COLUMN achievement.ac_user_achievement_progress.target_value IS '目标值'; COMMENT ON COLUMN achievement.ac_user_achievement_progress.progress_rate IS '完成率(0-100)'; COMMENT ON COLUMN achievement.ac_user_achievement_progress.effort_index IS '努力指数(0-100)'; COMMENT ON COLUMN achievement.ac_user_achievement_progress.improvement_rate IS '进步率(可为负)'; COMMENT ON COLUMN achievement.ac_user_achievement_progress.resilience_index IS '学习韧性指数(0-100)'; COMMENT ON COLUMN achievement.ac_user_achievement_progress.streak_days IS '连续打卡天数'; COMMENT ON COLUMN achievement.ac_user_achievement_progress.last_checkin_date IS '最近打卡日期'; COMMENT ON COLUMN achievement.ac_user_achievement_progress.progress_status IS '进度状态(IN_PROGRESS/ACHIEVED/EXPIRED)'; COMMENT ON COLUMN achievement.ac_user_achievement_progress.progress_snapshot_json IS '进度快照JSON(可记录最近一次评估明细)'; COMMENT ON COLUMN achievement.ac_user_achievement_progress.last_evaluated_at IS '最近评估时间'; COMMENT ON COLUMN achievement.ac_user_achievement_progress.achieved_at IS '达成时间'; COMMENT ON COLUMN achievement.ac_user_achievement_progress.tenant_id IS '租户ID'; COMMENT ON COLUMN achievement.ac_user_achievement_progress.created_at IS '创建时间'; COMMENT ON COLUMN achievement.ac_user_achievement_progress.updated_at IS '更新时间'; DROP TABLE IF EXISTS achievement.ac_user_achievement_daily_fact CASCADE; CREATE TABLE IF NOT EXISTS achievement.ac_user_achievement_daily_fact ( stat_date DATE NOT NULL, user_id VARCHAR(64) NOT NULL, role_id VARCHAR(64) NOT NULL, tenant_id VARCHAR(64) NOT NULL, gained_achievement_count INTEGER NOT NULL DEFAULT 0, active_achievement_count INTEGER NOT NULL DEFAULT 0, progress_delta NUMERIC(10,4) NOT NULL DEFAULT 0, effort_index NUMERIC(6,2) NOT NULL DEFAULT 0, improvement_rate NUMERIC(6,2) NOT NULL DEFAULT 0, resilience_index NUMERIC(6,2) NOT NULL DEFAULT 0, streak_days INTEGER NOT NULL DEFAULT 0, learning_minutes INTEGER NOT NULL DEFAULT 0, checkin_status VARCHAR(16) NOT NULL DEFAULT 'NONE', created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (stat_date, user_id, role_id), CONSTRAINT chk_ac_user_achievement_daily_fact_gained CHECK (gained_achievement_count >= 0), CONSTRAINT chk_ac_user_achievement_daily_fact_active CHECK (active_achievement_count >= 0), CONSTRAINT chk_ac_user_achievement_daily_fact_effort CHECK (effort_index >= 0 AND effort_index <= 100), CONSTRAINT chk_ac_user_achievement_daily_fact_improvement CHECK (improvement_rate >= -100 AND improvement_rate <= 1000), CONSTRAINT chk_ac_user_achievement_daily_fact_resilience CHECK (resilience_index >= 0 AND resilience_index <= 100), CONSTRAINT chk_ac_user_achievement_daily_fact_streak CHECK (streak_days >= 0), CONSTRAINT chk_ac_user_achievement_daily_fact_learning_minutes CHECK (learning_minutes >= 0), CONSTRAINT chk_ac_user_achievement_daily_fact_checkin CHECK (checkin_status IN ('NONE', 'CHECKED_IN', 'BROKEN')), CONSTRAINT fk_ac_user_achievement_daily_fact_user FOREIGN KEY (user_id) REFERENCES upms.tb_sys_user(user_id), CONSTRAINT fk_ac_user_achievement_daily_fact_role FOREIGN KEY (role_id) REFERENCES upms.tb_sys_role(role_id) ); COMMENT ON TABLE achievement.ac_user_achievement_daily_fact IS '用户成就激励日事实表(激励数据即成就数据)'; COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.stat_date IS '统计日期'; COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.user_id IS '用户ID'; COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.role_id IS '角色ID'; COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.tenant_id IS '租户ID'; COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.gained_achievement_count IS '当日新增成就数'; COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.active_achievement_count IS '当日活跃成就数'; COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.progress_delta IS '当日进度变化量'; COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.effort_index IS '当日努力指数(0-100)'; COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.improvement_rate IS '当日进步率(可为负)'; COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.resilience_index IS '当日学习韧性指数(0-100)'; COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.streak_days IS '当日连续打卡天数'; COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.learning_minutes IS '当日学习分钟数'; COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.checkin_status IS '打卡状态'; COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.created_at IS '创建时间'; COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.updated_at IS '更新时间'; DROP TABLE IF EXISTS achievement.ac_achievement_rule_template CASCADE; DROP TABLE IF EXISTS achievement.ac_achievement_metric_def CASCADE; DROP TABLE IF EXISTS achievement.ac_achievement_event_dict CASCADE; CREATE TABLE IF NOT EXISTS achievement.ac_achievement_event_dict ( event_code VARCHAR(64) PRIMARY KEY, event_name VARCHAR(128) NOT NULL, event_domain VARCHAR(32) NOT NULL DEFAULT 'LEARNING_LOOP', event_desc TEXT, payload_schema_json JSONB NOT NULL DEFAULT '{}'::JSONB, enabled BOOLEAN NOT NULL DEFAULT TRUE, tenant_id VARCHAR(64) NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT chk_ac_achievement_event_dict_domain CHECK (event_domain IN ('LEARNING_LOOP', 'GRADING', 'REVIEW', 'CHECKIN', 'SYSTEM')), CONSTRAINT chk_ac_achievement_event_dict_payload_json CHECK (jsonb_typeof(payload_schema_json) = 'object') ); COMMENT ON TABLE achievement.ac_achievement_event_dict IS '成就事件字典表(通用触发事件定义)'; COMMENT ON COLUMN achievement.ac_achievement_event_dict.event_code IS '事件编码'; COMMENT ON COLUMN achievement.ac_achievement_event_dict.event_name IS '事件名称'; COMMENT ON COLUMN achievement.ac_achievement_event_dict.event_domain IS '事件域'; COMMENT ON COLUMN achievement.ac_achievement_event_dict.event_desc IS '事件描述'; COMMENT ON COLUMN achievement.ac_achievement_event_dict.payload_schema_json IS '事件载荷结构定义JSON'; COMMENT ON COLUMN achievement.ac_achievement_event_dict.enabled IS '是否启用'; COMMENT ON COLUMN achievement.ac_achievement_event_dict.tenant_id IS '租户ID'; COMMENT ON COLUMN achievement.ac_achievement_event_dict.created_at IS '创建时间'; COMMENT ON COLUMN achievement.ac_achievement_event_dict.updated_at IS '更新时间'; CREATE TABLE IF NOT EXISTS achievement.ac_achievement_metric_def ( metric_id VARCHAR(64) PRIMARY KEY, metric_code VARCHAR(64) NOT NULL, metric_name VARCHAR(128) NOT NULL, metric_type VARCHAR(16) NOT NULL DEFAULT 'NUM', metric_unit VARCHAR(32), source_domain VARCHAR(32) NOT NULL DEFAULT 'SYSTEM', agg_method VARCHAR(16) NOT NULL DEFAULT 'LATEST', default_value_num NUMERIC(18,6), default_value_text VARCHAR(255), expr_json JSONB NOT NULL DEFAULT '{}'::JSONB, enabled BOOLEAN NOT NULL DEFAULT TRUE, tenant_id VARCHAR(64) NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT uq_ac_achievement_metric_def_tenant_code UNIQUE (tenant_id, metric_code), CONSTRAINT chk_ac_achievement_metric_def_type CHECK (metric_type IN ('NUM', 'BOOL', 'TEXT', 'RATE', 'COUNT')), CONSTRAINT chk_ac_achievement_metric_def_source_domain CHECK (source_domain IN ('COURSE', 'HOMEWORK', 'GRADING', 'REVIEW', 'RECOMMENDATION', 'ACHIEVEMENT', 'SYSTEM')), CONSTRAINT chk_ac_achievement_metric_def_agg_method CHECK (agg_method IN ('LATEST', 'SUM', 'AVG', 'MAX', 'MIN', 'COUNT')), CONSTRAINT chk_ac_achievement_metric_def_expr_json CHECK (jsonb_typeof(expr_json) = 'object') ); COMMENT ON TABLE achievement.ac_achievement_metric_def IS '成就指标定义表(通用指标注册)'; COMMENT ON COLUMN achievement.ac_achievement_metric_def.metric_id IS '指标ID'; COMMENT ON COLUMN achievement.ac_achievement_metric_def.metric_code IS '指标编码'; COMMENT ON COLUMN achievement.ac_achievement_metric_def.metric_name IS '指标名称'; COMMENT ON COLUMN achievement.ac_achievement_metric_def.metric_type IS '指标类型'; COMMENT ON COLUMN achievement.ac_achievement_metric_def.metric_unit IS '指标单位'; COMMENT ON COLUMN achievement.ac_achievement_metric_def.source_domain IS '指标来源域'; COMMENT ON COLUMN achievement.ac_achievement_metric_def.agg_method IS '聚合方式'; COMMENT ON COLUMN achievement.ac_achievement_metric_def.default_value_num IS '默认数值'; COMMENT ON COLUMN achievement.ac_achievement_metric_def.default_value_text IS '默认文本值'; COMMENT ON COLUMN achievement.ac_achievement_metric_def.expr_json IS '计算表达式JSON'; COMMENT ON COLUMN achievement.ac_achievement_metric_def.enabled IS '是否启用'; COMMENT ON COLUMN achievement.ac_achievement_metric_def.tenant_id IS '租户ID'; COMMENT ON COLUMN achievement.ac_achievement_metric_def.created_at IS '创建时间'; COMMENT ON COLUMN achievement.ac_achievement_metric_def.updated_at IS '更新时间'; CREATE TABLE IF NOT EXISTS achievement.ac_achievement_rule_template ( template_id VARCHAR(64) PRIMARY KEY, template_code VARCHAR(64) NOT NULL, template_name VARCHAR(128) NOT NULL, event_code VARCHAR(64) NOT NULL, role_id VARCHAR(64), achievement_category VARCHAR(32) NOT NULL DEFAULT 'PROGRESS', rule_condition_json JSONB NOT NULL DEFAULT '{}'::JSONB, reward_action_json JSONB NOT NULL DEFAULT '{}'::JSONB, priority INTEGER NOT NULL DEFAULT 100, template_status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE', valid_from TIMESTAMP, valid_to TIMESTAMP, tenant_id VARCHAR(64) NOT NULL, created_by VARCHAR(64), created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT uq_ac_achievement_rule_template_tenant_code UNIQUE (tenant_id, template_code), CONSTRAINT chk_ac_achievement_rule_template_category CHECK (achievement_category IN ('SCORE', 'PROGRESS', 'TEACHING', 'ENGAGEMENT', 'MANUAL')), CONSTRAINT chk_ac_achievement_rule_template_status CHECK (template_status IN ('ACTIVE', 'INACTIVE', 'ARCHIVED')), CONSTRAINT chk_ac_achievement_rule_template_condition_json CHECK (jsonb_typeof(rule_condition_json) = 'object'), CONSTRAINT chk_ac_achievement_rule_template_reward_json CHECK (jsonb_typeof(reward_action_json) = 'object'), CONSTRAINT chk_ac_achievement_rule_template_valid CHECK (valid_to IS NULL OR valid_from IS NULL OR valid_to >= valid_from), CONSTRAINT fk_ac_achievement_rule_template_event FOREIGN KEY (event_code) REFERENCES achievement.ac_achievement_event_dict(event_code), CONSTRAINT fk_ac_achievement_rule_template_role FOREIGN KEY (role_id) REFERENCES upms.tb_sys_role(role_id), CONSTRAINT fk_ac_achievement_rule_template_created_by FOREIGN KEY (created_by) REFERENCES upms.tb_sys_user(user_id) ); COMMENT ON TABLE achievement.ac_achievement_rule_template IS '成就规则模板表(通用配置驱动)'; COMMENT ON COLUMN achievement.ac_achievement_rule_template.template_id IS '模板ID'; COMMENT ON COLUMN achievement.ac_achievement_rule_template.template_code IS '模板编码'; COMMENT ON COLUMN achievement.ac_achievement_rule_template.template_name IS '模板名称'; COMMENT ON COLUMN achievement.ac_achievement_rule_template.event_code IS '触发事件编码'; COMMENT ON COLUMN achievement.ac_achievement_rule_template.role_id IS '适用角色ID'; COMMENT ON COLUMN achievement.ac_achievement_rule_template.achievement_category IS '成就类别'; COMMENT ON COLUMN achievement.ac_achievement_rule_template.rule_condition_json IS '规则条件JSON'; COMMENT ON COLUMN achievement.ac_achievement_rule_template.reward_action_json IS '奖励动作JSON'; COMMENT ON COLUMN achievement.ac_achievement_rule_template.priority IS '优先级'; COMMENT ON COLUMN achievement.ac_achievement_rule_template.template_status IS '模板状态'; COMMENT ON COLUMN achievement.ac_achievement_rule_template.valid_from IS '生效开始时间'; COMMENT ON COLUMN achievement.ac_achievement_rule_template.valid_to IS '生效结束时间'; COMMENT ON COLUMN achievement.ac_achievement_rule_template.tenant_id IS '租户ID'; COMMENT ON COLUMN achievement.ac_achievement_rule_template.created_by IS '创建人'; COMMENT ON COLUMN achievement.ac_achievement_rule_template.created_at IS '创建时间'; COMMENT ON COLUMN achievement.ac_achievement_rule_template.updated_at IS '更新时间'; CREATE INDEX IF NOT EXISTS idx_ac_achievement_tenant_status ON achievement.ac_achievement(tenant_id, status, created_at DESC); CREATE INDEX IF NOT EXISTS idx_ac_achievement_role_rel_role ON achievement.ac_achievement_role_rel(role_id, tenant_id); CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_user_role ON achievement.ac_user_achievement(user_id, role_id, last_achieved_at DESC); CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_tenant_time ON achievement.ac_user_achievement(tenant_id, last_achieved_at DESC); CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_summary ON achievement.ac_user_achievement(summary_id); CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_task ON achievement.ac_user_achievement(grading_task_id); CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_progress_user_status ON achievement.ac_user_achievement_progress(user_id, role_id, progress_status, last_evaluated_at DESC); CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_progress_tenant_status ON achievement.ac_user_achievement_progress(tenant_id, progress_status, last_evaluated_at DESC); CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_progress_achievement ON achievement.ac_user_achievement_progress(achievement_id, role_id); CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_progress_streak ON achievement.ac_user_achievement_progress(user_id, role_id, streak_days DESC, last_evaluated_at DESC); CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_daily_fact_tenant_date ON achievement.ac_user_achievement_daily_fact(tenant_id, stat_date DESC); CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_daily_fact_user_date ON achievement.ac_user_achievement_daily_fact(user_id, role_id, stat_date DESC); CREATE INDEX IF NOT EXISTS idx_ac_achievement_event_dict_tenant_enabled ON achievement.ac_achievement_event_dict(tenant_id, enabled, event_domain); CREATE INDEX IF NOT EXISTS idx_ac_achievement_metric_def_tenant_enabled ON achievement.ac_achievement_metric_def(tenant_id, enabled, source_domain); CREATE INDEX IF NOT EXISTS idx_ac_achievement_rule_template_tenant_event ON achievement.ac_achievement_rule_template(tenant_id, event_code, template_status, priority);