Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions assets/flutter_i18n/en_US.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,19 @@ library:
borrow_list_info: Borrowing {borrow} book(s), among which {dued} book(s) have expired
search_book_window: null
search_here: Search here
normal_search: Normal Search
advanced_search: Advanced Search
search: Search
match_mode: Match Mode
match_exact: Exact
match_fuzzy: Fuzzy
match_prefix: Prefix
document_type: Document Type
document_type_all: All
document_type_book: Book
only_on_shelf: Only on shelf
publish_year_begin: Publish year from
publish_year_end: Publish year to
book_detail: Book details
no_result: No result, change parameter or start your search
library_card:
Expand Down
13 changes: 13 additions & 0 deletions assets/flutter_i18n/zh_CN.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,19 @@ library:
borrow_list_info: 在借 {borrow} 本,其中已过期 {dued} 本
search_book_window: null
search_here: 在此搜索
normal_search: 普通搜索
advanced_search: 高级搜索
search: 搜索
match_mode: 匹配方式
match_exact: 精确匹配
match_fuzzy: 模糊匹配
match_prefix: 前方一致
document_type: 文献类型
document_type_all: 全部
document_type_book: 图书
only_on_shelf: 仅看在架
publish_year_begin: 出版年起
publish_year_end: 出版年止
book_detail: 书籍详细信息
no_result: 没有结果,请修改搜索参数或者开始你的搜索
library_card:
Expand Down
13 changes: 13 additions & 0 deletions assets/flutter_i18n/zh_TW.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,19 @@ library:
borrow_list_info: 在借 {borrow} 本,其中已過期 {dued} 本
search_book_window: null
search_here: 在此搜索
normal_search: 普通搜索
advanced_search: 高級搜索
search: 搜索
match_mode: 匹配方式
match_exact: 精確匹配
match_fuzzy: 模糊匹配
match_prefix: 前方一致
document_type: 文獻類型
document_type_all: 全部
document_type_book: 圖書
only_on_shelf: 僅看在架
publish_year_begin: 出版年起
publish_year_end: 出版年止
book_detail: 書籍詳細信息
no_result: 沒有結果,請修改搜索參數或者開始你的搜索
library_card:
Expand Down
18 changes: 18 additions & 0 deletions lib/controller/library_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'package:watermeter/repository/xidian_ids/library_session.dart';
class LibraryController {
static final LibraryController i = LibraryController._();
bool _isReloading = false;
final Map<int, Future<List<BookLocation>>> _bookLocationFutures = {};

LibraryController._();

Expand All @@ -33,4 +34,21 @@ class LibraryController {
_isReloading = false;
}
}

Future<List<BookLocation>> loadBookLocations(BookInfo book) {
final items = book.items;
if (items != null) {
return Future.value(items);
}

return _bookLocationFutures.putIfAbsent(book.docNumber, () async {
try {
return await LibrarySession().bookLocations(book.docNumber);
} catch (e, s) {
_bookLocationFutures.remove(book.docNumber);
log.handle(e, s, "[LibraryController][loadBookLocations] Have issue");
rethrow;
}
});
}
}
183 changes: 171 additions & 12 deletions lib/model/xidian_ids/library.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,33 +10,55 @@ part 'library.g.dart';

