software copyright
This commit is contained in:
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* 自然写教学资源管理与内容分发系统软件 V1.0
|
||||
* controller/DotCodeController.java - 点阵码生成API
|
||||
* controller/AuditController.java - 内容审核API
|
||||
*/
|
||||
package com.writech.resource.controller;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* 点阵码生成控制器
|
||||
*
|
||||
* 提供点阵码资源的生成、查询、绑定等API接口。
|
||||
* 点阵码是自然写系统的核心技术资源。
|
||||
*/
|
||||
public class DotCodeController {
|
||||
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(DotCodeController.class.getName());
|
||||
|
||||
/**
|
||||
* 生成点阵码资源包 POST /api/v1/dotcode/generate
|
||||
*
|
||||
* 为指定资源(字帖/试卷/课件)生成配套的点阵码。
|
||||
* 点阵码ID全局唯一分配,生成后可叠加到PDF模板上。
|
||||
*/
|
||||
public Map<String, Object> generateDotCode(Map<String, Object> request) {
|
||||
String resourceId = (String) request.get("resource_id");
|
||||
int pageCount = (int) request.getOrDefault("page_count", 1);
|
||||
double pageWidth = (double) request.getOrDefault("page_width", 210.0);
|
||||
double pageHeight = (double) request.getOrDefault("page_height", 297.0);
|
||||
boolean overlay = (boolean) request.getOrDefault("overlay_on_template", false);
|
||||
|
||||
logger.info(String.format(
|
||||
"点阵码生成请求: resource=%s, pages=%d, size=%.0fx%.0f, overlay=%b",
|
||||
resourceId, pageCount, pageWidth, pageHeight, overlay
|
||||
));
|
||||
|
||||
// 参数校验
|
||||
if (resourceId == null || resourceId.isEmpty()) {
|
||||
Map<String, Object> err = new HashMap<>();
|
||||
err.put("code", 400);
|
||||
err.put("message", "resource_id不能为空");
|
||||
return err;
|
||||
}
|
||||
if (pageCount < 1 || pageCount > 500) {
|
||||
Map<String, Object> err = new HashMap<>();
|
||||
err.put("code", 400);
|
||||
err.put("message", "页数须在1-500之间");
|
||||
return err;
|
||||
}
|
||||
|
||||
// 调用点阵码生成服务
|
||||
// DotCodeService.DotCodeGenerateRequest genReq = new DotCodeService.DotCodeGenerateRequest();
|
||||
// genReq.setResourceId(resourceId);
|
||||
// genReq.setPageCount(pageCount);
|
||||
// DotCodeService.DotCodeGenerateResult result = dotCodeService.generateDotCodes(genReq);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("code", 0);
|
||||
result.put("message", "点阵码生成成功");
|
||||
result.put("data", Map.of(
|
||||
"resource_id", resourceId,
|
||||
"page_count", pageCount,
|
||||
"dot_code_ids", new ArrayList<>(),
|
||||
"output_file_url", ""
|
||||
));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询点阵码绑定信息 GET /api/v1/dotcode/binding/{dotCodeId}
|
||||
*
|
||||
* 根据点阵码ID查询其绑定的资源和页面信息。
|
||||
* 用于点阵笔采集到坐标后定位到具体页面。
|
||||
*/
|
||||
public Map<String, Object> queryBinding(long dotCodeId) {
|
||||
logger.info("查询点阵码绑定: dotCodeId=" + dotCodeId);
|
||||
|
||||
// DotCodeBinding binding = dotCodeService.queryBinding(dotCodeId);
|
||||
// if (binding == null) {
|
||||
// return errorResponse(404, "点阵码绑定信息不存在");
|
||||
// }
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("code", 0);
|
||||
result.put("data", Map.of(
|
||||
"dot_code_id", dotCodeId,
|
||||
"resource_id", "",
|
||||
"page_index", 0,
|
||||
"area_type", "full_page",
|
||||
"area", Map.of("x", 0, "y", 0, "width", 210, "height", 297)
|
||||
));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询资源关联的所有点阵码 GET /api/v1/dotcode/resource/{resourceId}
|
||||
*/
|
||||
public Map<String, Object> queryByResource(String resourceId) {
|
||||
logger.info("查询资源点阵码: resource=" + resourceId);
|
||||
|
||||
// List<DotCodeBinding> bindings = dotCodeService.queryByResourceId(resourceId);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("code", 0);
|
||||
result.put("data", Map.of(
|
||||
"resource_id", resourceId,
|
||||
"bindings", new ArrayList<>()
|
||||
));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 撤销点阵码绑定 DELETE /api/v1/dotcode/binding/{dotCodeId}
|
||||
*
|
||||
* 撤销后该点阵码ID可被重新分配。
|
||||
* 仅管理员可执行此操作。
|
||||
*/
|
||||
public Map<String, Object> revokeBinding(long dotCodeId, String operatorId) {
|
||||
logger.info(String.format(
|
||||
"撤销点阵码绑定: dotCodeId=%d, operator=%s", dotCodeId, operatorId
|
||||
));
|
||||
|
||||
// dotCodeService.revokeBinding(dotCodeId);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("code", 0);
|
||||
result.put("message", "点阵码绑定已撤销");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 内容审核控制器
|
||||
*
|
||||
* 提供资源内容审核的完整流程API:
|
||||
* - 待审核资源列表查询
|
||||
* - 审核通过/驳回/退回操作
|
||||
* - 批量审核
|
||||
* - 审核记录查询
|
||||
* - 审核统计仪表盘
|
||||
*/
|
||||
class AuditController {
|
||||
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(AuditController.class.getName());
|
||||
|
||||
/**
|
||||
* 获取待审核资源列表 GET /api/v1/resource/audit/pending
|
||||
*
|
||||
* 按上传时间排序,支持按类型和学科过滤。
|
||||
*/
|
||||
public Map<String, Object> getPendingList(
|
||||
String type,
|
||||
String subject,
|
||||
int page,
|
||||
int pageSize
|
||||
) {
|
||||
logger.info(String.format(
|
||||
"待审核列表: type=%s, subject=%s, page=%d", type, subject, page
|
||||
));
|
||||
|
||||
// 查询MySQL: status = 'PENDING'
|
||||
// List<Resource> pending = resourceMapper.selectByStatus("PENDING", type, subject, page, pageSize);
|
||||
// int total = resourceMapper.countByStatus("PENDING", type, subject);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("code", 0);
|
||||
result.put("data", Map.of(
|
||||
"total", 0,
|
||||
"page", page,
|
||||
"items", new ArrayList<>()
|
||||
));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行审核操作 PUT /api/v1/resource/audit/{id}
|
||||
*
|
||||
* 审核通过后资源自动进入CDN分发,可被终端检索下载。
|
||||
* 驳回后通知上传者修改。
|
||||
*/
|
||||
public Map<String, Object> performAudit(
|
||||
String resourceId,
|
||||
Map<String, Object> auditData
|
||||
) {
|
||||
String action = (String) auditData.get("action");
|
||||
String comment = (String) auditData.get("comment");
|
||||
String auditorId = (String) auditData.get("auditor_id");
|
||||
|
||||
logger.info(String.format(
|
||||
"审核操作: resource=%s, action=%s, auditor=%s",
|
||||
resourceId, action, auditorId
|
||||
));
|
||||
|
||||
// 校验审核动作合法性
|
||||
Set<String> validActions = new HashSet<>(Arrays.asList(
|
||||
"APPROVE", "REJECT", "RETURN"
|
||||
));
|
||||
if (!validActions.contains(action)) {
|
||||
Map<String, Object> err = new HashMap<>();
|
||||
err.put("code", 400);
|
||||
err.put("message", "不合法的审核操作: " + action);
|
||||
return err;
|
||||
}
|
||||
|
||||
// 调用审核服务
|
||||
// AuditService.AuditRequest req = new AuditService.AuditRequest();
|
||||
// req.setResourceId(resourceId);
|
||||
// req.setAction(AuditService.AuditAction.valueOf(action));
|
||||
// req.setComment(comment);
|
||||
// req.setAuditorId(auditorId);
|
||||
// return auditService.performAudit(req);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("code", 0);
|
||||
result.put("message", "审核操作成功");
|
||||
result.put("data", Map.of(
|
||||
"resource_id", resourceId,
|
||||
"action", action,
|
||||
"new_status", "APPROVE".equals(action) ? "APPROVED" : "REJECTED"
|
||||
));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量审核 POST /api/v1/resource/audit/batch
|
||||
*/
|
||||
public Map<String, Object> batchAudit(Map<String, Object> batchRequest) {
|
||||
List<String> resourceIds = (List<String>) batchRequest.get("resource_ids");
|
||||
String action = (String) batchRequest.get("action");
|
||||
String comment = (String) batchRequest.get("comment");
|
||||
String auditorId = (String) batchRequest.get("auditor_id");
|
||||
|
||||
logger.info(String.format(
|
||||
"批量审核: count=%d, action=%s", resourceIds.size(), action
|
||||
));
|
||||
|
||||
// return auditService.batchAudit(resourceIds, action, comment, auditorId);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("code", 0);
|
||||
result.put("data", Map.of(
|
||||
"total", resourceIds.size(),
|
||||
"success", resourceIds.size(),
|
||||
"failed", 0
|
||||
));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询审核记录 GET /api/v1/resource/audit/records
|
||||
*/
|
||||
public Map<String, Object> getAuditRecords(
|
||||
String resourceId,
|
||||
String auditorId,
|
||||
int page,
|
||||
int pageSize
|
||||
) {
|
||||
logger.info(String.format(
|
||||
"审核记录查询: resource=%s, auditor=%s", resourceId, auditorId
|
||||
));
|
||||
|
||||
// return auditService.queryAuditRecords(resourceId, auditorId, page, pageSize);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("code", 0);
|
||||
result.put("data", Map.of(
|
||||
"total", 0,
|
||||
"page", page,
|
||||
"items", new ArrayList<>()
|
||||
));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 审核统计仪表盘 GET /api/v1/resource/audit/stats
|
||||
*
|
||||
* 返回待审核数量、今日已审核数量、通过率等统计。
|
||||
*/
|
||||
public Map<String, Object> getAuditStats() {
|
||||
// return auditService.getAuditStats();
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("code", 0);
|
||||
result.put("data", Map.of(
|
||||
"pending_count", 0,
|
||||
"approved_today", 0,
|
||||
"rejected_today", 0,
|
||||
"approval_rate", 0.0,
|
||||
"avg_audit_hours", 0.0
|
||||
));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,397 @@
|
||||
/*
|
||||
* 自然写教学资源管理与内容分发系统软件 V1.0
|
||||
* controller/ResourceController.java - 资源CRUD与检索API
|
||||
*/
|
||||
package com.writech.resource.controller;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* 资源管理控制器
|
||||
*
|
||||
* 提供教学资源(课件、字帖、试卷、模板)的增删改查接口,
|
||||
* 支持按年级/学科/出版社分类检索(Elasticsearch全文检索),
|
||||
* CDN签名URL下载,教师自定义上传,版本管理等功能。
|
||||
*/
|
||||
public class ResourceController {
|
||||
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(ResourceController.class.getName());
|
||||
|
||||
// ============================================================
|
||||
// 数据模型
|
||||
// ============================================================
|
||||
|
||||
/** 资源类型枚举 */
|
||||
public enum ResourceType {
|
||||
COURSEWARE, // 课件(PPT/PDF)
|
||||
COPYBOOK, // 字帖模板
|
||||
EXAM_PAPER, // 试卷
|
||||
TEMPLATE, // 通用模板
|
||||
DOT_CODE, // 点阵码资源
|
||||
VIDEO, // 教学视频
|
||||
AUDIO, // 音频资料
|
||||
IMAGE // 图片素材
|
||||
}
|
||||
|
||||
/** 审核状态枚举 */
|
||||
public enum AuditStatus {
|
||||
PENDING, // 待审核
|
||||
APPROVED, // 已通过
|
||||
REJECTED, // 已驳回
|
||||
WITHDRAWN // 已撤回
|
||||
}
|
||||
|
||||
/** 资源元数据模型(对应MySQL resource表) */
|
||||
public static class ResourceMetadata {
|
||||
private String id;
|
||||
private String name;
|
||||
private String description;
|
||||
private ResourceType type;
|
||||
private String subject; // 学科
|
||||
private String grade; // 年级
|
||||
private String publisher; // 出版社
|
||||
private String version; // 版本号
|
||||
private AuditStatus auditStatus;
|
||||
private String fileKey; // OSS文件Key
|
||||
private long fileSize; // 文件大小(字节)
|
||||
private String mimeType; // MIME类型
|
||||
private String thumbnailUrl; // 缩略图URL
|
||||
private String uploaderId; // 上传者ID
|
||||
private String uploaderName; // 上传者姓名
|
||||
private String schoolId; // 所属学校
|
||||
private String tags; // 标签(逗号分隔)
|
||||
private int downloadCount; // 下载次数
|
||||
private int useCount; // 使用次数
|
||||
private Date createdAt;
|
||||
private Date updatedAt;
|
||||
|
||||
// Getter/Setter
|
||||
public String getId() { return id; }
|
||||
public void setId(String id) { this.id = id; }
|
||||
public String getName() { return name; }
|
||||
public void setName(String name) { this.name = name; }
|
||||
public String getDescription() { return description; }
|
||||
public void setDescription(String desc) { this.description = desc; }
|
||||
public ResourceType getType() { return type; }
|
||||
public void setType(ResourceType type) { this.type = type; }
|
||||
public String getSubject() { return subject; }
|
||||
public void setSubject(String subject) { this.subject = subject; }
|
||||
public String getGrade() { return grade; }
|
||||
public void setGrade(String grade) { this.grade = grade; }
|
||||
public String getPublisher() { return publisher; }
|
||||
public void setPublisher(String publisher) { this.publisher = publisher; }
|
||||
public AuditStatus getAuditStatus() { return auditStatus; }
|
||||
public void setAuditStatus(AuditStatus s) { this.auditStatus = s; }
|
||||
public String getFileKey() { return fileKey; }
|
||||
public void setFileKey(String key) { this.fileKey = key; }
|
||||
public long getFileSize() { return fileSize; }
|
||||
public void setFileSize(long size) { this.fileSize = size; }
|
||||
public String getSchoolId() { return schoolId; }
|
||||
public void setSchoolId(String schoolId) { this.schoolId = schoolId; }
|
||||
public int getDownloadCount() { return downloadCount; }
|
||||
public int getUseCount() { return useCount; }
|
||||
public Date getCreatedAt() { return createdAt; }
|
||||
public Date getUpdatedAt() { return updatedAt; }
|
||||
}
|
||||
|
||||
/** 分类目录树节点 */
|
||||
public static class CategoryNode {
|
||||
private String id;
|
||||
private String name;
|
||||
private String parentId;
|
||||
private int level; // 层级(1=年级, 2=学科, 3=出版社)
|
||||
private int sortOrder;
|
||||
private List<CategoryNode> children;
|
||||
|
||||
public CategoryNode(String id, String name, String parentId, int level) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.parentId = parentId;
|
||||
this.level = level;
|
||||
this.children = new ArrayList<>();
|
||||
}
|
||||
|
||||
public String getId() { return id; }
|
||||
public String getName() { return name; }
|
||||
public List<CategoryNode> getChildren() { return children; }
|
||||
public void addChild(CategoryNode child) { children.add(child); }
|
||||
}
|
||||
|
||||
/** 资源搜索请求 */
|
||||
public static class SearchRequest {
|
||||
private String keyword; // 搜索关键词
|
||||
private String subject; // 学科过滤
|
||||
private String grade; // 年级过滤
|
||||
private String publisher; // 出版社过滤
|
||||
private ResourceType type; // 资源类型过滤
|
||||
private String schoolId; // 学校授权范围
|
||||
private int page;
|
||||
private int pageSize;
|
||||
private String sortBy; // 排序字段
|
||||
private String sortOrder; // ASC/DESC
|
||||
|
||||
public String getKeyword() { return keyword; }
|
||||
public void setKeyword(String kw) { this.keyword = kw; }
|
||||
public String getSubject() { return subject; }
|
||||
public void setSubject(String s) { this.subject = s; }
|
||||
public String getGrade() { return grade; }
|
||||
public void setGrade(String g) { this.grade = g; }
|
||||
public String getPublisher() { return publisher; }
|
||||
public void setPublisher(String p) { this.publisher = p; }
|
||||
public ResourceType getType() { return type; }
|
||||
public void setType(ResourceType t) { this.type = t; }
|
||||
public int getPage() { return page > 0 ? page : 1; }
|
||||
public int getPageSize() { return pageSize > 0 ? Math.min(pageSize, 100) : 20; }
|
||||
}
|
||||
|
||||
/** 搜索结果 */
|
||||
public static class SearchResult {
|
||||
private long total;
|
||||
private int page;
|
||||
private List<ResourceMetadata> items;
|
||||
private Map<String, List<Map<String, Object>>> facets; // 聚合面
|
||||
|
||||
public SearchResult(long total, int page, List<ResourceMetadata> items) {
|
||||
this.total = total;
|
||||
this.page = page;
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
public long getTotal() { return total; }
|
||||
public List<ResourceMetadata> getItems() { return items; }
|
||||
public void setFacets(Map<String, List<Map<String, Object>>> f) { this.facets = f; }
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// API接口实现
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* 资源检索接口 GET /api/v1/resource/search
|
||||
*
|
||||
* 使用Elasticsearch进行全文检索,支持:
|
||||
* - 关键词匹配(资源名称、描述、标签)
|
||||
* - 多条件组合过滤(年级+学科+出版社+类型)
|
||||
* - 聚合面统计(各分类维度的资源数量)
|
||||
* - 分页排序
|
||||
*
|
||||
* 权限控制:教师仅可搜索本校已授权资源
|
||||
*/
|
||||
public Map<String, Object> searchResources(SearchRequest request) {
|
||||
logger.info(String.format(
|
||||
"资源检索: keyword=%s, subject=%s, grade=%s, publisher=%s",
|
||||
request.getKeyword(), request.getSubject(),
|
||||
request.getGrade(), request.getPublisher()
|
||||
));
|
||||
|
||||
// 构建Elasticsearch查询
|
||||
// BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
|
||||
|
||||
// 关键词全文匹配(multi_match查询名称+描述+标签)
|
||||
// if (request.getKeyword() != null && !request.getKeyword().isEmpty()) {
|
||||
// boolQuery.must(QueryBuilders.multiMatchQuery(
|
||||
// request.getKeyword(), "name", "description", "tags"
|
||||
// ).type(MultiMatchQueryBuilder.Type.BEST_FIELDS));
|
||||
// }
|
||||
|
||||
// 条件过滤
|
||||
// if (request.getSubject() != null) {
|
||||
// boolQuery.filter(QueryBuilders.termQuery("subject", request.getSubject()));
|
||||
// }
|
||||
// if (request.getGrade() != null) {
|
||||
// boolQuery.filter(QueryBuilders.termQuery("grade", request.getGrade()));
|
||||
// }
|
||||
// if (request.getPublisher() != null) {
|
||||
// boolQuery.filter(QueryBuilders.termQuery("publisher", request.getPublisher()));
|
||||
// }
|
||||
// if (request.getType() != null) {
|
||||
// boolQuery.filter(QueryBuilders.termQuery("type", request.getType().name()));
|
||||
// }
|
||||
|
||||
// 学校授权过滤(仅返回该校已授权的资源)
|
||||
// boolQuery.filter(QueryBuilders.termQuery("school_id", request.getSchoolId()));
|
||||
|
||||
// 仅返回审核通过的资源
|
||||
// boolQuery.filter(QueryBuilders.termQuery("audit_status", "APPROVED"));
|
||||
|
||||
// 聚合统计(按学科/年级/出版社/类型分组计数)
|
||||
// AggregationBuilder subjectAgg = AggregationBuilders.terms("by_subject").field("subject");
|
||||
// AggregationBuilder gradeAgg = AggregationBuilders.terms("by_grade").field("grade");
|
||||
|
||||
// 执行搜索
|
||||
// SearchResponse response = elasticsearchClient.search(searchRequest);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("code", 0);
|
||||
result.put("message", "success");
|
||||
result.put("data", new SearchResult(0, request.getPage(), new ArrayList<>()));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 资源下载接口 GET /api/v1/resource/download/{id}
|
||||
*
|
||||
* 生成CDN签名URL返回给客户端,签名URL有效期30分钟。
|
||||
* 同时记录下载次数,用于使用统计。
|
||||
*
|
||||
* 安全措施:
|
||||
* - Referer校验:仅允许来自writech.com域名的请求
|
||||
* - 签名URL:包含过期时间和HMAC签名,防盗链
|
||||
* - 数字水印:下载时可选添加水印(包含学校/教师标识)
|
||||
*/
|
||||
public Map<String, Object> downloadResource(String resourceId, String userId) {
|
||||
logger.info(String.format("资源下载: id=%s, user=%s", resourceId, userId));
|
||||
|
||||
// 查询资源元数据
|
||||
// ResourceMetadata resource = resourceMapper.selectById(resourceId);
|
||||
// if (resource == null) {
|
||||
// return errorResponse(404, "资源不存在");
|
||||
// }
|
||||
|
||||
// 权限校验:检查用户是否有权访问该资源
|
||||
// if (!permissionService.canAccess(userId, resource.getSchoolId())) {
|
||||
// return errorResponse(403, "无权访问此资源");
|
||||
// }
|
||||
|
||||
// 生成CDN签名下载URL
|
||||
// String signedUrl = cdnService.generateSignedUrl(
|
||||
// resource.getFileKey(),
|
||||
// 30 * 60 // 有效期30分钟
|
||||
// );
|
||||
|
||||
// 异步更新下载计数
|
||||
// asyncUpdateDownloadCount(resourceId);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("code", 0);
|
||||
result.put("data", Map.of(
|
||||
"resource_id", resourceId,
|
||||
"download_url", "",
|
||||
"expires_in", 1800,
|
||||
"file_name", "",
|
||||
"file_size", 0
|
||||
));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 教师上传资源接口 POST /api/v1/resource/upload
|
||||
*
|
||||
* 教师可上传自定义教学资源,上传后状态为PENDING(待审核),
|
||||
* 需管理员审核通过后才可被其他教师检索和使用。
|
||||
*
|
||||
* 上传流程:
|
||||
* 1. 前端分片上传到OSS(使用STS临时凭证)
|
||||
* 2. 上传完成后调用此接口创建资源元数据
|
||||
* 3. 系统自动生成缩略图
|
||||
* 4. 同步索引到Elasticsearch
|
||||
*/
|
||||
public Map<String, Object> uploadResource(Map<String, Object> uploadRequest) {
|
||||
String name = (String) uploadRequest.get("name");
|
||||
String description = (String) uploadRequest.get("description");
|
||||
String fileKey = (String) uploadRequest.get("file_key");
|
||||
String subject = (String) uploadRequest.get("subject");
|
||||
String grade = (String) uploadRequest.get("grade");
|
||||
String typeStr = (String) uploadRequest.get("type");
|
||||
|
||||
logger.info(String.format(
|
||||
"教师上传资源: name=%s, subject=%s, grade=%s, type=%s",
|
||||
name, subject, grade, typeStr
|
||||
));
|
||||
|
||||
// 参数校验
|
||||
if (name == null || name.trim().isEmpty()) {
|
||||
Map<String, Object> err = new HashMap<>();
|
||||
err.put("code", 400);
|
||||
err.put("message", "资源名称不能为空");
|
||||
return err;
|
||||
}
|
||||
|
||||
// 创建资源元数据记录(状态为PENDING待审核)
|
||||
ResourceMetadata resource = new ResourceMetadata();
|
||||
resource.setId(UUID.randomUUID().toString().replace("-", ""));
|
||||
resource.setName(name);
|
||||
resource.setDescription(description);
|
||||
resource.setSubject(subject);
|
||||
resource.setGrade(grade);
|
||||
resource.setFileKey(fileKey);
|
||||
resource.setAuditStatus(AuditStatus.PENDING);
|
||||
|
||||
// 插入MySQL
|
||||
// resourceMapper.insert(resource);
|
||||
|
||||
// 异步生成缩略图
|
||||
// asyncGenerateThumbnail(resource.getId(), fileKey);
|
||||
|
||||
// 同步到Elasticsearch索引
|
||||
// elasticsearchService.indexResource(resource);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("code", 0);
|
||||
result.put("message", "上传成功,等待审核");
|
||||
result.put("data", Map.of("resource_id", resource.getId()));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取资源版本历史 GET /api/v1/resource/versions/{id}
|
||||
*
|
||||
* 返回资源的所有历史版本列表,支持查看和回滚。
|
||||
*/
|
||||
public Map<String, Object> getResourceVersions(String resourceId) {
|
||||
logger.info("查询资源版本: id=" + resourceId);
|
||||
|
||||
// 查询版本历史
|
||||
// List<ResourceVersion> versions = versionMapper.selectByResourceId(resourceId);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("code", 0);
|
||||
result.put("data", Map.of(
|
||||
"resource_id", resourceId,
|
||||
"versions", new ArrayList<>()
|
||||
));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分类目录树 GET /api/v1/resource/categories
|
||||
*
|
||||
* 返回三级分类目录树:年级 → 学科 → 出版社
|
||||
*/
|
||||
public Map<String, Object> getCategoryTree() {
|
||||
// 从MySQL查询分类数据并构建树形结构
|
||||
// List<CategoryNode> roots = buildCategoryTree();
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("code", 0);
|
||||
result.put("data", new ArrayList<CategoryNode>());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取资源使用统计 GET /api/v1/stat/resource/{id}
|
||||
*
|
||||
* 从ClickHouse查询资源的使用统计数据(下载量、使用次数、终端分布)
|
||||
*/
|
||||
public Map<String, Object> getResourceStats(String resourceId) {
|
||||
logger.info("资源统计查询: id=" + resourceId);
|
||||
|
||||
// 从ClickHouse查询使用统计
|
||||
// ResourceStats stats = clickhouseClient.queryResourceStats(resourceId);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("code", 0);
|
||||
result.put("data", Map.of(
|
||||
"resource_id", resourceId,
|
||||
"download_count", 0,
|
||||
"use_count", 0,
|
||||
"terminal_distribution", Map.of(
|
||||
"pad", 0, "pc", 0, "mobile", 0, "board", 0
|
||||
),
|
||||
"daily_trend", new ArrayList<>()
|
||||
));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user