Files
K12Study/init/pg/achievement/10_create_achievement_tables.sql

408 lines
27 KiB
MySQL
Raw Normal View History

2026-04-16 11:30:30 +08:00
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);