Flutter 框架跨平台鸿蒙开发 - 书法印章制作记录应用开发教程

Flutter书法印章制作记录应用开发教程

项目简介

书法印章制作记录应用是一款专为印章制作工艺师设计的管理工具,帮助记录和追踪印章制作的全过程。应用涵盖了从设计到完成的每个制作步骤,同时管理材料库存、客户信息和业务统计,是印章制作行业的数字化管理解决方案。
运行效果图



核心功能特性

  • 制作记录管理:完整记录印章制作过程,包括设计、雕刻、打磨等各个步骤
  • 进度追踪:实时显示制作进度,支持步骤完成状态管理
  • 材料库存管理:管理各类印章制作材料,监控库存状态
  • 客户信息管理:维护客户档案,记录订单历史和消费统计
  • 多维度筛选:支持按状态、类型、书体等条件筛选记录
  • 统计分析:提供制作统计、材料使用分析、客户统计等数据洞察
  • 智能提醒:库存不足提醒、制作进度监控
  • 动画效果:流畅的界面动画,提升用户体验

技术架构

开发环境

  • 框架:Flutter 3.x
  • 开发语言:Dart
  • UI组件:Material Design 3
  • 状态管理:StatefulWidget
  • 数据存储:内存存储(可扩展为本地数据库)

项目结构

复制代码
lib/
├── main.dart                 # 应用入口和主要逻辑
├── models/                   # 数据模型(本教程中集成在main.dart)
│   ├── seal_making_record.dart
│   ├── process_step.dart
│   ├── material_inventory.dart
│   └── client_info.dart
├── pages/                    # 页面组件
│   ├── records_page.dart
│   ├── materials_page.dart
│   ├── clients_page.dart
│   └── statistics_page.dart
└── widgets/                  # 自定义组件
    ├── record_card.dart
    ├── material_card.dart
    └── client_card.dart

数据模型设计

1. 印章制作记录模型(SealMakingRecord)

dart 复制代码
class SealMakingRecord {
  final String id;              // 记录ID
  final String sealName;        // 印章名称
  final String content;         // 印章内容/文字
  final String sealType;        // 印章类型:姓名章、闲章、藏书章等
  final String style;           // 书体:篆书、隶书、楷书等
  final String material;        // 材质:寿山石、青田石、牛角等
  final String size;            // 尺寸
  final DateTime startDate;     // 开始制作日期
  final DateTime? completionDate; // 完成日期
  final String status;          // 状态:设计中、雕刻中、完成、暂停
  final String clientName;      // 客户姓名
  final String clientContact;   // 客户联系方式
  final double price;           // 价格
  final String notes;           // 备注
  final List<String> photos;    // 制作过程照片
  final List<ProcessStep> processSteps; // 制作步骤
  final String difficulty;      // 难度等级:简单、中等、困难
}

设计要点

  • 使用可选的completionDate来区分进行中和已完成的记录
  • processSteps列表记录详细的制作步骤
  • photos列表存储制作过程的图片路径
  • difficulty字段帮助评估制作复杂度

2. 制作步骤模型(ProcessStep)

dart 复制代码
class ProcessStep {
  final String id;              // 步骤ID
  final String stepName;        // 步骤名称
  final String description;     // 步骤描述
  final DateTime? completedDate; // 完成日期
  final bool isCompleted;       // 是否完成
  final String notes;           // 步骤备注
  final List<String> photos;    // 步骤照片
  final int estimatedHours;     // 预计耗时
  final int actualHours;        // 实际耗时
}

设计要点

  • 支持时间估算和实际用时对比
  • 每个步骤可以独立记录照片和备注
  • isCompleted字段用于进度计算

3. 材料库存模型(MaterialInventory)

dart 复制代码
class MaterialInventory {
  final String id;              // 材料ID
  final String materialName;    // 材料名称
  final String category;        // 分类:石材、木材、金属等
  final String specification;   // 规格
  final int quantity;           // 数量
  final double unitPrice;       // 单价
  final String supplier;        // 供应商
  final DateTime purchaseDate;  // 采购日期
  final String storageLocation; // 存放位置
  final String notes;           // 备注
}

