# 课程资源分享 API 文档(v2) 更新时间:2025-11-04 - 概览(注意:本文档为旧版总览,建议优先阅读分册文档:docs/api/课程资源-门户.md 与 docs/api/课程资源-管理.md) - 架构:前台门户(/portal 查询 + “我的资源”自助增删改/上下架)+ 后台管理(/manage 增删改审)。 - 业务:专业 → 课程 → 资源;资源支持压缩包(OSS)或外链;创建/编辑均进入审核流转。 - 角色:普通用户(user)、专业负责人(major_lead)、管理员(admin/super_admin)。 - 重要说明:门户侧 /portal 下的“我的资源”写操作仅需登录;后台管理 /manage 的写操作需对应 `manage:*` 按钮级权限(详见“权限与鉴权”)。 - 新增:资源支持“最佳推荐”标记(isBest),门户列表按 `isBest desc` 置顶展示。 ## 约定与通用 - 鉴权:统一请求头 `Authorization: Bearer `。 - 基础路径:门户只读 `/portal`;后台管理 `/manage`。 - 分页:`pageNum`(默1),`pageSize`(默10,建议≤50);返回 `{ rows, total }`。 - 排序:`orderByColumn`(白名单:create_time, download_count 等),`isAsc`(asc/desc)。 - 时间格式:`yyyy-MM-dd HH:mm:ss`。 - 响应包: - 成功:`{ code:200, msg:'成功', data: {...} }` 或 `{ code:200, rows:[...], total:n }` - 失败:`{ code:4xx/5xx, msg:'错误说明' }` - 错误码: - 400 参数错误/校验失败(含重复冲突) - 401 未登录;403 无权限;404 不存在 - 409 状态冲突(如非待审不可审核) - 413 负载过大(文件超限) - 幂等与唯一: - 文件:`(courseId, resourceType, fileHash)` 唯一 - 外链:`(courseId, resourceType, linkUrl)` 唯一(规范化:去空格、去尾斜杠、小写域名) - 文件限制:仅 zip/rar/7z/tar/tar.gz/tar.bz2/tar.xz;≤100MB;服务端二次校验。 ## 权限与鉴权 - 门户查询(/portal):登录即可,无需 `manage:*` 权限。 - 普通用户写操作(/manage):需授予以下按钮权限: - 上传:`manage:upload:oss` - 新增资源:`manage:courseResource:add` - 编辑/删除/上下架:`manage:courseResource:edit|remove|offline|online` - 审核/最佳:`manage:courseResource:approve|reject|best`(负责人/管理员) - 审核与课程维护: - 专业负责人:本专业范围内 `manage:course:*` 与 `manage:courseResource:approve|reject` - 管理员:全量 `manage:*` ## 数据模型(Schema) - Major ```json { "id": 1, "majorName": "计算机科学与技术", "status": "0", "remark": "", "createTime": "2025-10-18 10:00:00", "updateTime": null } ``` - Course ```json { "id": 4101, "majorId": 4, "courseName": "数据结构", "courseCode": "CS-DS", "status": "0", "remark": "", "createTime": "2025-10-18 10:00:00", "updateTime": null, "majorName": "计算机科学与技术" } ``` - Resource ```json { "id": 10001, "majorId": 4, "courseId": 4101, "resourceName": "数据结构-资料包示例", "resourceType": 0, "fileUrl": "https://oss-example/bucket/cs/ds/sample.zip", "fileHash": "sha256:...", "fileSize": 102400, "linkUrl": null, "description": "示例数据:包含笔记与课件", "status": 1, "isBest": 1, "bestBy": "majorLeadA", "bestTime": "2025-11-04 12:00:00", "auditBy": "admin", "auditTime": "2025-10-18 12:00:00", "auditReason": null, "publishTime": "2025-10-18 12:00:00", "downloadCount": 5, "lastDownloadTime": "2025-10-18 12:30:00", "uploaderId": 1, "uploaderName": "admin", "createTime": "2025-10-18 11:00:00", "updateTime": "2025-10-18 11:10:00", "majorName": "计算机科学与技术", "courseName": "数据结构" } ``` ## 门户只读接口(/portal) ### 专业列表 - GET `/portal/major/list` - Query:`majorName?`,分页 - Resp:`{ rows: Major[], total }` ### 课程列表 - GET `/portal/course/list` - Query:`majorId`,`courseName?`,分页 ### 资源列表(仅已通过) - GET `/portal/resource/list` - Query:`majorId?`,`courseId?`,`keyword?`,分页 ### 资源详情 - GET `/portal/resource/{id}` ### 下载(计数+302) - GET `/portal/resource/{id}/download` - 说明:计数成功后 302 跳转至 `fileUrl/linkUrl`;门户接口需登录(暂不开放匿名) ### 排行榜 - GET `/portal/resource/top` - Query:`scope=global|major|course`(默global),`majorId?`,`courseId?`,`days?=7`,`limit?=10` - Resp:`Resource[]`(按 `downloadCount` 降序) ### 用户积分排行榜(新增) - GET `/portal/score/rank` - 业务:按积分从高到低进行用户排名;可筛选专业;默认统计全站 - Query: - `majorId?`(long,可选;缺省或 0=全站;>0=指定专业) - `pageNum?`(int,默认1) - `pageSize?`(int,默认10,建议≤50) - Resp:`{ rows: RankItem[], total }` - RankItem: ```json { "rank": 1, "userId": 100, "username": "alice", "majorId": 4, "majorName": "计算机科学与技术", "totalScore": 135, "approveCount": 12, "bestCount": 3 } ``` 前端展示说明(非接口): - 每行显示“代表作Top5”(按下载数降序,取该用户 `/portal/resource/list?uploaderId=[&majorId=]` 的结果本地排序生成)。 - 点击用户名弹出抽屉,集中展示“全部代表作”,支持筛选(关键词/课程/类型/仅最佳)与排序(按下载/按时间)。 ## 后台管理接口(/manage) ### 专业(Major) - GET `/manage/major/list` 权限:`manage:major:list` - POST `/manage/major` 权限:`manage:major:add` - PUT `/manage/major` 权限:`manage:major:edit` - DELETE `/manage/major/{ids}` 权限:`manage:major:remove` ### 课程(Course) - GET `/manage/course/list` 权限:`manage:course:list` - POST `/manage/course` 权限:`manage:course:add` - PUT `/manage/course` 权限:`manage:course:edit` - DELETE `/manage/course/{ids}` 权限:`manage:course:remove` - 说明:同专业下课程名唯一;负责人仅本专业。 ### 资源(Resource) - GET `/manage/courseResource/list` 权限:`manage:courseResource:list` - GET `/manage/courseResource/{id}` 权限:`manage:courseResource:query` - POST `/manage/courseResource` 权限:`manage:courseResource:add` - 文件型:`{ majorId, courseId, resourceName, resourceType:0, fileUrl, fileHash, fileSize, description }` - 外链型:`{ majorId, courseId, resourceName, resourceType:1, linkUrl, description }` - PUT `/manage/courseResource` 权限:`manage:courseResource:edit`(编辑即待审) - DELETE `/manage/courseResource/{ids}` 权限:`manage:courseResource:remove` - 学生:仅能删除本人“待审/驳回/已下架”;已通过需先下架 - 负责人/管理员:可强制删除(仅删库,不删 OSS) - PUT `/manage/courseResource/{id}/approve` 权限:`manage:courseResource:approve` - PUT `/manage/courseResource/{id}/reject` 权限:`manage:courseResource:reject` Body:`{ reason }`(必填) - PUT `/manage/courseResource/{id}/offline` 权限:`manage:courseResource:offline` Body:`{ reason }`(必填) - PUT `/manage/courseResource/{id}/online` 权限:`manage:courseResource:online`(置为待审) - GET `/manage/courseResource/{id}/download` 权限:`manage:courseResource:download`(后台使用,不建议前台使用) - GET `/manage/courseResource/top` 权限:`manage:courseResource:list` ### 最佳推荐(Best) - PUT `/manage/courseResource/{id}/best` 权限:`manage:courseResource:best` - 说明:设为最佳。管理员或本专业 `major_lead` 可操作 - PUT `/manage/courseResource/{id}/unbest` 权限:`manage:courseResource:best` - 说明:取消最佳 返回字段补充(详情/列表均可能包含): - `isBest`:0/1 是否为最佳 - `bestBy`:标记人 - `bestTime`:标记时间 - `auditReason`:驳回/下架原因(当 status=2/3 时建议前端详情页高亮显示) ### 用户积分排行榜(后台) - GET `/manage/score/user/rank` - 权限:`manage:score:list` - Query:同门户接口;支持分页;可扩展导出 - 返回:同门户接口 ### 专业负责人(MajorLead & 角色联动) - GET `/manage/majorLead/list` 权限:`manage:majorLead:list` - 说明:返回 `tb_major_lead` 映射列表;支持 `majorId`/`userId` 查询;分页 - GET `/manage/majorLead/roleUsers` 权限:`manage:majorLead:list` - 说明:返回所有拥有 RuoYi 角色 `major_lead` 的用户;若传 `majorId`,仅返回已绑定该专业的用户;分页 - 返回示例:`{ rows: [{ userId, userName, nickName, majorIds:"1,2", majorNames:"计算机科学与技术,数学" }], total }` - GET `/manage/majorLead/myMajors` 权限:`manage:majorLead:list` - 说明:返回当前登录用户被分配到的专业列表([{ id, majorName }...])。前端“课程管理/新增课程”的专业下拉在 `major_lead` 角色下使用该接口,仅允许选择被分配的专业。 - POST `/manage/majorLead` 权限:`manage:majorLead:add` - Body:`{ majorId, userId, remark? }` - 行为: 1) 新增 `tb_major_lead(major_id, user_id)`(唯一组合) 2) 若该用户未拥有 `major_lead` 角色,则自动写入 `sys_user_role` - 校验:`userId` 必须存在于 `sys_user` 且 `del_flag='0'` - DELETE `/manage/majorLead/{ids}` 权限:`manage:majorLead:remove` - 行为:删除映射;如该用户不再承担任何专业负责人(`tb_major_lead` 中计数=0),则自动从 `sys_user_role` 撤销 `major_lead` 角色 - DELETE `/manage/majorLead?majorId=..&userId=..` 权限:`manage:majorLead:remove` - 行为同上(按专业+用户删除) - DELETE `/manage/majorLead/retire/{userId}` 权限:`manage:majorLead:remove` - 行为:卸任负责人。删除该用户在 `tb_major_lead` 的所有记录,并从 `sys_user_role` 撤销 `major_lead` 角色 示例:查询所有拥有 major_lead 角色的用户 ```bash curl -H "Authorization: Bearer $TOKEN" \ "$BASE/manage/majorLead/roleUsers?pageNum=1&pageSize=10" ``` 示例:给用户 7 绑定“计算机科学”专业负责人 ```bash curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \ -d '{"majorId":1,"userId":7}' \ "$BASE/manage/majorLead" ``` 示例:删除绑定(若用户不再承担任何专业,则自动撤销角色) ```bash curl -X DELETE -H "Authorization: Bearer $TOKEN" \ "$BASE/manage/majorLead?majorId=1&userId=7" ``` ## 示例(curl) ### 门户:查询资源列表(仅已通过) ```bash curl -H "Authorization: Bearer $TOKEN" \ "$BASE/portal/resource/list?pageNum=1&pageSize=10&majorId=4&courseId=4101" ``` ### 管理:新增(文件型) ```bash curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \ -d '{ "majorId": 4, "courseId": 4101, "resourceName": "数据结构-作业合集", "resourceType": 0, "fileUrl": "https://oss/bucket/xxx.zip", "fileHash": "sha256:abcd...", "fileSize": 73400320, "description": "包含平时作业与解答" }' \ "$BASE/manage/courseResource" ``` ### 审核驳回 ```bash curl -X PUT -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \ -d '{"reason":"外链不可达,请修正后再提交"}' \ "$BASE/manage/courseResource/10086/reject" ``` ## 积分发放说明(仅文档说明,接口由审核/最佳触发) - 审核通过(首次):上传者获得 +5 积分;流水 `event_type=APPROVE`;若重复则忽略 - 标记最佳(首次):上传者获得 +10 积分;流水 `event_type=BEST`;取消最佳不扣分 - 聚合更新:对 `(user_id, major_id=资源专业)` 与 `(user_id, major_id=0)` 分别累计 `total_score/approve_count/best_count`;`majorName` 通过联查 `tb_major` 获取 ## 备注与最佳实践 - 幂等:利用唯一索引避免重复;前端提交前可提示“检测到重复,是否继续”。 - 排序:默认 `create_time desc`;下载榜按 `download_count desc`。 - 安全:文件类型与大小后端二次校验;OSS 凭据走环境变量;敏感配置不入库/不入 Git。 - 前后端对齐:门户仅读,写操作统一走 `/manage` 并按按钮权限控制,普通用户需要写权限方可上传。 - 下载: - 门户下载 `/portal/resource/{id}/download` 需登录(携带 Authorization 头),计数后 302 跳转; - 管理端下载 `/manage/courseResource/{id}/download` 需对应按钮权限;若使用 `window.open`,可追加 `?token=` 完成认证。