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 = '''
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:item_tracker/provider/item_category_provider.dart';
import 'package:item_tracker/provider/item_provider.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:provider/provider.dart';
import 'database/sqlite_helper.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
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('数据库初始化完成');
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(
create: (_) => ItemProvider(repository: repository),
child: MyApp(),),
create: (_) => ItemProvider(repository: itemRepository),
),
ChangeNotifierProvider(
create: (_) => ItemCategoryProvider(repository: itemCategoryRepository),
),
],
child: MyApp(),
),
);
}

View File

@ -16,11 +16,11 @@ class ItemCategory {
// fromMap map -> Dart
factory ItemCategory.fromMap(Map<String, dynamic> map) {
return ItemCategory(
id: map['id'] as int?,
name: map['name'] as String,
description: map['description'] as String?,
createdAt: map['created_at'] as String?,
updatedAt: map['updated_at'] as String?,
id: map['id'],
name: map['name'],
description: map['description'],
createdAt: map['created_at'],
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 '../models/item_category_model.dart';
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)
Future<int> insert(ItemCategory category) async {
return await db.insert(
'item_category',
final db = await _db;
return db.insert(
_tableName,
category.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
@ -18,15 +26,17 @@ class ItemCategoryRepository {
// (Read All)
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();
}
// (Read One by id)
Future<ItemCategory?> getById(int id) async {
final List<Map<String, dynamic>> maps = await db.query(
'item_category',
where: 'id = ?',
final db = await _db;
final maps = await db.query(
_tableName,
where: _whereId,
whereArgs: [id],
limit: 1,
);
@ -38,19 +48,21 @@ class ItemCategoryRepository {
// (Update)
Future<int> update(ItemCategory category) async {
return await db.update(
'item_category',
final db = await _db;
return db.update(
_tableName,
category.toMap(),
where: 'id = ?',
where: _whereId,
whereArgs: [category.id],
);
}
// (Delete)
Future<int> delete(int id) async {
return await db.delete(
'item_category',
where: 'id = ?',
final db = await _db;
return db.delete(
_tableName,
where: _whereId,
whereArgs: [id],
);
}

View File

@ -1,42 +1,64 @@
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
Widget build(BuildContext context) {
const items = 20;
return Scaffold(
appBar: AppBar(
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'),
),
title: Text('分类列表'),
),
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}')
],
),
),
);
}
}