feat(category): 添加分类功能
- 新增分类列表页面和分类详情页面 - 实现分类数据的加载、刷新和展示 - 添加分类相关的数据模型、提供者和仓库 - 优化数据库操作,统一表名和查询条件
This commit is contained in:
parent
b2217ae2be
commit
b53fe04e54
@ -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, '默认分类', '系统默认分类');
|
||||
''';
|
||||
|
||||
@ -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(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -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'],
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
39
lib/provider/item_category_provider.dart
Normal file
39
lib/provider/item_category_provider.dart
Normal 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;
|
||||
}
|
||||
}
|
||||
@ -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],
|
||||
);
|
||||
}
|
||||
|
||||
@ -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))));
|
||||
}
|
||||
}
|
||||
|
||||
26
lib/screens/category_screens/detail_category_screen.dart
Normal file
26
lib/screens/category_screens/detail_category_screen.dart
Normal 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}')
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user