设计要点

  • 支持多种材料分类管理
  • 记录采购信息便于成本核算
  • storageLocation帮助快速定位材料

4. 客户信息模型(ClientInfo)

dart 复制代码
class ClientInfo {
  final String id;              // 客户ID
  final String name;            // 姓名
  final String phone;           // 电话
  final String email;           // 邮箱
  final String address;         // 地址
  final DateTime firstOrderDate; // 首次下单日期
  final int totalOrders;        // 总订单数
  final double totalSpent;      // 总消费金额
  final String notes;           // 备注
  final List<String> orderHistory; // 订单历史
}

设计要点

  • 记录客户的完整消费历史
  • 支持客户价值分析
  • orderHistory关联具体的制作记录

核心功能实现

1. 制作记录管理

记录列表展示
dart 复制代码
Widget _buildRecordCard(SealMakingRecord record) {
  final completedSteps = record.processSteps.where((step) => step.isCompleted).length;
  final totalSteps = record.processSteps.length;
  final progress = totalSteps > 0 ? completedSteps / totalSteps : 0.0;

  return Card(
    elevation: 4,
    margin: const EdgeInsets.only(bottom: 16),
    child: InkWell(
      onTap: () => _showRecordDetail(record),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // 标题和状态
            Row(
              children: [
                Expanded(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(record.sealName, style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
                      Text('${record.sealType} • ${record.style} • ${record.material}'),
                    ],
                  ),
                ),
                Container(
                  padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
                  decoration: BoxDecoration(
                    color: _getStatusColor(record.status),
                    borderRadius: BorderRadius.circular(12),
                  ),
                  child: Text(record.status, style: TextStyle(color: Colors.white)),
                ),
              ],
            ),
            
            // 印章内容展示
            Container(
              padding: EdgeInsets.all(12),
              decoration: BoxDecoration(
                color: Colors.brown.withValues(alpha: 0.1),
                borderRadius: BorderRadius.circular(8),
                border: Border.all(color: Colors.brown.withValues(alpha: 0.3)),
              ),
              child: Center(
                child: Text(record.content, style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
              ),
            ),
            
            // 进度条
            LinearProgressIndicator(
              value: progress,
              backgroundColor: Colors.grey.shade300,
              valueColor: AlwaysStoppedAnimation<Color>(_getStatusColor(record.status)),
            ),
          ],
        ),
      ),
    ),
  );
}

实现要点

  • 动态计算制作进度百分比
  • 使用不同颜色表示制作状态
  • 印章内容使用特殊样式突出显示
  • 支持点击查看详情
多维度筛选功能
dart 复制代码
List<SealMakingRecord> _getFilteredRecords() {
  return _sealRecords.where((record) {
    // 搜索过滤
    if (_searchQuery.isNotEmpty) {
      final query = _searchQuery.toLowerCase();
      if (!record.sealName.toLowerCase().contains(query) &&
          !record.content.toLowerCase().contains(query) &&
          !record.clientName.toLowerCase().contains(query)) {
        return false;
      }
    }

    // 状态过滤
    if (_selectedStatus != null && record.status != _selectedStatus) {
      return false;
    }

    // 类型过滤
    if (_selectedType != null && record.sealType != _selectedType) {
      return false;
    }

    // 书体过滤
    if (_selectedStyle != null && record.style != _selectedStyle) {
      return false;
    }

    // 完成状态过滤
    if (_showCompletedOnly && record.status != '完成') {
      return false;
    }

    return true;
  }).toList()..sort((a, b) => b.startDate.compareTo(a.startDate));
}

实现要点

  • 支持文本搜索(印章名称、内容、客户姓名)
  • 多个筛选条件可以组合使用
  • 结果按开始日期倒序排列
  • 实时筛选,无需刷新页面

2. 材料库存管理

