diff --git a/making_school_asignment_app/lib/common/utils/gesture_recognition/shape_recognizer.dart b/making_school_asignment_app/lib/common/utils/gesture_recognition/shape_recognizer.dart index 77d2d84..c4dc179 100644 --- a/making_school_asignment_app/lib/common/utils/gesture_recognition/shape_recognizer.dart +++ b/making_school_asignment_app/lib/common/utils/gesture_recognition/shape_recognizer.dart @@ -180,7 +180,7 @@ class ShapeRecognizer { // return GestureType.none; } - /// 辅助函数:根据您的方案,判断一个组合是否构成半勾。 + /// 辅助函数:判断一个组合是否构成半勾。 /// [checkCandidate] 可能是勾的笔画 /// [crosserCandidate] 可能是交叉线的笔画 /// [checkDetails] 勾的细节信息 @@ -217,7 +217,7 @@ class ShapeRecognizer { return false; // 交叉点或角度不满足条件,此组合失败。 } - /// [新增] 专为“半勾”设计的交叉检测函数,以实现的判断方案。 + /// 专为“半勾”设计的交叉检测函数,以实现的判断方案。 /// 它允许交叉点靠近 `checkLeg` 的终点,但对 `crossLine` 保持严格的内部交叉要求。 Offset? _findIntersectionNearTip( Offset crossLineStart, Offset crossLineEnd, Offset checkLegStart, Offset checkLegEnd) { diff --git a/making_school_asignment_app/lib/main.dart b/making_school_asignment_app/lib/main.dart index 285cf43..12dc883 100644 --- a/making_school_asignment_app/lib/main.dart +++ b/making_school_asignment_app/lib/main.dart @@ -41,7 +41,7 @@ void main() async { statusBarColor: Colors.transparent, //状态栏背景颜色 statusBarIconBrightness: Brightness.light // dark:一般显示黑色 light:一般显示白色 )); - SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.top]); // 屏幕刘海 + SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky, overlays: [SystemUiOverlay.top]); // 屏幕刘海 await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); // 屏幕强制竖屏 runApp(const MyApp()); diff --git a/making_school_asignment_app/lib/main_offest.dart b/making_school_asignment_app/lib/main_offest.dart index 9c10524..e489925 100644 --- a/making_school_asignment_app/lib/main_offest.dart +++ b/making_school_asignment_app/lib/main_offest.dart @@ -40,7 +40,7 @@ class _GestureCanvasPageState extends State { GestureType _recognizedGesture = GestureType.none; late ShapeRecognizer _recognizer; - // [新增] 用于控制是否显示可视化特征点的状态 + // 用于控制是否显示可视化特征点的状态 bool _showSimplifiedPoints = true; @override @@ -123,7 +123,7 @@ class _GestureCanvasPageState extends State { appBar: AppBar( title: const Text('手势识别 (可视化调试)'), actions: [ - // [新增] 在AppBar中添加一个信息提示 + // 在AppBar中添加一个信息提示 Padding( padding: const EdgeInsets.only(right: 16.0), child: Icon( @@ -179,7 +179,7 @@ class _GestureCanvasPageState extends State { child: const Icon(Icons.clear), ), const SizedBox(height: 10), - // [新增] 用于切换可视化模式的按钮 + // 用于切换可视化模式的按钮 FloatingActionButton( onPressed: () { setState(() { @@ -205,7 +205,7 @@ class _GestureCanvasPainter extends CustomPainter { final List> allStrokes; final double rdpEpsilon; final bool showSimplifiedPoints; - final Paint _debugPaint; // [新增] 专门用于绘制特征点的画笔 + final Paint _debugPaint; // 专门用于绘制特征点的画笔 _GestureCanvasPainter({ required this.cachedImage, @@ -218,7 +218,7 @@ class _GestureCanvasPainter extends CustomPainter { ..strokeCap = StrokeCap.round ..strokeWidth = 5.0 ..style = PaintingStyle.stroke, - // [新增] 初始化调试画笔 + // 初始化调试画笔 _debugPaint = Paint() ..color = Colors.red ..strokeCap = StrokeCap.round @@ -241,7 +241,7 @@ class _GestureCanvasPainter extends CustomPainter { canvas.drawPath(path, _paint); } - // [新增] 步骤3: 如果开启了可视化,则绘制简化后的特征点 + // 步骤3: 如果开启了可视化,则绘制简化后的特征点 if (showSimplifiedPoints) { // 为所有已完成的笔画绘制特征点 for (final stroke in allStrokes) { diff --git a/making_school_asignment_app/lib/page/home_page/children/homework_review/components/bottom_operation_bar.dart b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/bottom_operation_bar.dart index 0780a0d..44aa0a6 100644 --- a/making_school_asignment_app/lib/page/home_page/children/homework_review/components/bottom_operation_bar.dart +++ b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/bottom_operation_bar.dart @@ -7,7 +7,6 @@ import 'package:making_school_asignment_app/common/job/marking_models/do_paper_b import 'package:making_school_asignment_app/common/mixins/event_bus_mixin.dart'; import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart'; import 'package:making_school_asignment_app/common/utils/utils.dart'; -import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; import '../configuration_files/index.dart'; @@ -62,19 +61,23 @@ class _BottomAnnotationSwitchJobState extends State @override Widget build(BuildContext context) { - double iconSize = 18.sp; - Color actionColor = Colors.white; - Color defaultColor = const Color.fromRGBO(132, 146, 163, 1); - return SafeArea( left: false, right: false, top: false, child: Container( width: double.infinity, - height: _animationController.value * 64.h, - color: const Color.fromRGBO(83, 83, 83, 1), - // padding: EdgeInsets.symmetric(vertical: 1.h), + height: _animationController.value * 70.h, + decoration: BoxDecoration( + color: const Color.fromRGBO(83, 83, 83, 1), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + blurRadius: 8, + offset: const Offset(0, -2), + ), + ], + ), child: Row( children: [ Expanded( @@ -87,109 +90,83 @@ class _BottomAnnotationSwitchJobState extends State children: [ // 全对按钮 Expanded( - child: SizedBox( - width: double.infinity, - height: double.infinity, - child: TextButton( - child: quickText('全 对', color: Colors.white, size: 12.sp), - onPressed: () => easyThrottle('homework_bottom_operation_bar_scoring_related', - () => _homeworkLogic.allPairs(context)), - ), + child: _buildActionButton( + '全对', + Icons.check_circle_outline, + () => easyThrottle('homework_bottom_operation_bar_scoring_related', + () => _homeworkLogic.allPairs(context)), + isEnabled: !_homeworkLogic.state.submitLoading.value, + isPrimary: true, ), ), - Container(width: 0.3.w, height: double.infinity, color: Colors.white), + Container(width: 0.5.w, height: double.infinity, color: Colors.white.withOpacity(0.3)), // 注解笔 Expanded( - child: SizedBox( - width: double.infinity, - height: double.infinity, - child: IconButton( - icon: Obx(() { - return Icon( - const IconData(0xe635, fontFamily: "AlibabaIcon"), - size: iconSize, - color: _logicControl.pen.value ? Theme.of(context).primaryColor : defaultColor, - ); - }), - onPressed: () => easyThrottle('homework_bottom_action_bar_annotations', () { - _logicControl.gestureMove.value = false; - _logicControl.pen.value = !_logicControl.pen.value; - }), - ), - ), + child: Obx(() => _buildIconButton( + const IconData(0xe635, fontFamily: "AlibabaIcon"), + () => easyThrottle('homework_bottom_action_bar_annotations', () { + // 互斥:启用注解笔,禁用滑动 + _logicControl.gestureMove.value = false; + _logicControl.pen.value = true; + }), + isActive: _logicControl.pen.value, + tooltip: '注解笔', + )), ), - Container(width: 0.3.w, height: double.infinity, color: Colors.white), + Container(width: 0.5.w, height: double.infinity, color: Colors.white.withOpacity(0.3)), // 滑动试题 Expanded( - child: SizedBox( - width: double.infinity, - height: double.infinity, - child: IconButton( - icon: Obx( - () { - return Icon( - const IconData(0xe636, fontFamily: "AlibabaIcon"), - size: iconSize, - color: _logicControl.gestureMove.value ? actionColor : defaultColor, - ); - }, - ), - onPressed: () => easyThrottle('homework_bottom_action_bar_annotations', () { - _logicControl.pen.value = false; - _logicControl.gestureMove.value = !_logicControl.gestureMove.value; - }), - ), - ), + child: Obx(() => _buildIconButton( + const IconData(0xe636, fontFamily: "AlibabaIcon"), + () => easyThrottle('homework_bottom_action_bar_annotations', () { + // 互斥:启用滑动,禁用注解笔 + _logicControl.pen.value = false; + _logicControl.gestureMove.value = true; + }), + isActive: _logicControl.gestureMove.value, + tooltip: '滑动试题', + )), ), ], ), ), - Container(width: double.infinity, color: Colors.white, height: 0.35.h), + Container(width: double.infinity, color: Colors.white.withOpacity(0.3), height: 0.5.h), Expanded( child: Row( children: [ // 全错按钮 Expanded( - child: SizedBox( - width: double.infinity, - height: double.infinity, - child: TextButton( - onPressed: () => easyThrottle('homework_bottom_operation_bar_scoring_related', - () => _homeworkLogic.allWrongRating(context)), - child: quickText('全 错', color: Colors.white, size: 12.sp), - ), + child: _buildActionButton( + '全错', + Icons.cancel_outlined, + () => easyThrottle('homework_bottom_operation_bar_scoring_related', + () => _homeworkLogic.allWrongRating(context)), + isEnabled: !_homeworkLogic.state.submitLoading.value, + isPrimary: false, ), ), - Container(width: 0.3.w, height: double.infinity, color: Colors.white), + Container(width: 0.5.w, height: double.infinity, color: Colors.white.withOpacity(0.3)), // 撤销上一步 Expanded( - child: SizedBox( - width: double.infinity, - height: double.infinity, - child: IconButton( - onPressed: () => easyThrottle( - 'homework_bottom_action_bar_annotations', - () => eventFire(model: BottomOperationBar(revokeAll: false, revokePreStep: true)), - ), - icon: Icon(const IconData(0xe638, fontFamily: "AlibabaIcon"), - size: iconSize, color: defaultColor), + child: _buildIconButton( + const IconData(0xe638, fontFamily: "AlibabaIcon"), + () => easyThrottle( + 'homework_bottom_action_bar_annotations', + () => eventFire(model: BottomOperationBar(revokeAll: false, revokePreStep: true)), ), + tooltip: '撤销上一步', ), ), - Container(width: 0.3.w, height: double.infinity, color: Colors.white), + Container(width: 0.5.w, height: double.infinity, color: Colors.white.withOpacity(0.3)), // 全部撤销 Expanded( - child: SizedBox( - width: double.infinity, - height: double.infinity, - child: IconButton( - icon: Icon(const IconData(0xe637, fontFamily: "AlibabaIcon"), - size: iconSize, color: defaultColor), - onPressed: () => easyThrottle( - 'homework_bottom_action_bar_annotations', - () => eventFire(model: BottomOperationBar(revokeAll: true, revokePreStep: false)), - ), + child: _buildIconButton( + const IconData(0xe637, fontFamily: "AlibabaIcon"), + () => easyThrottle( + 'homework_bottom_action_bar_annotations', + () => eventFire(model: BottomOperationBar(revokeAll: true, revokePreStep: false)), ), + tooltip: '全部撤销', ), ), ], @@ -198,49 +175,36 @@ class _BottomAnnotationSwitchJobState extends State ], ), ), - Container(width: 0.3.w, height: double.infinity, color: Colors.white), + Container(width: 0.5.w, height: double.infinity, color: Colors.white.withOpacity(0.3)), Expanded( flex: 3, child: Row( children: [ Expanded( - child: SizedBox( - width: double.infinity, - height: double.infinity, - child: TextButton( - onPressed: () => easyThrottle( - 'homework_bottom_operation_bar_scoring_related', () => _homeworkLogic.cancelAllRatings()), - child: quickText('取 消', size: 14.sp, color: Colors.white), - ), + child: _buildActionButton( + '取消', + Icons.clear, + () => easyThrottle( + 'homework_bottom_operation_bar_scoring_related', () => _homeworkLogic.cancelAllRatings()), + isEnabled: true, + isPrimary: false, + isSecondary: true, ), ), - Container(width: 0.3.w, height: double.infinity, color: Colors.white), + Container(width: 0.5.w, height: double.infinity, color: Colors.white.withOpacity(0.3)), Expanded( - child: SizedBox( - width: double.infinity, - height: double.infinity, - child: TextButton( - onPressed: () => easyThrottle( + child: Obx(() { + final submitLoading = _homeworkLogic.state.submitLoading.value; + return _buildActionButton( + '提交', + Icons.send, + () => easyThrottle( 'homework_bottom_operation_bar_scoring_related', () => _homeworkLogic.submit(context)), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Obx(() { - if (_homeworkLogic.state.submitLoading.value) { - return Padding( - padding: EdgeInsets.only(right: 4.w), - child: const SizedBox( - width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2)), - ); - } - return const SizedBox(); - }), - quickText('提 交', size: 14.sp, color: Theme.of(context).primaryColor), - ], - ), - ), - ), + isEnabled: !submitLoading, + isPrimary: true, + isLoading: submitLoading, + ); + }), ), ], ), @@ -249,4 +213,124 @@ class _BottomAnnotationSwitchJobState extends State ), )); } + + Widget _buildActionButton( + String text, + IconData icon, + VoidCallback? onPressed, { + required bool isEnabled, + required bool isPrimary, + bool isSecondary = false, + bool isLoading = false, + }) { + final primaryColor = Theme.of(context).primaryColor; + const defaultColor = Color.fromRGBO(132, 146, 163, 1); + + return Material( + color: Colors.transparent, + child: InkWell( + onTap: isEnabled ? onPressed : null, + child: Semantics( + label: text, + hint: isLoading ? '正在处理中' : (isEnabled ? '点击执行$text操作' : '$text按钮已禁用'), + button: true, + enabled: isEnabled && !isLoading, + child: Container( + width: double.infinity, + height: double.infinity, + decoration: BoxDecoration( + color: isPrimary + ? (isEnabled ? primaryColor : primaryColor.withOpacity(0.5)) + : isSecondary + ? Colors.transparent + : Colors.transparent, + borderRadius: BorderRadius.circular(4.r), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (isLoading) + SizedBox( + width: 16.w, + height: 16.w, + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: AlwaysStoppedAnimation( + isPrimary ? Colors.white : primaryColor, + ), + ), + ) + else + Icon( + icon, + size: 16.sp, + color: isEnabled + ? (isPrimary ? Colors.white : (isSecondary ? Colors.white70 : defaultColor)) + : Colors.white38, + ), + SizedBox(height: 2.h), + Text( + text, + style: TextStyle( + fontSize: 10.sp, + color: isEnabled + ? (isPrimary ? Colors.white : (isSecondary ? Colors.white70 : Colors.white)) + : Colors.white38, + fontWeight: FontWeight.w500, + ), + ), + ], + ), + ), + ), + ), + ); + } + + Widget _buildIconButton( + IconData icon, + VoidCallback? onPressed, { + bool isActive = false, + String? tooltip, + }) { + final primaryColor = Theme.of(context).primaryColor; + const defaultColor = Color.fromRGBO(132, 146, 163, 1); + + return Material( + color: Colors.transparent, + child: InkWell( + onTap: onPressed, + child: Tooltip( + message: tooltip ?? '', + child: Container( + width: double.infinity, + height: double.infinity, + decoration: BoxDecoration( + color: isActive ? primaryColor.withOpacity(0.2) : Colors.transparent, + borderRadius: BorderRadius.circular(4.r), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + icon, + size: 18.sp, + color: isActive ? primaryColor : defaultColor, + ), + SizedBox(height: 2.h), + Container( + width: 4.w, + height: 4.w, + decoration: BoxDecoration( + color: isActive ? primaryColor : Colors.transparent, + shape: BoxShape.circle, + ), + ), + ], + ), + ), + ), + ), + ); + } } diff --git a/making_school_asignment_app/lib/page/home_page/children/homework_review/components/dropdown_switch_students_type.dart b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/dropdown_switch_students_type.dart index 191a0ed..d243eba 100644 --- a/making_school_asignment_app/lib/page/home_page/children/homework_review/components/dropdown_switch_students_type.dart +++ b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/dropdown_switch_students_type.dart @@ -6,7 +6,6 @@ import 'package:get/get.dart'; import 'package:making_school_asignment_app/common/job/marking_models/do_paper_details_param.dart'; import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart'; import 'package:making_school_asignment_app/common/utils/toast_utils.dart'; -import 'package:making_school_asignment_app/common/utils/utils.dart'; import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; import 'package:making_school_asignment_app/page/home_page/children/homework_review/configuration_files/index.dart'; import 'package:making_school_asignment_app/routes/app_pages.dart'; @@ -61,7 +60,8 @@ class DropdownSwitchStudentsType extends StatelessWidget { items: sateData.value?.templateIdKeys?.map((e) { return DropdownMenuItem( value: e, - child: quickText('${sateData.value!.templateIdKeyMap![e]}页', color: const Color.fromRGBO(79, 79, 79, 1), size: 14.sp), + child: quickText('${sateData.value!.templateIdKeyMap![e]}页', + color: const Color.fromRGBO(79, 79, 79, 1), size: 14.sp), ); }).toList(), onChanged: (value) { @@ -77,7 +77,9 @@ class DropdownSwitchStudentsType extends StatelessWidget { final students = sateData.value?.students ?? []; // 获取当前学生姓名 - final currentStudent = currentStudentId != null ? students.firstWhereOrNull((e) => e.id == currentStudentId) : null; + final currentStudent = currentStudentId != null + ? students.firstWhereOrNull((e) => e.id == currentStudentId) + : null; final studentName = currentStudent?.name ?? '当前学生'; final questionNumber = templateIdKeyMap?[value] ?? '当前选择页'; @@ -95,7 +97,7 @@ class DropdownSwitchStudentsType extends StatelessWidget { }), ), ), - const Expanded(flex: 1, child: SizedBox()), + SizedBox(width: 8.w), Expanded( flex: 3, child: Stack( @@ -120,7 +122,9 @@ class DropdownSwitchStudentsType extends StatelessWidget { alignment: const FractionalOffset(0, 0.62), children: [ Container( - padding: sateData.value?.studentId != e.id && e.isPriority ? EdgeInsets.only(left: 14.w) : null, + padding: sateData.value?.studentId != e.id && e.isPriority + ? EdgeInsets.only(left: 14.w) + : null, child: quickText( e.name, size: 14.sp, @@ -134,7 +138,9 @@ class DropdownSwitchStudentsType extends StatelessWidget { Icon( const IconData(0xe63d, fontFamily: "AlibabaIcon"), size: 12.sp, - color: e.isPriority ? Theme.of(context).primaryColor : const Color.fromRGBO(164, 164, 164, 1), + color: e.isPriority + ? Theme.of(context).primaryColor + : const Color.fromRGBO(164, 164, 164, 1), ), quickText('优先', size: 4.sp, color: Colors.white), ], @@ -161,7 +167,9 @@ class DropdownSwitchStudentsType extends StatelessWidget { return Icon( const IconData(0xe63d, fontFamily: "AlibabaIcon"), size: 12.sp, - color: sateData.value?.priority ?? false ? Theme.of(context).primaryColor : const Color.fromRGBO(164, 164, 164, 1), + color: sateData.value?.priority ?? false + ? Theme.of(context).primaryColor + : const Color.fromRGBO(164, 164, 164, 1), ); }), quickText('优先', size: 4.sp, color: Colors.white), @@ -173,9 +181,9 @@ class DropdownSwitchStudentsType extends StatelessWidget { ), // const Expanded(flex: 1, child: SizedBox()), SizedBox(width: 8.w), - Expanded( - flex: isPad() ? 4 : 5, - child: const Row( + const Expanded( + flex: 5, + child: Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ @@ -208,7 +216,8 @@ Widget $studentHandwriting(BuildContext context) { if (templateIdKeyMap != null && templateId != null) { pageNum = templateIdKeyMap[templateId]; } - await showAnswerHandwriting(context, homeworkId: homeworkId, studentId: studentId, templateId: templateId, pageNum: pageNum); + await showAnswerHandwriting(context, + homeworkId: homeworkId, studentId: studentId, templateId: templateId, pageNum: pageNum); ToastUtils.dismiss(); }, ), @@ -238,7 +247,10 @@ Widget $continueToReview(BuildContext context, {bool isFloatingAction = false}) int? annotatedCount = data?.annotatedCount; // 批阅数量 // || (submitCount == annotatedCount || (param.templateId == null && param.studentId == null)) // if (data == null || (data.needAnnotate ? true : data.totalUnAnnotateCount <= 0) ) return const SizedBox(); - if (data == null || (data.needAnnotate ? (data.continuePage == null ? true : data.continuePage!.templateId == data.templateId) : data.totalUnAnnotateCount <= 0)) return const SizedBox(); + if (data == null || + (data.needAnnotate + ? (data.continuePage == null ? true : data.continuePage!.templateId == data.templateId) + : data.totalUnAnnotateCount <= 0)) return const SizedBox(); callFun() => easyThrottle( 'DO_PAPERS_JOB_CONTINUE_TO_REVIEW', () { @@ -292,7 +304,11 @@ Widget $historyHomework(BuildContext context) { var currentStudent = sateData.value!.students.firstWhereOrNull((e) => e.id == studentId); if (currentStudent == null) return; var theState = Get.find().state; - Get.toNamed(Routes.studentWorkDetailPage, arguments: {'studentId': studentId, 'studentName': currentStudent.name, 'subject': theState.param.value.subject}); + Get.toNamed(Routes.studentWorkDetailPage, arguments: { + 'studentId': studentId, + 'studentName': currentStudent.name, + 'subject': theState.param.value.subject + }); }), child: Row( crossAxisAlignment: CrossAxisAlignment.center, diff --git a/making_school_asignment_app/lib/page/home_page/children/homework_review/components/question_paper_view.dart b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/question_paper_view.dart index 805fb9f..12b4b4c 100644 --- a/making_school_asignment_app/lib/page/home_page/children/homework_review/components/question_paper_view.dart +++ b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/question_paper_view.dart @@ -547,20 +547,18 @@ class QuestionImageView extends HookWidget with EventBusMixin logic.zoomLogic.onScaleUpdate(zoom), - onPositionUpdate: logic.zoomLogic.onPanUpPosition, - transformationController: logic.zoomController, - child: Stack( - children: [ - $TheCachedNetworkImage( - imgWidth: maxWidth, - imageUrl: sateData.data.value!.zgtAnswer, - (_, imageProvider) => Image(image: imageProvider, fit: BoxFit.fitWidth), + Obx( + () => Zoom( + key: zoomKey.value, + // initTotalZoomOut: true, // 展示全部内容 初始化不产生滚动条 + zoomSensibility: 0.05, + scrollWeight: 4.r, + doubleTapAnimDuration: Duration.zero, + maxZoomWidth: maxWidth, + maxZoomHeight: actualHeight, + canvasColor: Colors.transparent, + doubleTapScaleChange: 1, + // initPosition: initPosition.value, + // initScale: logic.zoomLogic.zoomState.initScale.value ?? 1, + backgroundColor: Colors.transparent, + onScaleUpdate: (double scale, double zoom) => logic.zoomLogic.onScaleUpdate(zoom), + onPositionUpdate: logic.zoomLogic.onPanUpPosition, + transformationController: logic.zoomController, + child: Stack( + children: [ + $TheCachedNetworkImage( + imgWidth: maxWidth, + imageUrl: sateData.data.value!.zgtAnswer, + (_, imageProvider) => Image(image: imageProvider, fit: BoxFit.fitWidth), + ), + RepaintBoundary( + key: logic.pictureOverviewKey, + child: CustomPaint( + // isComplex: true, + size: Size(maxWidth, actualHeight), + foregroundPainter: DrawingPainter(ctrl: vnHandWritings), + // child: $TheCachedNetworkImage( + // imgWidth: maxWidth, + // imageUrl: showZgtAnnotate ?? sateData.data.value!.zgtAnswer, + // (_, imageProvider) => Image(image: imageProvider, fit: BoxFit.fitWidth), + // ), + child: showZgtAnnotate != null + ? $TheCachedNetworkImage( + imgWidth: maxWidth, + imageUrl: showZgtAnnotate, + (_, imageProvider) => Image(image: imageProvider, fit: BoxFit.fitWidth)) + : null, + ), + ), + ], ), - RepaintBoundary( - key: logic.pictureOverviewKey, - child: CustomPaint( - // isComplex: true, - size: Size(maxWidth, zoomState.zoomFile.value!.actualHeight!), - foregroundPainter: DrawingPainter(ctrl: vnHandWritings), - // child: $TheCachedNetworkImage( - // imgWidth: maxWidth, - // imageUrl: showZgtAnnotate ?? sateData.data.value!.zgtAnswer, - // (_, imageProvider) => Image(image: imageProvider, fit: BoxFit.fitWidth), - // ), - child: showZgtAnnotate != null - ? $TheCachedNetworkImage( - imgWidth: maxWidth, - imageUrl: showZgtAnnotate, - (_, imageProvider) => Image(image: imageProvider, fit: BoxFit.fitWidth)) - : null, - ), - ), - ], - ), - ), - ), + ), + )), ); }), ); diff --git a/making_school_asignment_app/lib/page/home_page/children/homework_review/configuration_files/index.dart b/making_school_asignment_app/lib/page/home_page/children/homework_review/configuration_files/index.dart index 717ec6b..ad7882a 100644 --- a/making_school_asignment_app/lib/page/home_page/children/homework_review/configuration_files/index.dart +++ b/making_school_asignment_app/lib/page/home_page/children/homework_review/configuration_files/index.dart @@ -6,6 +6,7 @@ import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:making_school_asignment_app/common/job/annotate_list_to_refresh.dart'; import 'package:making_school_asignment_app/common/job/marking_models/do_paper_details_param.dart'; @@ -18,7 +19,6 @@ import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dar import 'package:making_school_asignment_app/common/utils/permission_describe_util.dart'; import 'package:making_school_asignment_app/common/utils/toast_utils.dart'; import 'package:making_school_asignment_app/common/utils/upload_oss_img_utils.dart'; -import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:zoom_widget/zoom_widget.dart' as zoomWidget; @@ -88,7 +88,6 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus @override void onInit() { appBarHeight = MediaQuery.of(Get.context!).padding.top; - print("appBarHeight :$appBarHeight"); // WidgetsFlutterBinding.ensureInitialized(); // SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); // 屏幕刘海 @@ -158,17 +157,13 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus } void getData() async { + // 防止重复请求 + if (state.submitLoading.value) return; + var timerControl = Timer(const Duration(milliseconds: 300), () => ToastUtils.showLoading()); try { DoPaperDetailsResult data = await getClient().getDoPaperDetails(state.param.value); - // var studentQuestions = data.studentQuestions; - // // 第0个的下标数据不需要处理 - // for (var i = 0; i < studentQuestions.length; i++) { - // var item = studentQuestions[i]; - - // item.topHeight = itemPre.height; - // } state.getDataError.value = false; state.handwritings = []; @@ -179,8 +174,8 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus state.data.value = data; } catch (e) { print('获取数据报错了:$e'); - // ToastUtils.showError('未获取到试题数据,请重试'); state.getDataError.value = true; + ToastUtils.showError('获取试题数据失败,请检查网络连接后重试'); } finally { if (timerControl.isActive) timerControl.cancel(); ToastUtils.dismiss(); @@ -278,18 +273,24 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus ToastUtils.showInfo("正在提交批阅数据,请勿重复操作"); return; } + state.submitLoading.value = true; var data = state.data.value; - if (data == null) return; - - if ((state.data.value?.studentQuestions.isEmpty ?? true) || (state.studentQuestions.value?.isEmpty ?? true)) { + if (data == null) { + ToastUtils.showError('数据异常,请重新加载'); return; } + + if ((state.data.value?.studentQuestions.isEmpty ?? true) || (state.studentQuestions.value?.isEmpty ?? true)) { + ToastUtils.showError('没有可批阅的试题'); + return; + } + var studentQuestions = state.studentQuestions.value!.where((e) => e.useTime != null && e.useTime! > 0).toList(); // 跳过学生未作答的题 var noRatingElement = studentQuestions.firstWhereOrNull((e) => e.studentScore == null); if (noRatingElement != null) { - ToastUtils.showInfo('${noRatingElement.questionNo}题请评分'); + ToastUtils.showInfo('第${noRatingElement.questionNo}题请评分'); return; } @@ -320,35 +321,13 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus if (totalUnAnnotateCount <= 0) { // 批阅完成 if (!state.lastQuestionPrompt) { - await showDialog( - context: Get.context ?? context, - builder: (BuildContext context1) { - return AlertDialog( - title: quickText('批阅已完成'), - content: const Text('暂无更多批阅项'), - actions: [ - TextButton( - child: const Text('继续'), - onPressed: () { - state.lastQuestionPrompt = true; - Navigator.of(context1).pop(); - }, - ), - TextButton( - child: const Text('退出批阅'), - onPressed: () { - Navigator.of(context1).pop(); - Get.back(); - }), - ], - ); - }, - ); + await _showCompletionDialog(context); } else { - ToastUtils.showSuccess("已经提交", duration: const Duration(milliseconds: 800)); + ToastUtils.showSuccess("批阅已提交", duration: const Duration(milliseconds: 800)); } return; } + var newParams = DoPaperDetailsParam.fromJson(state.param.value.toJson()); if (totalUnAnnotateCount > 0) { // 当前批阅任务完成 重复提交后 停留在当前数据位置 @@ -356,14 +335,52 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus newParams.studentId = null; } state.param.value = newParams; + ToastUtils.showSuccess("批阅已提交"); }); - } catch (_) { - print("批阅提交报错 $_"); + } catch (e) { + print("批阅提交报错 $e"); + ToastUtils.showError('提交失败,请检查网络连接后重试'); } finally { state.submitLoading.value = false; } } + Future _showCompletionDialog(BuildContext context) async { + await showDialog( + context: Get.context ?? context, + barrierDismissible: false, + builder: (BuildContext context1) { + return AlertDialog( + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.r)), + title: Row( + children: [ + Icon(Icons.check_circle, color: Colors.green, size: 24.sp), + SizedBox(width: 8.w), + Text('批阅已完成', style: TextStyle(fontSize: 18.sp, fontWeight: FontWeight.w600)), + ], + ), + content: Text('暂无更多批阅项,是否继续?', style: TextStyle(fontSize: 14.sp)), + actions: [ + TextButton( + child: Text('退出批阅', style: TextStyle(color: Colors.grey[600])), + onPressed: () { + Navigator.of(context1).pop(); + Get.back(); + }, + ), + TextButton( + child: Text('继续', style: TextStyle(color: Theme.of(context).primaryColor)), + onPressed: () { + state.lastQuestionPrompt = true; + Navigator.of(context1).pop(); + }, + ), + ], + ); + }, + ); + } + Future toFavorite() async { try { var data = state.data.value!; diff --git a/making_school_asignment_app/lib/page/home_page/children/homework_review/index.dart b/making_school_asignment_app/lib/page/home_page/children/homework_review/index.dart index c157c46..42eb117 100644 --- a/making_school_asignment_app/lib/page/home_page/children/homework_review/index.dart +++ b/making_school_asignment_app/lib/page/home_page/children/homework_review/index.dart @@ -3,7 +3,6 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:making_school_asignment_app/common/job/annotate_list_to_refresh.dart'; import 'package:making_school_asignment_app/page/global_widget/ReturnToHomepage.dart'; -import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; import 'package:making_school_asignment_app/page/home_page/children/annotate_class/annotate_class_logic.dart'; import 'package:making_school_asignment_app/page/home_page/children/homework_review/components/bottom_operation_bar.dart'; import 'package:making_school_asignment_app/page/home_page/children/homework_review/components/question_paper_view.dart'; @@ -55,8 +54,16 @@ class HomeworkReview extends StatelessWidget { children: [ SizedBox(width: 5.w), IconButton( - icon: const Icon(Icons.arrow_back_ios, color: Colors.black), onPressed: () => Get.back()), - Expanded(child: quickText(sateData.param.value.homeworkName, size: 18.sp).paddingOnly(top: 2.h)), + icon: const Icon(Icons.arrow_back_ios, color: Colors.black), + onPressed: () => Get.back(), + tooltip: '返回'), + Expanded( + child: Text( + sateData.param.value.homeworkName, + style: TextStyle(fontSize: 18.sp, fontWeight: FontWeight.w600), + overflow: TextOverflow.ellipsis, + ), + ), const FavoriteWidget(), SizedBox(width: 10.w), const ReturnToHomepage(), diff --git a/making_school_asignment_app/lib/page/home_page/home_logic.dart b/making_school_asignment_app/lib/page/home_page/home_logic.dart index 46853f6..198c7a3 100644 --- a/making_school_asignment_app/lib/page/home_page/home_logic.dart +++ b/making_school_asignment_app/lib/page/home_page/home_logic.dart @@ -3,7 +3,6 @@ import 'package:get/get.dart'; import 'package:making_school_asignment_app/common/job/work_student.dart'; import 'package:making_school_asignment_app/common/job/work_student_params.dart'; import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; -import 'package:making_school_asignment_app/common/store/user_store.dart'; import 'home_state.dart'; @@ -24,16 +23,20 @@ class HomeLogic extends GetxController with RequestToolMixin, GetTickerProviderS } void getList() async { - params.pageNumber = state.pageNumber; - WorkStudent data = await getClient().getUnAnnotateList(params); - state.totalCount.value = data.totalCount; - state.readOver.value = data.items.length; - /* if(params.pageNumber == 1){ - state.workList.value = data.items; - }else{ - state.workList.addAll(data.items); + try { + params.pageNumber = state.pageNumber; + WorkStudent data = await getClient().getUnAnnotateList(params); + state.totalCount.value = data.totalCount; + state.readOver.value = data.items.length; + + // 完成刷新 + refreshController.finishRefresh(); + } catch (e) { + print('获取作业列表失败: $e'); + // 完成刷新并显示错误 + refreshController.finishRefresh(); + // 可以在这里添加错误提示 } - refreshController.finishRefresh();*/ } @override diff --git a/making_school_asignment_app/lib/page/home_page/home_view.dart b/making_school_asignment_app/lib/page/home_page/home_view.dart index d55076e..c811c22 100644 --- a/making_school_asignment_app/lib/page/home_page/home_view.dart +++ b/making_school_asignment_app/lib/page/home_page/home_view.dart @@ -40,93 +40,104 @@ class HomePage extends GetxKeepAliveWidget { enableControlFinishLoad: true, controller: controller.refreshController, header: MaterialHeader(), - // footer: TaurusFooter(), onRefresh: () async { state.pageNumber = 1; return controller.getList(); }, - // onLoad: () async { - // if (state.workList.length < state.totalCount.value) { - // state.pageNumber++; - // return logic.getList(); - // } - // }, - child: Stack( - children: [ - Image.asset( - 'assets/images/home_banner.png', - width: Get.width, - fit: BoxFit.fill, - ), - Container( - margin: EdgeInsets.only(top: 300.h), - padding: EdgeInsets.symmetric(vertical: 0, horizontal: 20.r), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only(topLeft: Radius.circular(30.r), topRight: Radius.circular(30.r))), - child: Column( - children: [ - SizedBox(height: 15.r), - Text( - '我的作业管理', - style: TextStyle(fontSize: 20.sp, color: const Color(0xFF676666), fontWeight: FontWeight.w600), - ), - SizedBox(height: 15.r), - Row( - children: [ - Expanded( - child: Obx(() { - return $MenuItem( - bgImg: 'assets/images/home_bg_01.png', - name: '作业批阅', - value: state.totalCount.value.toString(), - url: Routes.readOverPage, - ); - }), - ), - SizedBox(width: 20.r), - const Expanded( - child: $MenuItem( - bgImg: 'assets/images/home_bg_02.png', - name: '知识点掌握', - url: Routes.studentHistoryWorkPage, - page: 'points'), - ), - ], - ), - SizedBox(height: 20.r), - Row( - children: [ - const Expanded( - child: $MenuItem( - bgImg: 'assets/images/home_bg_03.png', - name: '学生历史作业', - url: Routes.studentHistoryWorkPage, - page: 'history'), - ), - SizedBox(width: 20.r), - const Expanded( - child: $MenuItem( - bgImg: 'assets/images/home_bg_04.png', name: '答题轨迹', url: Routes.answerTrajectoryPage), - ), - ], - ), - SizedBox(height: 20.r), - Row( - children: [ - const $MenuItem( - bgImg: 'assets/images/home_bg_05.png', - name: '优先批阅设定', - url: Routes.studentHistoryWorkPage, - page: 'set', - ), - SizedBox(width: 20.r), - ], - ), - SizedBox(height: 15.h), - ], + child: CustomScrollView( + slivers: [ + // 顶部横幅区域 + SliverAppBar( + expandedHeight: 300.h, + floating: false, + pinned: false, + backgroundColor: Colors.transparent, + flexibleSpace: FlexibleSpaceBar( + background: Image.asset( + 'assets/images/home_banner.png', + width: Get.width, + fit: BoxFit.cover, + ), ), - ) + ), + // 主要内容区域 + SliverToBoxAdapter( + child: Container( + padding: EdgeInsets.symmetric(vertical: 0, horizontal: 20.r), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only(topLeft: Radius.circular(30.r), topRight: Radius.circular(30.r)), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 20.r), + // 标题区域 + Row( + children: [ + Icon( + Icons.assignment_outlined, + size: 24.sp, + color: const Color(0xFF4F4F4F), + ), + SizedBox(width: 8.r), + Text( + '我的作业管理', + style: TextStyle( + fontSize: 22.sp, color: const Color(0xFF2C2C2C), fontWeight: FontWeight.w700), + ), + const Spacer(), + // 刷新按钮 + Obx(() => IconButton( + onPressed: state.totalCount.value > 0 ? () => controller.getList() : null, + icon: Icon( + Icons.refresh, + size: 20.sp, + color: const Color(0xFF4F4F4F), + ), + tooltip: '刷新数据', + )), + ], + ), + SizedBox(height: 20.r), + // 统计信息卡片 + Container( + padding: EdgeInsets.all(16.r), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + borderRadius: BorderRadius.circular(12.r), + border: Border.all(color: const Color(0xFFE9ECEF), width: 1), + ), + child: Row( + children: [ + Expanded( + child: _buildStatCard( + '待批阅', + state.totalCount.value.toString(), + const Color(0xFFFF6969), + Icons.assignment_turned_in, + ), + ), + SizedBox(width: 16.r), + Expanded( + child: _buildStatCard( + '已批阅', + '0', // 这里可以添加已批阅数量 + const Color(0xFF28A745), + Icons.check_circle_outline, + ), + ), + ], + ), + ), + SizedBox(height: 24.r), + // 功能菜单网格 + _buildMenuGrid(context, state), + SizedBox(height: 20.r), + ], + ), + ), + ), ], ), ); @@ -134,64 +145,230 @@ class HomePage extends GetxKeepAliveWidget { ), ); } + + Widget _buildStatCard(String title, String value, Color color, IconData icon) { + return Container( + padding: EdgeInsets.all(12.r), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8.r), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], + ), + child: Column( + children: [ + Icon(icon, color: color, size: 20.sp), + SizedBox(height: 4.r), + Text( + value, + style: TextStyle( + fontSize: 18.sp, + fontWeight: FontWeight.bold, + color: color, + ), + ), + Text( + title, + style: TextStyle( + fontSize: 12.sp, + color: const Color(0xFF6C757D), + ), + ), + ], + ), + ); + } + + Widget _buildMenuGrid(BuildContext context, dynamic state) { + return Column( + children: [ + // 第一行 + Row( + children: [ + Expanded( + child: Obx(() => $menuItem( + bgImg: 'assets/images/home_bg_01.png', + name: '作业批阅', + value: state.totalCount.value > 0 ? state.totalCount.value.toString() : null, + url: Routes.readOverPage, + isPrimary: true, + )), + ), + SizedBox(width: 16.r), + Expanded( + child: $menuItem( + bgImg: 'assets/images/home_bg_02.png', + name: '知识点掌握', + url: Routes.studentHistoryWorkPage, + page: 'points', + ), + ), + ], + ), + SizedBox(height: 16.r), + // 第二行 + Row( + children: [ + Expanded( + child: $menuItem( + bgImg: 'assets/images/home_bg_03.png', + name: '学生历史作业', + url: Routes.studentHistoryWorkPage, + page: 'history', + ), + ), + SizedBox(width: 16.r), + Expanded( + child: $menuItem(bgImg: 'assets/images/home_bg_04.png', name: '答题轨迹', url: Routes.answerTrajectoryPage), + ), + ], + ), + SizedBox(height: 16.r), + // 第三行 + Row( + children: [ + Expanded( + child: $menuItem( + bgImg: 'assets/images/home_bg_05.png', + name: '优先批阅设定', + url: Routes.studentHistoryWorkPage, + page: 'set', + ), + ), + SizedBox(width: 16.r), + // 占位空间 + const Expanded(child: SizedBox()), + ], + ), + ], + ); + } } @swidget -Widget $menuItem({required String bgImg, required String name, String? value, required String url, String? page}) { - return InkWell( - onTap: () { - Get.toNamed(url, arguments: {'page': page ?? ''}); - }, - child: Container( - width: (Get.width - 60.r) / 2, - height: (Get.width - 60.r) / 2 * 86 / 164, - padding: EdgeInsets.symmetric(vertical: 15.r, horizontal: 15.r), - decoration: BoxDecoration( - image: DecorationImage( - image: AssetImage(bgImg), - fit: BoxFit.contain, +Widget $menuItem({ + required String bgImg, + required String name, + String? value, + required String url, + String? page, + bool isPrimary = false, +}) { + return Material( + color: Colors.transparent, + child: InkWell( + onTap: () { + Get.toNamed(url, arguments: {'page': page ?? ''}); + }, + borderRadius: BorderRadius.circular(12.r), + child: Semantics( + label: '$name${value != null ? ',待处理数量:$value' : ''}', + hint: '点击进入$name页面', + button: true, + child: Container( + width: (Get.width - 60.r) / 2, + height: (Get.width - 60.r) / 2 * 86 / 164, + padding: EdgeInsets.all(16.r), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12.r), + gradient: isPrimary + ? const LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + Color(0xFF667eea), + Color(0xFF764ba2), + ], + ) + : null, + color: isPrimary ? null : Colors.white, + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.08), + blurRadius: 8, + offset: const Offset(0, 2), + ), + ], + image: !isPrimary + ? DecorationImage( + image: AssetImage(bgImg), + fit: BoxFit.cover, + colorFilter: ColorFilter.mode( + Colors.white.withOpacity(0.9), + BlendMode.srcATop, + ), + ) + : null, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Text( + name, + style: TextStyle( + fontSize: 14.sp, + color: isPrimary ? Colors.white : const Color(0xFF2C2C2C), + fontWeight: FontWeight.w600, + ), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + ), + if (value != null && value != '') + Semantics( + label: '待处理数量:$value', + child: Container( + width: 20.r, + height: 20.r, + alignment: Alignment.center, + decoration: BoxDecoration( + color: isPrimary ? Colors.white : const Color(0xFFFF6969), + borderRadius: BorderRadius.all(Radius.circular(10.r)), + ), + child: Text( + value, + style: TextStyle( + fontSize: 10.sp, + color: isPrimary ? const Color(0xFFFF6969) : Colors.white, + fontWeight: FontWeight.w600), + ), + ), + ) + ], + ), + const Spacer(), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + if (isPrimary) + Icon( + Icons.arrow_forward_ios, + size: 14.sp, + color: Colors.white, + ) + else + Image.asset( + 'assets/images/home_right_icon.png', + width: 16.r, + height: 16.r, + semanticLabel: '进入图标', + ), + ], + ), + ], + ), ), ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text( - name, - style: TextStyle(fontSize: 14.sp, color: const Color(0xFF4F4F4F), fontWeight: FontWeight.w600), - ), - if (value != null && value != '') - Container( - width: 18.r, - height: 18.r, - alignment: Alignment.center, - decoration: BoxDecoration( - color: const Color(0xFFFF6969), - borderRadius: BorderRadius.all(Radius.circular(9.r)), - ), - child: Text( - value, - style: TextStyle(fontSize: 10.sp, color: Colors.white, fontWeight: FontWeight.w600), - ), - ) - ], - ), - const Spacer(), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Image.asset( - 'assets/images/home_right_icon.png', - width: 16.r, - height: 16.r, - ), - ], - ), - ], - ), ), ); } diff --git a/making_school_asignment_app/pubspec.yaml b/making_school_asignment_app/pubspec.yaml index 997f768..8d65203 100644 --- a/making_school_asignment_app/pubspec.yaml +++ b/making_school_asignment_app/pubspec.yaml @@ -68,8 +68,9 @@ dependencies: # zoom_widget: ^2.0.1 zoom_widget: git: - url: https://github.com/semakers/zoom-widget.git - ref: a35c9da6afe405c23b5897b449683d424016e9f1 + url: https://gitea.23544.com/wangyang/zoom_widget.git + # url: https://github.com/semakers/zoom-widget.git + # ref: a35c9da6afe405c23b5897b449683d424016e9f1 # start retrofit请求封装 retrofit: ^4.1.0 json_annotation: 4.9.0