Compare commits

...

2 Commits

Author SHA1 Message Date
vipg
5c71c93eee add 2025-11-15 18:01:31 +08:00
vipg
03f14394e5 add 2025-11-15 17:55:43 +08:00
3 changed files with 183 additions and 97 deletions

View File

@@ -1,4 +1,4 @@
curl -X POST http://localhost:20010/api/variety/create \ curl -X POST http://localhost:20010/variety/create \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{ -d '{
"name": "螺纹钢", "name": "螺纹钢",
@@ -6,3 +6,11 @@ curl -X POST http://localhost:20010/api/variety/create \
"tick": 1.0, "tick": 1.0,
"tick_price": 10.0 "tick_price": 10.0
}' }'
curl -X POST http://localhost:20010/exchange/create \
-H "Content-Type: application/json" \
-d '{
"name": "1234",
"code": "ads"
}'

View File

@@ -54,14 +54,14 @@ func main() {
zap.L().Info("✅ 配置跨域中间件完成") zap.L().Info("✅ 配置跨域中间件完成")
// 注册品种接口 // 注册品种接口
variety := r.Group("/api/variety") variety := r.Group("/variety")
{ {
variety.POST("/create", logic4variety.CreateVarietyHandler) variety.POST("/create", logic4variety.CreateVarietyHandler)
} }
zap.L().Info("✅ 品种接口注册完成") zap.L().Info("✅ 品种接口注册完成")
// 注册交易所接口 // 注册交易所接口
exchangeGroup := r.Group("/api/exchange") exchangeGroup := r.Group("/exchange")
{ {
exchangeGroup.POST("/create", logic4exchange.CreateExchangeHandler) exchangeGroup.POST("/create", logic4exchange.CreateExchangeHandler)
} }

View File

@@ -1,15 +1,132 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import 'package:shared_preferences/shared_preferences.dart';
class AddExchangePage extends StatelessWidget { class AddExchangePage extends StatefulWidget {
// 功能列表数据 const AddExchangePage({super.key});
final List<Map<String, dynamic>> features = [
{'icon': Icons.bar_chart, 'title': '数据分析'},
{'icon': Icons.balance, 'title': '交易'},
{'icon': Icons.account_balance, 'title': '交易所'},
{'icon': Icons.branding_watermark, 'title': '品种'},
];
AddExchangePage({super.key}); @override
State<AddExchangePage> createState() => _AddExchangePageState();
}
class _AddExchangePageState extends State<AddExchangePage> {
// 输入控制器
final TextEditingController _nameController = TextEditingController();
final TextEditingController _codeController = TextEditingController();
// 加载状态
bool _isLoading = false;
// 表单验证键
final _formKey = GlobalKey<FormState>();
// 创建交易所
Future<void> _createExchange() async {
if (!_formKey.currentState!.validate()) {
return;
}
setState(() {
_isLoading = true;
});
try {
// 获取用户ID
final prefs = await SharedPreferences.getInstance();
final userId = prefs.getString('user_id');
if (userId == null) {
if (mounted) {
_showDialog('错误', '请先登录');
Navigator.pushReplacementNamed(context, '/login');
}
return;
}
// 准备请求数据
// const baseUrl = 'https://api.fishestlife.com';
const baseUrl = 'http://localhost:20010';
const path = '/exchange/create';
final url = '$baseUrl$path';
final requestData = {
'name': _nameController.text.trim(),
'code': _codeController.text.trim(),
};
// 发送请求
final dio = Dio();
final response = await dio.post(
url,
data: requestData,
options: Options(
headers: {'Content-Type': 'application/json', 'X-User-ID': userId},
),
);
// 处理响应
if (response.statusCode == 200) {
final result = response.data;
if (result['success'] == true) {
if (mounted) {
_showDialog('成功', '交易所创建成功', () {
Navigator.pop(context, true); // 返回并通知上一页刷新
});
}
} else {
if (mounted) {
_showDialog('失败', result['message'] ?? '创建失败,请重试');
}
}
} else {
if (mounted) {
_showDialog('错误', '服务器响应异常: ${response.statusCode}');
}
}
} on DioException catch (e) {
String errorMessage = '网络请求失败';
if (e.response != null) {
errorMessage = '请求失败: ${e.response?.statusCode}';
} else if (e.type == DioExceptionType.connectionTimeout) {
errorMessage = '连接超时,请检查网络';
} else if (e.type == DioExceptionType.connectionError) {
errorMessage = '网络连接错误';
}
if (mounted) {
_showDialog('错误', errorMessage);
}
} catch (e) {
if (mounted) {
_showDialog('错误', '发生未知错误: $e');
}
} finally {
if (mounted) {
setState(() {
_isLoading = false;
});
}
}
}
// 显示对话框
void _showDialog(String title, String content, [VoidCallback? onConfirm]) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(title),
content: Text(content),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);
onConfirm?.call();
},
child: const Text('确定'),
),
],
),
);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -22,109 +139,70 @@ class AddExchangePage extends StatelessWidget {
elevation: 4, elevation: 4,
shadowColor: Colors.black12, shadowColor: Colors.black12,
backgroundColor: theme.colorScheme.surfaceContainerHighest, backgroundColor: theme.colorScheme.surfaceContainerHighest,
// 1. 左上角返回按钮及功能实现
leading: IconButton( leading: IconButton(
icon: const Icon(Icons.arrow_back), icon: const Icon(Icons.arrow_back),
onPressed: () { onPressed: () {
Navigator.of(context).pop(); // 返回上一页 Navigator.of(context).pop();
}, },
), ),
// 2. 右上角添加按钮(展示功能)
actions: [ actions: [
IconButton( IconButton(
icon: const Icon(Icons.save), icon: const Icon(Icons.save),
onPressed: () { onPressed: _isLoading ? null : _createExchange,
// 暂为展示功能,可后续添加具体逻辑
},
), ),
], ],
), ),
// 使用SafeArea确保内容在安全区域内
body: SafeArea( body: SafeArea(
// 移除不必要的Expanded避免约束冲突
child: Container( child: Container(
color: theme.colorScheme.surface, color: theme.colorScheme.surface,
// 让容器占满整个可用空间
width: double.infinity, width: double.infinity,
height: double.infinity, padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
child: ListView.builder( child: Form(
// 修改为ListView.builder key: _formKey,
padding: const EdgeInsets.symmetric(vertical: 8), child: Column(
itemCount: features.length, children: [
// 优化Web端滚动物理效果同时支持触摸和鼠标滚动 // 交易所名称输入框
physics: const ScrollPhysics(parent: BouncingScrollPhysics()), TextFormField(
itemBuilder: (context, index) { controller: _nameController,
// 构建列表项 style: TextStyle(color: theme.colorScheme.onSurface),
Widget item = _buildFeatureItem( decoration: InputDecoration(
context: context, labelText: '交易所名称',
icon: features[index]['icon'], hintText: '请输入交易所名称',
title: features[index]['title'], prefixIcon: Icon(
); Icons.account_balance,
color: theme.colorScheme.secondary,
// 在每个列表项下方添加分割线,包括最后一个 ),
return Column(
mainAxisSize: MainAxisSize.min,
children: [
item,
Divider(
height: 1,
thickness: 1,
indent: 72,
endIndent: 16,
color: theme.dividerColor,
), ),
], validator: (value) {
); if (value == null || value.trim().isEmpty) {
}, return '请输入交易所名称';
), }
), return null;
), },
);
}
Widget _buildFeatureItem({
required BuildContext context,
required IconData icon,
required String title,
}) {
final theme = Theme.of(context);
return Material(
color: Colors.transparent,
child: InkWell(
onTap: () {
// 点击事件可以在这里添加
},
borderRadius: BorderRadius.circular(8),
splashColor: theme.colorScheme.primary.withAlpha(26), // 0.1透明度的alpha值
highlightColor: theme.colorScheme.primary.withAlpha(
13,
), // 0.05透明度的alpha值
child: Container(
height: 64,
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Row(
children: [
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: theme.colorScheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(8),
), ),
child: Icon(icon, size: 24, color: theme.colorScheme.secondary), const SizedBox(height: 24),
),
const SizedBox(width: 16), // 交易所代码输入框
Text( TextFormField(
title, controller: _codeController,
style: theme.textTheme.titleMedium?.copyWith( style: TextStyle(color: theme.colorScheme.onSurface),
fontWeight: FontWeight.w500, decoration: InputDecoration(
color: theme.colorScheme.onSurface, labelText: '交易所代码',
hintText: '请输入交易所代码',
prefixIcon: Icon(
Icons.code,
color: theme.colorScheme.secondary,
),
),
validator: (value) {
if (value == null || value.trim().isEmpty) {
return '请输入交易所代码';
}
return null;
},
), ),
), ],
const Spacer(), ),
Icon(Icons.arrow_forward_ios, size: 18, color: theme.hintColor),
],
), ),
), ),
), ),