SHA256
193 lines
6.1 KiB
Dart
193 lines
6.1 KiB
Dart
part of 'studio_app.dart';
|
|
|
|
class StudioHistoryPage extends StatefulWidget {
|
|
const StudioHistoryPage({
|
|
super.key,
|
|
required this.tab,
|
|
required this.runtime,
|
|
required this.onAction,
|
|
});
|
|
|
|
final StudioTab tab;
|
|
final StudioRuntime runtime;
|
|
final void Function(String title, String detail) onAction;
|
|
|
|
@override
|
|
State<StudioHistoryPage> createState() => _StudioHistoryPageState();
|
|
}
|
|
|
|
class _StudioHistoryPageState extends State<StudioHistoryPage> {
|
|
bool _loading = true;
|
|
String? _errorMessage;
|
|
List<Map<String, dynamic>> _rows = <Map<String, dynamic>>[];
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_reload();
|
|
}
|
|
|
|
Future<void> _reload() async {
|
|
setState(() {
|
|
_loading = true;
|
|
_errorMessage = null;
|
|
});
|
|
try {
|
|
final rows = await widget.runtime.client.fetchUpgradeLogs(
|
|
session: widget.runtime.session,
|
|
);
|
|
if (!mounted) {
|
|
return;
|
|
}
|
|
setState(() {
|
|
_rows = rows;
|
|
});
|
|
} catch (error, stackTrace) {
|
|
_printError('加载历史失败', error, stackTrace);
|
|
if (!mounted) {
|
|
return;
|
|
}
|
|
setState(() {
|
|
_errorMessage = _normalizeError(error);
|
|
});
|
|
} finally {
|
|
if (mounted) {
|
|
setState(() {
|
|
_loading = false;
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
void _printError(String title, Object error, StackTrace stackTrace) {
|
|
debugPrint('========== $title ==========');
|
|
debugPrint('error: $error');
|
|
debugPrint('stackTrace:\n$stackTrace');
|
|
debugPrint('========== $title end ==========');
|
|
}
|
|
|
|
String _normalizeError(Object error) {
|
|
final text = error.toString();
|
|
const marker = 'Bad state: ';
|
|
if (text.startsWith(marker)) {
|
|
return text.substring(marker.length);
|
|
}
|
|
return text;
|
|
}
|
|
|
|
String _value(Map<String, dynamic> row, List<String> keys, [String fallback = '']) {
|
|
for (final key in keys) {
|
|
final value = row[key];
|
|
if (value != null && value.toString().trim().isNotEmpty) {
|
|
return value.toString();
|
|
}
|
|
}
|
|
return fallback;
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return SingleChildScrollView(
|
|
child: Card(
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(18),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
widget.tab.title,
|
|
style: Theme.of(context).textTheme.headlineSmall
|
|
?.copyWith(fontWeight: FontWeight.w700),
|
|
),
|
|
const SizedBox(height: 6),
|
|
Text(
|
|
'从后端读取发布与修改历史。',
|
|
style: Theme.of(context).textTheme.bodyMedium
|
|
?.copyWith(color: _mutedColor(context)),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
FilledButton.tonalIcon(
|
|
onPressed: _loading ? null : _reload,
|
|
icon: _loading
|
|
? const SizedBox(
|
|
width: 16,
|
|
height: 16,
|
|
child: CircularProgressIndicator(strokeWidth: 2),
|
|
)
|
|
: const Icon(Icons.refresh_rounded),
|
|
label: const Text('刷新'),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 12),
|
|
if (_errorMessage != null) ...[
|
|
SelectableText(
|
|
_errorMessage!,
|
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
|
color: Theme.of(context).colorScheme.error,
|
|
),
|
|
),
|
|
const SizedBox(height: 12),
|
|
],
|
|
if (_loading)
|
|
const Padding(
|
|
padding: EdgeInsets.symmetric(vertical: 28),
|
|
child: Center(child: CircularProgressIndicator()),
|
|
)
|
|
else
|
|
SizedBox(
|
|
width: double.infinity,
|
|
child: DataTable(
|
|
columns: const [
|
|
DataColumn(label: Text('版本')),
|
|
DataColumn(label: Text('操作者')),
|
|
DataColumn(label: Text('时间')),
|
|
DataColumn(label: Text('状态')),
|
|
DataColumn(label: Text('说明')),
|
|
],
|
|
rows: _rows
|
|
.map(
|
|
(row) => DataRow(
|
|
cells: [
|
|
DataCell(Text(_value(row, const ['version', 'tag', 'name'], ''))),
|
|
DataCell(Text(_value(row, const ['user', 'operator', 'creator'], ''))),
|
|
DataCell(Text(_value(row, const ['time', 'createTime', 'date'], ''))),
|
|
DataCell(Text(_value(row, const ['status', 'state'], ''))),
|
|
DataCell(
|
|
SelectableText(
|
|
_value(
|
|
row,
|
|
const ['note', 'msg', 'message', 'summary', 'desc'],
|
|
row.toString(),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
)
|
|
.toList(),
|
|
),
|
|
),
|
|
const SizedBox(height: 8),
|
|
Text(
|
|
'共 ${_rows.length} 条历史记录',
|
|
style: Theme.of(context).textTheme.bodySmall
|
|
?.copyWith(color: _mutedColor(context, 0.62)),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|