feat(category): 添加分类功能并更新相关页面

- 新增 AddCategoryScreen 页面用于添加分类
- 更新 CategoryScreen 页面,添加浮动按钮用于导航到添加分类页面
- 修改 CategoryDropdown 组件,支持 ItemCategory 模型
- 更新 Item模型,将 location 改为字符串类型
- 修改 ItemScreen 页面,支持新的分类选择逻辑
- 更新数据库表结构,将 location 字段改为 TEXT 类型
This commit is contained in:
LingandRX 2025-05-11 15:39:55 +08:00
parent b53fe04e54
commit f2eb1fa265
6 changed files with 116 additions and 15 deletions

View File

@ -3,7 +3,7 @@ CREATE TABLE items (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL, name TEXT NOT NULL,
category_id INTEGER, category_id INTEGER,
location_id INTEGER, location TEXT,
description TEXT, description TEXT,
price REAL, price REAL,
purchase_date TEXT, purchase_date TEXT,

View File

@ -7,7 +7,7 @@ class Item {
// //
final int? categoryId; final int? categoryId;
// //
final int? locationId; final String? location;
// //
final String? description; final String? description;
// //
@ -27,7 +27,7 @@ class Item {
this.id, this.id,
required this.name, required this.name,
this.categoryId, this.categoryId,
this.locationId, this.location,
this.description, this.description,
this.price, this.price,
this.purchaseDate, this.purchaseDate,
@ -41,7 +41,7 @@ class Item {
return { return {
'name': name, 'name': name,
'category_id': categoryId, 'category_id': categoryId,
'location_id': locationId, 'location': location,
'description': description, 'description': description,
'price': price, 'price': price,
'purchase_date': purchaseDate, 'purchase_date': purchaseDate,
@ -57,7 +57,7 @@ class Item {
id: map['id'], id: map['id'],
name: map['name'], name: map['name'],
categoryId: map['category_id'], categoryId: map['category_id'],
locationId: map['location_id'], location: map['location'],
description: map['description'], description: map['description'],
price: map['price'], price: map['price'],
purchaseDate: map['purchase_date'], purchaseDate: map['purchase_date'],

View File

@ -0,0 +1,73 @@
import 'package:flutter/material.dart';
import 'package:item_tracker/provider/item_category_provider.dart';
import 'package:item_tracker/screens/category_screens/category_screen.dart';
import 'package:provider/provider.dart';
import '../../models/item_category_model.dart';
class AddCategoryScreen extends StatefulWidget {
@override
_AddCategoryScreenState createState() => _AddCategoryScreenState();
}
class _AddCategoryScreenState extends State<AddCategoryScreen> {
final _formKey = GlobalKey<FormState>();
final _nameController = TextEditingController();
final _descriptionController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('添加分类'),
),
body: Column(
children: [
Form(
key: _formKey,
child: Column(
children: [
TextFormField(
controller: _nameController,
decoration: InputDecoration(labelText: '名称'),
validator: (value) {
if (value == null || value.isEmpty) {
return '请输入名称';
}
return null;
},
),
TextFormField(
controller: _descriptionController,
),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
final category = ItemCategory(
name: _nameController.text,
description: _descriptionController.text
);
Provider.of<ItemCategoryProvider>(context, listen: false).addCategory(category);
//
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('添加成功'),
duration: Duration(seconds: 1),
));
Navigator.pop(context);
Navigator.pop(context);
}
},
child: Text('添加'),
)
]
)
)
]
),
);
}
}

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import '../../provider/item_category_provider.dart'; import '../../provider/item_category_provider.dart';
import 'add_category_screen.dart';
import 'detail_category_screen.dart'; import 'detail_category_screen.dart';
class CategoryScreen extends StatefulWidget { class CategoryScreen extends StatefulWidget {
@ -59,6 +60,18 @@ class _CategoryScreenState extends State<CategoryScreen> {
}).toList(), }).toList(),
)); ));
}), }),
floatingActionButton: FloatingActionButton(
onPressed: () async {
final shouldRefresh = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => AddCategoryScreen()),
);
},
child: Icon(
Icons.add,
color: Colors.white,
)
)
); );
} }
} }

View File

@ -1,4 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:item_tracker/models/item_category_model.dart';
import 'package:item_tracker/provider/item_category_provider.dart';
import 'package:item_tracker/screens/item_screens/widgets/category_dropdown.dart'; import 'package:item_tracker/screens/item_screens/widgets/category_dropdown.dart';
import 'package:item_tracker/screens/item_screens/widgets/date_picker_field.dart'; import 'package:item_tracker/screens/item_screens/widgets/date_picker_field.dart';
import 'package:item_tracker/screens/item_screens/widgets/description_field.dart'; import 'package:item_tracker/screens/item_screens/widgets/description_field.dart';
@ -56,12 +58,14 @@ class _FromTestRouteSate extends State<ItemScreen> {
String _selected = ''; String _selected = '';
double? _price; double? _price;
DateTime? _selectedDate; DateTime? _selectedDate;
String? _selectedCategory; // int? _selectedCategory; //
ItemIsUse? _itemIsUse = ItemIsUse.yes; ItemIsUse? _itemIsUse = ItemIsUse.yes;
GlobalKey<FormState> _formKey = GlobalKey<FormState>(); GlobalKey<FormState> _formKey = GlobalKey<FormState>();
late ItemCategoryProvider _itemCategoryProvider;
// //
List<String> _categories = ['A', 'B', 'C', 'D']; // late List<ItemCategory> _categories; //
@override @override
void initState() { void initState() {
@ -70,12 +74,22 @@ class _FromTestRouteSate extends State<ItemScreen> {
if (item != null) { if (item != null) {
_name = item.name; _name = item.name;
_description = item.description!; _description = item.description!;
_location = (item.location == null ? '' : item.location)!;
_selectedDate = item.purchaseDate; _selectedDate = item.purchaseDate;
} }
_itemCategoryProvider = Provider.of<ItemCategoryProvider>(context, listen: false);
Future.microtask(() {
_itemCategoryProvider =
Provider.of<ItemCategoryProvider>(context, listen: false);
_itemCategoryProvider.loadCategories();
});
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final _c = _itemCategoryProvider.categories;
_categories = _c.toList();
print(_categories);
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text('新增物品'), title: Text('新增物品'),
@ -130,7 +144,7 @@ class _FromTestRouteSate extends State<ItemScreen> {
final newItem = Item( final newItem = Item(
name: _name, name: _name,
description: _description, description: _description,
purchaseDate: _selectedDate, categoryId: _selectedCategory,
isInUse: _itemIsUse, isInUse: _itemIsUse,
price: _price, price: _price,
); );

View File

@ -1,9 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:item_tracker/models/item_category_model.dart';
class CategoryDropdown extends StatelessWidget { class CategoryDropdown extends StatelessWidget {
final List<String> categories; final List<ItemCategory> categories;
final String? selectedCategory; final int? selectedCategory;
final ValueChanged<String?> onChanged; final ValueChanged<int?> onChanged;
CategoryDropdown({ CategoryDropdown({
required this.categories, required this.categories,
@ -13,12 +14,12 @@ class CategoryDropdown extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return DropdownButtonFormField<String>( return DropdownButtonFormField<int>(
value: selectedCategory, value: selectedCategory,
items: categories.map((category) { items: categories.map((category) {
return DropdownMenuItem<String>( return DropdownMenuItem<int>(
value: category, value: category.id,
child: Text(category), child: Text(category.name),
); );
}).toList(), }).toList(),
onChanged: onChanged, onChanged: onChanged,