库存状态监控
dart 复制代码
Widget _buildMaterialCard(MaterialInventory material) {
  final isLowStock = material.quantity < 5;

  return Card(
    child: Padding(
      padding: const EdgeInsets.all(16),
      child: Column(
        children: [
          Row(
            children: [
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(material.materialName, style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
                    Text('${material.category} • ${material.specification}'),
                  ],
                ),
              ),
              Column(
                crossAxisAlignment: CrossAxisAlignment.end,
                children: [
                  Text(
                    '${material.quantity}件',
                    style: TextStyle(
                      fontSize: 18,
                      fontWeight: FontWeight.bold,
                      color: isLowStock ? Colors.red : Colors.green,
                    ),
                  ),
                  if (isLowStock)
                    Container(
                      padding: EdgeInsets.symmetric(horizontal: 6, vertical: 2),
                      decoration: BoxDecoration(
                        color: Colors.red,
                        borderRadius: BorderRadius.circular(8),
                      ),
                      child: Text('库存不足', style: TextStyle(color: Colors.white, fontSize: 10)),
                    ),
                ],
              ),
            ],
          ),
        ],
      ),
    ),
  );
}

实现要点

  • 自动检测库存不足(数量<5)
  • 使用颜色区分库存状态
  • 显示库存不足警告标签
  • 记录供应商和采购信息

3. 客户管理系统

客户信息展示
dart 复制代码
Widget _buildClientCard(ClientInfo client) {
  return Card(
    child: InkWell(
      onTap: () => _showClientDetail(client),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          children: [
            Row(
              children: [
                CircleAvatar(
                  backgroundColor: Colors.brown.withValues(alpha: 0.1),
                  child: Text(client.name.isNotEmpty ? client.name[0] : '?'),
                ),
                SizedBox(width: 12),
                Expanded(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(client.name, style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
                      Text(client.phone),
                    ],
                  ),
                ),
                Column(
                  crossAxisAlignment: CrossAxisAlignment.end,
                  children: [
                    Text('¥${client.totalSpent.toStringAsFixed(0)}', 
                         style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.green.shade600)),
                    Text('${client.totalOrders}个订单'),
                  ],
                ),
              ],
            ),
          ],
        ),
      ),
    ),
  );
}

实现要点

  • 使用头像显示客户姓名首字母
  • 突出显示客户价值(总消费金额)
  • 记录客户的订单统计
  • 支持点击查看详细信息

4. 统计分析功能

总体统计
dart 复制代码
Widget _buildOverallStatsCard() {
  final totalRecords = _sealRecords.length;
  final completedRecords = _sealRecords.where((r) => r.status == '完成').length;
  final totalRevenue = _sealRecords.fold(0.0, (sum, record) => sum + record.price);
  final avgPrice = totalRecords > 0 ? totalRevenue / totalRecords : 0.0;

  return Card(
    child: Padding(
      padding: const EdgeInsets.all(16),
      child: Column(
        children: [
          Row(
            children: [
              Expanded(child: _buildStatItem('总订单', '$totalRecords个', Icons.assignment, Colors.blue)),
              Expanded(child: _buildStatItem('已完成', '$completedRecords个', Icons.check_circle, Colors.green)),
            ],
          ),
          SizedBox(height: 16),
          Row(
            children: [
              Expanded(child: _buildStatItem('总收入', '¥${totalRevenue.toStringAsFixed(0)}', Icons.attach_money, Colors.orange)),
              Expanded(child: _buildStatItem('平均价格', '¥${avgPrice.toStringAsFixed(0)}', Icons.trending_up, Colors.purple)),
            ],
          ),
        ],
      ),
    ),
  );
}

实现要点

  • 计算总订单数和完成率
  • 统计总收入和平均价格
  • 使用图标和颜色区分不同指标
  • 数据实时更新
