feat(Materials): add new materials navigation and href functions
All checks were successful
Frontend CI / build-and-push-web (push) Successful in 2m59s
Frontend CI / ota-android (push) Successful in 18m11s
Frontend CI / build-android-apk (push) Successful in 1h21m54s

- Introduced href functions for accessing materials, including hrefMaterials, hrefMaterialSubject, and hrefMaterialDetail.
- Updated AppsScreen to include a new entry for materials, enhancing the app's educational resources section.
- Exported material types in index.ts to support the new materials functionality.
This commit is contained in:
lafay
2026-03-25 21:17:17 +08:00
parent 619f08275c
commit 9529ea39c4
14 changed files with 2099 additions and 0 deletions

View File

@@ -0,0 +1,418 @@
/**
* 学习资料 Mock 数据
*/
import type { MaterialSubject, MaterialFile, MaterialFileType, SUBJECT_COLORS } from '../../types/material';
// 学科分类 Mock 数据
export const MOCK_SUBJECTS: MaterialSubject[] = [
{
id: 'subject-math',
name: '数学',
icon: 'calculator-variant',
color: '#FF6B6B',
description: '高等数学、线性代数、概率论等',
sort_order: 1,
material_count: 15,
created_at: '2024-01-01T00:00:00Z',
updated_at: '2024-03-20T10:00:00Z',
},
{
id: 'subject-english',
name: '英语',
icon: 'translate',
color: '#4ECDC4',
description: '四六级、考研英语、托福雅思等',
sort_order: 2,
material_count: 12,
created_at: '2024-01-01T00:00:00Z',
updated_at: '2024-03-18T14:30:00Z',
},
{
id: 'subject-physics',
name: '物理',
icon: 'atom',
color: '#45B7D1',
description: '大学物理、电磁学、力学等',
sort_order: 3,
material_count: 8,
created_at: '2024-01-01T00:00:00Z',
updated_at: '2024-03-15T09:00:00Z',
},
{
id: 'subject-chemistry',
name: '化学',
icon: 'flask',
color: '#96CEB4',
description: '有机化学、无机化学、分析化学等',
sort_order: 4,
material_count: 6,
created_at: '2024-01-01T00:00:00Z',
updated_at: '2024-03-10T16:00:00Z',
},
{
id: 'subject-cs',
name: '计算机',
icon: 'laptop',
color: '#FFEAA7',
description: '数据结构、算法、操作系统等',
sort_order: 5,
material_count: 20,
created_at: '2024-01-01T00:00:00Z',
updated_at: '2024-03-22T11:30:00Z',
},
{
id: 'subject-economics',
name: '经济管理',
icon: 'chart-line',
color: '#DDA0DD',
description: '微观经济学、宏观经济学、管理学等',
sort_order: 6,
material_count: 10,
created_at: '2024-01-01T00:00:00Z',
updated_at: '2024-03-19T08:45:00Z',
},
{
id: 'subject-law',
name: '法学',
icon: 'scale-balance',
color: '#F39C12',
description: '民法、刑法、宪法等',
sort_order: 7,
material_count: 7,
created_at: '2024-01-01T00:00:00Z',
updated_at: '2024-03-12T13:20:00Z',
},
{
id: 'subject-chinese',
name: '语文文学',
icon: 'book-open-page-variant',
color: '#3498DB',
description: '古代文学、现代文学、写作等',
sort_order: 8,
material_count: 5,
created_at: '2024-01-01T00:00:00Z',
updated_at: '2024-03-08T15:00:00Z',
},
];
// 文件资料 Mock 数据
export const MOCK_MATERIALS: MaterialFile[] = [
// 数学
{
id: 'math-001',
subject_id: 'subject-math',
title: '高等数学上册重点笔记',
description: '包含极限、导数、积分等重点章节的详细笔记,配有典型例题解析',
file_type: 'pdf',
file_size: 5242880, // 5MB
file_url: 'https://example.com/materials/math/advanced_math_1.pdf',
file_name: '高等数学上册重点笔记.pdf',
download_count: 1256,
author_name: '张同学',
tags: ['高等数学', '期末复习', '重点笔记'],
created_at: '2024-01-15T10:00:00Z',
updated_at: '2024-02-20T14:30:00Z',
},
{
id: 'math-002',
subject_id: 'subject-math',
title: '线性代数公式大全',
description: '线性代数所有公式汇总,适合考前突击复习',
file_type: 'pdf',
file_size: 1572864, // 1.5MB
file_url: 'https://example.com/materials/math/linear_algebra_formulas.pdf',
file_name: '线性代数公式大全.pdf',
download_count: 2341,
author_name: '李同学',
tags: ['线性代数', '公式', '复习'],
created_at: '2024-01-20T09:00:00Z',
updated_at: '2024-01-20T09:00:00Z',
},
{
id: 'math-003',
subject_id: 'subject-math',
title: '概率论与数理统计课件',
description: '概率论课程完整PPT课件包含所有章节',
file_type: 'ppt',
file_size: 15728640, // 15MB
file_url: 'https://example.com/materials/math/probability_slides.pptx',
file_name: '概率论与数理统计课件.pptx',
download_count: 876,
author_name: '王老师',
tags: ['概率论', '课件', 'PPT'],
created_at: '2024-02-01T08:00:00Z',
updated_at: '2024-02-15T10:00:00Z',
},
// 英语
{
id: 'english-001',
subject_id: 'subject-english',
title: '四级核心词汇手册',
description: '精选四级核心词汇2000个附带例句和记忆技巧',
file_type: 'pdf',
file_size: 3145728, // 3MB
file_url: 'https://example.com/materials/english/cet4_vocabulary.pdf',
file_name: '四级核心词汇手册.pdf',
download_count: 3567,
author_name: '刘同学',
tags: ['四级', '词汇', '备考'],
created_at: '2024-01-10T11:00:00Z',
updated_at: '2024-02-28T16:00:00Z',
},
{
id: 'english-002',
subject_id: 'subject-english',
title: '六级阅读理解技巧总结',
description: '六级阅读理解题型分析与解题技巧,包含真题解析',
file_type: 'word',
file_size: 2097152, // 2MB
file_url: 'https://example.com/materials/english/cet6_reading.docx',
file_name: '六级阅读理解技巧总结.docx',
download_count: 1892,
author_name: '陈同学',
tags: ['六级', '阅读理解', '技巧'],
created_at: '2024-01-25T14:00:00Z',
updated_at: '2024-01-25T14:00:00Z',
},
{
id: 'english-003',
subject_id: 'subject-english',
title: '考研英语作文模板',
description: '考研英语大作文、小作文模板合集,覆盖常考话题',
file_type: 'pdf',
file_size: 1048576, // 1MB
file_url: 'https://example.com/materials/english/kaoyan_writing.pdf',
file_name: '考研英语作文模板.pdf',
download_count: 4521,
author_name: '周同学',
tags: ['考研', '英语', '作文'],
created_at: '2024-02-05T10:30:00Z',
updated_at: '2024-03-10T09:00:00Z',
},
// 物理
{
id: 'physics-001',
subject_id: 'subject-physics',
title: '大学物理期末复习提纲',
description: '大学物理上下册复习要点,包含公式总结和典型例题',
file_type: 'pdf',
file_size: 4194304, // 4MB
file_url: 'https://example.com/materials/physics/university_physics_review.pdf',
file_name: '大学物理期末复习提纲.pdf',
download_count: 987,
author_name: '吴同学',
tags: ['大学物理', '复习', '期末'],
created_at: '2024-01-18T15:00:00Z',
updated_at: '2024-02-22T11:00:00Z',
},
{
id: 'physics-002',
subject_id: 'subject-physics',
title: '电磁学实验报告模板',
description: '电磁学实验报告标准格式和填写示例',
file_type: 'word',
file_size: 524288, // 512KB
file_url: 'https://example.com/materials/physics/em_lab_template.docx',
file_name: '电磁学实验报告模板.docx',
download_count: 654,
author_name: '实验室',
tags: ['电磁学', '实验', '报告'],
created_at: '2024-02-10T09:00:00Z',
updated_at: '2024-02-10T09:00:00Z',
},
// 化学
{
id: 'chemistry-001',
subject_id: 'subject-chemistry',
title: '有机化学反应机理汇总',
description: '有机化学常见反应机理图文详解',
file_type: 'pdf',
file_size: 8388608, // 8MB
file_url: 'https://example.com/materials/chemistry/organic_mechanisms.pdf',
file_name: '有机化学反应机理汇总.pdf',
download_count: 1123,
author_name: '赵同学',
tags: ['有机化学', '反应机理', '重点'],
created_at: '2024-01-22T10:00:00Z',
updated_at: '2024-02-18T14:00:00Z',
},
// 计算机
{
id: 'cs-001',
subject_id: 'subject-cs',
title: '数据结构与算法笔记',
description: '数据结构核心内容整理,包含时间复杂度分析和代码实现',
file_type: 'pdf',
file_size: 7340032, // 7MB
file_url: 'https://example.com/materials/cs/data_structures.pdf',
file_name: '数据结构与算法笔记.pdf',
download_count: 5678,
author_name: '孙同学',
tags: ['数据结构', '算法', '笔记'],
created_at: '2024-01-05T08:00:00Z',
updated_at: '2024-03-15T10:30:00Z',
},
{
id: 'cs-002',
subject_id: 'subject-cs',
title: '操作系统概念详解',
description: '操作系统核心概念讲解,进程、内存、文件系统等',
file_type: 'pdf',
file_size: 6291456, // 6MB
file_url: 'https://example.com/materials/cs/operating_systems.pdf',
file_name: '操作系统概念详解.pdf',
download_count: 3421,
author_name: '钱同学',
tags: ['操作系统', '计算机', '笔记'],
created_at: '2024-01-12T09:30:00Z',
updated_at: '2024-02-25T16:00:00Z',
},
{
id: 'cs-003',
subject_id: 'subject-cs',
title: '计算机网络课件',
description: '计算机网络课程完整PPT涵盖TCP/IP协议栈',
file_type: 'ppt',
file_size: 20971520, // 20MB
file_url: 'https://example.com/materials/cs/network_slides.pptx',
file_name: '计算机网络课件.pptx',
download_count: 2134,
author_name: '计算机学院',
tags: ['计算机网络', '课件', 'PPT'],
created_at: '2024-02-08T10:00:00Z',
updated_at: '2024-02-28T09:00:00Z',
},
{
id: 'cs-004',
subject_id: 'subject-cs',
title: 'LeetCode刷题笔记',
description: 'LeetCode热门题目解题思路和代码实现',
file_type: 'pdf',
file_size: 10485760, // 10MB
file_url: 'https://example.com/materials/cs/leetcode_notes.pdf',
file_name: 'LeetCode刷题笔记.pdf',
download_count: 8765,
author_name: '郑同学',
tags: ['算法', '面试', 'LeetCode'],
created_at: '2024-01-28T14:00:00Z',
updated_at: '2024-03-20T11:00:00Z',
},
// 经济管理
{
id: 'economics-001',
subject_id: 'subject-economics',
title: '微观经济学重点总结',
description: '微观经济学核心理论和图形分析',
file_type: 'pdf',
file_size: 3145728, // 3MB
file_url: 'https://example.com/materials/economics/microeconomics.pdf',
file_name: '微观经济学重点总结.pdf',
download_count: 1456,
author_name: '冯同学',
tags: ['微观经济学', '重点', '复习'],
created_at: '2024-01-30T11:00:00Z',
updated_at: '2024-02-20T15:00:00Z',
},
{
id: 'economics-002',
subject_id: 'subject-economics',
title: '管理学案例分析模板',
description: '管理学课程案例分析报告格式和范例',
file_type: 'word',
file_size: 1572864, // 1.5MB
file_url: 'https://example.com/materials/economics/management_case.docx',
file_name: '管理学案例分析模板.docx',
download_count: 876,
author_name: '商学院',
tags: ['管理学', '案例分析', '模板'],
created_at: '2024-02-12T10:00:00Z',
updated_at: '2024-02-12T10:00:00Z',
},
// 法学
{
id: 'law-001',
subject_id: 'subject-law',
title: '民法总则笔记',
description: '民法总则核心知识点梳理',
file_type: 'pdf',
file_size: 2621440, // 2.5MB
file_url: 'https://example.com/materials/law/civil_law.pdf',
file_name: '民法总则笔记.pdf',
download_count: 765,
author_name: '何同学',
tags: ['民法', '笔记', '法学'],
created_at: '2024-02-03T09:00:00Z',
updated_at: '2024-02-15T14:00:00Z',
},
// 语文文学
{
id: 'chinese-001',
subject_id: 'subject-chinese',
title: '古代文学作品选读',
description: '中国古代文学经典篇目赏析',
file_type: 'pdf',
file_size: 5242880, // 5MB
file_url: 'https://example.com/materials/chinese/ancient_literature.pdf',
file_name: '古代文学作品选读.pdf',
download_count: 543,
author_name: '中文系',
tags: ['古代文学', '作品选', '赏析'],
created_at: '2024-02-18T14:00:00Z',
updated_at: '2024-02-18T14:00:00Z',
},
];
// 获取学科列表
export function getMockSubjects(): Promise<MaterialSubject[]> {
return new Promise((resolve) => {
setTimeout(() => {
resolve([...MOCK_SUBJECTS].sort((a, b) => a.sort_order - b.sort_order));
}, 300);
});
}
// 根据学科ID获取资料列表
export function getMockMaterialsBySubject(subjectId: string): Promise<MaterialFile[]> {
return new Promise((resolve) => {
setTimeout(() => {
const materials = MOCK_MATERIALS.filter((m) => m.subject_id === subjectId);
resolve(materials);
}, 300);
});
}
// 搜索资料
export function searchMockMaterials(keyword: string): Promise<MaterialFile[]> {
return new Promise((resolve) => {
setTimeout(() => {
const lowerKeyword = keyword.toLowerCase();
const materials = MOCK_MATERIALS.filter(
(m) =>
m.title.toLowerCase().includes(lowerKeyword) ||
m.description?.toLowerCase().includes(lowerKeyword) ||
m.tags?.some((t) => t.toLowerCase().includes(lowerKeyword))
);
resolve(materials);
}, 300);
});
}
// 根据ID获取资料详情
export function getMockMaterialById(id: string): Promise<MaterialFile | null> {
return new Promise((resolve) => {
setTimeout(() => {
const material = MOCK_MATERIALS.find((m) => m.id === id);
resolve(material || null);
}, 200);
});
}
// 根据ID获取学科详情
export function getMockSubjectById(id: string): Promise<MaterialSubject | null> {
return new Promise((resolve) => {
setTimeout(() => {
const subject = MOCK_SUBJECTS.find((s) => s.id === id);
resolve(subject || null);
}, 200);
});
}

