feat(category): 添加分类功能

- 新增分类列表页面和分类详情页面
- 实现分类数据的加载、刷新和展示
- 添加分类相关的数据模型、提供者和仓库
- 优化数据库操作,统一表名和查询条件
This commit is contained in:
LingandRX 2025-05-08 21:06:52 +08:00
parent b2217ae2be
commit b53fe04e54
7 changed files with 171 additions and 59 deletions

View File

@ -9,5 +9,5 @@ CREATE TABLE item_category (
'''; ''';
const String insertDefaultCategory = ''' const String insertDefaultCategory = '''
INSERT INTO item_category (name, description) VALUES ('默认分类', '系统默认分类'); INSERT INTO item_category (id, name, description) VALUES (0, '默认分类', '系统默认分类');
'''; ''';

View File

@ -1,22 +1,35 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:item_tracker/provider/item_category_provider.dart';
import 'package:item_tracker/provider/item_provider.dart'; import 'package:item_tracker/provider/item_provider.dart';
import 'package:item_tracker/repository/item_repository.dart'; import 'package:item_tracker/repository/item_repository.dart';
import 'package:item_tracker/repository/item_category_repository.dart';
import 'package:item_tracker/screens/home_screen.dart'; import 'package:item_tracker/screens/home_screen.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'database/sqlite_helper.dart'; import 'database/sqlite_helper.dart';
void main() async { void main() async {
WidgetsFlutterBinding.ensureInitialized();
final dbHelper = DatabaseHelper(); final dbHelper = DatabaseHelper();
final repository = ItemRepository(dbHelper: dbHelper); await dbHelper.database;
final itemRepository = ItemRepository(dbHelper: dbHelper);
final itemCategoryRepository = ItemCategoryRepository(dbHelper: dbHelper);
WidgetsFlutterBinding.ensureInitialized();
await DatabaseHelper().database;
print('数据库初始化完成'); print('数据库初始化完成');
runApp( runApp(
ChangeNotifierProvider( MultiProvider(
create: (_) => ItemProvider(repository: repository), providers: [
child: MyApp(),), ChangeNotifierProvider(
create: (_) => ItemProvider(repository: itemRepository),
),
ChangeNotifierProvider(
create: (_) => ItemCategoryProvider(repository: itemCategoryRepository),
),
],
child: MyApp(),
),
); );
} }
@ -31,4 +44,4 @@ class MyApp extends StatelessWidget {
home: HomeScreen(), // HomeScreen home: HomeScreen(), // HomeScreen
); );
} }
} }

View File

