196 lines
5.6 KiB
Dart
196 lines
5.6 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:provider/provider.dart';
|
||
import 'package:http/http.dart' as http;
|
||
import 'dart:convert';
|
||
import '../services/auth_service.dart';
|
||
|
||
class KodBoxCard extends StatefulWidget {
|
||
const KodBoxCard({super.key});
|
||
|
||
@override
|
||
State<KodBoxCard> createState() => _KodBoxCardState();
|
||
}
|
||
|
||
class _KodBoxCardState extends State<KodBoxCard> {
|
||
List<dynamic> _logs = [];
|
||
bool _isLoading = false;
|
||
String? _error;
|
||
|
||
Future<void> _fetchLogs() async {
|
||
setState(() {
|
||
_isLoading = true;
|
||
_error = null;
|
||
});
|
||
|
||
try {
|
||
final authService = Provider.of<AuthService>(context, listen: false);
|
||
final token = authService.credentials['kodbox'];
|
||
|
||
if (token == null || token.isEmpty) {
|
||
throw Exception('未配置 KodBox Token');
|
||
}
|
||
|
||
// 计算时间范围(最近7天)
|
||
final now = DateTime.now();
|
||
final sevenDaysAgo = now.subtract(const Duration(days: 7));
|
||
final timeTo = (now.millisecondsSinceEpoch / 1000).round();
|
||
final timeFrom = (sevenDaysAgo.millisecondsSinceEpoch / 1000).round();
|
||
|
||
final request = http.MultipartRequest(
|
||
'POST',
|
||
Uri.parse('https://cloud.jdysya.top/?admin/log/get&accessToken=$token'),
|
||
);
|
||
|
||
request.fields.addAll({
|
||
'page': '1',
|
||
'pageNum': '50',
|
||
'sortField': 'createTime',
|
||
'sortType': 'down',
|
||
'timeFrom': timeFrom.toString(),
|
||
'timeTo': timeTo.toString(),
|
||
});
|
||
|
||
final response = await request.send();
|
||
final responseBody = await response.stream.bytesToString();
|
||
|
||
if (response.statusCode == 200) {
|
||
final data = jsonDecode(responseBody);
|
||
if (data['code'] == true) {
|
||
setState(() {
|
||
_logs = data['data'];
|
||
_isLoading = false;
|
||
});
|
||
} else {
|
||
throw Exception('请求失败: ${data['info'] ?? '未知错误'}');
|
||
}
|
||
} else {
|
||
throw Exception('请求失败: ${response.statusCode}');
|
||
}
|
||
} catch (e) {
|
||
setState(() {
|
||
_error = e.toString();
|
||
_isLoading = false;
|
||
});
|
||
}
|
||
}
|
||
|
||
String _formatTimestamp(String timestamp) {
|
||
final date = DateTime.fromMillisecondsSinceEpoch(
|
||
(double.parse(timestamp) * 1000).round(),
|
||
);
|
||
return date.toString().substring(0, 19);
|
||
}
|
||
|
||
Widget _buildLogItem(Map<String, dynamic> log) {
|
||
final desc = log['desc'];
|
||
final isFileOperation =
|
||
desc != null &&
|
||
(desc['sourceInfo'] != null || desc['parentInfo'] != null);
|
||
|
||
return Card(
|
||
margin: const EdgeInsets.symmetric(vertical: 4.0),
|
||
child: Padding(
|
||
padding: const EdgeInsets.all(12.0),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Row(
|
||
children: [
|
||
CircleAvatar(
|
||
radius: 16,
|
||
child: Text(log['nickName']?[0].toUpperCase() ?? '?'),
|
||
),
|
||
const SizedBox(width: 8),
|
||
Text(
|
||
log['nickName'] ?? log['name'] ?? '未知用户',
|
||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||
),
|
||
const SizedBox(width: 8),
|
||
Text(log['title'] ?? '未知操作'),
|
||
],
|
||
),
|
||
if (isFileOperation && desc['sourceInfo'] != null) ...[
|
||
const SizedBox(height: 8),
|
||
Text(
|
||
'文件路径: ${desc['sourceInfo']['pathDisplay']}',
|
||
style: const TextStyle(color: Colors.blue),
|
||
),
|
||
],
|
||
const SizedBox(height: 8),
|
||
Text(
|
||
'时间: ${_formatTimestamp(log['createTime'])}',
|
||
style: const TextStyle(fontSize: 12, color: Colors.grey),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
_fetchLogs();
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Card(
|
||
child: Padding(
|
||
padding: const EdgeInsets.all(16.0),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Row(
|
||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||
children: [
|
||
const Text(
|
||
'KodBox 最近操作',
|
||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||
),
|
||
IconButton(
|
||
icon: const Icon(Icons.refresh),
|
||
onPressed: _isLoading ? null : _fetchLogs,
|
||
),
|
||
],
|
||
),
|
||
if (_isLoading)
|
||
const Center(
|
||
child: Padding(
|
||
padding: EdgeInsets.all(16.0),
|
||
child: CircularProgressIndicator(),
|
||
),
|
||
)
|
||
else if (_error != null)
|
||
Center(
|
||
child: Padding(
|
||
padding: const EdgeInsets.all(16.0),
|
||
child: Text(
|
||
_error!,
|
||
style: const TextStyle(color: Colors.red),
|
||
),
|
||
),
|
||
)
|
||
else if (_logs.isEmpty)
|
||
const Center(
|
||
child: Padding(
|
||
padding: EdgeInsets.all(16.0),
|
||
child: Text('暂无操作记录'),
|
||
),
|
||
)
|
||
else
|
||
Expanded(
|
||
child: ListView.builder(
|
||
itemCount: _logs.length,
|
||
itemBuilder: (context, index) {
|
||
return _buildLogItem(_logs[index]);
|
||
},
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|