fix: harden school imports and add optional feedback diagnostics
This commit is contained in:
@@ -192,6 +192,14 @@ class HttpFeedbackSender implements FeedbackSender {
|
||||
bytes.add(attachment.bytes);
|
||||
write('\r\n');
|
||||
}
|
||||
if (submission.diagnosticLog != null) {
|
||||
write(
|
||||
'--$boundary\r\nContent-Disposition: form-data; name="diagnostics"; filename="TPSchedule-diagnostics.txt"\r\n'
|
||||
'Content-Type: text/plain; charset=utf-8\r\n\r\n',
|
||||
);
|
||||
bytes.add(submission.diagnosticLog!);
|
||||
write('\r\n');
|
||||
}
|
||||
write('--$boundary--\r\n');
|
||||
return bytes.takeBytes();
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../app/app_theme.dart';
|
||||
import '../../services/diagnostic_log.dart';
|
||||
import 'feedback_submission.dart';
|
||||
|
||||
typedef FeedbackAttachmentPicker = Future<FeedbackAttachment?> Function();
|
||||
@@ -32,6 +33,7 @@ class _FeedbackPageState extends State<FeedbackPage> {
|
||||
var _picking = false;
|
||||
var _success = false;
|
||||
var _uncertain = false;
|
||||
var _includeLogs = false;
|
||||
String? _error;
|
||||
FeedbackSubmission? _pendingSubmission;
|
||||
|
||||
@@ -103,6 +105,7 @@ class _FeedbackPageState extends State<FeedbackPage> {
|
||||
if (_submitting || _picking) return;
|
||||
if (!_uncertain && !(_form.currentState?.validate() ?? false)) return;
|
||||
FocusScope.of(context).unfocus();
|
||||
setState(() => _submitting = true);
|
||||
try {
|
||||
_pendingSubmission ??= _kind == FeedbackKind.problem
|
||||
? FeedbackSubmission.problem(
|
||||
@@ -111,6 +114,9 @@ class _FeedbackPageState extends State<FeedbackPage> {
|
||||
contact: _contact.text,
|
||||
attachments: _attachments,
|
||||
limits: widget.limits,
|
||||
diagnosticLog: _includeLogs
|
||||
? await DiagnosticLog.instance.export()
|
||||
: null,
|
||||
)
|
||||
: FeedbackSubmission.development(
|
||||
id: FeedbackSubmission.newId(),
|
||||
@@ -256,6 +262,24 @@ class _FeedbackPageState extends State<FeedbackPage> {
|
||||
: null,
|
||||
),
|
||||
if (_kind == FeedbackKind.problem) ...[
|
||||
CheckboxListTile(
|
||||
key: const Key('feedback-logs'),
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: const Text('附带近10分钟诊断日志'),
|
||||
subtitle: const Text(
|
||||
'包含登录跳转、课表读取及错误状态,帮助排查问题;不包含密码、验证码或课表内容。',
|
||||
),
|
||||
value: _includeLogs,
|
||||
onChanged: _submitting
|
||||
? null
|
||||
: (value) {
|
||||
setState(() {
|
||||
_includeLogs = value ?? false;
|
||||
_pendingSubmission = null;
|
||||
_error = null;
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
const Text(
|
||||
'图片或视频(选填)',
|
||||
|
||||
@@ -102,6 +102,7 @@ class FeedbackSubmission {
|
||||
this.contact,
|
||||
this.school,
|
||||
this.attachments = const [],
|
||||
this.diagnosticLog,
|
||||
});
|
||||
|
||||
factory FeedbackSubmission.problem({
|
||||
@@ -110,18 +111,26 @@ class FeedbackSubmission {
|
||||
String? contact,
|
||||
List<FeedbackAttachment> attachments = const [],
|
||||
FeedbackLimits limits = FeedbackLimits.defaults,
|
||||
Uint8List? diagnosticLog,
|
||||
}) {
|
||||
final text = message.trim();
|
||||
if (text.isEmpty) throw const FeedbackException('请填写问题或建议');
|
||||
if (text.length > 5000) throw const FeedbackException('问题或建议不能超过 5000 个字符');
|
||||
_validateContact(contact);
|
||||
validateAttachments(attachments, limits);
|
||||
if (diagnosticLog != null &&
|
||||
(diagnosticLog.isEmpty || diagnosticLog.length > 256 * 1024)) {
|
||||
throw const FeedbackException('日志附件不能超过256 KB');
|
||||
}
|
||||
return FeedbackSubmission._(
|
||||
id: id,
|
||||
kind: FeedbackKind.problem,
|
||||
message: text,
|
||||
contact: _optional(contact),
|
||||
attachments: List.unmodifiable(attachments),
|
||||
diagnosticLog: diagnosticLog == null
|
||||
? null
|
||||
: Uint8List.fromList(diagnosticLog).asUnmodifiableView(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -151,6 +160,7 @@ class FeedbackSubmission {
|
||||
final String? contact;
|
||||
final String? school;
|
||||
final List<FeedbackAttachment> attachments;
|
||||
final Uint8List? diagnosticLog;
|
||||
|
||||
static String newId() {
|
||||
final random = Random.secure();
|
||||
|
||||
Reference in New Issue
Block a user