View File

@@ -0,0 +1,289 @@
/**
* 学习资料 Repository
* 提供学习资料的数据访问接口
*/
import type {
MaterialSubject,
MaterialFile,
MaterialFileType,
} from '../../types/material';
import { api } from '../../services/api';
// ==================== 接口定义 ====================
export interface GetMaterialsParams {
subjectId?: string;
fileType?: MaterialFileType;
keyword?: string;
sortBy?: 'createdAt' | 'downloadCount' | 'title';
sortOrder?: 'asc' | 'desc';
page?: number;
pageSize?: number;
}
export interface MaterialsResult {
materials: MaterialFile[];
total: number;
page: number;
pageSize: number;
hasMore: boolean;
}
// ==================== API 响应类型 ====================
interface SubjectResponse {
id: string;
name: string;
icon: string;
color: string;
description: string;
sort_order: number;
is_active: boolean;
material_count: number;
created_at: string;
updated_at: string;
}
interface MaterialFileResponse {
id: string;
subject_id: string;
title: string;
description: string;
file_type: string;
file_size: number;
file_url: string;
file_name: string;
download_count: number;
author_id: string;
tags: string[];
status: string;
created_at: string;
updated_at: string;
subject?: SubjectResponse;
}
// ==================== 转换函数 ====================
function toMaterialSubject(res: SubjectResponse): MaterialSubject {
return {
id: res.id,
name: res.name,
icon: res.icon,
color: res.color,
description: res.description,
sort_order: res.sort_order,
is_active: res.is_active,
material_count: res.material_count,
created_at: res.created_at,
updated_at: res.updated_at,
};
}
function toMaterialFile(res: MaterialFileResponse): MaterialFile {
return {
id: res.id,
subject_id: res.subject_id,
title: res.title,
description: res.description,
file_type: res.file_type as MaterialFileType,
file_size: res.file_size,
file_url: res.file_url,
file_name: res.file_name,
download_count: res.download_count,
author_id: res.author_id,
tags: res.tags || [],
status: res.status as 'active' | 'inactive',
created_at: res.created_at,
updated_at: res.updated_at,
subject: res.subject ? toMaterialSubject(res.subject) : undefined,
};
}
// ==================== Repository 实现 ====================
/**
* 学习资料数据仓库
* 使用真实 API
*/
export class MaterialRepository {
private static instance: MaterialRepository;
private constructor() {}
static getInstance(): MaterialRepository {
if (!MaterialRepository.instance) {
MaterialRepository.instance = new MaterialRepository();
}
return MaterialRepository.instance;
}
/**
* 获取学科分类列表
*/
async getSubjects(): Promise<MaterialSubject[]> {
try {
const response = await api.get<{ list: SubjectResponse[] }>('/materials/subjects');
return response.data.list.map(toMaterialSubject);
} catch (error) {
console.error('获取学科列表失败:', error);
return [];
}
}
/**
* 根据ID获取学科详情
*/
async getSubjectById(id: string): Promise<MaterialSubject | null> {
try {
const response = await api.get<SubjectResponse>(`/materials/subjects/${id}`);
return toMaterialSubject(response.data);
} catch (error) {
console.error('获取学科详情失败:', error);
return null;
}
}
/**
* 获取资料列表
*/
async getMaterials(params: GetMaterialsParams): Promise<MaterialsResult> {
const {
subjectId,
fileType,
keyword,
sortBy = 'createdAt',
sortOrder = 'desc',
page = 1,
pageSize = 20,
} = params;
try {
const queryParams: Record<string, any> = {
page,
page_size: pageSize,
};
if (subjectId) {
queryParams.subject_id = subjectId;
}
if (fileType) {
queryParams.file_type = fileType;
}
if (keyword) {
queryParams.keyword = keyword;
}
const response = await api.get<{
list: MaterialFileResponse[];
total: number;
page: number;
page_size: number;
has_more: boolean;
}>('/materials', queryParams);
return {
materials: response.data.list.map(toMaterialFile),
total: response.data.total,
page: response.data.page,
pageSize: response.data.page_size,
hasMore: response.data.has_more,
};
} catch (error) {
console.error('获取资料列表失败:', error);
return {
materials: [],
total: 0,
page: 1,
pageSize,
hasMore: false,
};
}
}
/**
* 根据ID获取资料详情
*/
async getMaterialById(id: string): Promise<MaterialFile | null> {
try {
const response = await api.get<MaterialFileResponse>(`/materials/${id}`);
return toMaterialFile(response.data);
} catch (error) {
console.error('获取资料详情失败:', error);
return null;
}
}
/**
* 搜索资料
*/
async searchMaterials(keyword: string, params?: { fileType?: MaterialFileType }): Promise<MaterialsResult> {
return this.getMaterials({
keyword,
fileType: params?.fileType,
});
}
/**
* 获取热门资料
*/
async getHotMaterials(limit: number = 10): Promise<MaterialFile[]> {
try {
const response = await api.get<{
list: MaterialFileResponse[];
total: number;
page: number;
page_size: number;
has_more: boolean;
}>('/materials', {
page: 1,
page_size: limit,
sort_by: 'download_count',
sort_order: 'desc',
});
return response.data.list.map(toMaterialFile);
} catch (error) {
console.error('获取热门资料失败:', error);
return [];
}
}
/**
* 获取最新资料
*/
async getLatestMaterials(limit: number = 10): Promise<MaterialFile[]> {
try {
const response = await api.get<{
list: MaterialFileResponse[];
total: number;
page: number;
page_size: number;
has_more: boolean;
}>('/materials', {
page: 1,
page_size: limit,
sort_by: 'created_at',
sort_order: 'desc',
});
return response.data.list.map(toMaterialFile);
} catch (error) {
console.error('获取最新资料失败:', error);
return [];
}
}
/**
* 获取资料的下载链接(增加下载次数)
*/
async downloadMaterial(id: string): Promise<{ file_url: string; file_name: string } | null> {
try {
const response = await api.get<{ file_url: string; file_name: string }>(`/materials/${id}/download`);
return response.data;
} catch (error) {
console.error('获取下载链接失败:', error);
return null;
}
}
}
// 导出单例
export const materialRepository = MaterialRepository.getInstance();