@ -16,11 +16,11 @@ class ItemCategory {
// fromMap map -> Dart // fromMap map -> Dart
factory ItemCategory.fromMap(Map<String, dynamic> map) { factory ItemCategory.fromMap(Map<String, dynamic> map) {
return ItemCategory( return ItemCategory(
id: map['id'] as int?, id: map['id'],
name: map['name'] as String, name: map['name'],
description: map['description'] as String?, description: map['description'],
createdAt: map['created_at'] as String?, createdAt: map['created_at'],
updatedAt: map['updated_at'] as String?, updatedAt: map['updated_at'],
); );
} }

View File

@ -0,0 +1,39 @@
import 'package:flutter/material.dart';
import 'package:item_tracker/models/item_category_model.dart';
import 'package:item_tracker/repository/item_category_repository.dart';
class ItemCategoryProvider extends ChangeNotifier {
List<ItemCategory> _categories = [];
List<ItemCategory> get categories => _categories;
final ItemCategoryRepository repository;
ItemCategoryProvider({required this.repository});
Future<void> loadCategories() async {
_categories = await repository.getAll();
notifyListeners();
}
Future<void> addCategory(ItemCategory) async {
await repository.insert(ItemCategory);
await loadCategories();
}
Future<void> updateCategory(ItemCategory) async {
await repository.update(ItemCategory);
await loadCategories();
}
Future<void> deleteCategory(ItemCategory) async {
await repository.delete(ItemCategory.id!);
await loadCategories();
}
Future<ItemCategory?> getCategoryById(int id) async {
final data = await repository.getById(id);
return data;
}
}

View File

@ -1,16 +1,24 @@
import 'package:item_tracker/database/sqlite_helper.dart';
import 'package:sqflite/sqflite.dart'; import 'package:sqflite/sqflite.dart';
import '../models/item_category_model.dart'; import '../models/item_category_model.dart';
class ItemCategoryRepository { class ItemCategoryRepository {
final Database db; static const String _tableName = 'item_category';
static const String _whereId = 'id = ?';
ItemCategoryRepository(this.db); final DatabaseHelper dbHelper;
ItemCategoryRepository({required this.dbHelper});
// Database getter
Future<Database> get _db async => await dbHelper.database;
// (Create) // (Create)
Future<int> insert(ItemCategory category) async { Future<int> insert(ItemCategory category) async {
return await db.insert( final db = await _db;
'item_category', return db.insert(
_tableName,
category.toMap(), category.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace, conflictAlgorithm: ConflictAlgorithm.replace,
); );
@ -18,15 +26,17 @@ class ItemCategoryRepository {
// (Read All) // (Read All)
Future<List<ItemCategory>> getAll() async { Future<List<ItemCategory>> getAll() async {
final List<Map<String, dynamic>> maps = await db.query('item_category'); final db = await _db;
final maps = await db.query(_tableName);
return maps.map((map) => ItemCategory.fromMap(map)).toList(); return maps.map((map) => ItemCategory.fromMap(map)).toList();
} }
// (Read One by id) // (Read One by id)
Future<ItemCategory?> getById(int id) async { Future<ItemCategory?> getById(int id) async {
final List<Map<String, dynamic>> maps = await db.query( final db = await _db;
'item_category', final maps = await db.query(
where: 'id = ?', _tableName,
where: _whereId,
whereArgs: [id], whereArgs: [id],
limit: 1, limit: 1,
); );
@ -38,19 +48,21 @@ class ItemCategoryRepository {
// (Update) // (Update)
Future<int> update(ItemCategory category) async { Future<int> update(ItemCategory category) async {
return await db.update( final db = await _db;
'item_category', return db.update(
_tableName,
category.toMap(), category.toMap(),
where: 'id = ?', where: _whereId,
whereArgs: [category.id], whereArgs: [category.id],
); );
} }
// (Delete) // (Delete)
Future<int> delete(int id) async { Future<int> delete(int id) async {
return await db.delete( final db = await _db;
'item_category', return db.delete(
where: 'id = ?', _tableName,
where: _whereId,
whereArgs: [id], whereArgs: [id],
); );
} }

View File

@ -1,42 +1,64 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../provider/item_category_provider.dart';
import 'detail_category_screen.dart';
class CategoryScreen extends StatefulWidget {
@override
_CategoryScreenState createState() => _CategoryScreenState();
}
class _CategoryScreenState extends State<CategoryScreen> {
late ItemCategoryProvider _itemCategoryProvider;
@override
void initState() {
super.initState();
Future.microtask(() {
_itemCategoryProvider =
Provider.of<ItemCategoryProvider>(context, listen: false);
_itemCategoryProvider.loadCategories();
});
}
Future<void> _refreshData() async {
await _itemCategoryProvider.loadCategories(); //
}
class CategoryScreen extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
const items = 20;
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text('分类'), title: Text('分类列表'),
),
body: LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraints.maxHeight),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: List.generate(
items,
(index) => ItemWidget(text: 'Item $index'),
),
),
),
);
},
), ),
body: Consumer<ItemCategoryProvider>(builder: (context, provider, _) {
final categories = provider.categories;
if (categories.isEmpty) {
return Center(child: Text("暂无分类"));
}
return RefreshIndicator(
onRefresh: _refreshData,
child: ListView(
children: categories.map((category) {
return ListTile(
title: Text(category.name),
subtitle: Text(category.description ?? ""),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
DetailCategoryScreen(category: category),
),
);
},
);
}).toList(),
));
}),
); );
} }
} }
class ItemWidget extends StatelessWidget {
const ItemWidget({super.key, required this.text});
final String text;
@override
Widget build(BuildContext context) {
return Card(child: SizedBox(height: 100, child: Center(child: Text(text))));
}
}

View File

@ -0,0 +1,26 @@
import 'package:flutter/material.dart';
import 'package:item_tracker/models/item_category_model.dart';
class DetailCategoryScreen extends StatelessWidget {
final ItemCategory category;
DetailCategoryScreen({required this.category});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('分类详情'),
),
body: Center(
child: Column(
children: [
Text('${category.name}'),
Text('${category.description}')
],
),
),
);
}
}