feat:"初始化仓库,并更新基础代码。"

This commit is contained in:
2026-01-14 09:25:52 +08:00
commit 9a91c40a97
140 changed files with 6513 additions and 0 deletions

179
lib/db/database_helper.dart Normal file
View File

@@ -0,0 +1,179 @@
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
import '../models/category_model.dart';
import '../models/transaction_model.dart';
class DatabaseHelper {
static final DatabaseHelper instance = DatabaseHelper._init();
static Database? _database;
DatabaseHelper._init();
Future<Database> get database async {
if (_database != null) return _database!;
_database = await _initDB('expense_tracker.db');
return _database!;
}
Future<Database> _initDB(String filePath) async {
final dbPath = await getDatabasesPath();
final path = join(dbPath, filePath);
return await openDatabase(
path,
version: 2,
onCreate: _createDB,
onUpgrade: _upgradeDB,
);
}
Future _createDB(Database db, int version) async {
const idType = 'INTEGER PRIMARY KEY AUTOINCREMENT';
const textType = 'TEXT NOT NULL';
const realType = 'REAL NOT NULL';
const intType = 'INTEGER NOT NULL';
const intNullableType = 'INTEGER';
// Create Categories Table
await db.execute('''
CREATE TABLE categories (
id $idType,
name $textType,
type $textType,
icon $textType,
color $intType,
parentId $intNullableType
)
''');
// Create Transactions Table
await db.execute('''
CREATE TABLE transactions (
id TEXT PRIMARY KEY,
amount $realType,
type $textType,
categoryId $intType,
date $intType,
note TEXT,
createdAt $intType,
updatedAt $intType,
FOREIGN KEY (categoryId) REFERENCES categories (id)
)
''');
// Insert Default Categories
await _insertDefaultCategories(db);
}
Future _upgradeDB(Database db, int oldVersion, int newVersion) async {
if (oldVersion < 2) {
await db.execute('ALTER TABLE categories ADD COLUMN parentId INTEGER');
}
}
Future _insertDefaultCategories(Database db) async {
// Parent Categories
final foodId = await db.insert('categories', Category(name: '餐饮', type: 'expense', icon: 'restaurant', color: 0xFFFF5722).toMap());
final transportId = await db.insert('categories', Category(name: '交通', type: 'expense', icon: 'directions_bus', color: 0xFF2196F3).toMap());
final shoppingId = await db.insert('categories', Category(name: '购物', type: 'expense', icon: 'shopping_cart', color: 0xFFE91E63).toMap());
await db.insert('categories', Category(name: '娱乐', type: 'expense', icon: 'movie', color: 0xFF9C27B0).toMap());
await db.insert('categories', Category(name: '医疗', type: 'expense', icon: 'local_hospital', color: 0xFFF44336).toMap());
// Income
await db.insert('categories', Category(name: '工资', type: 'income', icon: 'attach_money', color: 0xFF4CAF50).toMap());
await db.insert('categories', Category(name: '投资', type: 'income', icon: 'trending_up', color: 0xFF009688).toMap());
// Sub Categories
await db.insert('categories', Category(name: '早餐', type: 'expense', icon: 'breakfast_dining', color: 0xFFFF5722, parentId: foodId).toMap());
await db.insert('categories', Category(name: '午餐', type: 'expense', icon: 'lunch_dining', color: 0xFFFF5722, parentId: foodId).toMap());
await db.insert('categories', Category(name: '晚餐', type: 'expense', icon: 'dinner_dining', color: 0xFFFF5722, parentId: foodId).toMap());
await db.insert('categories', Category(name: '地铁', type: 'expense', icon: 'subway', color: 0xFF2196F3, parentId: transportId).toMap());
await db.insert('categories', Category(name: '打车', type: 'expense', icon: 'local_taxi', color: 0xFF2196F3, parentId: transportId).toMap());
await db.insert('categories', Category(name: '衣服', type: 'expense', icon: 'checkroom', color: 0xFFE91E63, parentId: shoppingId).toMap());
await db.insert('categories', Category(name: '数码', type: 'expense', icon: 'devices', color: 0xFFE91E63, parentId: shoppingId).toMap());
}
// Transactions CRUD
Future<void> createTransaction(TransactionModel transaction) async {
final db = await instance.database;
await db.insert('transactions', transaction.toMap());
}
Future<TransactionModel> readTransaction(String id) async {
final db = await instance.database;
final maps = await db.query(
'transactions',
columns: null,
where: 'id = ?',
whereArgs: [id],
);
if (maps.isNotEmpty) {
return TransactionModel.fromMap(maps.first);
} else {
throw Exception('ID $id not found');
}
}
Future<List<TransactionModel>> readAllTransactions() async {
final db = await instance.database;
final orderBy = 'date DESC';
final result = await db.query('transactions', orderBy: orderBy);
return result.map((json) => TransactionModel.fromMap(json)).toList();
}
Future<int> updateTransaction(TransactionModel transaction) async {
final db = await instance.database;
return db.update(
'transactions',
transaction.toMap(),
where: 'id = ?',
whereArgs: [transaction.id],
);
}
Future<int> deleteTransaction(String id) async {
final db = await instance.database;
return await db.delete(
'transactions',
where: 'id = ?',
whereArgs: [id],
);
}
// Categories CRUD
Future<List<Category>> readAllCategories() async {
final db = await instance.database;
final result = await db.query('categories');
return result.map((json) => Category.fromMap(json)).toList();
}
Future<int> createCategory(Category category) async {
final db = await instance.database;
return await db.insert('categories', category.toMap());
}
Future<int> updateCategory(Category category) async {
final db = await instance.database;
return await db.update(
'categories',
category.toMap(),
where: 'id = ?',
whereArgs: [category.id],
);
}
Future<int> deleteCategory(int id) async {
final db = await instance.database;
// Check if it has children, if so, maybe update them or delete them?
// For simplicity, we won't cascade delete here but UI should warn.
return await db.delete(
'categories',
where: 'id = ?',
whereArgs: [id],
);
}
}