Initial commit of akmon project
This commit is contained in:
125
doc_zhipao/create_achievement_system.sql
Normal file
125
doc_zhipao/create_achievement_system.sql
Normal file
@@ -0,0 +1,125 @@
|
||||
-- 学生成就系统表结构
|
||||
-- 用于记录学生获得的各种成就和徽章
|
||||
|
||||
-- 成就定义表
|
||||
CREATE TABLE IF NOT EXISTS public.ak_achievements (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(128) NOT NULL UNIQUE, -- 成就名称 (添加唯一约束)
|
||||
description TEXT, -- 成就描述
|
||||
category VARCHAR(32) DEFAULT 'general', -- 成就分类 (training, skill, progress, persistence, special)
|
||||
difficulty VARCHAR(16) DEFAULT 'easy', -- 难度等级 (easy, medium, hard, expert)
|
||||
points INT DEFAULT 10, -- 奖励积分
|
||||
icon VARCHAR(16) DEFAULT '🏆', -- 成就图标
|
||||
requirements TEXT, -- 获得条件说明
|
||||
is_active BOOLEAN DEFAULT true, -- 是否启用
|
||||
sort_order INT DEFAULT 0, -- 排序顺序
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT now()
|
||||
);
|
||||
COMMENT ON TABLE public.ak_achievements IS '成就定义表';
|
||||
|
||||
-- 学生成就记录表
|
||||
CREATE TABLE IF NOT EXISTS public.ak_student_achievements (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
student_id uuid REFERENCES public.ak_users(id) ON DELETE CASCADE, -- 学生ID
|
||||
achievement_id uuid REFERENCES public.ak_achievements(id) ON DELETE CASCADE, -- 成就ID
|
||||
unlocked_at TIMESTAMP WITH TIME ZONE DEFAULT now(), -- 获得时间
|
||||
progress_current INT DEFAULT 0, -- 当前进度
|
||||
progress_target INT DEFAULT 1, -- 目标进度
|
||||
is_featured BOOLEAN DEFAULT false, -- 是否为精选成就
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT now()
|
||||
);
|
||||
COMMENT ON TABLE public.ak_student_achievements IS '学生成就记录表';
|
||||
|
||||
-- 创建索引
|
||||
CREATE INDEX IF NOT EXISTS idx_achievements_category ON public.ak_achievements(category);
|
||||
CREATE INDEX IF NOT EXISTS idx_achievements_difficulty ON public.ak_achievements(difficulty);
|
||||
CREATE INDEX IF NOT EXISTS idx_student_achievements_student_id ON public.ak_student_achievements(student_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_student_achievements_achievement_id ON public.ak_student_achievements(achievement_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_student_achievements_unlocked_at ON public.ak_student_achievements(unlocked_at);
|
||||
|
||||
-- 防止重复获得同一成就
|
||||
ALTER TABLE public.ak_student_achievements
|
||||
ADD CONSTRAINT uk_student_achievement_unique UNIQUE (student_id, achievement_id);
|
||||
|
||||
-- 插入一些基础成就
|
||||
INSERT INTO public.ak_achievements (name, description, category, difficulty, points, icon, requirements) VALUES
|
||||
('初出茅庐', '完成第一次训练记录', 'training', 'easy', 10, '🎯', '完成任意一次训练记录'),
|
||||
('坚持不懈', '连续训练7天', 'persistence', 'medium', 50, '🔥', '连续7天都有训练记录'),
|
||||
('技术精进', '单项技能评分达到90分以上', 'skill', 'hard', 100, '⚡', '在任意技能项目中获得90分以上评分'),
|
||||
('全能选手', '完成所有训练项目', 'training', 'expert', 200, '🏆', '完成系统中所有的训练项目'),
|
||||
('进步之星', '单月内平均分提升10分以上', 'progress', 'medium', 75, '📈', '在一个月内平均成绩提升10分或以上'),
|
||||
('月度之王', '成为月度训练积分第一名', 'special', 'expert', 300, '👑', '在月度排行榜中获得第一名')
|
||||
ON CONFLICT (name) DO NOTHING;
|
||||
|
||||
-- 创建触发器函数,自动检查成就获得条件
|
||||
CREATE OR REPLACE FUNCTION check_student_achievements()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
student_uuid uuid;
|
||||
achievement_uuid uuid;
|
||||
assignment_count INT;
|
||||
avg_score FLOAT;
|
||||
consecutive_days INT;
|
||||
BEGIN
|
||||
-- 获取学生ID
|
||||
student_uuid := NEW.student_id;
|
||||
|
||||
-- 检查"初出茅庐"成就 - 完成第一次训练记录
|
||||
SELECT id INTO achievement_uuid FROM public.ak_achievements WHERE name = '初出茅庐';
|
||||
IF achievement_uuid IS NOT NULL THEN
|
||||
SELECT COUNT(*) INTO assignment_count
|
||||
FROM public.ak_assignment_submissions
|
||||
WHERE student_id = student_uuid AND status = 'submitted';
|
||||
|
||||
IF assignment_count = 1 THEN
|
||||
INSERT INTO public.ak_student_achievements (student_id, achievement_id)
|
||||
VALUES (student_uuid, achievement_uuid)
|
||||
ON CONFLICT (student_id, achievement_id) DO NOTHING;
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
-- 检查"技术精进"成就 - 90分以上评分
|
||||
SELECT id INTO achievement_uuid FROM public.ak_achievements WHERE name = '技术精进';
|
||||
IF achievement_uuid IS NOT NULL AND NEW.final_score >= 90 THEN
|
||||
INSERT INTO public.ak_student_achievements (student_id, achievement_id)
|
||||
VALUES (student_uuid, achievement_uuid)
|
||||
ON CONFLICT (student_id, achievement_id) DO NOTHING;
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- 创建触发器
|
||||
DROP TRIGGER IF EXISTS trigger_check_achievements ON public.ak_assignment_submissions;
|
||||
CREATE TRIGGER trigger_check_achievements
|
||||
AFTER INSERT OR UPDATE ON public.ak_assignment_submissions
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION check_student_achievements();
|
||||
|
||||
-- 创建获取用户成就统计的函数
|
||||
CREATE OR REPLACE FUNCTION get_student_achievement_stats(p_student_id uuid)
|
||||
RETURNS TABLE(
|
||||
total_achievements INT,
|
||||
total_points INT,
|
||||
completion_rate FLOAT,
|
||||
recent_achievements_count INT
|
||||
) AS $$
|
||||
BEGIN
|
||||
RETURN QUERY
|
||||
SELECT
|
||||
COUNT(sa.id)::INT as total_achievements,
|
||||
COALESCE(SUM(a.points), 0)::INT as total_points,
|
||||
CASE
|
||||
WHEN COUNT(DISTINCT a_all.id) > 0
|
||||
THEN (COUNT(sa.id)::FLOAT / COUNT(DISTINCT a_all.id) * 100)
|
||||
ELSE 0.0
|
||||
END as completion_rate,
|
||||
COUNT(CASE WHEN sa.unlocked_at >= NOW() - INTERVAL '7 days' THEN 1 END)::INT as recent_achievements_count
|
||||
FROM public.ak_achievements a_all
|
||||
LEFT JOIN public.ak_student_achievements sa ON a_all.id = sa.achievement_id AND sa.student_id = p_student_id
|
||||
LEFT JOIN public.ak_achievements a ON sa.achievement_id = a.id
|
||||
WHERE a_all.is_active = true;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
Reference in New Issue
Block a user