feat(category): 添加分类功能
- 新增分类列表页面和分类详情页面 - 实现分类数据的加载、刷新和展示 - 添加分类相关的数据模型、提供者和仓库 - 优化数据库操作,统一表名和查询条件
This commit is contained in:
parent
b2217ae2be
commit
b53fe04e54
@ -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, '默认分类', '系统默认分类');
|
||||||
''';
|
''';
|
||||||
|
|||||||
@ -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
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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'],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
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 '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],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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))));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
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