# 课程资源分享模块 — 数据模型介绍(v2) > 基于本仓库最新 DDL 汇总与解析: > > - 设计与DDL:`docs/sql/课程资源分享-DDL.md` > - 草案汇总:`book-mis.sql` > - 日期:2025-11-04(含此前 2025-10-18 核心结构) > > 约定:新文件仅允许“压缩包或外链”,大小≤100MB;审核状态:0-待审 1-已通过 2-驳回 3-已下架。 --- ## 模块概览 - 目标:围绕“专业-课程-资源”,管理资料上传、审核、最佳推荐、下载统计与积分排行。 - 核心对象:专业(tb_major)、课程(tb_course)、课程资源(tb_course_resource)。 - 可见范围:通过“专业负责人映射”(tb_major_lead)限制负责人在后台的可见与可操作范围。 - 最佳推荐:以独立表 tb_course_resource_best 标记“最佳”,避免污染主表结构。 - 审计追踪:全生命周期动作写入 tb_course_resource_log。 - 排行积分:按用户×专业聚合(tb_cr_user_score),流水表幂等(tb_cr_user_score_log)。 - 统一规范:所有表包含审计字段(create_by/create_time/update_by/update_time)与软删字段(del_flag)。 --- ## 关系图(ER 概览) ```mermaid erDiagram TB_MAJOR ||--o{ TB_COURSE : contains TB_COURSE ||--o{ TB_COURSE_RESOURCE : has TB_MAJOR ||--o{ TB_COURSE_RESOURCE : filters SYS_USER ||--o{ TB_COURSE_RESOURCE : uploads SYS_USER ||--o{ TB_MAJOR_LEAD : manages TB_COURSE_RESOURCE ||--o| TB_COURSE_RESOURCE_BEST : hasOne TB_COURSE_RESOURCE ||--o{ TB_COURSE_RESOURCE_LOG : logs SYS_USER ||--o{ TB_CR_USER_SCORE : aggregates SYS_USER ||--o{ TB_CR_USER_SCORE_LOG : streams TB_COURSE_RESOURCE ||--o{ TB_CR_USER_SCORE_LOG : awards TB_MAJOR { BIGINT id PK VARCHAR major_name UK CHAR status CHAR del_flag } TB_COURSE { BIGINT id PK BIGINT major_id FK VARCHAR course_name UK(partitioned-by-major) CHAR status CHAR del_flag } TB_MAJOR_LEAD { BIGINT id PK BIGINT major_id FK BIGINT user_id FK CHAR del_flag } TB_COURSE_RESOURCE { BIGINT id PK BIGINT major_id FK BIGINT course_id FK VARCHAR resource_name TINYINT resource_type VARCHAR file_url VARCHAR file_hash BIGINT file_size VARCHAR link_url TEXT description TINYINT status INT download_count DATETIME last_download_time BIGINT uploader_id FK VARCHAR uploader_name CHAR del_flag } TB_COURSE_RESOURCE_BEST { BIGINT id PK BIGINT resource_id UK,FK VARCHAR best_by DATETIME best_time CHAR del_flag } TB_COURSE_RESOURCE_LOG { BIGINT id PK BIGINT resource_id FK VARCHAR action BIGINT actor_id VARCHAR actor_name TEXT detail VARCHAR result CHAR del_flag } TB_CR_USER_SCORE { BIGINT id PK BIGINT user_id FK VARCHAR username BIGINT major_id INT total_score INT approve_count INT best_count CHAR del_flag } TB_CR_USER_SCORE_LOG { BIGINT id PK BIGINT user_id FK VARCHAR username BIGINT major_id BIGINT resource_id FK VARCHAR event_type INT delta CHAR del_flag } ``` > 说明:与 `sys_user` 的关系为“逻辑外键”,通过索引与应用层保障一致性。 --- ## 表与字段详解(逐表) ### 1) tb_major(专业表) - 用途:独立维护专业名称集合,不依赖 RuoYi 部门体系。 - 关键约束与索引: - PK:`id` - UK:`uk_major_name(major_name)` 专业名全局唯一 - 字段说明: - `id` BIGINT PK — 专业主键ID。 - `major_name` VARCHAR(128) NOT NULL — 专业名称,作为前端筛选与展示;唯一约束避免重名。 - `status` CHAR(1) DEFAULT '0' — 状态(0正常 1停用);停用后不可在新增课程/资源时选择。 - `remark` VARCHAR(500) — 备注。 - `create_by/create_time/update_by/update_time` — 审计字段。 - `del_flag` CHAR(1) DEFAULT '0' — 软删标记(0存在 2删除)。 - 关联:被 `tb_course.major_id` 引用(一对多);也被 `tb_course_resource.major_id` 冗余引用以利索引。 ### 2) tb_course(课程表) - 用途:挂载在专业下;同一专业内课程名唯一。 - 关键约束与索引: - PK:`id` - UK:`uk_course_unique(major_id, course_name)` - IDX:`idx_course_major(major_id)` - 字段说明: - `id` BIGINT PK — 课程主键ID。 - `major_id` BIGINT NOT NULL — 所属专业(逻辑外键:tb_major.id)。 - `course_name` VARCHAR(255) NOT NULL — 课程名称(同专业内唯一)。 - `course_code` VARCHAR(64) — 课程编码(可选)。 - `status` CHAR(1) DEFAULT '0' — 状态(0正常 1停用)。 - `remark` VARCHAR(500) — 备注。 - `create_by/create_time/update_by/update_time/del_flag` — 审计与软删。 - 关联:被 `tb_course_resource.course_id` 引用(一对多)。 ### 3) tb_major_lead(专业负责人映射表) - 用途:绑定用户与专业,实现“专业负责人”的可见范围限制;一专业可多负责人。 - 关键约束与索引: - PK:`id` - UK:`uk_major_user(major_id, user_id)` - IDX:`idx_lead_user(user_id)` - 字段说明: - `id` BIGINT PK — 主键。 - `major_id` BIGINT NOT NULL — 专业ID(逻辑外键:tb_major.id)。 - `user_id` BIGINT NOT NULL — 负责人用户ID(逻辑外键:sys_user.id)。 - `remark` VARCHAR(500) — 备注。 - `create_by/create_time/update_by/update_time/del_flag` — 审计与软删。 - 业务联动(应用层约定): - 新增映射:若用户尚无“major_lead”角色,则插入 sys_user_role 赋予该角色。 - 删除映射:若用户不再负责任何专业(tb_major_lead 计数=0),从 sys_user_role 撤销该角色。 ### 4) tb_course_resource(课程资源主表) - 用途:承载资源基本信息、审核状态、统计信息;资源类型仅“文件或外链”。 - 关键约束与索引: - PK:`id` - UK:`uk_course_filehash(course_id, resource_type, file_hash)`(文件型去重) - UK:`uk_course_linkurl(course_id, resource_type, link_url(191))`(外链型去重) - IDX:`idx_course_status(course_id, status)`、`idx_status_time(status, create_time)` - IDX:`idx_download_count(download_count)`、`idx_uploader_id(uploader_id)`、`idx_major_course(major_id, course_id)` - 字段说明: - `id` BIGINT PK — 资源主键ID。 - `major_id` BIGINT NOT NULL — 专业ID(与所属课程的专业一致,冗余用于高频筛选)。 - `course_id` BIGINT NOT NULL — 课程ID(逻辑外键:tb_course.id)。 - `resource_name` VARCHAR(255) NOT NULL — 资源显示名(用户可编辑)。 - `resource_type` TINYINT NOT NULL — 资源类型:0-文件 1-外链。 - `file_url` VARCHAR(512) — 文件直链(resource_type=0 时必填,建议 OSS 直链/带授权)。 - `file_hash` VARCHAR(128) — 文件哈希(resource_type=0 时必填,建议 SHA-256 防篡改与去重)。 - `file_size` BIGINT — 文件大小(字节)。 - `link_url` VARCHAR(512) — 外链 URL(resource_type=1 时必填)。 - `description` TEXT NOT NULL — 资源简介(必填,便于审核与检索)。 - `status` TINYINT DEFAULT 0 — 审核状态:0待审 1已通过 2驳回 3已下架。 - `audit_by` VARCHAR(64) / `audit_time` DATETIME / `audit_reason` VARCHAR(512) — 审核信息(仅审核动作更新)。 - `publish_time` DATETIME — 首次上架时间(第一次从待审进入已通过时写入)。 - `download_count` INT DEFAULT 0 — 下载次数(可由 Redis 自增聚合后回写)。 - `last_download_time` DATETIME — 最近下载时间(真实下载后刷新)。 - `uploader_id` BIGINT NOT NULL / `uploader_name` VARCHAR(64) NOT NULL — 上传者信息(逻辑外键:sys_user.id,冗余用户名快照)。 - `create_by/create_time/update_by/update_time/del_flag` — 审计与软删。 - 重要约定: - 文件型必须提供 `file_url + file_hash`;外链型必须提供 `link_url`。 - 仅允许压缩包(zip/rar/7z/tar/tar.gz/tar.bz2/tar.xz)或外链;>100MB 的文件由应用层拒绝。 - 状态流转:0→1/2,1→3(下架),2→0(修正后重提),3→0(修订后重上架);由后端控制。 ### 5) tb_course_resource_best(最佳标记表) - 用途:将“最佳”与主表解耦,是否最佳通过 LEFT JOIN 判断是否存在记录。 - 关键约束与索引: - PK:`id` - UK:`uk_best_resource(resource_id)`(一条资源仅可有一个“最佳”标记) - 字段说明: - `id` BIGINT PK — 主键。 - `resource_id` BIGINT NOT NULL — 资源ID(逻辑外键:tb_course_resource.id)。 - `best_by` VARCHAR(64) NOT NULL — 标记人(用户名快照)。 - `best_time` DATETIME NOT NULL — 标记时间。 - `create_by/create_time/update_by/update_time/del_flag` — 审计与软删。 - 业务约定:取消“最佳”即删除该行;不回退积分(详见积分规则)。 ### 6) tb_course_resource_log(操作审计表) - 用途:记录资源全生命周期的关键动作与上下文,便于追责与统计。 - 索引:`idx_log_resource_time(resource_id, create_time)` - 字段说明: - `id` BIGINT PK — 主键。 - `resource_id` BIGINT NOT NULL — 资源ID(逻辑外键:tb_course_resource.id)。 - `action` VARCHAR(32) NOT NULL — 'CREATE'/'EDIT'/'APPROVE'/'REJECT'/'ONLINE'/'OFFLINE'/'DOWNLOAD'/'DELETE'/'HARD_DELETE'。 - `actor_id` BIGINT / `actor_name` VARCHAR(64) — 操作者(系统自动动作可为空)。 - `ip` VARCHAR(64) / `user_agent` VARCHAR(255) — 访问来源信息。 - `detail` TEXT — JSON 文本,记录差异/意见等上下文。 - `result` VARCHAR(16) — 'SUCCESS'/'FAIL'。 - `create_by/create_time/update_by/update_time/del_flag` — 审计与软删。 ### 7) tb_cr_user_score(用户积分聚合,CR 专属) - 用途:按用户×专业聚合积分,并区分 `major_id=0` 的“全站总分”。 - 关键约束与索引: - PK:`id` - UK:`uk_user_major(user_id, major_id)`(同用户×专业唯一) - IDX:`idx_major_score(major_id, total_score)`、`idx_user(user_id)` - 字段说明: - `id` BIGINT PK — 主键。 - `user_id` BIGINT NOT NULL / `username` VARCHAR(64) NOT NULL — 用户标识与快照(逻辑外键:sys_user.id)。 - `major_id` BIGINT NOT NULL DEFAULT 0 — 维度:资源所属专业ID;0 表示全站聚合行。 - `total_score` INT DEFAULT 0 — 累计积分。 - `approve_count` INT DEFAULT 0 — 审核通过次数(仅首次通过计数)。 - `best_count` INT DEFAULT 0 — 被评为最佳次数(仅首次计数)。 - `remark` VARCHAR(255) — 备注。 - `create_by/create_time/update_by/update_time/del_flag` — 审计与软删。 ### 8) tb_cr_user_score_log(用户积分流水,CR 专属) - 用途:记录“首次事件”积分发放,保障幂等防刷;取消“最佳”不记负数流水。 - 关键约束与索引: - PK:`id` - UK:`uk_once_event(user_id, resource_id, event_type)`(每个用户×资源×事件仅一次) - IDX:`idx_user_time(user_id, create_time)`、`idx_major_time(major_id, create_time)` - 字段说明: - `id` BIGINT PK — 主键。 - `user_id` BIGINT NOT NULL / `username` VARCHAR(64) NOT NULL — 得分用户(资源上传者)。 - `major_id` BIGINT NOT NULL DEFAULT 0 — 资源所属专业;0 表示全站维度。 - `resource_id` BIGINT NOT NULL — 资源ID(逻辑外键:tb_course_resource.id)。 - `event_type` VARCHAR(16) NOT NULL — 'APPROVE'(首次通过)/'BEST'(首次设为最佳)。 - `delta` INT NOT NULL — 积分变动(正数)。 - `remark` VARCHAR(255) — 备注。 - `create_by/create_time/update_by/update_time/del_flag` — 审计与软删。 --- ## 枚举与状态 - 专业/课程 `status`:'0'=正常、'1'=停用。 - 资源 `resource_type`:0=文件、1=外链。 - 资源 `status`:0=待审、1=已通过、2=驳回、3=已下架。 - 日志 `action`:CREATE/EDIT/APPROVE/REJECT/ONLINE/OFFLINE/DOWNLOAD/DELETE/HARD_DELETE。 - 积分流水 `event_type`:APPROVE/BEST。 - 软删 `del_flag`:'0'=存在、'2'=删除。 --- ## 典型查询与用法示例 - 列表(含是否最佳): ```sql SELECT r.*, (b.id IS NOT NULL) AS is_best FROM tb_course_resource r LEFT JOIN tb_course_resource_best b ON b.resource_id = r.id WHERE r.status = 1 AND r.del_flag = '0' AND r.course_id = ? ORDER BY r.create_time DESC LIMIT ?, ?; ``` - 专业/课程筛选 + 审核队列: ```sql SELECT r.id, r.resource_name, r.status, r.create_time FROM tb_course_resource r WHERE r.major_id = ? AND r.status IN (0,2) AND r.del_flag='0' ORDER BY r.create_time ASC; ``` - 热门下载: ```sql SELECT id, resource_name, download_count FROM tb_course_resource WHERE status = 1 AND del_flag='0' ORDER BY download_count DESC, id ASC LIMIT 20; ``` - 排行榜(指定专业或全站): ```sql SELECT user_id, username, total_score, approve_count, best_count FROM tb_cr_user_score WHERE major_id = ? AND del_flag='0' ORDER BY total_score DESC, id ASC LIMIT 100; -- 全站:major_id = 0;分专业:major_id = 专业ID ``` - 下载计数落库(示意): ```sql -- 接口侧 Redis 计数:INCR app:cr:dl:{resourceId} -- 定时/阈值回写: UPDATE tb_course_resource SET download_count = download_count + ?, last_download_time = NOW(), update_by = 'system', update_time = NOW() WHERE id = ? AND del_flag='0'; ``` --- ## 设计要点与实现建议 - 去重策略: - 文件型:唯一键 `(course_id, resource_type, file_hash)`; - 外链型:唯一键 `(course_id, resource_type, link_url(191))`。 - 审核/最佳与积分: - 首次“审核通过”加 +5 分;首次“设为最佳”加 +10 分(MVP 固定值,后续可配置)。 - 取消“最佳”不扣分;再次通过/再次设为最佳不再加分(流水表唯一键保障幂等)。 - 聚合表同时维护两维度:`major_id=资源专业` 与 `major_id=0`(全站),便于生成两类榜单。 - 一致性: - 采用“逻辑外键 + 必要索引”,由应用层保证 `major_id` 与 `course_id` 的专业一致性。 - 资源更新为“文件→外链”或反向切换时,应校验并清理无效字段(file_* 或 link_url)。 - 性能与扩展: - 列表/审核频繁使用 `(course_id,status)`、`(status,create_time)`、`(major_id,course_id)` 索引; - 热点下载使用 `download_count` 索引,定时聚合回写; - 最佳推荐解耦为独立表,避免主表频繁结构调整。 - 安全与风控: - 文件类型与大小在应用层严格校验; - 外链需做白名单与 URL 规范化; - 审核日志写入 `tb_course_resource_log`,关键字段落 JSON `detail` 以便追溯。 --- ## 建表顺序与示例数据 - 建表顺序:`tb_major` → `tb_course` → `tb_major_lead` → `tb_course_resource` → `tb_course_resource_best` → `tb_course_resource_log` → `tb_cr_user_score` → `tb_cr_user_score_log`。 - 示例数据:参考 `docs/sql/课程资源分享-DDL.md` 中“示例基础数据”段(含专业/课程/资源/日志样例)。 --- ## 版本记录 - 2025-10-18:建立独立专业与课程;资源扩展仅限压缩包或外链;状态流转定义。 - 2025-11-04: - 最佳推荐改为独立表 `tb_course_resource_best`; - 新增积分聚合表 `tb_cr_user_score` 与流水表 `tb_cr_user_score_log`; - 明确与 `sys_user_role` 的角色联动约定(专业负责人)。 --- > 注:本文件为模型解释文档,标准 DDL 以 `docs/sql/课程资源分享-DDL.md` 为准;如有差异,以 DDL 为最终依据。