import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../../../constants/app_constants.dart'; import '../../../services/get/theme_controller.dart'; class ManuscriptRecord { final String name; final String catename; final String url; final String keywords; final String introduce; final String platform; final DateTime submitTime; ManuscriptRecord({ required this.name, required this.catename, required this.url, required this.keywords, required this.introduce, required this.platform, required this.submitTime, }); Map toJson() { return { 'name': name, 'catename': catename, 'url': url, 'keywords': keywords, 'introduce': introduce, 'platform': platform, 'submitTime': submitTime.toIso8601String(), }; } factory ManuscriptRecord.fromJson(Map json) { return ManuscriptRecord( name: json['name'] ?? '', catename: json['catename'] ?? '', url: json['url'] ?? '', keywords: json['keywords'] ?? '', introduce: json['introduce'] ?? '', platform: json['platform'] ?? '', submitTime: DateTime.parse( json['submitTime'] ?? DateTime.now().toIso8601String(), ), ); } } class TougaoPage extends StatefulWidget { const TougaoPage({super.key}); @override State createState() => _TougaoPageState(); } class _TougaoPageState extends State { final ThemeController _themeController = Get.find(); List _records = []; bool _isLoading = true; @override void initState() { super.initState(); _loadRecords(); } Future _loadRecords() async { try { final prefs = await SharedPreferences.getInstance(); final recordsJson = prefs.getStringList('manuscript_records') ?? []; setState(() { _records = recordsJson .map((json) => ManuscriptRecord.fromJson(jsonDecode(json))) .toList() ..sort((a, b) => b.submitTime.compareTo(a.submitTime)); _isLoading = false; }); } catch (e) { setState(() => _isLoading = false); } } Future _clearAllRecords() async { final confirm = await showDialog( context: context, builder: (context) => AlertDialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), title: const Row( children: [ Icon(Icons.warning_amber_rounded, color: AppConstants.errorColor), SizedBox(width: 8), Text('确认清空'), ], ), content: const Text('确定要清空所有投稿记录吗?此操作不可恢复。'), actions: [ TextButton( onPressed: () => Navigator.pop(context, false), child: const Text('取消'), ), ElevatedButton( onPressed: () => Navigator.pop(context, true), style: ElevatedButton.styleFrom( backgroundColor: AppConstants.errorColor, foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: const Text('确认清空'), ), ], ), ); if (confirm == true) { final prefs = await SharedPreferences.getInstance(); await prefs.remove('manuscript_records'); await _loadRecords(); if (mounted) { ScaffoldMessenger.of( context, ).showSnackBar(const SnackBar(content: Text('已清空所有记录'))); } } } String _formatDate(DateTime date) { return '${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')} ' '${date.hour.toString().padLeft(2, '0')}:${date.minute.toString().padLeft(2, '0')}'; } @override Widget build(BuildContext context) { return Obx(() { final isDark = _themeController.isDarkMode; return Scaffold( backgroundColor: isDark ? const Color(0xFF1A1A1A) : Colors.white, appBar: AppBar( title: Text( '投稿记录', style: TextStyle(color: _themeController.currentThemeColor), ), backgroundColor: isDark ? const Color(0xFF2A2A2A) : Colors.white, elevation: 0, actions: [ if (_records.isNotEmpty) IconButton( icon: Icon( Icons.delete_sweep_outlined, color: _themeController.currentThemeColor, ), onPressed: _clearAllRecords, tooltip: '清空记录', ), ], ), body: _isLoading ? const Center(child: CircularProgressIndicator()) : _records.isEmpty ? _buildEmptyState(isDark) : _buildRecordsList(isDark), ); }); } Widget _buildEmptyState(bool isDark) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.history_outlined, size: 80, color: isDark ? Colors.grey[600] : Colors.grey[300], ), const SizedBox(height: 16), Text( '暂无投稿记录', style: TextStyle( fontSize: 16, color: isDark ? Colors.grey[400] : Colors.grey[600], ), ), ], ), ); } Widget _buildRecordsList(bool isDark) { return ListView.builder( padding: const EdgeInsets.all(16), itemCount: _records.length, itemBuilder: (context, index) { final record = _records[index]; return _buildRecordCard(record, isDark); }, ); } Widget _buildRecordCard(ManuscriptRecord record, bool isDark) { return Card( elevation: 0, color: isDark ? const Color(0xFF2A2A2A) : Colors.grey[50], shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), child: ExpansionTile( iconColor: isDark ? Colors.white : Colors.black87, collapsedIconColor: isDark ? Colors.white : Colors.black87, title: Row( children: [ Expanded( child: Text( record.name, style: TextStyle( fontWeight: FontWeight.bold, fontSize: 15, color: isDark ? Colors.white : Colors.black87, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), ), const SizedBox(width: 8), Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: _themeController.currentThemeColor.withValues( alpha: 0.2, ), borderRadius: BorderRadius.circular(8), ), child: Text( record.catename, style: TextStyle( fontSize: 12, color: _themeController.currentThemeColor, fontWeight: FontWeight.w500, ), ), ), ], ), subtitle: Padding( padding: const EdgeInsets.only(top: 4), child: Row( children: [ Icon( Icons.access_time, size: 14, color: isDark ? Colors.grey[400] : Colors.grey[500], ), const SizedBox(width: 4), Text( _formatDate(record.submitTime), style: TextStyle( fontSize: 12, color: isDark ? Colors.grey[400] : Colors.grey[500], ), ), ], ), ), childrenPadding: const EdgeInsets.fromLTRB(16, 0, 16, 16), children: [ _buildDetailItem('诗人和标题', record.url, isDark), _buildDetailItem('关键词', record.keywords, isDark), _buildDetailItem('平台', record.platform, isDark), _buildDetailItem('诗词介绍', record.introduce, isDark, maxLines: 3), ], ), ); } Widget _buildDetailItem( String label, String value, bool isDark, { int maxLines = 1, }) { return Padding( padding: const EdgeInsets.only(bottom: 12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label, style: TextStyle( fontSize: 13, color: isDark ? Colors.grey[400] : Colors.grey[600], fontWeight: FontWeight.w500, ), ), const SizedBox(height: 4), Text( value, style: TextStyle( fontSize: 14, color: isDark ? Colors.white : Colors.black87, ), maxLines: maxLines, overflow: TextOverflow.ellipsis, ), ], ), ); } }