马良AI写作初始化仓库

This commit is contained in:
邓滨杰
2025-09-10 00:07:52 +08:00
parent 3c06bb1a03
commit 39c0f8840f
1309 changed files with 318528 additions and 0 deletions

View File

@@ -0,0 +1,616 @@
import 'package:flutter/material.dart';
import '../../../config/provider_icons.dart';
/// 模型服务卡片的数据模型
class ModelServiceData {
final String id;
final String name;
final String provider;
final String path;
final bool verified;
final bool isDefault;
final String? status;
final DateTime timestamp;
final String? description;
final List<String>? tags;
final String? apiEndpoint;
final ModelPerformance? performance;
ModelServiceData({
required this.id,
required this.name,
required this.provider,
required this.path,
required this.verified,
required this.isDefault,
this.status,
required this.timestamp,
this.description,
this.tags,
this.apiEndpoint,
this.performance,
});
}
/// 模型性能数据
class ModelPerformance {
final int latency; // 毫秒
final double throughput; // 请求/秒
ModelPerformance({
required this.latency,
required this.throughput,
});
}
/// 模型服务卡片组件
class ModelServiceCard extends StatefulWidget {
const ModelServiceCard({
super.key,
required this.model,
required this.onSetDefault,
required this.onValidate,
required this.onEdit,
required this.onDelete,
});
final ModelServiceData model;
final Function(String) onSetDefault;
final Function(String) onValidate;
final Function(String) onEdit;
final Function(String) onDelete;
@override
State<ModelServiceCard> createState() => _ModelServiceCardState();
}
class _ModelServiceCardState extends State<ModelServiceCard> {
bool _expanded = false;
// 未使用的变量已移除
// 获取提供商图标
Widget _getProviderLogo(String provider) {
return ProviderIcons.getProviderIconForContext(
provider,
iconSize: IconSize.medium,
);
}
// 获取状态颜色(未使用,保留以备后续扩展)
Color _getStatusColor(String status) {
final statusLower = status.toLowerCase();
if (statusLower.contains('error') || statusLower.contains('失败')) {
return Theme.of(context).colorScheme.error;
} else if (statusLower.contains('warning') || statusLower.contains('警告')) {
return Theme.of(context).colorScheme.tertiary;
} else {
return Theme.of(context).colorScheme.primary;
}
}
// 获取状态文本(未使用,保留以备后续扩展)
String _getStatusText(String status) {
return status;
}
// 格式化日期
String _formatDate(DateTime date) {
return '${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}';
}
// 获取性能颜色
Color _getPerformanceColor(int latency) {
if (latency < 100) {
return Theme.of(context).colorScheme.secondary;
} else if (latency < 300) {
return Theme.of(context).colorScheme.tertiary;
} else {
return Theme.of(context).colorScheme.error;
}
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final isDark = theme.brightness == Brightness.dark;
return Container(
margin: EdgeInsets.zero,
decoration: BoxDecoration(
color: theme.colorScheme.surface,
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: widget.model.verified
? theme.colorScheme.outline.withAlpha(51)
: theme.colorScheme.outline.withAlpha(77),
width: widget.model.verified ? 0.5 : 1,
),
boxShadow: [
BoxShadow(
color: Theme.of(context).colorScheme.shadow.withOpacity(0.08),
blurRadius: 4,
offset: const Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 卡片主体内容
Padding(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 头部:图标、名称和操作菜单
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 提供商图标
Container(
width: 36,
height: 36,
decoration: BoxDecoration(
color: theme.colorScheme.surfaceContainerHighest.withAlpha(128),
borderRadius: BorderRadius.circular(8),
),
child: Center(
child: _getProviderLogo(widget.model.provider),
),
),
const SizedBox(width: 12),
// 名称和路径
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.model.name,
style: theme.textTheme.titleSmall?.copyWith(
fontWeight: FontWeight.bold,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 4),
Row(
children: [
Text(
widget.model.provider,
style: theme.textTheme.bodySmall?.copyWith(
fontWeight: FontWeight.w500,
fontSize: 11,
),
),
const SizedBox(width: 8),
Text(
'',
style: TextStyle(
color: theme.colorScheme.onSurface.withAlpha(77),
),
),
const SizedBox(width: 8),
Expanded(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: theme.colorScheme.surfaceContainerHighest.withAlpha(128),
borderRadius: BorderRadius.circular(4),
),
child: Text(
widget.model.path,
style: TextStyle(
fontFamily: 'monospace',
fontSize: 11,
color: theme.colorScheme.onSurfaceVariant,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
),
],
),
],
),
),
// 操作菜单
PopupMenuButton(
icon: Icon(
Icons.more_vert,
size: 18,
color: theme.colorScheme.onSurface.withAlpha(153),
),
itemBuilder: (context) => <PopupMenuEntry<String>>[
const PopupMenuItem<String>(
value: 'edit',
child: Row(
children: [
Icon(Icons.edit, size: 16),
SizedBox(width: 8),
Text('编辑', style: TextStyle(fontSize: 13)),
],
),
),
const PopupMenuItem<String>(
value: 'copy_path',
child: Row(
children: [
Icon(Icons.copy, size: 16),
SizedBox(width: 8),
Text('复制模型路径', style: TextStyle(fontSize: 13)),
],
),
),
if (widget.model.apiEndpoint != null)
const PopupMenuItem<String>(
value: 'visit_api',
child: Row(
children: [
Icon(Icons.open_in_new, size: 16),
SizedBox(width: 8),
Text('访问API', style: TextStyle(fontSize: 13)),
],
),
),
const PopupMenuDivider(),
PopupMenuItem<String>(
value: 'delete',
child: Row(
children: [
Icon(Icons.delete_outline, size: 16, color: theme.colorScheme.error),
const SizedBox(width: 8),
Text('删除', style: TextStyle(fontSize: 13, color: theme.colorScheme.error)),
],
),
),
],
onSelected: (String value) {
switch (value) {
case 'edit':
widget.onEdit(widget.model.id);
break;
case 'copy_path':
// 复制路径逻辑
break;
case 'visit_api':
// 访问API逻辑
break;
case 'delete':
widget.onDelete(widget.model.id);
break;
}
},
),
],
),
const SizedBox(height: 8),
// 状态标签和时间戳
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// 状态标签
Row(
children: [
// 验证状态
Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 3),
decoration: BoxDecoration(
color: widget.model.verified
? theme.colorScheme.secondaryContainer
: theme.colorScheme.tertiaryContainer,
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: widget.model.verified
? theme.colorScheme.secondary.withOpacity(0.5)
: theme.colorScheme.tertiary.withOpacity(0.5),
width: 1,
),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
widget.model.verified
? Icons.check_circle_outline
: Icons.access_time,
size: 12,
color: widget.model.verified
? theme.colorScheme.secondary
: theme.colorScheme.tertiary,
),
const SizedBox(width: 4),
Text(
widget.model.verified ? '已验证' : '未验证',
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.w500,
color: widget.model.verified
? theme.colorScheme.onSecondaryContainer
: theme.colorScheme.onTertiaryContainer,
),
),
],
),
),
// 默认状态标签
if (widget.model.isDefault)
Padding(
padding: const EdgeInsets.only(left: 8),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 3),
decoration: BoxDecoration(
color: theme.colorScheme.primary.withAlpha(26),
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: theme.colorScheme.primary.withAlpha(77),
width: 1,
),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.star,
size: 12,
color: theme.colorScheme.primary,
),
const SizedBox(width: 4),
Text(
'默认',
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.w500,
color: theme.colorScheme.primary,
),
),
],
),
),
),
],
),
// 时间戳
Row(
children: [
Icon(
Icons.access_time,
size: 12,
color: theme.colorScheme.onSurface.withAlpha(128),
),
const SizedBox(width: 4),
Text(
_formatDate(widget.model.timestamp),
style: TextStyle(
fontSize: 11,
color: theme.colorScheme.onSurface.withAlpha(128),
),
),
],
),
],
),
// 性能指标
if (widget.model.performance != null)
Padding(
padding: const EdgeInsets.only(top: 8),
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: theme.colorScheme.surfaceContainerHighest.withAlpha(77),
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
// 延迟
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'延迟',
style: TextStyle(
fontSize: 11,
color: theme.colorScheme.onSurface.withAlpha(153),
),
),
const SizedBox(height: 2),
Row(
children: [
Icon(
Icons.bolt,
size: 14,
color: _getPerformanceColor(widget.model.performance!.latency),
),
const SizedBox(width: 4),
Text(
'${widget.model.performance!.latency}ms',
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
color: _getPerformanceColor(widget.model.performance!.latency),
),
),
],
),
],
),
),
// 吞吐量
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'吞吐量',
style: TextStyle(
fontSize: 11,
color: theme.colorScheme.onSurface.withAlpha(153),
),
),
const SizedBox(height: 2),
Text(
'${widget.model.performance!.throughput} 次/秒',
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
color: theme.colorScheme.onSurface,
),
),
],
),
),
],
),
),
),
// 展开的详情内容
if (_expanded && widget.model.description != null)
Padding(
padding: const EdgeInsets.only(top: 8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Divider(
color: theme.colorScheme.outline.withAlpha(26),
),
const SizedBox(height: 8),
Text(
widget.model.description!,
style: TextStyle(
fontSize: 13,
color: theme.colorScheme.onSurface.withAlpha(204),
height: 1.5,
),
),
// 标签
if (widget.model.tags != null && widget.model.tags!.isNotEmpty)
Padding(
padding: const EdgeInsets.only(top: 12),
child: Wrap(
spacing: 6,
runSpacing: 6,
children: widget.model.tags!.map((tag) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: theme.colorScheme.primary.withAlpha(26),
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: theme.colorScheme.primary.withAlpha(77),
width: 1,
),
),
child: Text(
tag,
style: TextStyle(
fontSize: 11,
color: theme.colorScheme.primary,
),
),
);
}).toList(),
),
),
],
),
),
],
),
),
// 底部操作区
Container(
decoration: BoxDecoration(
border: Border(
top: BorderSide(
color: theme.colorScheme.outline.withAlpha(26),
width: 1,
),
),
),
child: Row(
children: [
// 查看详情按钮
Expanded(
child: InkWell(
onTap: () {
setState(() {
_expanded = !_expanded;
});
},
child: Container(
padding: const EdgeInsets.symmetric(vertical: 8),
decoration: BoxDecoration(
color: theme.colorScheme.surfaceContainerHighest.withAlpha(77),
),
alignment: Alignment.center,
child: Text(
_expanded ? '收起详情' : '查看详情',
style: TextStyle(
fontSize: 13,
color: theme.colorScheme.onSurface.withAlpha(179),
),
),
),
),
),
// 设为默认按钮(仅未验证时显示)
Expanded(
child: InkWell(
onTap: () {
// 如果未验证,则执行验证逻辑
if (!widget.model.verified) {
widget.onValidate(widget.model.id);
} else {
// 如果已验证,则执行设为默认逻辑
if (!widget.model.isDefault) {
widget.onSetDefault(widget.model.id);
}
}
},
child: Container(
padding: const EdgeInsets.symmetric(vertical: 8),
decoration: BoxDecoration(
border: Border(
left: BorderSide(
color: theme.colorScheme.outline.withAlpha(26),
width: 1,
),
),
),
alignment: Alignment.center,
child: Text(
widget.model.verified
? (widget.model.isDefault ? '默认模型' : '设为默认')
: '验证连接', // 未验证时显示验证
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
color: widget.model.verified && widget.model.isDefault
? theme.colorScheme.onSurface.withAlpha(100) // 如果是默认,灰色显示
: theme.colorScheme.primary, // 否则高亮
),
),
),
),
),
],
),
),
],
),
);
}
}