状态分布统计
dart 复制代码
Widget _buildStatusDistributionCard() {
  final statusStats = <String, int>{};
  for (final record in _sealRecords) {
    statusStats[record.status] = (statusStats[record.status] ?? 0) + 1;
  }

  return Card(
    child: Padding(
      padding: const EdgeInsets.all(16),
      child: Column(
        children: statusStats.entries.map((entry) {
          final percentage = entry.value / _sealRecords.length;
          return Column(
            children: [
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Text(entry.key),
                  Text('${entry.value}个 (${(percentage * 100).toStringAsFixed(1)}%)'),
                ],
              ),
              LinearProgressIndicator(
                value: percentage,
                valueColor: AlwaysStoppedAnimation<Color>(_getStatusColor(entry.key)),
              ),
            ],
          );
        }).toList(),
      ),
    ),
  );
}

实现要点

  • 统计各状态的记录数量
  • 计算百分比分布
  • 使用进度条可视化比例
  • 颜色与状态保持一致

动画效果实现

1. 页面淡入动画

dart 复制代码
void _setupAnimations() {
  _fadeAnimationController = AnimationController(
    duration: const Duration(milliseconds: 800),
    vsync: this,
  );

  _fadeAnimation = Tween<double>(
    begin: 0.0,
    end: 1.0,
  ).animate(CurvedAnimation(
    parent: _fadeAnimationController,
    curve: Curves.easeInOut,
  ));

  _fadeAnimationController.forward();
}

// 在build方法中使用
FadeTransition(
  opacity: _fadeAnimation,
  child: IndexedStack(
    index: _selectedIndex,
    children: [
      _buildRecordsPage(),
      _buildMaterialsPage(),
      _buildClientsPage(),
      _buildStatisticsPage(),
    ],
  ),
)

2. 进度条动画

dart 复制代码
AnimatedBuilder(
  animation: _progressAnimation,
  builder: (context, child) {
    return LinearProgressIndicator(
      value: progress * _progressAnimation.value,
      backgroundColor: Colors.grey.shade300,
      valueColor: AlwaysStoppedAnimation<Color>(_getStatusColor(record.status)),
    );
  },
)

动画特点

  • 页面切换时的平滑淡入效果
  • 进度条的动态加载动画
  • 使用不同的缓动曲线增强视觉效果

用户界面设计

1. 色彩方案

dart 复制代码
theme: ThemeData(
  colorScheme: ColorScheme.fromSeed(seedColor: Colors.brown),
  useMaterial3: true,
),

设计理念

  • 主色调使用棕色,符合印章制作的传统文化氛围
  • 采用Material Design 3设计规范
  • 状态颜色:蓝色(设计中)、橙色(雕刻中)、绿色(完成)、红色(取消)

2. 卡片设计

dart 复制代码
Card(
  elevation: 4,
  margin: const EdgeInsets.only(bottom: 16),
  child: InkWell(
    onTap: () => _showRecordDetail(record),
    child: Padding(
      padding: const EdgeInsets.all(16),
      child: // 卡片内容
    ),
  ),
)

设计要点

  • 使用阴影增强层次感
  • 支持点击交互
  • 统一的内边距和外边距
  • 圆角设计更加现代

3. 信息层次

dart 复制代码
Widget _buildInfoItem(IconData icon, String label, String value, Color color) {
  return Column(
    children: [
      Icon(icon, color: color, size: 20),
      SizedBox(height: 4),
      Text(label, style: TextStyle(fontSize: 10, color: Colors.grey.shade600)),
      SizedBox(height: 2),
      Text(value, style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold, color: color)),
    ],
  );
}

设计原则

  • 图标+标签+数值的三层信息结构
  • 使用颜色区分不同类型的信息
  • 字体大小层次分明

数据管理策略

1. 示例数据初始化

