diff --git a/lib/api/recipe.dart b/lib/api/recipe.dart index ff1bbcd..a6c57ca 100644 --- a/lib/api/recipe.dart +++ b/lib/api/recipe.dart @@ -4,40 +4,40 @@ import 'package:food_hub_app/utils/index.dart'; Future queryRecipeByIdApi(int id) { return HttpUtil().get( - "/food/recipe/$id", + "/food-service/food/recipe/$id", converter: (data) => Recipe.fromJson(data), ); } Future addRecipeApi(Recipe recipe) { - return HttpUtil().post("/food/food/recipe", data: recipe); + return HttpUtil().post("/food-service/food/food/recipe", data: recipe); } Future updateRecipeApi(int id, Recipe recipe) { - return HttpUtil().put("/food/food/recipe/$id", data: recipe); + return HttpUtil().put("/food-service/food/food/recipe/$id", data: recipe); } Future deleteRecipeApi(int id) { - return HttpUtil().delete("/food/food/recipe/$id"); + return HttpUtil().delete("/food-service/food/food/recipe/$id"); } Future> queryRecipeByUserApi(int id) { return HttpUtil().get>( - "/food/recipe/user/$id", + "/food-service/food/recipe/user/$id", converter: (data) => convertListResponse(data, Recipe.fromJson), ); } Future> queryRecipeUserFavouriteApi() { return HttpUtil().get>( - "/food/recipe/user/favourite", + "/food-service/food/recipe/user/favourite", converter: (data) => convertListResponse(data, Recipe.fromJson), ); } Future> queryRecipeApi(RecipeQuery recipeQuery) { return HttpUtil().get>( - "/food/recipe", + "/food-service/food/recipe", queryParameters: recipeQuery.toJson(), converter: (data) => convertListResponse(data, Recipe.fromJson), ); diff --git a/lib/api/session.dart b/lib/api/session.dart index 616dc25..22cd8c0 100644 --- a/lib/api/session.dart +++ b/lib/api/session.dart @@ -3,7 +3,7 @@ import 'package:food_hub_app/utils/http_util.dart'; Future loginApi(String username, String password) { return HttpUtil().post( - "/session", + "/food-service/session", queryParameters: {"username": username, "password": password}, converter: (data) => Session.fromJson(data), ); diff --git a/lib/utils/http_util.dart b/lib/utils/http_util.dart index 0c7aa0e..81ba4cd 100644 --- a/lib/utils/http_util.dart +++ b/lib/utils/http_util.dart @@ -10,7 +10,8 @@ class HttpUtil { factory HttpUtil() => _instance; late Dio _dio; - String baseUrl = "http://172.29.101.108:8100/"; + bool isMock = true; + String baseUrl = "http://192.168.1.3:8100"; // 请求头配置 Map headers = { @@ -80,6 +81,10 @@ class HttpUtil { T Function(dynamic data)? converter, }) async { try { + if (isMock) { + path = path.replaceFirst('/food-service', ''); + } + Response response = await _dio.request( path, data: data, diff --git a/lib/views/login.dart b/lib/views/login.dart index 83f07e4..ef2f29e 100644 --- a/lib/views/login.dart +++ b/lib/views/login.dart @@ -36,7 +36,7 @@ class _LoginPage extends State { Future _loadRememberState() async { bool? isRemember = await SPUtil.getBool('isRemember'); if (isRemember) { - setState(() { + setState(() { _isRemember = true; _username = SPUtil.getString('username'); _password = SPUtil.getString('password'); @@ -81,34 +81,11 @@ class _LoginPage extends State { backgroundColor: Colors.grey[100], body: Form( key: _formKey, - autovalidateMode: AutovalidateMode.onUserInteraction, + // autovalidateMode: AutovalidateMode.onUserInteraction, child: Column( children: [ // 可滚动的主要内容区域 - Expanded( - child: ListView( - padding: const EdgeInsets.symmetric(horizontal: 20), - children: [ - const SizedBox(height: kToolbarHeight), - buildTitle(), - const SizedBox(height: 60), - buildUsernameTextField(), - const SizedBox(height: 20), - buildPasswordTextField(context), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - buildRememberPasswordCheckbox(context), // 记住密码(左对齐) - buildForgetPasswordText(context), - ], - ), - - const SizedBox(height: 20), // 调整与登录按钮的间距 - buildLoginButton(context), - ], - ), - ), + Expanded(child: buildLoginForm()), // 固定在底部的其他登录选项区域 Padding( @@ -137,6 +114,31 @@ class _LoginPage extends State { ); } + Widget buildLoginForm() { + return ListView( + padding: const EdgeInsets.symmetric(horizontal: 20), + children: [ + const SizedBox(height: kToolbarHeight), + buildTitle(), + const SizedBox(height: 60), + buildUsernameTextField(), + const SizedBox(height: 20), + buildPasswordTextField(context), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + buildRememberPasswordCheckbox(context), // 记住密码(左对齐) + buildForgetPasswordText(context), + ], + ), + + const SizedBox(height: 20), // 调整与登录按钮的间距 + buildLoginButton(context), + ], + ); + } + Widget buildUsernameTextField() { return Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/widgets/common/index.dart b/lib/widgets/common/index.dart index a2b84cf..cde3247 100644 --- a/lib/widgets/common/index.dart +++ b/lib/widgets/common/index.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; -// import 'package:fluttertoast/fluttertoast.dart'; Widget formLabelText({required String labelText, bool isRequired = false}) { return Text.rich( @@ -28,6 +27,7 @@ InputDecoration formInputDecoration({ ); } +/// 确认按钮样式 ButtonStyle primaryButtonStyle() { return ButtonStyle( backgroundColor: WidgetStateProperty.all(Colors.green), @@ -37,6 +37,7 @@ ButtonStyle primaryButtonStyle() { ); } +/// 取消按钮样式 ButtonStyle cancelButtonStyle() { return ButtonStyle( backgroundColor: WidgetStateProperty.all(Colors.grey), @@ -50,6 +51,22 @@ Text buttonText({required String text}) { return Text(text, style: TextStyle(color: Colors.white)); } +Widget errorImageContainer(double height) { + return Container( + height: height, + color: Colors.grey[200], + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(Icons.error, color: Colors.red), + const SizedBox(width: 5), + const Text("加载失败", style: TextStyle(color: Colors.red)), + ], + ), + ); +} + +/// 成功消息 void showSuccessToast(String message) { Fluttertoast.showToast( msg: message, @@ -62,6 +79,7 @@ void showSuccessToast(String message) { ); } +/// 错误消息 void showErrorToast(String message) { Fluttertoast.showToast( msg: message, diff --git a/lib/widgets/recipe/recipe_card.dart b/lib/widgets/recipe/recipe_card.dart index 0109d90..f701501 100644 --- a/lib/widgets/recipe/recipe_card.dart +++ b/lib/widgets/recipe/recipe_card.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:food_hub_app/models/recipe.dart'; +import 'package:food_hub_app/widgets/common/index.dart'; +import 'package:tdesign_flutter/tdesign_flutter.dart'; class RecipeCard extends StatelessWidget { final Recipe recipe; @@ -21,30 +23,25 @@ class RecipeCard extends StatelessWidget { height: 200, width: double.infinity, fit: BoxFit.contain, - errorBuilder: - (context, error, stackTrace) => Container( - height: 200, - color: Colors.grey[200], - child: const Icon(Icons.food_bank, color: Colors.grey), - ), + errorBuilder: (context, error, stackTrace) => errorImageContainer(200), ), - const Divider( + Divider( height: 1, thickness: 1, - color: Colors.green, + color: Theme.of(context).primaryColor, indent: 0, endIndent: 0, ), Padding( padding: const EdgeInsets.all(10), - child: _buildRecipeContent(), + child: _buildRecipeContent(context), ), ], ), ); } - Widget _buildRecipeContent() { + Widget _buildRecipeContent(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -54,39 +51,29 @@ class RecipeCard extends StatelessWidget { Expanded( child: Text( recipe.name, - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), + style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), maxLines: 1, // 限制单行,避免挤压按钮 overflow: TextOverflow.ellipsis, ), ), Row( children: [ - IconButton( - icon: const Icon(Icons.edit, size: 14), - color: Colors.white, - style: ButtonStyle( - backgroundColor: WidgetStateProperty.all( - Colors.green, - ), - shape: WidgetStateProperty.all(CircleBorder()), - minimumSize: WidgetStateProperty.all(Size(20, 20)), - ), - onPressed: () {}, + TDButton( + icon: Icons.edit, + size: TDButtonSize.small, + type: TDButtonType.fill, + shape: TDButtonShape.circle, + theme: TDButtonTheme.primary, + onTap: () => {}, ), - IconButton( - icon: const Icon(Icons.book, size: 14), - color: Colors.white, - style: ButtonStyle( - backgroundColor: WidgetStateProperty.all( - Colors.green, - ), - shape: WidgetStateProperty.all(CircleBorder()), - minimumSize: WidgetStateProperty.all(Size(20, 20)), - ), - onPressed: () {}, + SizedBox(width: 10), + TDButton( + icon: Icons.book, + size: TDButtonSize.small, + type: TDButtonType.fill, + shape: TDButtonShape.circle, + theme: TDButtonTheme.primary, + onTap: () => {}, ), ], ), @@ -102,7 +89,7 @@ class RecipeCard extends StatelessWidget { _buildIconText( icon: Icons.food_bank, text: recipe.category, - color: Colors.green, + color: Theme.of(context).primaryColor, ), const SizedBox(width: 12), _buildIconText( @@ -156,4 +143,4 @@ class RecipeCard extends StatelessWidget { ], ); } -} \ No newline at end of file +}