feat(my): add 我的笔记 page and related functions
1. 新增我的笔记页面,包含学科筛选Tab和游标分页列表 2. 新增user_note接口封装和对应数据模型 3. 在我的页面添加笔记入口跳转 4. 优化收藏/错题卡片的按压反馈效果
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
import 'package:new_learn/core/api/user_collect/model.dart';
|
||||
import 'package:new_learn/core/api/user_note/model.dart';
|
||||
import 'package:new_learn/core/network/dio_client.dart';
|
||||
|
||||
/// ============================================================
|
||||
/// 【user_note 模块接口】我的笔记 —— 对标 Vue3 端 api/userNote/index.ts
|
||||
///
|
||||
/// getSubjects —— 学科筛选项(顶部 Tab,无参)
|
||||
/// GET /api/v1/UserNote/GetUserCollectSubject
|
||||
///
|
||||
/// getNoteList —— 笔记分页列表(游标分页)
|
||||
/// GET /api/v1/UserNote/GetUserNotes
|
||||
/// 参数:subjectId(可选) / pageIndex / pageSize / prevPageId
|
||||
///
|
||||
/// 列表不按笔记类型过滤;type(1题目/2讲义) 由每条数据自带,
|
||||
/// 前端用卡片角标图标区分。
|
||||
///
|
||||
/// 注意:Vue 同文件里的 OSS 凭证/上传地址接口归属 OSS 模块
|
||||
/// (Flutter 端见 core/network/oss_api.dart),不在此重复封装。
|
||||
/// ============================================================
|
||||
class UserNoteApi {
|
||||
UserNoteApi._();
|
||||
|
||||
static final UserNoteApi instance = UserNoteApi._();
|
||||
|
||||
/// 学科筛选项
|
||||
Future<List<CollectTab>> getSubjects() async {
|
||||
final data = await DioClient.instance.get(
|
||||
'/api/v1/UserNote/GetUserCollectSubject',
|
||||
);
|
||||
// 兼容裸数组 / {data: [...]} 响应壳
|
||||
final List<dynamic> list = data is List
|
||||
? data
|
||||
: (data is Map<String, dynamic>
|
||||
? (data['data'] as List<dynamic>? ?? const [])
|
||||
: const []);
|
||||
return list
|
||||
.whereType<Map<String, dynamic>>()
|
||||
.map(CollectTab.fromJson)
|
||||
.toList();
|
||||
}
|
||||
|
||||
/// 笔记分页列表
|
||||
///
|
||||
/// [subjectId] 不传 = 全部学科;[prevPageId] 游标:首页传 0,
|
||||
/// 翻页传上一页最后一条 id。
|
||||
Future<UserNotePage> getNoteList({
|
||||
int? subjectId,
|
||||
required int pageIndex,
|
||||
int pageSize = 10,
|
||||
int prevPageId = 0,
|
||||
}) async {
|
||||
final query = <String, dynamic>{
|
||||
'pageIndex': pageIndex,
|
||||
'pageSize': pageSize,
|
||||
'prevPageId': prevPageId,
|
||||
};
|
||||
// 对齐 Vue useList:subjectId 为 null 时不带该参数
|
||||
if (subjectId != null) query['subjectId'] = subjectId;
|
||||
|
||||
final data = await DioClient.instance.get(
|
||||
'/api/v1/UserNote/GetUserNotes',
|
||||
query: query,
|
||||
);
|
||||
return UserNotePage.fromJson(data as Map<String, dynamic>);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/// ============================================================
|
||||
/// 【user_note 模块模型】我的笔记 —— 对标 Vue3 端 api/userNote/type.ts
|
||||
///
|
||||
/// UserNoteItem 笔记列表项(type 1=题目笔记 2=讲义笔记)
|
||||
/// UserNotePage 分页响应(游标分页:pageIndex + prevPageId)
|
||||
///
|
||||
/// 学科筛选 Tab 复用收藏模块的 CollectTab(见 api.dart 的 import,
|
||||
/// 与 Vue 端 api/userNote/index.ts 从 ../userCollect/type 引入一致)。
|
||||
/// ============================================================
|
||||
library;
|
||||
|
||||
/// 兼容后端 id 字段:雪花 id 后端可能以 String 返回(防 JS 精度丢失)
|
||||
int? _noteToInt(dynamic v) {
|
||||
if (v == null) return null;
|
||||
if (v is num) return v.toInt();
|
||||
if (v is String && v.isNotEmpty) return int.tryParse(v);
|
||||
return null;
|
||||
}
|
||||
|
||||
/// 我的笔记列表项
|
||||
class UserNoteItem {
|
||||
const UserNoteItem({
|
||||
this.id = 0,
|
||||
this.subjectName = '',
|
||||
this.type = 0,
|
||||
this.title = '',
|
||||
this.content = '',
|
||||
this.createTime = '',
|
||||
});
|
||||
|
||||
/// 笔记 id(游标分页 prevPageId 取本页最后一条的 id;详情页参数 id)
|
||||
final int id;
|
||||
|
||||
/// 学科名(SubjectTag 配色用)
|
||||
final String subjectName;
|
||||
|
||||
/// 笔记类型:1=题目笔记 2=讲义笔记(卡片角标/详情页区分用)
|
||||
final int type;
|
||||
|
||||
/// 笔记标题
|
||||
final String title;
|
||||
|
||||
/// 笔记内容 HTML(RichTextContent 渲染)
|
||||
final String content;
|
||||
|
||||
/// 记笔记时间字符串
|
||||
final String createTime;
|
||||
|
||||
factory UserNoteItem.fromJson(Map<String, dynamic> json) {
|
||||
return UserNoteItem(
|
||||
id: _noteToInt(json['id']) ?? 0,
|
||||
subjectName: json['subjectName'] as String? ?? '',
|
||||
type: _noteToInt(json['type']) ?? 0,
|
||||
title: json['title'] as String? ?? '',
|
||||
content: json['content'] as String? ?? '',
|
||||
createTime: json['createTime'] as String? ?? '',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 我的笔记分页响应
|
||||
class UserNotePage {
|
||||
const UserNotePage({
|
||||
this.data = const [],
|
||||
this.total = 0,
|
||||
this.pageIndex = 1,
|
||||
this.pageSize = 10,
|
||||
});
|
||||
|
||||
final List<UserNoteItem> data;
|
||||
final int total;
|
||||
final int pageIndex;
|
||||
final int pageSize;
|
||||
|
||||
/// 兼容业务响应壳 {code, message, data: {...}}:data 存在就取 data
|
||||
factory UserNotePage.fromJson(Map<String, dynamic> json) {
|
||||
final payload = (json['data'] is Map<String, dynamic>)
|
||||
? json['data'] as Map<String, dynamic>
|
||||
: json;
|
||||
return UserNotePage(
|
||||
data: (payload['data'] as List<dynamic>? ?? const [])
|
||||
.whereType<Map<String, dynamic>>()
|
||||
.map(UserNoteItem.fromJson)
|
||||
.toList(),
|
||||
total: _noteToInt(payload['total']) ?? 0,
|
||||
pageIndex: _noteToInt(payload['pageIndex']) ?? 1,
|
||||
pageSize: _noteToInt(payload['pageSize']) ?? 10,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user