dart 复制代码
void _initializeData() {
  _sealRecords = [
    SealMakingRecord(
      id: '1',
      sealName: '王羲之印',
      content: '王羲之印',
      sealType: '姓名章',
      style: '篆书',
      material: '寿山石',
      size: '2.5×2.5cm',
      startDate: DateTime.now().subtract(const Duration(days: 15)),
      completionDate: DateTime.now().subtract(const Duration(days: 3)),
      status: '完成',
      clientName: '王先生',
      clientContact: '138****1234',
      price: 280.0,
      notes: '客户要求古朴风格,字体要求工整',
      photos: ['design_1.jpg', 'carving_1.jpg', 'finished_1.jpg'],
      processSteps: [
        ProcessStep(
          id: '1-1',
          stepName: '设计稿',
          description: '根据客户要求设计印章布局和字体',
          completedDate: DateTime.now().subtract(const Duration(days: 14)),
          isCompleted: true,
          notes: '采用汉印风格,布局均匀',
          photos: ['design_sketch.jpg'],
          estimatedHours: 2,
          actualHours: 3,
        ),
        // 更多步骤...
      ],
      difficulty: '中等',
    ),
    // 更多记录...
  ];
}

2. 数据筛选和搜索

dart 复制代码
// 搜索功能
void _showSearchDialog() {
  showDialog(
    context: context,
    builder: (context) => AlertDialog(
      title: const Text('搜索记录'),
      content: TextField(
        autofocus: true,
        decoration: const InputDecoration(
          hintText: '输入印章名称、内容或客户姓名',
          prefixIcon: Icon(Icons.search),
        ),
        onChanged: (value) => _searchQuery = value,
        onSubmitted: (value) {
          Navigator.of(context).pop();
          setState(() {});
        },
      ),
      actions: [
        TextButton(onPressed: () => Navigator.of(context).pop(), child: const Text('取消')),
        ElevatedButton(
          onPressed: () {
            Navigator.of(context).pop();
            setState(() {});
          },
          child: const Text('搜索'),
        ),
      ],
    ),
  );
}

扩展功能建议

1. 数据持久化

dart 复制代码
// 使用SharedPreferences存储数据
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:convert';

class DataManager {
  static const String _recordsKey = 'seal_records';
  static const String _materialsKey = 'materials';
  static const String _clientsKey = 'clients';

  static Future<void> saveRecords(List<SealMakingRecord> records) async {
    final prefs = await SharedPreferences.getInstance();
    final recordsJson = records.map((r) => r.toJson()).toList();
    await prefs.setString(_recordsKey, json.encode(recordsJson));
  }

  static Future<List<SealMakingRecord>> loadRecords() async {
    final prefs = await SharedPreferences.getInstance();
    final recordsString = prefs.getString(_recordsKey);
    if (recordsString != null) {
      final recordsJson = json.decode(recordsString) as List;
      return recordsJson.map((json) => SealMakingRecord.fromJson(json)).toList();
    }
    return [];
  }
}

2. 图片管理

dart 复制代码
// 使用image_picker选择图片
import 'package:image_picker/image_picker.dart';

class ImageManager {
  static final ImagePicker _picker = ImagePicker();

  static Future<String?> pickImage() async {
    final XFile? image = await _picker.pickImage(source: ImageSource.gallery);
    return image?.path;
  }

  static Future<List<String>> pickMultipleImages() async {
    final List<XFile> images = await _picker.pickMultiImage();
    return images.map((image) => image.path).toList();
  }
}

3. 导出功能

dart 复制代码
// 导出制作记录为PDF
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;

