SHA256
151 lines
4.5 KiB
Dart
151 lines
4.5 KiB
Dart
part of 'studio_app.dart';
|
|
|
|
class StudioPortalMaintainPage extends StatefulWidget {
|
|
const StudioPortalMaintainPage({
|
|
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<StudioPortalMaintainPage> createState() => _StudioPortalMaintainPageState();
|
|
}
|
|
|
|
class _StudioPortalMaintainPageState extends State<StudioPortalMaintainPage> {
|
|
bool _loading = true;
|
|
String _status = '正在加载门户';
|
|
List<Map<String, dynamic>> _rows = <Map<String, dynamic>>[];
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_reload();
|
|
}
|
|
|
|
Future<void> _reload() async {
|
|
setState(() {
|
|
_loading = true;
|
|
_status = '正在加载门户';
|
|
});
|
|
try {
|
|
final rows = await widget.runtime.client.fetchPortalConfigs(
|
|
session: widget.runtime.session,
|
|
);
|
|
if (!mounted) {
|
|
return;
|
|
}
|
|
setState(() {
|
|
_rows = rows;
|
|
_status = '门户已加载';
|
|
});
|
|
widget.onAction('加载门户', widget.tab.title);
|
|
} catch (error, stackTrace) {
|
|
debugPrint('========== 加载门户失败 ==========');
|
|
debugPrint('error: $error');
|
|
debugPrint('stackTrace:\n$stackTrace');
|
|
debugPrint('========== 加载门户失败 end ==========');
|
|
if (!mounted) {
|
|
return;
|
|
}
|
|
setState(() {
|
|
_status = error.toString();
|
|
});
|
|
} finally {
|
|
if (mounted) {
|
|
setState(() {
|
|
_loading = false;
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
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(
|
|
'读取后端 portal 配置列表。',
|
|
style: Theme.of(context).textTheme.bodyMedium
|
|
?.copyWith(color: _mutedColor(context)),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
FilledButton.tonalIcon(
|
|
onPressed: _loading ? null : _reload,
|
|
icon: const Icon(Icons.refresh_rounded),
|
|
label: const Text('刷新'),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 12),
|
|
SelectableText(_status),
|
|
const SizedBox(height: 12),
|
|
if (_loading)
|
|
const Padding(
|
|
padding: EdgeInsets.symmetric(vertical: 24),
|
|
child: Center(child: CircularProgressIndicator()),
|
|
)
|
|
else
|
|
DataTable(
|
|
columns: const [
|
|
DataColumn(label: Text('编码')),
|
|
DataColumn(label: Text('名称')),
|
|
DataColumn(label: Text('描述')),
|
|
],
|
|
rows: _rows
|
|
.map(
|
|
(row) => DataRow(
|
|
cells: [
|
|
DataCell(Text(_value(row, const ['id', 'code']))),
|
|
DataCell(Text(_value(row, const ['label', 'name']))),
|
|
DataCell(
|
|
SelectableText(
|
|
_value(row, const ['remark', 'description', 'portal']),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
)
|
|
.toList(),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|