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,
name TEXT NOT NULL,
category_id INTEGER,
location_id INTEGER,
location TEXT,
description TEXT,
price REAL,
purchase_date TEXT,

View File

@ -7,7 +7,7 @@ class Item {
//
final int? categoryId;
//
final int? locationId;
final String? location;
//
final String? description;
//
@ -27,7 +27,7 @@ class Item {
this.id,
required this.name,
this.categoryId,
this.locationId,
this.location,
this.description,
this.price,
this.purchaseDate,
@ -41,7 +41,7 @@ class Item {
return {
'name': name,
'category_id': categoryId,
'location_id': locationId,
'location': location,
'description': description,
'price': price,
'purchase_date': purchaseDate,
@ -57,7 +57,7 @@ class Item {
id: map['id'],
name: map['name'],
categoryId: map['category_id'],
locationId: map['location_id'],
location: map['location'],
description: map['description'],
price: map['price'],
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 '../../provider/item_category_provider.dart';
import 'add_category_screen.dart';
import 'detail_category_screen.dart';
class CategoryScreen extends StatefulWidget {
@ -59,6 +60,18 @@ class _CategoryScreenState extends State<CategoryScreen> {
}).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: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/date_picker_field.dart';
import 'package:item_tracker/screens/item_screens/widgets/description_field.dart';
@ -56,12 +58,14 @@ class _FromTestRouteSate extends State<ItemScreen> {
String _selected = '';
double? _price;
DateTime? _selectedDate;
String? _selectedCategory; //
int? _selectedCategory; //
ItemIsUse? _itemIsUse = ItemIsUse.yes;
GlobalKey<FormState> _formKey = GlobalKey<FormState>();
late ItemCategoryProvider _itemCategoryProvider;
//
List<String> _categories = ['A', 'B', 'C', 'D']; //
late List<ItemCategory> _categories; //
@override
void initState() {
@ -70,12 +74,22 @@ class _FromTestRouteSate extends State<ItemScreen> {
if (item != null) {
_name = item.name;
_description = item.description!;
_location = (item.location == null ? '' : item.location)!;
_selectedDate = item.purchaseDate;
}
_itemCategoryProvider = Provider.of<ItemCategoryProvider>(context, listen: false);
Future.microtask(() {
_itemCategoryProvider =
Provider.of<ItemCategoryProvider>(context, listen: false);
_itemCategoryProvider.loadCategories();
});
}
@override
Widget build(BuildContext context) {
final _c = _itemCategoryProvider.categories;
_categories = _c.toList();
print(_categories);
return Scaffold(
appBar: AppBar(
title: Text('新增物品'),
@ -130,7 +144,7 @@ class _FromTestRouteSate extends State<ItemScreen> {
final newItem = Item(
name: _name,
description: _description,
purchaseDate: _selectedDate,
categoryId: _selectedCategory,
isInUse: _itemIsUse,
price: _price,
);

View File

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