class ExportManager {
  static Future<void> exportRecordToPDF(SealMakingRecord record) async {
    final pdf = pw.Document();
    
    pdf.addPage(
      pw.Page(
        build: (pw.Context context) {
          return pw.Column(
            crossAxisAlignment: pw.CrossAxisAlignment.start,
            children: [
              pw.Text('印章制作记录', style: pw.TextStyle(fontSize: 24, fontWeight: pw.FontWeight.bold)),
              pw.SizedBox(height: 20),
              pw.Text('印章名称: ${record.sealName}'),
              pw.Text('印章内容: ${record.content}'),
              pw.Text('印章类型: ${record.sealType}'),
              pw.Text('书体: ${record.style}'),
              pw.Text('材质: ${record.material}'),
              pw.Text('尺寸: ${record.size}'),
              pw.Text('客户: ${record.clientName}'),
              pw.Text('价格: ¥${record.price}'),
              pw.SizedBox(height: 20),
              pw.Text('制作步骤:', style: pw.TextStyle(fontSize: 18, fontWeight: pw.FontWeight.bold)),
              ...record.processSteps.map((step) => pw.Text('• ${step.stepName}: ${step.description}')),
            ],
          );
        },
      ),
    );
    
    // 保存PDF文件
    // final output = await getTemporaryDirectory();
    // final file = File("${output.path}/seal_record_${record.id}.pdf");
    // await file.writeAsBytes(await pdf.save());
  }
}

4. 通知提醒

dart 复制代码
// 使用flutter_local_notifications实现提醒
import 'package:flutter_local_notifications/flutter_local_notifications.dart';

class NotificationManager {
  static final FlutterLocalNotificationsPlugin _notifications = FlutterLocalNotificationsPlugin();

  static Future<void> initialize() async {
    const AndroidInitializationSettings initializationSettingsAndroid = 
        AndroidInitializationSettings('@mipmap/ic_launcher');
    
    const InitializationSettings initializationSettings = InitializationSettings(
      android: initializationSettingsAndroid,
    );
    
    await _notifications.initialize(initializationSettings);
  }

  static Future<void> scheduleReminder(String title, String body, DateTime scheduledDate) async {
    await _notifications.schedule(
      0,
      title,
      body,
      scheduledDate,
      const NotificationDetails(
        android: AndroidNotificationDetails(
          'seal_making_channel',
          '印章制作提醒',
          channelDescription: '印章制作进度和库存提醒',
          importance: Importance.max,
          priority: Priority.high,
        ),
      ),
    );
  }
}

性能优化建议

1. 列表优化

dart 复制代码
// 使用ListView.builder进行懒加载
ListView.builder(
  itemCount: filteredRecords.length,
  itemBuilder: (context, index) {
    final record = filteredRecords[index];
    return _buildRecordCard(record);
  },
)

// 对于大量数据,可以使用分页加载
class PaginatedRecordsList extends StatefulWidget {
  @override
  _PaginatedRecordsListState createState() => _PaginatedRecordsListState();
}

class _PaginatedRecordsListState extends State<PaginatedRecordsList> {
  final ScrollController _scrollController = ScrollController();
  List<SealMakingRecord> _displayedRecords = [];
  int _currentPage = 0;
  final int _pageSize = 20;

  @override
  void initState() {
    super.initState();
    _loadMoreRecords();
    _scrollController.addListener(_onScroll);
  }

  void _onScroll() {
    if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
      _loadMoreRecords();
    }
  }

  void _loadMoreRecords() {
    final startIndex = _currentPage * _pageSize;
    final endIndex = startIndex + _pageSize;
    final newRecords = _allRecords.skip(startIndex).take(_pageSize).toList();
    
    setState(() {
      _displayedRecords.addAll(newRecords);
      _currentPage++;
    });
  }
}

2. 图片缓存

dart 复制代码
// 使用cached_network_image缓存网络图片
import 'package:cached_network_image/cached_network_image.dart';

Widget _buildPhotoThumbnail(String photoPath) {
  return CachedNetworkImage(
    imageUrl: photoPath,
    width: 60,
    height: 60,
    fit: BoxFit.cover,
    placeholder: (context, url) => Container(
      width: 60,
      height: 60,
      color: Colors.grey.shade300,
      child: Icon(Icons.image, color: Colors.grey.shade600),
    ),
    errorWidget: (context, url, error) => Container(
      width: 60,
      height: 60,
      color: Colors.grey.shade300,
      child: Icon(Icons.error, color: Colors.red),
    ),
  );
}

3. 状态管理优化

dart 复制代码
// 使用Provider进行状态管理
import 'package:provider/provider.dart';

