refactor(client): widgets 颜色迁移到 context.tokens

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-06-24 23:12:20 +08:00
parent a6c583b468
commit fb8c5b6926
20 changed files with 151 additions and 137 deletions
@@ -288,7 +288,7 @@ class _StockInListScreenState extends ConsumerState<StockInListScreen> {
? '¥${o.totalAmount!.toStringAsFixed(2)}' ? '¥${o.totalAmount!.toStringAsFixed(2)}'
: '-')); : '-'));
case 'status': case 'status':
final rb = returnStateBadge(o.returnState); final rb = returnStateBadge(context, o.returnState);
return DataCell(Row(mainAxisSize: MainAxisSize.min, children: [ return DataCell(Row(mainAxisSize: MainAxisSize.min, children: [
StatusBadge(_apiStatusToEnum(o.status)), StatusBadge(_apiStatusToEnum(o.status)),
if (rb != null) ...[const SizedBox(width: 4), rb], if (rb != null) ...[const SizedBox(width: 4), rb],
@@ -520,6 +520,7 @@ class _StockInListScreenState extends ConsumerState<StockInListScreen> {
/// 入库特有的「打标签」通过 afterPrint 注入。 /// 入库特有的「打标签」通过 afterPrint 注入。
List<Widget> _orderActions(BuildContext context, StockInOrder o) { List<Widget> _orderActions(BuildContext context, StockInOrder o) {
return buildOrderRowActions( return buildOrderRowActions(
context: context,
readonly: WriteGuard.isReadonly(ref), readonly: WriteGuard.isReadonly(ref),
canWithdraw: ref.watch(isAdminProvider) || canWithdraw: ref.watch(isAdminProvider) ||
(o.operatorId != null && (o.operatorId != null &&
@@ -586,9 +587,9 @@ class _StockInListScreenState extends ConsumerState<StockInListScreen> {
style: const TextStyle(fontFamily: 'monospace', fontSize: 14)), style: const TextStyle(fontFamily: 'monospace', fontSize: 14)),
trailing: Row(mainAxisSize: MainAxisSize.min, children: [ trailing: Row(mainAxisSize: MainAxisSize.min, children: [
StatusBadge(_apiStatusToEnum(o.status)), StatusBadge(_apiStatusToEnum(o.status)),
if (returnStateBadge(o.returnState) != null) ...[ if (returnStateBadge(context, o.returnState) != null) ...[
const SizedBox(width: 4), const SizedBox(width: 4),
returnStateBadge(o.returnState)!, returnStateBadge(context, o.returnState)!,
], ],
]), ]),
fields: [ fields: [
@@ -291,7 +291,7 @@ class _StockOutListScreenState extends ConsumerState<StockOutListScreen> {
? '¥${o.totalAmount!.toStringAsFixed(2)}' ? '¥${o.totalAmount!.toStringAsFixed(2)}'
: '-')); : '-'));
case 'status': case 'status':
final rb = returnStateBadge(o.returnState); final rb = returnStateBadge(context, o.returnState);
return DataCell(Row(mainAxisSize: MainAxisSize.min, children: [ return DataCell(Row(mainAxisSize: MainAxisSize.min, children: [
StatusBadge(_apiStatusToEnum(o.status)), StatusBadge(_apiStatusToEnum(o.status)),
if (rb != null) ...[const SizedBox(width: 4), rb], if (rb != null) ...[const SizedBox(width: 4), rb],
@@ -548,6 +548,7 @@ class _StockOutListScreenState extends ConsumerState<StockOutListScreen> {
/// 操作按钮列表,表格与移动端卡片共用。 /// 操作按钮列表,表格与移动端卡片共用。
List<Widget> _orderActions(BuildContext context, StockOutOrder o) { List<Widget> _orderActions(BuildContext context, StockOutOrder o) {
return buildOrderRowActions( return buildOrderRowActions(
context: context,
readonly: WriteGuard.isReadonly(ref), readonly: WriteGuard.isReadonly(ref),
canWithdraw: ref.watch(isAdminProvider) || canWithdraw: ref.watch(isAdminProvider) ||
(o.operatorId != null && (o.operatorId != null &&
@@ -584,9 +585,9 @@ class _StockOutListScreenState extends ConsumerState<StockOutListScreen> {
style: const TextStyle(fontFamily: 'monospace', fontSize: 14)), style: const TextStyle(fontFamily: 'monospace', fontSize: 14)),
trailing: Row(mainAxisSize: MainAxisSize.min, children: [ trailing: Row(mainAxisSize: MainAxisSize.min, children: [
StatusBadge(_apiStatusToEnum(o.status)), StatusBadge(_apiStatusToEnum(o.status)),
if (returnStateBadge(o.returnState) != null) ...[ if (returnStateBadge(context, o.returnState) != null) ...[
const SizedBox(width: 4), const SizedBox(width: 4),
returnStateBadge(o.returnState)!, returnStateBadge(context, o.returnState)!,
], ],
]), ]),
fields: [ fields: [
+14 -14
View File
@@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../core/responsive/responsive.dart'; import '../core/responsive/responsive.dart';
import '../core/theme/app_theme.dart'; import '../core/theme/context_tokens.dart';
class DataTableCard extends StatefulWidget { class DataTableCard extends StatefulWidget {
final List<DataColumn> columns; final List<DataColumn> columns;
@@ -53,7 +53,7 @@ class _DataTableCardState extends State<DataTableCard> {
children: [ children: [
if (widget.toolbar != null) if (widget.toolbar != null)
Container( Container(
color: AppTheme.surface, color: context.tokens.surface,
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
child: widget.toolbar!, child: widget.toolbar!,
), ),
@@ -67,14 +67,14 @@ class _DataTableCardState extends State<DataTableCard> {
if (widget.totalCount != null) if (widget.totalCount != null)
Container( Container(
height: 48, height: 48,
color: AppTheme.surface, color: context.tokens.surface,
padding: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.symmetric(horizontal: 16),
child: Row( child: Row(
children: [ children: [
Text( Text(
'${widget.totalCount} 条记录', '${widget.totalCount} 条记录',
style: const TextStyle( style: TextStyle(
fontSize: 13, color: AppTheme.textSecondary), fontSize: 13, color: context.tokens.muted),
), ),
const Spacer(), const Spacer(),
_PaginationBar( _PaginationBar(
@@ -132,11 +132,11 @@ class _DataTableCardState extends State<DataTableCard> {
Widget _buildMobileList() { Widget _buildMobileList() {
final cards = widget.mobileCards!; final cards = widget.mobileCards!;
if (cards.isEmpty) { if (cards.isEmpty) {
return const Center( return Center(
child: Padding( child: Padding(
padding: EdgeInsets.all(32), padding: const EdgeInsets.all(32),
child: Text('暂无数据', child: Text('暂无数据',
style: TextStyle(color: AppTheme.textSecondary, fontSize: 14)), style: TextStyle(color: context.tokens.muted, fontSize: 14)),
), ),
); );
} }
@@ -155,10 +155,10 @@ class _DataTableCardState extends State<DataTableCard> {
return Padding( return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
child: DefaultTextStyle( child: DefaultTextStyle(
style: const TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: AppTheme.primaryDark, color: context.tokens.primaryDark,
), ),
child: col.numeric child: col.numeric
? Align(alignment: Alignment.centerRight, child: col.label) ? Align(alignment: Alignment.centerRight, child: col.label)
@@ -189,8 +189,8 @@ class _DataTableCardState extends State<DataTableCard> {
padding: padding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 10), const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
child: DefaultTextStyle( child: DefaultTextStyle(
style: const TextStyle( style: TextStyle(
fontSize: 13, color: AppTheme.textPrimary), fontSize: 13, color: context.tokens.text),
child: cell.child, child: cell.child,
), ),
), ),
@@ -227,13 +227,13 @@ class _PaginationBar extends StatelessWidget {
children: [ children: [
// 每页条数选择器 // 每页条数选择器
if (onPageSizeChanged != null) ...[ if (onPageSizeChanged != null) ...[
const Text('每页', style: TextStyle(fontSize: 13, color: AppTheme.textSecondary)), Text('每页', style: TextStyle(fontSize: 13, color: context.tokens.muted)),
const SizedBox(width: 4), const SizedBox(width: 4),
DropdownButtonHideUnderline( DropdownButtonHideUnderline(
child: DropdownButton<int>( child: DropdownButton<int>(
value: effectiveSize, value: effectiveSize,
isDense: true, isDense: true,
style: const TextStyle(fontSize: 13, color: AppTheme.textPrimary), style: TextStyle(fontSize: 13, color: context.tokens.text),
items: _pageSizeOptions items: _pageSizeOptions
.map((n) => DropdownMenuItem(value: n, child: Text('$n'))) .map((n) => DropdownMenuItem(value: n, child: Text('$n')))
.toList(), .toList(),
+3 -3
View File
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../core/theme/app_theme.dart'; import '../core/theme/context_tokens.dart';
import '../core/utils/date_util.dart'; import '../core/utils/date_util.dart';
/// 可键入日期框 + 日历图标(替代旧的「年/月/日」三下拉)。 /// 可键入日期框 + 日历图标(替代旧的「年/月/日」三下拉)。
@@ -138,8 +138,8 @@ class _DatePickerFieldState extends State<DatePickerField> {
const EdgeInsets.symmetric(horizontal: 8, vertical: 8), const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
errorText: field.errorText, errorText: field.errorText,
suffixIcon: IconButton( suffixIcon: IconButton(
icon: const Icon(Icons.calendar_today, icon: Icon(Icons.calendar_today,
size: 16, color: AppTheme.textSecondary), size: 16, color: context.tokens.muted),
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
constraints: const BoxConstraints(minWidth: 34, minHeight: 34), constraints: const BoxConstraints(minWidth: 34, minHeight: 34),
tooltip: '选择日期', tooltip: '选择日期',
+4 -5
View File
@@ -1,6 +1,5 @@
import '../core/utils/dialog_util.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../core/theme/app_theme.dart'; import '../core/theme/context_tokens.dart';
/// Generic dialog wrapper for forms /// Generic dialog wrapper for forms
class FormDialog extends StatelessWidget { class FormDialog extends StatelessWidget {
@@ -35,9 +34,9 @@ class FormDialog extends StatelessWidget {
Container( Container(
height: 48, height: 48,
padding: const EdgeInsets.symmetric(horizontal: 20), padding: const EdgeInsets.symmetric(horizontal: 20),
decoration: const BoxDecoration( decoration: BoxDecoration(
color: AppTheme.primary, color: context.tokens.primary,
borderRadius: BorderRadius.only( borderRadius: const BorderRadius.only(
topLeft: Radius.circular(4), topLeft: Radius.circular(4),
topRight: Radius.circular(4), topRight: Radius.circular(4),
), ),
+17 -17
View File
@@ -2,7 +2,7 @@ import 'dart:typed_data';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import '../core/errors/error_reporter.dart'; import '../core/errors/error_reporter.dart';
import '../core/theme/app_theme.dart'; import '../core/theme/context_tokens.dart';
import '../core/responsive/responsive.dart'; import '../core/responsive/responsive.dart';
import '../core/utils/print_util.dart'; import '../core/utils/print_util.dart';
import '../core/utils/label_data.dart'; import '../core/utils/label_data.dart';
@@ -164,13 +164,13 @@ class _LabelPreviewDialogState extends State<LabelPreviewDialog> {
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 6), padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 6),
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border.all( border: Border.all(
color: isSelected ? AppTheme.primary : AppTheme.border, color: isSelected ? context.tokens.primary : context.tokens.border,
width: isSelected ? 2 : 1, width: isSelected ? 2 : 1,
), ),
borderRadius: BorderRadius.circular(6), borderRadius: BorderRadius.circular(6),
color: isSelected color: isSelected
? AppTheme.primary.withOpacity(0.04) ? context.tokens.primary.withOpacity(0.04)
: AppTheme.surface, : context.tokens.surface,
), ),
child: Row( child: Row(
children: [ children: [
@@ -204,8 +204,8 @@ class _LabelPreviewDialogState extends State<LabelPreviewDialog> {
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
color: isSelected color: isSelected
? AppTheme.primary ? context.tokens.primary
: AppTheme.textSecondary, : context.tokens.muted,
fontWeight: fontWeight:
isSelected ? FontWeight.w600 : FontWeight.normal, isSelected ? FontWeight.w600 : FontWeight.normal,
), ),
@@ -228,7 +228,7 @@ class _LabelPreviewDialogState extends State<LabelPreviewDialog> {
child: Container( child: Container(
constraints: const BoxConstraints(maxWidth: 420, maxHeight: 230), constraints: const BoxConstraints(maxWidth: 420, maxHeight: 230),
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border.all(color: AppTheme.border), border: Border.all(color: context.tokens.border),
borderRadius: BorderRadius.circular(4), borderRadius: BorderRadius.circular(4),
color: Colors.white, color: Colors.white,
), ),
@@ -297,9 +297,9 @@ class _LabelPreviewDialogState extends State<LabelPreviewDialog> {
Container( Container(
padding: padding:
const EdgeInsets.symmetric(horizontal: 20, vertical: 14), const EdgeInsets.symmetric(horizontal: 20, vertical: 14),
decoration: const BoxDecoration( decoration: BoxDecoration(
color: AppTheme.primary, color: context.tokens.primary,
borderRadius: BorderRadius.only( borderRadius: const BorderRadius.only(
topLeft: Radius.circular(12), topLeft: Radius.circular(12),
topRight: Radius.circular(12), topRight: Radius.circular(12),
), ),
@@ -334,24 +334,24 @@ class _LabelPreviewDialogState extends State<LabelPreviewDialog> {
child: _printers.isEmpty child: _printers.isEmpty
? Text( ? Text(
_printersChecked ? '无打印机可用' : '正在检测打印机...', _printersChecked ? '无打印机可用' : '正在检测打印机...',
style: const TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
color: AppTheme.textSecondary)) color: context.tokens.muted))
: DropdownButtonHideUnderline( : DropdownButtonHideUnderline(
child: Container( child: Container(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 10, vertical: 4), horizontal: 10, vertical: 4),
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border.all(color: AppTheme.border), border: Border.all(color: context.tokens.border),
borderRadius: BorderRadius.circular(6), borderRadius: BorderRadius.circular(6),
), ),
child: DropdownButton<String>( child: DropdownButton<String>(
value: _printer, value: _printer,
isExpanded: true, isExpanded: true,
isDense: true, isDense: true,
style: const TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
color: AppTheme.textPrimary), color: context.tokens.text),
items: _printers items: _printers
.map((p) => DropdownMenuItem( .map((p) => DropdownMenuItem(
value: p, value: p,
@@ -410,8 +410,8 @@ class _LabelPreviewDialogState extends State<LabelPreviewDialog> {
Expanded( Expanded(
child: Text( child: Text(
_status, _status,
style: const TextStyle( style: TextStyle(
fontSize: 12, color: AppTheme.textSecondary), fontSize: 12, color: context.tokens.muted),
), ),
) )
else else
+11 -11
View File
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../core/theme/app_theme.dart'; import '../core/theme/context_tokens.dart';
/// 移动端列表卡片的单个字段(label: value)。 /// 移动端列表卡片的单个字段(label: value)。
class MobileCardField { class MobileCardField {
@@ -56,19 +56,19 @@ class MobileListCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
DefaultTextStyle( DefaultTextStyle(
style: const TextStyle( style: TextStyle(
fontSize: 15, fontSize: 15,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: AppTheme.textPrimary, color: context.tokens.text,
), ),
child: title, child: title,
), ),
if (subtitle != null) ...[ if (subtitle != null) ...[
const SizedBox(height: 2), const SizedBox(height: 2),
DefaultTextStyle( DefaultTextStyle(
style: const TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
color: AppTheme.textSecondary), color: context.tokens.muted),
child: subtitle!, child: subtitle!,
), ),
], ],
@@ -83,7 +83,7 @@ class MobileListCard extends StatelessWidget {
), ),
if (fields.isNotEmpty) ...[ if (fields.isNotEmpty) ...[
const SizedBox(height: 10), const SizedBox(height: 10),
...fields.map(_buildField), ...fields.map((f) => _buildField(context, f)),
], ],
if (actions != null && actions!.isNotEmpty) ...[ if (actions != null && actions!.isNotEmpty) ...[
const Divider(height: 18), const Divider(height: 18),
@@ -102,7 +102,7 @@ class MobileListCard extends StatelessWidget {
); );
} }
Widget _buildField(MobileCardField f) { Widget _buildField(BuildContext context, MobileCardField f) {
return Padding( return Padding(
padding: const EdgeInsets.symmetric(vertical: 3), padding: const EdgeInsets.symmetric(vertical: 3),
child: Row( child: Row(
@@ -112,16 +112,16 @@ class MobileListCard extends StatelessWidget {
width: 64, width: 64,
child: Text( child: Text(
f.label, f.label,
style: const TextStyle( style: TextStyle(
fontSize: 13, color: AppTheme.textSecondary), fontSize: 13, color: context.tokens.muted),
), ),
), ),
Expanded( Expanded(
child: f.valueWidget ?? child: f.valueWidget ??
Text( Text(
f.value ?? '', f.value ?? '',
style: const TextStyle( style: TextStyle(
fontSize: 13, color: AppTheme.textPrimary), fontSize: 13, color: context.tokens.text),
), ),
), ),
], ],
+13 -13
View File
@@ -1,6 +1,6 @@
import '../core/utils/dialog_util.dart'; import '../core/utils/dialog_util.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../core/theme/app_theme.dart'; import '../core/theme/context_tokens.dart';
/// Compact button → dialog with checkboxes for multi-select filtering /// Compact button → dialog with checkboxes for multi-select filtering
class MultiSelectDropdown extends StatelessWidget { class MultiSelectDropdown extends StatelessWidget {
@@ -23,8 +23,8 @@ class MultiSelectDropdown extends StatelessWidget {
return OutlinedButton( return OutlinedButton(
onPressed: options.isEmpty ? null : () => _show(context), onPressed: options.isEmpty ? null : () => _show(context),
style: OutlinedButton.styleFrom( style: OutlinedButton.styleFrom(
foregroundColor: active ? AppTheme.primary : AppTheme.textSecondary, foregroundColor: active ? context.tokens.primary : context.tokens.muted,
side: BorderSide(color: active ? AppTheme.primary : AppTheme.border), side: BorderSide(color: active ? context.tokens.primary : context.tokens.border),
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
minimumSize: Size.zero, minimumSize: Size.zero,
tapTargetSize: MaterialTapTargetSize.shrinkWrap, tapTargetSize: MaterialTapTargetSize.shrinkWrap,
@@ -143,8 +143,8 @@ class _MultiSelectDialogState extends State<_MultiSelectDialog> {
onDeleted: () => setState(() => _selected.remove(s)), onDeleted: () => setState(() => _selected.remove(s)),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
visualDensity: VisualDensity.compact, visualDensity: VisualDensity.compact,
backgroundColor: AppTheme.primary.withOpacity(0.08), backgroundColor: context.tokens.primary.withOpacity(0.08),
side: BorderSide(color: AppTheme.primary.withOpacity(0.3), width: 0.5), side: BorderSide(color: context.tokens.primary.withOpacity(0.3), width: 0.5),
labelPadding: const EdgeInsets.symmetric(horizontal: 2), labelPadding: const EdgeInsets.symmetric(horizontal: 2),
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 0), padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 0),
)).toList(), )).toList(),
@@ -168,12 +168,12 @@ class _MultiSelectDialogState extends State<_MultiSelectDialog> {
ConstrainedBox( ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 280), constraints: const BoxConstraints(maxHeight: 280),
child: filtered.isEmpty child: filtered.isEmpty
? const Padding( ? Padding(
padding: EdgeInsets.symmetric(vertical: 16), padding: const EdgeInsets.symmetric(vertical: 16),
child: Center( child: Center(
child: Text('无匹配项', child: Text('无匹配项',
style: TextStyle( style: TextStyle(
fontSize: 13, color: AppTheme.textSecondary)), fontSize: 13, color: context.tokens.muted)),
), ),
) )
: ListView( : ListView(
@@ -256,7 +256,7 @@ class _FilterableColumnHeaderState extends State<FilterableColumnHeader> {
child: Icon( child: Icon(
active ? Icons.filter_alt : Icons.filter_alt_outlined, active ? Icons.filter_alt : Icons.filter_alt_outlined,
size: 16, size: 16,
color: active ? AppTheme.primary : AppTheme.textSecondary, color: active ? context.tokens.primary : context.tokens.muted,
), ),
), ),
), ),
@@ -264,8 +264,8 @@ class _FilterableColumnHeaderState extends State<FilterableColumnHeader> {
InkWell( InkWell(
onTap: () => widget.onChanged({}), onTap: () => widget.onChanged({}),
borderRadius: BorderRadius.circular(4), borderRadius: BorderRadius.circular(4),
child: const Icon(Icons.cancel, size: 14, child: Icon(Icons.cancel, size: 14,
color: AppTheme.primary), color: context.tokens.primary),
), ),
], ],
), ),
@@ -327,8 +327,8 @@ class ColumnToggleButton extends StatelessWidget {
return OutlinedButton( return OutlinedButton(
onPressed: () => _show(context), onPressed: () => _show(context),
style: OutlinedButton.styleFrom( style: OutlinedButton.styleFrom(
foregroundColor: AppTheme.textSecondary, foregroundColor: context.tokens.muted,
side: const BorderSide(color: AppTheme.border), side: BorderSide(color: context.tokens.border),
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
minimumSize: Size.zero, minimumSize: Size.zero,
tapTargetSize: MaterialTapTargetSize.shrinkWrap, tapTargetSize: MaterialTapTargetSize.shrinkWrap,
+2 -2
View File
@@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../core/theme/app_theme.dart'; import '../core/theme/context_tokens.dart';
import '../providers/connectivity_provider.dart'; import '../providers/connectivity_provider.dart';
/// 离线提示里的「重试」按钮: /// 离线提示里的「重试」按钮:
@@ -27,7 +27,7 @@ class NetworkRetryButton extends ConsumerWidget {
..hideCurrentSnackBar() ..hideCurrentSnackBar()
..showSnackBar(SnackBar( ..showSnackBar(SnackBar(
content: Text(ok ? '已重新连接服务器' : '仍无法连接服务器,请稍后重试'), content: Text(ok ? '已重新连接服务器' : '仍无法连接服务器,请稍后重试'),
backgroundColor: ok ? AppTheme.success : AppTheme.danger, backgroundColor: ok ? context.tokens.success : context.tokens.danger,
duration: const Duration(seconds: 2), duration: const Duration(seconds: 2),
behavior: SnackBarBehavior.floating, behavior: SnackBarBehavior.floating,
)); ));
+30 -30
View File
@@ -1,18 +1,18 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../core/responsive/responsive.dart'; import '../core/responsive/responsive.dart';
import '../core/theme/app_theme.dart'; import '../core/theme/context_tokens.dart';
import '../core/utils/dialog_util.dart'; import '../core/utils/dialog_util.dart';
/// 退单状态小徽章(none 返回 null 不显示)。partial=部分退单(amber)full=已退单(红)。 /// 退单状态小徽章(none 返回 null 不显示)。partial=部分退单(amber)full=已退单(红)。
Widget? returnStateBadge(String state) { Widget? returnStateBadge(BuildContext context, String state) {
Color? c; Color? c;
String? t; String? t;
if (state == 'partial') { if (state == 'partial') {
c = AppTheme.warning; c = context.tokens.warn;
t = '部分退单'; t = '部分退单';
} else if (state == 'full') { } else if (state == 'full') {
c = AppTheme.danger; c = context.tokens.danger;
t = '已退单'; t = '已退单';
} else { } else {
return null; return null;
@@ -109,7 +109,7 @@ class _OrderReturnDialogState extends State<_OrderReturnDialog> {
title: const Text('退单确认', style: TextStyle(fontSize: 16)), title: const Text('退单确认', style: TextStyle(fontSize: 16)),
content: RichText( content: RichText(
text: TextSpan( text: TextSpan(
style: const TextStyle(fontSize: 13, color: AppTheme.textPrimary, height: 1.6), style: TextStyle(fontSize: 13, color: context.tokens.text, height: 1.6),
children: [ children: [
const TextSpan(text: '确认退掉以下明细?\n'), const TextSpan(text: '确认退掉以下明细?\n'),
TextSpan( TextSpan(
@@ -118,7 +118,7 @@ class _OrderReturnDialogState extends State<_OrderReturnDialog> {
TextSpan(text: ' · ${l.series} · ${l.spec}\n'), TextSpan(text: ' · ${l.series} · ${l.spec}\n'),
TextSpan( TextSpan(
text: '编码 ${l.code} · 数量 ${_q(l.quantity)}', text: '编码 ${l.code} · 数量 ${_q(l.quantity)}',
style: const TextStyle(color: AppTheme.textSecondary, fontSize: 12)), style: TextStyle(color: context.tokens.muted, fontSize: 12)),
], ],
), ),
), ),
@@ -129,7 +129,7 @@ class _OrderReturnDialogState extends State<_OrderReturnDialog> {
ElevatedButton( ElevatedButton(
onPressed: () => Navigator.pop(context, true), onPressed: () => Navigator.pop(context, true),
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: AppTheme.danger, foregroundColor: Colors.white), backgroundColor: context.tokens.danger, foregroundColor: Colors.white),
child: const Text('退单'), child: const Text('退单'),
), ),
], ],
@@ -154,7 +154,7 @@ class _OrderReturnDialogState extends State<_OrderReturnDialog> {
ElevatedButton( ElevatedButton(
onPressed: () => Navigator.pop(context, true), onPressed: () => Navigator.pop(context, true),
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: AppTheme.danger, foregroundColor: Colors.white), backgroundColor: context.tokens.danger, foregroundColor: Colors.white),
child: const Text('全部退单'), child: const Text('全部退单'),
), ),
], ],
@@ -181,7 +181,7 @@ class _OrderReturnDialogState extends State<_OrderReturnDialog> {
ElevatedButton( ElevatedButton(
onPressed: () => Navigator.pop(context, true), onPressed: () => Navigator.pop(context, true),
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: AppTheme.danger, foregroundColor: Colors.white), backgroundColor: context.tokens.danger, foregroundColor: Colors.white),
child: const Text('提交退单'), child: const Text('提交退单'),
), ),
], ],
@@ -192,15 +192,15 @@ class _OrderReturnDialogState extends State<_OrderReturnDialog> {
try { try {
await widget.onSubmit(_staged.toList()); await widget.onSubmit(_staged.toList());
if (mounted) { if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar( ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('退单成功'), backgroundColor: AppTheme.success)); content: const Text('退单成功'), backgroundColor: context.tokens.success));
Navigator.pop(context, true); Navigator.pop(context, true);
} }
} catch (e) { } catch (e) {
if (mounted) { if (mounted) {
setState(() => _submitting = false); setState(() => _submitting = false);
ScaffoldMessenger.of(context).showSnackBar(SnackBar( ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('退单失败:$e'), backgroundColor: AppTheme.danger)); content: Text('退单失败:$e'), backgroundColor: context.tokens.danger));
} }
} }
} }
@@ -232,8 +232,8 @@ class _OrderReturnDialogState extends State<_OrderReturnDialog> {
OutlinedButton( OutlinedButton(
onPressed: _submitting ? null : _confirmAll, onPressed: _submitting ? null : _confirmAll,
style: OutlinedButton.styleFrom( style: OutlinedButton.styleFrom(
foregroundColor: AppTheme.danger, foregroundColor: context.tokens.danger,
side: const BorderSide(color: AppTheme.danger), side: BorderSide(color: context.tokens.danger),
visualDensity: VisualDensity.compact, visualDensity: VisualDensity.compact,
), ),
child: const Text('全部退单', style: TextStyle(fontSize: 12)), child: const Text('全部退单', style: TextStyle(fontSize: 12)),
@@ -255,10 +255,10 @@ class _OrderReturnDialogState extends State<_OrderReturnDialog> {
children: [ children: [
for (final (k, v) in widget.meta) for (final (k, v) in widget.meta)
Text.rich(TextSpan( Text.rich(TextSpan(
style: const TextStyle(fontSize: 12, color: AppTheme.textSecondary), style: TextStyle(fontSize: 12, color: context.tokens.muted),
children: [ children: [
TextSpan(text: '$k'), TextSpan(text: '$k'),
TextSpan(text: v, style: const TextStyle(color: AppTheme.textPrimary)), TextSpan(text: v, style: TextStyle(color: context.tokens.text)),
], ],
)), )),
], ],
@@ -271,14 +271,14 @@ class _OrderReturnDialogState extends State<_OrderReturnDialog> {
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
decoration: BoxDecoration( decoration: BoxDecoration(
color: const Color(0xFFF0F6FF), color: const Color(0xFFF0F6FF),
border: const Border(left: BorderSide(color: AppTheme.primary, width: 3)), border: Border(left: BorderSide(color: context.tokens.primary, width: 3)),
borderRadius: BorderRadius.circular(4), borderRadius: BorderRadius.circular(4),
), ),
child: Text( child: Text(
widget.isOut widget.isOut
? '提交后,已退单明细的数量将「加回库存」。退单的明细不会删除,以红色「已退单」标注。' ? '提交后,已退单明细的数量将「加回库存」。退单的明细不会删除,以红色「已退单」标注。'
: '提交后,已退单明细对应的库存将「从库存删除」。退单的明细不会删除,以红色「已退单」标注。', : '提交后,已退单明细对应的库存将「从库存删除」。退单的明细不会删除,以红色「已退单」标注。',
style: const TextStyle(fontSize: 12, color: AppTheme.primaryDark), style: TextStyle(fontSize: 12, color: context.tokens.primaryDark),
), ),
), ),
// 明细列表 // 明细列表
@@ -304,8 +304,8 @@ class _OrderReturnDialogState extends State<_OrderReturnDialog> {
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
color: _staged.isEmpty color: _staged.isEmpty
? AppTheme.textSecondary ? context.tokens.muted
: AppTheme.danger, : context.tokens.danger,
fontWeight: FontWeight.w600), fontWeight: FontWeight.w600),
), ),
), ),
@@ -317,7 +317,7 @@ class _OrderReturnDialogState extends State<_OrderReturnDialog> {
ElevatedButton( ElevatedButton(
onPressed: (_staged.isEmpty || _submitting) ? null : _submit, onPressed: (_staged.isEmpty || _submitting) ? null : _submit,
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: AppTheme.danger, backgroundColor: context.tokens.danger,
foregroundColor: Colors.white), foregroundColor: Colors.white),
child: _submitting child: _submitting
? const SizedBox( ? const SizedBox(
@@ -341,12 +341,12 @@ class _OrderReturnDialogState extends State<_OrderReturnDialog> {
final nameStyle = TextStyle( final nameStyle = TextStyle(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: returned ? AppTheme.danger : AppTheme.textPrimary, color: returned ? context.tokens.danger : context.tokens.text,
decoration: returned ? TextDecoration.lineThrough : null, decoration: returned ? TextDecoration.lineThrough : null,
); );
final subStyle = TextStyle( final subStyle = TextStyle(
fontSize: 11, fontSize: 11,
color: returned ? AppTheme.danger : AppTheme.textSecondary, color: returned ? context.tokens.danger : context.tokens.muted,
decoration: returned ? TextDecoration.lineThrough : null, decoration: returned ? TextDecoration.lineThrough : null,
); );
return Container( return Container(
@@ -357,8 +357,8 @@ class _OrderReturnDialogState extends State<_OrderReturnDialog> {
SizedBox( SizedBox(
width: 24, width: 24,
child: Text('${idx + 1}', child: Text('${idx + 1}',
style: const TextStyle( style: TextStyle(
fontSize: 12, color: AppTheme.textSecondary))), fontSize: 12, color: context.tokens.muted))),
Expanded( Expanded(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@@ -370,7 +370,7 @@ class _OrderReturnDialogState extends State<_OrderReturnDialog> {
Container( Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 1), padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 1),
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppTheme.danger, color: context.tokens.danger,
borderRadius: BorderRadius.circular(8)), borderRadius: BorderRadius.circular(8)),
child: const Text('已退单', child: const Text('已退单',
style: TextStyle(fontSize: 10, color: Colors.white)), style: TextStyle(fontSize: 10, color: Colors.white)),
@@ -396,14 +396,14 @@ class _OrderReturnDialogState extends State<_OrderReturnDialog> {
onPressed: _submitting onPressed: _submitting
? null ? null
: () => setState(() => _staged.remove(l.itemId)), : () => setState(() => _staged.remove(l.itemId)),
child: const Text('撤销', child: Text('撤销',
style: TextStyle(fontSize: 12, color: AppTheme.primary)), style: TextStyle(fontSize: 12, color: context.tokens.primary)),
) )
: OutlinedButton( : OutlinedButton(
onPressed: _submitting ? null : () => _confirmLine(l), onPressed: _submitting ? null : () => _confirmLine(l),
style: OutlinedButton.styleFrom( style: OutlinedButton.styleFrom(
foregroundColor: AppTheme.danger, foregroundColor: context.tokens.danger,
side: const BorderSide(color: AppTheme.danger), side: BorderSide(color: context.tokens.danger),
visualDensity: VisualDensity.compact, visualDensity: VisualDensity.compact,
padding: const EdgeInsets.symmetric(horizontal: 8), padding: const EdgeInsets.symmetric(horizontal: 8),
), ),
+12 -11
View File
@@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../core/theme/app_theme.dart'; import '../core/theme/context_tokens.dart';
import 'write_guard.dart'; import 'write_guard.dart';
/// 入/出库单行内操作按钮,列表表格与移动端卡片、入库与出库两屏共用。 /// 入/出库单行内操作按钮,列表表格与移动端卡片、入库与出库两屏共用。
@@ -12,6 +12,7 @@ import 'write_guard.dart';
/// - [afterPrint]:紧随「打印」之后的附加按钮(入库的「打标签」;出库传空)。 /// - [afterPrint]:紧随「打印」之后的附加按钮(入库的「打标签」;出库传空)。
/// - 各 `on*` 回调由调用方绑定到对应单据的确认/跳转逻辑。 /// - 各 `on*` 回调由调用方绑定到对应单据的确认/跳转逻辑。
List<Widget> buildOrderRowActions({ List<Widget> buildOrderRowActions({
required BuildContext context,
required bool readonly, required bool readonly,
required String status, required String status,
required int orderId, required int orderId,
@@ -56,32 +57,32 @@ List<Widget> buildOrderRowActions({
), ),
); );
return [ return [
btn('详情', AppTheme.primary, onDetail), btn('详情', context.tokens.primary, onDetail),
btn('打印', AppTheme.primary, onPrint), btn('打印', context.tokens.primary, onPrint),
...afterPrint, ...afterPrint,
if (!readonly && status == 'approved') if (!readonly && status == 'approved')
WriteGuard(child: btn('结清', AppTheme.accent, onSettle)), WriteGuard(child: btn('结清', context.tokens.accent, onSettle)),
// 退单(已审核单退货):红色实心按钮突出(与原型一致),按权限显示 // 退单(已审核单退货):红色实心按钮突出(与原型一致),按权限显示
if (!readonly && status == 'approved' && canReturn) if (!readonly && status == 'approved' && canReturn)
WriteGuard( WriteGuard(
child: filledBtn('退单', AppTheme.danger, onReturn, child: filledBtn('退单', context.tokens.danger, onReturn,
key: Key('btn_return_$orderId'))), key: Key('btn_return_$orderId'))),
if (!readonly && status == 'draft') ...[ if (!readonly && status == 'draft') ...[
WriteGuard(child: btn('修改', AppTheme.primary, onEdit)), WriteGuard(child: btn('修改', context.tokens.primary, onEdit)),
WriteGuard(child: btn('删除', AppTheme.danger, onDelete)), WriteGuard(child: btn('删除', context.tokens.danger, onDelete)),
WriteGuard(child: btn('提交', AppTheme.primary, onSubmit)), WriteGuard(child: btn('提交', context.tokens.primary, onSubmit)),
], ],
if (!readonly && status == 'pending') ...[ if (!readonly && status == 'pending') ...[
WriteGuard( WriteGuard(
child: btn('通过', AppTheme.success, onApprove, child: btn('通过', context.tokens.success, onApprove,
key: Key('btn_approve_$orderId'))), key: Key('btn_approve_$orderId'))),
WriteGuard( WriteGuard(
child: btn('拒绝', AppTheme.danger, onReject, child: btn('拒绝', context.tokens.danger, onReject,
key: Key('btn_reject_$orderId'))), key: Key('btn_reject_$orderId'))),
// 撤回(审核中→草稿):管理员/超管任意单、操作员本人单可见,用 warn 样式 // 撤回(审核中→草稿):管理员/超管任意单、操作员本人单可见,用 warn 样式
if (canWithdraw) if (canWithdraw)
WriteGuard( WriteGuard(
child: btn('撤回', AppTheme.warning, onWithdraw, child: btn('撤回', context.tokens.warn, onWithdraw,
key: Key('btn_withdraw_$orderId'))), key: Key('btn_withdraw_$orderId'))),
], ],
]; ];
+5 -5
View File
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../core/theme/app_theme.dart'; import '../core/theme/context_tokens.dart';
class PageScaffold extends StatefulWidget { class PageScaffold extends StatefulWidget {
final String title; final String title;
@@ -54,14 +54,14 @@ class _PageScaffoldState extends State<PageScaffold>
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Container( Container(
color: AppTheme.surface, color: context.tokens.surface,
child: TabBar( child: TabBar(
controller: _controller, controller: _controller,
isScrollable: true, isScrollable: true,
tabAlignment: TabAlignment.start, tabAlignment: TabAlignment.start,
labelColor: AppTheme.primary, labelColor: context.tokens.primary,
unselectedLabelColor: AppTheme.textSecondary, unselectedLabelColor: context.tokens.muted,
indicatorColor: AppTheme.primary, indicatorColor: context.tokens.primary,
indicatorWeight: 2, indicatorWeight: 2,
labelStyle: labelStyle:
const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
+10 -10
View File
@@ -4,7 +4,7 @@ import '../core/utils/dialog_util.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../core/responsive/responsive.dart'; import '../core/responsive/responsive.dart';
import 'package:lpinyin/lpinyin.dart'; import 'package:lpinyin/lpinyin.dart';
import '../core/theme/app_theme.dart'; import '../core/theme/context_tokens.dart';
class OptionItem { class OptionItem {
final int id; final int id;
@@ -100,18 +100,18 @@ class SearchableOptionField extends StatelessWidget {
suffixIcon: selected suffixIcon: selected
? GestureDetector( ? GestureDetector(
onTap: () => onChanged(null), onTap: () => onChanged(null),
child: const Icon(Icons.close, child: Icon(Icons.close,
size: 14, color: AppTheme.textSecondary), size: 14, color: context.tokens.muted),
) )
: const Icon(Icons.arrow_drop_down, : Icon(Icons.arrow_drop_down,
size: 16, color: AppTheme.textSecondary), size: 16, color: context.tokens.muted),
), ),
isEmpty: !selected, isEmpty: !selected,
child: Text( child: Text(
selected ? _displayText : hint, selected ? _displayText : hint,
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
color: selected ? Colors.black87 : AppTheme.textSecondary, color: selected ? Colors.black87 : context.tokens.muted,
), ),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
@@ -269,7 +269,7 @@ class _SearchDialogState extends State<_SearchDialog> {
? Center( ? Center(
child: Text( child: Text(
canCreate ? '无匹配结果,可新增到基础数据' : '无匹配结果', canCreate ? '无匹配结果,可新增到基础数据' : '无匹配结果',
style: const TextStyle(color: AppTheme.textSecondary), style: TextStyle(color: context.tokens.muted),
), ),
) )
: ListView.builder( : ListView.builder(
@@ -287,7 +287,7 @@ class _SearchDialogState extends State<_SearchDialog> {
: null, : null,
selected: isSelected, selected: isSelected,
selectedTileColor: selectedTileColor:
AppTheme.primary.withValues(alpha: 0.08), context.tokens.primary.withValues(alpha: 0.08),
onTap: () => Navigator.of(context).pop(opt.id), onTap: () => Navigator.of(context).pop(opt.id),
); );
}, },
@@ -316,8 +316,8 @@ class _SearchDialogState extends State<_SearchDialog> {
if (widget.selectedId != null) if (widget.selectedId != null)
TextButton( TextButton(
onPressed: () => Navigator.of(context).pop(-1), onPressed: () => Navigator.of(context).pop(-1),
child: const Text('清除选择', child: Text('清除选择',
style: TextStyle(color: AppTheme.textSecondary)), style: TextStyle(color: context.tokens.muted)),
), ),
TextButton( TextButton(
onPressed: () => Navigator.of(context).pop(null), onPressed: () => Navigator.of(context).pop(null),
+5 -5
View File
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../core/theme/app_theme.dart'; import '../core/theme/context_tokens.dart';
enum OrderStatus { draft, pending, approved, rejected } enum OrderStatus { draft, pending, approved, rejected }
@@ -29,19 +29,19 @@ class StatusBadge extends StatelessWidget {
switch (status) { switch (status) {
case OrderStatus.draft: case OrderStatus.draft:
bg = const Color(0xFFF5F5F5); bg = const Color(0xFFF5F5F5);
fg = AppTheme.textSecondary; fg = context.tokens.muted;
break; break;
case OrderStatus.pending: case OrderStatus.pending:
bg = const Color(0xFFFFF3E0); bg = const Color(0xFFFFF3E0);
fg = AppTheme.accent; fg = context.tokens.accent;
break; break;
case OrderStatus.approved: case OrderStatus.approved:
bg = const Color(0xFFE8F5E9); bg = const Color(0xFFE8F5E9);
fg = AppTheme.success; fg = context.tokens.success;
break; break;
case OrderStatus.rejected: case OrderStatus.rejected:
bg = const Color(0xFFFFEBEE); bg = const Color(0xFFFFEBEE);
fg = AppTheme.danger; fg = context.tokens.danger;
break; break;
} }
return Container( return Container(
+5
View File
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:jiu_client/core/theme/themes.dart';
import 'package:jiu_client/core/utils/date_util.dart'; import 'package:jiu_client/core/utils/date_util.dart';
import 'package:jiu_client/widgets/date_picker_field.dart'; import 'package:jiu_client/widgets/date_picker_field.dart';
@@ -33,6 +34,7 @@ void main() {
group('DatePickerField', () { group('DatePickerField', () {
testWidgets('渲染可键入框 + 日历图标', (tester) async { testWidgets('渲染可键入框 + 日历图标', (tester) async {
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
theme: buildTheme('a'),
home: Scaffold( home: Scaffold(
body: DatePickerField(value: '2026-06-19', onChanged: (_) {}), body: DatePickerField(value: '2026-06-19', onChanged: (_) {}),
), ),
@@ -44,6 +46,7 @@ void main() {
testWidgets('初始值回显到输入框', (tester) async { testWidgets('初始值回显到输入框', (tester) async {
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
theme: buildTheme('a'),
home: Scaffold( home: Scaffold(
body: DatePickerField(value: '2026-06-19', onChanged: (_) {}), body: DatePickerField(value: '2026-06-19', onChanged: (_) {}),
), ),
@@ -55,6 +58,7 @@ void main() {
testWidgets('只输年份归一为 yyyy-01-01', (tester) async { testWidgets('只输年份归一为 yyyy-01-01', (tester) async {
String? out; String? out;
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
theme: buildTheme('a'),
home: Scaffold( home: Scaffold(
body: DatePickerField(onChanged: (v) => out = v), body: DatePickerField(onChanged: (v) => out = v),
), ),
@@ -66,6 +70,7 @@ void main() {
testWidgets('年月归一为 yyyy-MM-01', (tester) async { testWidgets('年月归一为 yyyy-MM-01', (tester) async {
String? out; String? out;
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
theme: buildTheme('a'),
home: Scaffold( home: Scaffold(
body: DatePickerField(onChanged: (v) => out = v), body: DatePickerField(onChanged: (v) => out = v),
), ),
+3 -2
View File
@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:jiu_client/core/models/page_result.dart'; import 'package:jiu_client/core/models/page_result.dart';
import 'package:jiu_client/core/theme/themes.dart';
import 'package:jiu_client/models/license.dart'; import 'package:jiu_client/models/license.dart';
import 'package:jiu_client/models/partner.dart'; import 'package:jiu_client/models/partner.dart';
import 'package:jiu_client/providers/license_provider.dart'; import 'package:jiu_client/providers/license_provider.dart';
@@ -103,7 +104,7 @@ Widget _buildApp({
() => _FakePartnerNotifier('customer', customerState), () => _FakePartnerNotifier('customer', customerState),
), ),
], ],
child: const MaterialApp(home: Scaffold(body: PartnersScreen())), child: MaterialApp(theme: buildTheme('a'), home: const Scaffold(body: PartnersScreen())),
); );
} }
@@ -118,7 +119,7 @@ Widget _buildLoadingApp() {
() => _FakeLoadingPartnerNotifier('customer'), () => _FakeLoadingPartnerNotifier('customer'),
), ),
], ],
child: const MaterialApp(home: Scaffold(body: PartnersScreen())), child: MaterialApp(theme: buildTheme('a'), home: const Scaffold(body: PartnersScreen())),
); );
} }
@@ -8,6 +8,7 @@ import 'package:jiu_client/core/api/api_client.dart';
import 'package:jiu_client/core/auth/auth_state.dart'; import 'package:jiu_client/core/auth/auth_state.dart';
import 'package:jiu_client/core/config/license_copy.dart'; import 'package:jiu_client/core/config/license_copy.dart';
import 'package:jiu_client/core/models/page_result.dart'; import 'package:jiu_client/core/models/page_result.dart';
import 'package:jiu_client/core/theme/themes.dart';
import 'package:jiu_client/models/license.dart'; import 'package:jiu_client/models/license.dart';
import 'package:jiu_client/models/partner.dart'; import 'package:jiu_client/models/partner.dart';
import 'package:jiu_client/providers/license_provider.dart'; import 'package:jiu_client/providers/license_provider.dart';
@@ -76,7 +77,7 @@ Widget _buildApp({required bool readonly}) {
), ),
), ),
], ],
child: const MaterialApp(home: Scaffold(body: PartnersScreen())), child: MaterialApp(theme: buildTheme('a'), home: const Scaffold(body: PartnersScreen())),
); );
} }
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:jiu_client/core/theme/themes.dart';
import 'package:jiu_client/widgets/searchable_option_field.dart'; import 'package:jiu_client/widgets/searchable_option_field.dart';
void main() { void main() {
@@ -8,6 +9,7 @@ void main() {
Future<int?> Function(String)? onCreate, Future<int?> Function(String)? onCreate,
}) { }) {
return MaterialApp( return MaterialApp(
theme: buildTheme('a'),
home: Scaffold( home: Scaffold(
body: SearchableOptionField( body: SearchableOptionField(
options: [OptionItem(id: 1, name: '53度')], options: [OptionItem(id: 1, name: '53度')],
+3 -2
View File
@@ -5,6 +5,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:jiu_client/core/models/page_result.dart'; import 'package:jiu_client/core/models/page_result.dart';
import 'package:jiu_client/core/theme/themes.dart';
import 'package:jiu_client/models/license.dart'; import 'package:jiu_client/models/license.dart';
import 'package:jiu_client/models/stock_in.dart'; import 'package:jiu_client/models/stock_in.dart';
import 'package:jiu_client/providers/license_provider.dart'; import 'package:jiu_client/providers/license_provider.dart';
@@ -119,7 +120,7 @@ Widget _buildApp(AsyncValue<PageResult<StockInOrder>> state) {
licenseProvider.overrideWith(() => _FakeLicenseNotifier()), licenseProvider.overrideWith(() => _FakeLicenseNotifier()),
stockInListProvider.overrideWith(() => _FakeStockInNotifier(state)), stockInListProvider.overrideWith(() => _FakeStockInNotifier(state)),
], ],
child: MaterialApp.router(routerConfig: router), child: MaterialApp.router(theme: buildTheme('a'), routerConfig: router),
); );
} }
@@ -143,7 +144,7 @@ Widget _buildLoadingApp() {
licenseProvider.overrideWith(() => _FakeLicenseNotifier()), licenseProvider.overrideWith(() => _FakeLicenseNotifier()),
stockInListProvider.overrideWith(() => _FakeLoadingStockInNotifier()), stockInListProvider.overrideWith(() => _FakeLoadingStockInNotifier()),
], ],
child: MaterialApp.router(routerConfig: router), child: MaterialApp.router(theme: buildTheme('a'), routerConfig: router),
); );
} }
+2
View File
@@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:jiu_client/core/auth/auth_state.dart'; import 'package:jiu_client/core/auth/auth_state.dart';
import 'package:jiu_client/core/config/license_copy.dart'; import 'package:jiu_client/core/config/license_copy.dart';
import 'package:jiu_client/core/theme/themes.dart';
import 'package:jiu_client/models/license.dart'; import 'package:jiu_client/models/license.dart';
import 'package:jiu_client/providers/license_provider.dart'; import 'package:jiu_client/providers/license_provider.dart';
import 'package:jiu_client/widgets/write_guard.dart'; import 'package:jiu_client/widgets/write_guard.dart';
@@ -37,6 +38,7 @@ Widget _harness({
licenseProvider.overrideWith(() => _FakeLicenseNotifier(lic)), licenseProvider.overrideWith(() => _FakeLicenseNotifier(lic)),
], ],
child: MaterialApp( child: MaterialApp(
theme: buildTheme('a'),
home: Scaffold( home: Scaffold(
body: WriteGuard( body: WriteGuard(
child: ElevatedButton( child: ElevatedButton(