@JsonSerializable()
class BorrowData {
final int lendDay;
@JsonKey(fromJson: _intValue)
final int locationId;
@JsonKey(fromJson: _intValue)
final int loanId;
@JsonKey(fromJson: _intValue)
final int renewTimes;
@JsonKey(fromJson: _intValue)
final int recallTimes;
@JsonKey(fromJson: _stringValue)
final String loanDate;
@JsonKey(fromJson: _nullableStringValue)
final String? renewDate;
@JsonKey(fromJson: _stringValue)
final String normReturnDate;
@JsonKey(fromJson: _nullableStringValue)
final String? returnDate;
@JsonKey(fromJson: _stringValue)
final String loanType;
@JsonKey(fromJson: _stringValue)
final String locationName;
final String itemLibCode;
final String itemLibName;
@JsonKey(fromJson: _stringValue)
final String curLibCode;
@JsonKey(fromJson: _stringValue)
final String curLibName;
@JsonKey(fromJson: _stringValue)
final String loanDeskName;
@JsonKey(fromJson: _stringValue)
final String title;
@JsonKey(fromJson: _stringValue)
final String author;
@JsonKey(fromJson: _stringValue)
final String publisher;
@JsonKey(fromJson: _stringValue)
final String isbn;
@JsonKey(fromJson: _stringValue)
final String isbn10;
@JsonKey(fromJson: _stringValue)
final String isbn13;
@JsonKey(fromJson: _stringValue)
final String publishYear;
@JsonKey(fromJson: _nullableStringValue)
final String? titles;
final String barcode;
@JsonKey(fromJson: _stringValue)
final String propNo;
@JsonKey(fromJson: _intValue)
final int recordId;
String? imageUrl;

BorrowData({
required this.lendDay,
required this.locationId,
required this.loanId,
required this.renewTimes,
Expand All @@ -47,8 +69,8 @@ class BorrowData {
required this.returnDate,
required this.loanType,
required this.locationName,
required this.itemLibCode,
required this.itemLibName,
required this.curLibCode,
required this.curLibName,
required this.loanDeskName,
required this.title,
required this.author,
Expand All @@ -58,21 +80,51 @@ class BorrowData {
required this.isbn13,
required this.publishYear,
required this.titles,
required this.barcode,
required this.propNo,
required this.recordId,
this.imageUrl,
});

DateTime get loanDateTime => DateTime.parse(loanDate.replaceAll('/', '-'));
int get lendDay {
final today = DateTime.now();
final todayDate = DateTime(today.year, today.month, today.day);
return normReturnDateTime.difference(todayDate).inDays;
}

String get itemLibCode => curLibCode;

String get itemLibName => curLibName;

String get barcode => propNo;

DateTime get normReturnDateTime =>
DateTime.parse(normReturnDate.replaceAll('/', '-'));
DateTime get loanDateTime => _parseLibraryDate(loanDate);

DateTime get normReturnDateTime => _parseLibraryDate(normReturnDate);

factory BorrowData.fromJson(Map<String, dynamic> json) =>
_$BorrowDataFromJson(json);

Map<String, dynamic> toJson() => _$BorrowDataToJson(this);
}

int _intValue(Object? value) {
if (value is int) return value;
if (value is num) return value.toInt();
if (value is String) return int.tryParse(value) ?? 0;
return 0;
}

String _stringValue(Object? value) => value?.toString() ?? "";

String? _nullableStringValue(Object? value) => value?.toString();

DateTime _parseLibraryDate(String value) {
if (value.isEmpty) {
return DateTime.now();
}
return DateTime.parse(value.replaceAll('/', '-').split(' ').first);
}

@JsonSerializable()
class BookInfo {
final String? author;
Expand All @@ -92,6 +144,8 @@ class BookInfo {
final List<String?>? barCodes;
final List<String>? searchCode;
final List<BookLocation>? items;
final int? availableCount;
final int? storageCount;
String? imageUrl;

BookInfo({
Expand All @@ -112,15 +166,48 @@ class BookInfo {
this.searchCode,
required this.barCodes,
this.items,
this.availableCount,
this.storageCount,
this.imageUrl,
});

factory BookInfo.fromJson(Map<String, dynamic> json) =>
_$BookInfoFromJson(json);

factory BookInfo.fromOpacJson(Map<String, dynamic> json) {
final callNos = _stringList(json['callNo']);
final barCodes = _nullableStringList(
json['barCodes'] ?? json['barcode'] ?? json['propNo'],
);
return BookInfo(
author: _nullableStringValue(json['author']),
subject: _nullableStringValue(json['subjectWord']),
isbn: _nullableStringValue(json['isbn']),
description: _nullableStringValue(json['adstract'] ?? json['ddAbstract']),
bookName: _stringValue(json['title']),
barCode: _nullableStringValue(json['barcode'] ?? json['propNo']),
docNumber: _intValue(json['recordId']),
publishYear: _nullableStringValue(json['publishYear'] ?? json['year']),
publisherHouse: _nullableStringValue(json['publisher']),
groupCode: _nullableStringValue(json['groupCode']),
callNos: callNos,
searchCode: callNos,
barCodes: barCodes,
availableCount: _nullableIntValue(
json['onShelfCountI'] ?? json['canBrrowCountI'] ?? json['onShelfNum'],
),
storageCount: _nullableIntValue(
json['groupPhysicalCount'] ?? json['physicalCount'],
),
);
}

Map<String, dynamic> toJson() => _$BookInfoToJson(this);

int? get canBeBorrowed {
if (availableCount != null) {
return availableCount;
}
if (items == null) {
return null;
}
Expand All @@ -131,6 +218,20 @@ class BookInfo {
return toReturn;
}

int? get totalStorage {
if (storageCount != null) {
return storageCount;
}
return items?.length;
}

bool get hasBarCodes {
if (barCodes == null || barCodes!.isEmpty) {
return false;
}
return barCodes!.any((e) => e != null && e.isNotEmpty);
}

String get searchCodeStr {
if (searchCode == null || searchCode!.isEmpty) {
return "未提供";
Expand All @@ -142,10 +243,41 @@ class BookInfo {
if (barCodes == null || barCodes!.isEmpty) {
return "未提供";
}
return barCodes!.first ?? "未提供";
for (final code in barCodes!) {
if (code != null && code.isNotEmpty) {
return code;
}
}
return "未提供";
}
}

int? _nullableIntValue(Object? value) {
if (value == null) return null;
if (value is int) return value;
if (value is num) return value.toInt();
if (value is String) return int.tryParse(value);
return null;
}

List<String>? _stringList(Object? value) {
if (value == null) return null;
if (value is List) {
return value.map((e) => e.toString()).where((e) => e.isNotEmpty).toList();
}
final text = value.toString();
return text.isEmpty ? null : [text];
}

List<String?>? _nullableStringList(Object? value) {
if (value == null) return null;
if (value is List) {
return value.map((e) => e?.toString()).toList();
}
final text = value.toString();
return text.isEmpty ? null : [text];
}

@JsonSerializable()
class BookLocation {
final String? yearVol;
Expand Down Expand Up @@ -183,6 +315,33 @@ class BookLocation {
factory BookLocation.fromJson(Map<String, dynamic> json) =>
_$BookLocationFromJson(json);

factory BookLocation.fromOpacJson(Map<String, dynamic> json) {
final locationName = _stringValue(
json['realLocationName'] ?? json['locationName'],
);
final shelfName = _stringValue(json['urlName']);
final displayLocation = shelfName.isEmpty
? locationName
: "$locationName $shelfName";

return BookLocation(
yearVol: _nullableStringValue(json['vol'] ?? json['yearVol']),
locationName: displayLocation.isEmpty ? null : displayLocation,
searchCode: _stringValue(json['callNo']),
campus: _nullableStringValue(json['campus']),
inDate: _nullableStringValue(json['inDate']),
barCode: _nullableStringValue(json['barcode'] ?? json['propNo']),
itemId: _intValue(json['itemId']),
circAttr: _stringValue(json['circAttr']),
locationId: _nullableStringValue(json['locationId']),
processType: _stringValue(json['processType']),
curLocationId: _stringValue(json['curLocationId']),
propNo: _nullableStringValue(json['propNo']),
borrowStatus: _nullableStringValue(json['borrowStatus']),
noBorrowMessages: _nullableStringValue(json['noBorrowMessages']),
);
}

Map<String, dynamic> toJson() => _$BookLocationToJson(this);
}

Expand Down
Loading