class SealMakingProvider extends ChangeNotifier {
  List<SealMakingRecord> _records = [];
  List<MaterialInventory> _materials = [];
  List<ClientInfo> _clients = [];
  
  String _searchQuery = '';
  String? _selectedStatus;
  
  List<SealMakingRecord> get filteredRecords {
    return _records.where((record) {
      if (_searchQuery.isNotEmpty) {
        final query = _searchQuery.toLowerCase();
        if (!record.sealName.toLowerCase().contains(query)) {
          return false;
        }
      }
      if (_selectedStatus != null && record.status != _selectedStatus) {
        return false;
      }
      return true;
    }).toList();
  }
  
  void updateSearchQuery(String query) {
    _searchQuery = query;
    notifyListeners();
  }
  
  void updateStatusFilter(String? status) {
    _selectedStatus = status;
    notifyListeners();
  }
}

测试策略

1. 单元测试

dart 复制代码
// test/models/seal_making_record_test.dart
import 'package:flutter_test/flutter_test.dart';
import 'package:your_app/models/seal_making_record.dart';

void main() {
  group('SealMakingRecord', () {
    test('should calculate progress correctly', () {
      final record = SealMakingRecord(
        id: '1',
        sealName: 'Test Seal',
        // ... 其他必需字段
        processSteps: [
          ProcessStep(id: '1', stepName: 'Step 1', isCompleted: true, /* ... */),
          ProcessStep(id: '2', stepName: 'Step 2', isCompleted: false, /* ... */),
        ],
      );
      
      final progress = record.calculateProgress();
      expect(progress, equals(0.5));
    });
    
    test('should identify completed records', () {
      final record = SealMakingRecord(
        id: '1',
        status: '完成',
        completionDate: DateTime.now(),
        // ... 其他字段
      );
      
      expect(record.isCompleted, isTrue);
    });
  });
}

2. Widget测试

dart 复制代码
// test/widgets/record_card_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:your_app/widgets/record_card.dart';

void main() {
  group('RecordCard', () {
    testWidgets('should display record information correctly', (WidgetTester tester) async {
      final record = SealMakingRecord(
        id: '1',
        sealName: 'Test Seal',
        content: 'Test Content',
        status: '完成',
        // ... 其他字段
      );
      
      await tester.pumpWidget(
        MaterialApp(
          home: Scaffold(
            body: RecordCard(record: record),
          ),
        ),
      );
      
      expect(find.text('Test Seal'), findsOneWidget);
      expect(find.text('Test Content'), findsOneWidget);
      expect(find.text('完成'), findsOneWidget);
    });
    
    testWidgets('should show progress indicator', (WidgetTester tester) async {
      final record = SealMakingRecord(
        // ... 字段设置
        processSteps: [
          ProcessStep(isCompleted: true, /* ... */),
          ProcessStep(isCompleted: false, /* ... */),
        ],
      );
      
      await tester.pumpWidget(
        MaterialApp(
          home: Scaffold(
            body: RecordCard(record: record),
          ),
        ),
      );
      
      expect(find.byType(LinearProgressIndicator), findsOneWidget);
    });
  });
}

3. 集成测试

dart 复制代码
// integration_test/app_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:your_app/main.dart' as app;

void main() {
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();
  
  group('App Integration Tests', () {
    testWidgets('should navigate between tabs', (WidgetTester tester) async {
      app.main();
      await tester.pumpAndSettle();
      
      // 测试底部导航
      expect(find.text('制作记录'), findsOneWidget);
      
      await tester.tap(find.text('材料库存'));
      await tester.pumpAndSettle();
      expect(find.text('材料库存'), findsOneWidget);
      
      await tester.tap(find.text('客户管理'));
      await tester.pumpAndSettle();
      expect(find.text('客户管理'), findsOneWidget);
      
      await tester.tap(find.text('统计分析'));
      await tester.pumpAndSettle();
      expect(find.text('统计分析'), findsOneWidget);
    });
    
    testWidgets('should filter records correctly', (WidgetTester tester) async {
      app.main();
      await tester.pumpAndSettle();
      
      // 打开筛选对话框
      await tester.tap(find.byIcon(Icons.filter_list));
      await tester.pumpAndSettle();
      
      // 选择状态筛选
      await tester.tap(find.text('完成'));
      await tester.pumpAndSettle();
      
      await tester.tap(find.text('应用'));
      await tester.pumpAndSettle();
      
      // 验证筛选结果
      expect(find.byType(Card), findsWidgets);
    });
  });
}

部署和发布

1. Android打包

bash 复制代码
# 生成签名密钥
keytool -genkey -v -keystore ~/seal-making-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias seal-making

# 配置android/app/build.gradle
android {
    signingConfigs {
        release {
            keyAlias keystoreProperties['keyAlias']
            keyPassword keystoreProperties['keyPassword']
            storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
            storePassword keystoreProperties['storePassword']
        }
    }
    buildTypes {
        release {
            signingConfig signingConfigs.release
        }
    }
}

# 构建APK
flutter build apk --release

2. iOS打包

bash 复制代码
# 构建iOS应用
flutter build ios --release

# 使用Xcode进行最终打包和发布
open ios/Runner.xcworkspace

3. 应用商店发布

Google Play Store发布清单

  • 应用图标(512x512px)
  • 应用截图(至少2张)
  • 应用描述和关键词
  • 隐私政策链接
  • 应用分级评定
  • 测试版本验证

App Store发布清单

  • 应用图标(1024x1024px)
  • 应用截图(多种设备尺寸)
  • 应用描述和关键词
  • 应用分类选择
  • 年龄分级设置
  • TestFlight测试

总结

Flutter书法印章制作记录应用是一个功能完整的行业管理工具,涵盖了制作记录管理、材料库存监控、客户关系维护和数据统计分析等核心功能。通过本教程,你学习了:

  1. 完整的数据模型设计:从印章制作记录到客户信息的全面数据结构
  2. 丰富的UI组件实现:卡片式布局、进度显示、状态标识等现代化界面
  3. 智能的筛选和搜索:多维度数据筛选和实时搜索功能
  4. 直观的统计分析:业务数据的可视化展示和分析
  5. 流畅的动画效果:页面切换和进度显示的动画实现
  6. 可扩展的架构设计:支持数据持久化、图片管理、导出等功能扩展

这个应用不仅适用于印章制作行业,其设计模式和实现方法也可以应用到其他手工艺品制作、定制服务等相关领域。通过学习本教程,你掌握了Flutter应用开发的核心技能,能够独立开发类似的行业管理应用。

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

相关推荐
●VON2 小时前
从系统亮度监听到 UI 重绘:Flutter for OpenHarmony TodoList 深色模式的端到端响应式实现
学习·flutter·ui·openharmony·布局·von
恋猫de小郭2 小时前
Android Gradle Plugin 9.0 发布,为什么这会是个史诗级大坑版本
android·flutter·ios·开源
一起养小猫2 小时前
Flutter实战:从零实现俄罗斯方块(三)交互控制与事件处理
javascript·flutter·交互
Whisper_Sy3 小时前
Flutter for OpenHarmony移动数据使用监管助手App实战 - 周报告实现
开发语言·javascript·网络·flutter·php
一起养小猫3 小时前
Flutter for OpenHarmony 实战:按钮类 Widget 完全指南
前端·javascript·flutter
一起养小猫3 小时前
Flutter实战:从零实现俄罗斯方块(二)CustomPaint绘制游戏画面
flutter·游戏
2601_949575864 小时前
Flutter for OpenHarmony二手物品置换App实战 - 本地存储实现
flutter
向前V4 小时前
Flutter for OpenHarmony轻量级开源记事本App实战:笔记编辑器
开发语言·笔记·python·flutter·游戏·开源·编辑器
前端不太难4 小时前
HarmonyOS PC 多窗口,到底在解决什么
华为·状态模式·harmonyos