and so on
This commit is contained in:
@@ -1,52 +1,3 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// 工单模块颜色常量
|
||||
class WorkOrderColors {
|
||||
WorkOrderColors._();
|
||||
|
||||
/// 主色调
|
||||
static const Color primary = Color(0xFF165DFF);
|
||||
|
||||
/// 待处理色(橙色)
|
||||
static const Color pending = Color(0xFFFF7D00);
|
||||
|
||||
/// 执行中色(蓝色)
|
||||
static const Color executing = Color(0xFF165DFF);
|
||||
|
||||
/// 已完成色(绿色)
|
||||
static const Color completed = Color(0xFF00B42A);
|
||||
|
||||
/// 背景色
|
||||
static const Color background = Color(0xFFFFFFFF);
|
||||
|
||||
/// 页面背景色
|
||||
static const Color pageBackground = Color(0xFFF7F8FA);
|
||||
|
||||
/// 主要文字色
|
||||
static const Color primaryText = Color(0xFF1D2129);
|
||||
|
||||
/// 次要文字色
|
||||
static const Color secondaryText = Color(0xFF4E5969);
|
||||
|
||||
/// 辅助文字色
|
||||
static const Color auxiliaryText = Color(0xFF86909C);
|
||||
|
||||
/// 分割线颜色
|
||||
static const Color divider = Color(0xFFF0F0F0);
|
||||
|
||||
/// 进度条背景色
|
||||
static const Color progressBackground = Color(0xFFF0F0F0);
|
||||
|
||||
/// 卡片阴影
|
||||
static List<BoxShadow> get cardShadow => [
|
||||
const BoxShadow(
|
||||
color: Color(0x0D000000),
|
||||
blurRadius: 4,
|
||||
offset: Offset(0, 2),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
/// 工单模块尺寸常量
|
||||
class WorkOrderDimensions {
|
||||
WorkOrderDimensions._();
|
||||
@@ -71,21 +22,10 @@ class WorkOrderDimensions {
|
||||
class AppConstants {
|
||||
AppConstants._();
|
||||
|
||||
static const Color primaryColor = WorkOrderColors.primary;
|
||||
static const Color backgroundColor = WorkOrderColors.background;
|
||||
static const Color primaryTextColor = WorkOrderColors.primaryText;
|
||||
static const Color secondaryTextColor = WorkOrderColors.secondaryText;
|
||||
static const Color auxiliaryTextColor = WorkOrderColors.auxiliaryText;
|
||||
static const Color pendingColor = WorkOrderColors.pending;
|
||||
static const Color executingColor = WorkOrderColors.executing;
|
||||
static const Color completedColor = WorkOrderColors.completed;
|
||||
|
||||
static const double borderRadius = WorkOrderDimensions.borderRadius;
|
||||
static const double horizontalPadding = WorkOrderDimensions.horizontalPadding;
|
||||
static const double moduleSpacing = WorkOrderDimensions.moduleSpacing;
|
||||
static const double navigationBarHeight = WorkOrderDimensions.navigationBarHeight;
|
||||
|
||||
static List<BoxShadow> get cardShadow => WorkOrderColors.cardShadow;
|
||||
}
|
||||
|
||||
/// 工单状态枚举
|
||||
|
||||
@@ -141,6 +141,7 @@ import '../../features/devices/domain/usecases/recovery_task_usecase.dart';
|
||||
import '../../features/devices/presentation/bloc/device_task_cubit.dart';
|
||||
import '../app/app_user_cubit.dart';
|
||||
import '../localization/locale_cubit.dart';
|
||||
import '../theme/theme_cubit.dart';
|
||||
import '../../features/home/presentation/bloc/permission_request_bloc.dart';
|
||||
import '../network/dio_client.dart';
|
||||
import '../network/net_message_dispatcher.dart';
|
||||
@@ -216,7 +217,8 @@ Future<void> init() async {
|
||||
);
|
||||
|
||||
/// 1.5 --- MQTT Data Sources ---
|
||||
sl.registerFactory<DroneOsdDataSource>(
|
||||
/// 改为 LazySingleton:列表页预启动订阅和详情页共享同一实例,stream 互通
|
||||
sl.registerLazySingleton<DroneOsdDataSource>(
|
||||
() =>
|
||||
DroneOsdDataSourceImpl(sl<MqttClient>(instanceName: 'droneOsdClient')),
|
||||
);
|
||||
@@ -451,6 +453,9 @@ Future<void> init() async {
|
||||
// 🔥 语言管理 Cubit (单例)
|
||||
sl.registerLazySingleton(() => LocaleCubit());
|
||||
|
||||
// 🔥 主题管理 Cubit (单例,管理亮/暗/跟随系统)
|
||||
sl.registerLazySingleton(() => ThemeCubit());
|
||||
|
||||
// Tab 配置 Cubit (单例)
|
||||
sl.registerLazySingleton(() => TabConfigCubit(sl<SharedPreferences>()));
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ class DroneOsdDataSourceImpl implements DroneOsdDataSource {
|
||||
}) async {
|
||||
if (_isDisposed) return;
|
||||
|
||||
// 同一设备(SN 相同):只增加引用计数,共享订阅
|
||||
if (_listenerCount > 0 &&
|
||||
_deviceSn == deviceSn &&
|
||||
_gatewaySn == gatewaySn &&
|
||||
@@ -55,7 +56,11 @@ class DroneOsdDataSourceImpl implements DroneOsdDataSource {
|
||||
return;
|
||||
}
|
||||
|
||||
// 切换到不同设备:强制清理旧订阅
|
||||
// 不管引用计数多少,SN 变了就必须先取消旧订阅再订阅新的
|
||||
if (_deviceSn != null || _gatewaySn != null) {
|
||||
// 重置引用计数为 1,让 stopListening 能真正取消 MQTT 订阅
|
||||
_listenerCount = 1;
|
||||
await stopListening();
|
||||
}
|
||||
|
||||
@@ -113,15 +118,19 @@ class DroneOsdDataSourceImpl implements DroneOsdDataSource {
|
||||
if (_isDisposed) return;
|
||||
try {
|
||||
final jsonData = jsonDecode(message.payload) as Map<String, dynamic>;
|
||||
final osdData = DroneOsdEntity.fromJson(jsonData);
|
||||
|
||||
if (_gatewaySn != null &&
|
||||
_gatewaySn!.isNotEmpty &&
|
||||
message.topic.contains(_gatewaySn!)) {
|
||||
// 注入来源 SN,供下游解析层验证消息归属
|
||||
jsonData['_sourceSn'] = _gatewaySn;
|
||||
final osdData = DroneOsdEntity.fromJson(jsonData);
|
||||
_stationOsdController.add(osdData);
|
||||
} else if (_deviceSn != null &&
|
||||
_deviceSn!.isNotEmpty &&
|
||||
message.topic.contains(_deviceSn!)) {
|
||||
jsonData['_sourceSn'] = _deviceSn;
|
||||
final osdData = DroneOsdEntity.fromJson(jsonData);
|
||||
_droneOsdController.add(osdData);
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -130,9 +139,28 @@ class DroneOsdDataSourceImpl implements DroneOsdDataSource {
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
if (_isDisposed) return;
|
||||
_isDisposed = true;
|
||||
stopListening();
|
||||
|
||||
// 强制清理:不受引用计数限制,确保 MQTT 订阅被真正取消
|
||||
// 避免切换机场时旧订阅残留导致数据串台
|
||||
_listenerCount = 0;
|
||||
_subscription?.cancel();
|
||||
_subscription = null;
|
||||
|
||||
if (_deviceSn != null && _deviceSn!.isNotEmpty) {
|
||||
final deviceSn = _deviceSn!;
|
||||
mqttClient.unsubscribe('thing/product/$deviceSn/osd');
|
||||
}
|
||||
if (_gatewaySn != null && _gatewaySn!.isNotEmpty) {
|
||||
final gatewaySn = _gatewaySn!;
|
||||
mqttClient.unsubscribe('thing/product/$gatewaySn/osd');
|
||||
}
|
||||
|
||||
_deviceSn = null;
|
||||
_gatewaySn = null;
|
||||
|
||||
_droneOsdController.close();
|
||||
_stationOsdController.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,159 @@ import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// 应用级语义色扩展(浅色/深色各一套,随主题自动切换)
|
||||
///
|
||||
/// 用法:`context.appColors.cardBackground`
|
||||
/// 原理:颜色挂载在 ThemeData.extensions 上,主题切换时组件树自动重建,
|
||||
/// 页面无需写 `isDark ? A : B` 判断
|
||||
@immutable
|
||||
class AppColors extends ThemeExtension<AppColors> {
|
||||
const AppColors({
|
||||
required this.pageBackground,
|
||||
required this.cardBackground,
|
||||
required this.fillBackground,
|
||||
required this.textPrimary,
|
||||
required this.textSecondary,
|
||||
required this.textTertiary,
|
||||
required this.divider,
|
||||
required this.cardShadow,
|
||||
required this.primary,
|
||||
required this.danger,
|
||||
required this.warning,
|
||||
required this.success,
|
||||
});
|
||||
|
||||
/// 页面背景色
|
||||
final Color pageBackground;
|
||||
|
||||
/// 卡片背景色
|
||||
final Color cardBackground;
|
||||
|
||||
/// 卡片内嵌块填充色(输入框、上传按钮等)
|
||||
final Color fillBackground;
|
||||
|
||||
/// 主要文字色
|
||||
final Color textPrimary;
|
||||
|
||||
/// 次要文字色
|
||||
final Color textSecondary;
|
||||
|
||||
/// 辅助文字色(占位、说明)
|
||||
final Color textTertiary;
|
||||
|
||||
/// 分割线/浅色边框
|
||||
final Color divider;
|
||||
|
||||
/// 卡片阴影色
|
||||
final Color cardShadow;
|
||||
|
||||
/// 品牌主色(两种模式下保持一致)
|
||||
final Color primary;
|
||||
|
||||
/// 危险/错误色(两种模式下保持一致)
|
||||
final Color danger;
|
||||
|
||||
/// 警告色(两种模式下保持一致)
|
||||
final Color warning;
|
||||
|
||||
/// 成功/完成色(两种模式下保持一致)
|
||||
final Color success;
|
||||
|
||||
/// 浅色语义色(取自设计稿)
|
||||
static const AppColors light = AppColors(
|
||||
pageBackground: Color(0xFFF5F7FA),
|
||||
cardBackground: Color(0xFFFFFFFF),
|
||||
fillBackground: Color(0xFFF8F9FA),
|
||||
textPrimary: Color(0xFF1D2129),
|
||||
textSecondary: Color(0xFF4E5969),
|
||||
textTertiary: Color(0xFF86909C),
|
||||
divider: Color(0xFFF0F0F0),
|
||||
cardShadow: Color(0x0D000000),
|
||||
primary: Color(0xFF165DFF),
|
||||
danger: Color(0xFFF53F3F),
|
||||
warning: Color(0xFFFF7D00),
|
||||
success: Color(0xFF00B42A),
|
||||
);
|
||||
|
||||
/// 深色语义色(与 AppTheme.darkTheme 的 surface 色保持一致)
|
||||
static const AppColors dark = AppColors(
|
||||
pageBackground: Color(0xFF1C1C1E),
|
||||
cardBackground: Color(0xFF2C2C2E),
|
||||
fillBackground: Color(0xFF3A3A3C),
|
||||
textPrimary: Color(0xFFF2F3F5),
|
||||
textSecondary: Color(0xFFC9CDD4),
|
||||
textTertiary: Color(0xFF86909C),
|
||||
divider: Color(0xFF3A3A3C),
|
||||
cardShadow: Color(0x00000000), // 深色下无阴影,靠色差分层级
|
||||
primary: Color(0xFF165DFF),
|
||||
danger: Color(0xFFF53F3F),
|
||||
warning: Color(0xFFFF7D00),
|
||||
success: Color(0xFF00B42A),
|
||||
);
|
||||
|
||||
@override
|
||||
AppColors copyWith({
|
||||
Color? pageBackground,
|
||||
Color? cardBackground,
|
||||
Color? fillBackground,
|
||||
Color? textPrimary,
|
||||
Color? textSecondary,
|
||||
Color? textTertiary,
|
||||
Color? divider,
|
||||
Color? cardShadow,
|
||||
Color? primary,
|
||||
Color? danger,
|
||||
Color? warning,
|
||||
Color? success,
|
||||
}) {
|
||||
return AppColors(
|
||||
pageBackground: pageBackground ?? this.pageBackground,
|
||||
cardBackground: cardBackground ?? this.cardBackground,
|
||||
fillBackground: fillBackground ?? this.fillBackground,
|
||||
textPrimary: textPrimary ?? this.textPrimary,
|
||||
textSecondary: textSecondary ?? this.textSecondary,
|
||||
textTertiary: textTertiary ?? this.textTertiary,
|
||||
divider: divider ?? this.divider,
|
||||
cardShadow: cardShadow ?? this.cardShadow,
|
||||
primary: primary ?? this.primary,
|
||||
danger: danger ?? this.danger,
|
||||
warning: warning ?? this.warning,
|
||||
success: success ?? this.success,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AppColors lerp(AppColors? other, double t) {
|
||||
if (other == null) return this;
|
||||
return AppColors(
|
||||
pageBackground: Color.lerp(pageBackground, other.pageBackground, t)!,
|
||||
cardBackground: Color.lerp(cardBackground, other.cardBackground, t)!,
|
||||
fillBackground: Color.lerp(fillBackground, other.fillBackground, t)!,
|
||||
textPrimary: Color.lerp(textPrimary, other.textPrimary, t)!,
|
||||
textSecondary: Color.lerp(textSecondary, other.textSecondary, t)!,
|
||||
textTertiary: Color.lerp(textTertiary, other.textTertiary, t)!,
|
||||
divider: Color.lerp(divider, other.divider, t)!,
|
||||
cardShadow: Color.lerp(cardShadow, other.cardShadow, t)!,
|
||||
primary: Color.lerp(primary, other.primary, t)!,
|
||||
danger: Color.lerp(danger, other.danger, t)!,
|
||||
warning: Color.lerp(warning, other.warning, t)!,
|
||||
success: Color.lerp(success, other.success, t)!,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 便捷访问扩展:`context.appColors`
|
||||
extension AppColorsX on BuildContext {
|
||||
AppColors get appColors => Theme.of(this).extension<AppColors>()!;
|
||||
}
|
||||
|
||||
class AppTheme {
|
||||
// 基础色值定义
|
||||
static const Color _pureWhite = Color(0xFFFFFFFF);
|
||||
static const Color _offWhite = Color(0xFFfafafc); // 稍微带点灰的白,用于背景增加层次感
|
||||
static const Color _pureBlack = Color(0xFF000000);
|
||||
static const Color _darkGrey = Color(0xFF1C1C1E); // iOS 风格的深灰黑色
|
||||
static const Color _surfaceDark = Color(0xFF2C2C2E); // 深色模式下卡片、弹窗表面色
|
||||
|
||||
static ThemeData get lightTheme {
|
||||
return ThemeData(
|
||||
@@ -15,6 +162,9 @@ class AppTheme {
|
||||
brightness: Brightness.light,
|
||||
fontFamily: (Platform.isWindows) ? 'Microsoft YaHei' : null,
|
||||
|
||||
// 语义色扩展
|
||||
extensions: const [AppColors.light],
|
||||
|
||||
// 1. 整体背景色
|
||||
scaffoldBackgroundColor: _offWhite,
|
||||
|
||||
@@ -85,4 +235,84 @@ class AppTheme {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 深色主题 (与浅色主题对称的黑白简约风格)
|
||||
static ThemeData get darkTheme {
|
||||
return ThemeData(
|
||||
useMaterial3: true,
|
||||
brightness: Brightness.dark,
|
||||
fontFamily: (Platform.isWindows) ? 'Microsoft YaHei' : null,
|
||||
|
||||
// 语义色扩展
|
||||
extensions: const [AppColors.dark],
|
||||
|
||||
// 1. 整体背景色 (iOS 风格深灰黑)
|
||||
scaffoldBackgroundColor: _darkGrey,
|
||||
|
||||
// 2. 核心颜色方案 (与浅色主题反色:主色白色)
|
||||
colorScheme: const ColorScheme.dark(
|
||||
primary: _pureWhite, // 主色设为白色
|
||||
onPrimary: _pureBlack, // 白色背景上的文字设为黑色
|
||||
surface: _surfaceDark, // 卡片、弹窗等表面颜色
|
||||
onSurface: _pureWhite, // 表面上的文字色
|
||||
),
|
||||
|
||||
// 3. 全局按钮主题 (白底黑字)
|
||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: _pureWhite,
|
||||
foregroundColor: _pureBlack,
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 24),
|
||||
),
|
||||
),
|
||||
|
||||
// 4. 填充按钮主题 (常用语 Material 3)
|
||||
filledButtonTheme: FilledButtonThemeData(
|
||||
style: FilledButton.styleFrom(
|
||||
backgroundColor: _pureWhite,
|
||||
foregroundColor: _pureBlack,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// 5. AppBar 主题 (深灰黑背景,白色文字)
|
||||
appBarTheme: const AppBarTheme(
|
||||
backgroundColor: _darkGrey,
|
||||
surfaceTintColor: Colors.transparent,
|
||||
elevation: 0,
|
||||
centerTitle: true,
|
||||
iconTheme: IconThemeData(color: _pureWhite),
|
||||
titleTextStyle: TextStyle(
|
||||
color: _pureWhite,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w700,
|
||||
letterSpacing: -0.5,
|
||||
),
|
||||
),
|
||||
|
||||
// 6. 输入框主题 (深色填充,白色边框)
|
||||
inputDecorationTheme: InputDecorationTheme(
|
||||
filled: true,
|
||||
fillColor: _surfaceDark,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: const BorderSide(color: Colors.white12),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: const BorderSide(color: Colors.white12),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: const BorderSide(color: _pureWhite, width: 1.5),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
54
lib/core/theme/theme_cubit.dart
Normal file
54
lib/core/theme/theme_cubit.dart
Normal file
@@ -0,0 +1,54 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
/// 全局主题管理 Cubit(仿 LocaleCubit 模式)
|
||||
/// 支持 light / dark / system 三态,持久化到 SharedPreferences
|
||||
class ThemeCubit extends Cubit<ThemeMode> {
|
||||
static const String _themeKey = 'app_theme_mode';
|
||||
|
||||
ThemeCubit() : super(ThemeMode.light) {
|
||||
_loadSavedThemeMode();
|
||||
}
|
||||
|
||||
/// 从本地存储恢复上次保存的主题模式
|
||||
Future<void> _loadSavedThemeMode() async {
|
||||
try {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final saved = prefs.getString(_themeKey);
|
||||
emit(_parseThemeMode(saved));
|
||||
} catch (e) {
|
||||
emit(ThemeMode.light);
|
||||
}
|
||||
}
|
||||
|
||||
/// 设置主题模式并持久化
|
||||
Future<void> setThemeMode(ThemeMode mode) async {
|
||||
try {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString(_themeKey, mode.name);
|
||||
emit(mode);
|
||||
} catch (e) {
|
||||
debugPrint('❌ [ThemeCubit] 保存主题设置失败: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// 夜间模式开关(Switch 二态切换,不涉及跟随系统)
|
||||
Future<void> toggleDarkMode(bool enabled) =>
|
||||
setThemeMode(enabled ? ThemeMode.dark : ThemeMode.light);
|
||||
|
||||
/// 当前是否为深色模式
|
||||
bool get isDarkMode => state == ThemeMode.dark;
|
||||
|
||||
/// 将持久化的字符串解析为 ThemeMode
|
||||
ThemeMode _parseThemeMode(String? saved) {
|
||||
switch (saved) {
|
||||
case 'dark':
|
||||
return ThemeMode.dark;
|
||||
case 'system':
|
||||
return ThemeMode.system;
|
||||
default:
|
||||
return ThemeMode.light;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:maibu_satabot_v2/core/app/app_user_cubit.dart';
|
||||
import 'package:maibu_satabot_v2/core/di/injection.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import 'package:maibu_satabot_v2/features/devices/presentation/bloc/devices_cubit.dart';
|
||||
|
||||
import '../../../../core/router/route_paths.dart';
|
||||
@@ -33,9 +34,9 @@ class _LoginPageState extends State<LoginPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: context.appColors.pageBackground,
|
||||
// 保持 AppBar 简洁或直接去掉
|
||||
appBar: AppBar(backgroundColor: Colors.white, elevation: 0),
|
||||
appBar: AppBar(backgroundColor: context.appColors.pageBackground, elevation: 0),
|
||||
body: BlocListener<LoginCubit, LoginState>(
|
||||
listener: (context, state) {
|
||||
debugPrint('🔍 [LOGIN] 登录状态变化: $state');
|
||||
@@ -81,7 +82,7 @@ class _LoginPageState extends State<LoginPage> {
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: Colors.grey.shade600,
|
||||
color: context.appColors.textTertiary,
|
||||
height: 1.3,
|
||||
),
|
||||
),
|
||||
@@ -91,12 +92,12 @@ class _LoginPageState extends State<LoginPage> {
|
||||
),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
Text(
|
||||
"账号登录v1.1.5",
|
||||
style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold, color: Colors.brown),
|
||||
style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold, color: context.appColors.textPrimary),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const Text("请填写以下信息以验证身份", style: TextStyle(fontSize: 15, color: Colors.grey)),
|
||||
Text("请填写以下信息以验证身份", style: TextStyle(fontSize: 15, color: context.appColors.textTertiary)),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// 表单区域
|
||||
@@ -104,7 +105,8 @@ class _LoginPageState extends State<LoginPage> {
|
||||
_buildInputLabel("账号"),
|
||||
TextField(
|
||||
controller: _userCtrl,
|
||||
cursorColor: Colors.black,
|
||||
style: TextStyle(fontSize: 14, color: context.appColors.textPrimary),
|
||||
cursorColor: context.appColors.textPrimary,
|
||||
decoration: _inputDecoration(hint: "请输入用户名"),
|
||||
),
|
||||
|
||||
@@ -115,11 +117,12 @@ class _LoginPageState extends State<LoginPage> {
|
||||
TextField(
|
||||
controller: _pwdCtrl,
|
||||
obscureText: _obscurePwd,
|
||||
cursorColor: Colors.black,
|
||||
style: TextStyle(fontSize: 14, color: context.appColors.textPrimary),
|
||||
cursorColor: context.appColors.textPrimary,
|
||||
decoration: _inputDecoration(
|
||||
hint: "请输入密码",
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(_obscurePwd ? Icons.visibility_off_outlined : Icons.visibility_outlined, color: Colors.grey, size: 20),
|
||||
icon: Icon(_obscurePwd ? Icons.visibility_off_outlined : Icons.visibility_outlined, color: context.appColors.textTertiary, size: 20),
|
||||
onPressed: () => setState(() => _obscurePwd = !_obscurePwd),
|
||||
),
|
||||
),
|
||||
@@ -165,9 +168,9 @@ class _LoginPageState extends State<LoginPage> {
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
"没有账号吗?",
|
||||
style: TextStyle(fontSize: 14, color: Colors.grey),
|
||||
style: TextStyle(fontSize: 14, color: context.appColors.textTertiary),
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
@@ -182,7 +185,7 @@ class _LoginPageState extends State<LoginPage> {
|
||||
"立即注册",
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.black,
|
||||
color: context.appColors.textPrimary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
@@ -218,7 +221,7 @@ class _LoginPageState extends State<LoginPage> {
|
||||
Widget _buildInputLabel(String label) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8.0),
|
||||
child: Text(label, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w600)),
|
||||
child: Text(label, style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600, color: context.appColors.textSecondary)),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -226,17 +229,17 @@ class _LoginPageState extends State<LoginPage> {
|
||||
InputDecoration _inputDecoration({required String hint, Widget? suffixIcon}) {
|
||||
return InputDecoration(
|
||||
hintText: hint,
|
||||
hintStyle: TextStyle(color: Colors.grey.shade400, fontSize: 14),
|
||||
hintStyle: TextStyle(color: context.appColors.textTertiary, fontSize: 14),
|
||||
filled: true,
|
||||
fillColor: Colors.grey.shade50,
|
||||
fillColor: context.appColors.fillBackground,
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: BorderSide(color: Colors.grey.shade200),
|
||||
borderSide: BorderSide(color: context.appColors.divider),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: const BorderSide(color: Colors.black, width: 1),
|
||||
borderSide: BorderSide(color: context.appColors.primary, width: 1),
|
||||
),
|
||||
suffixIcon: suffixIcon,
|
||||
);
|
||||
@@ -252,7 +255,9 @@ class _LoginPageState extends State<LoginPage> {
|
||||
width: 24,
|
||||
child: Checkbox(
|
||||
value: _isAgreed,
|
||||
activeColor: Colors.black,
|
||||
activeColor: context.appColors.primary,
|
||||
checkColor: Colors.white,
|
||||
side: BorderSide(color: context.appColors.divider),
|
||||
onChanged: (val) => setState(() => _isAgreed = val!),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)),
|
||||
),
|
||||
@@ -261,9 +266,9 @@ class _LoginPageState extends State<LoginPage> {
|
||||
Expanded(
|
||||
child: Wrap(
|
||||
children: [
|
||||
const Text("我已阅读并同意 ", style: TextStyle(fontSize: 13, color: Colors.grey)),
|
||||
Text("我已阅读并同意 ", style: TextStyle(fontSize: 13, color: context.appColors.textTertiary)),
|
||||
_protocolText("《用户协议》", () => _showProtocolDetail("用户协议")),
|
||||
const Text(" 和 ", style: TextStyle(fontSize: 13, color: Colors.grey)),
|
||||
Text(" 和 ", style: TextStyle(fontSize: 13, color: context.appColors.textTertiary)),
|
||||
_protocolText("《隐私政策》", () => _showProtocolDetail("隐私政策")),
|
||||
],
|
||||
),
|
||||
@@ -277,7 +282,7 @@ class _LoginPageState extends State<LoginPage> {
|
||||
onTap: onTap,
|
||||
child: Text(
|
||||
text,
|
||||
style: const TextStyle(fontSize: 13, color: Colors.black, fontWeight: FontWeight.bold),
|
||||
style: TextStyle(fontSize: 13, color: context.appColors.textPrimary, fontWeight: FontWeight.bold),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -286,18 +291,18 @@ class _LoginPageState extends State<LoginPage> {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: context.appColors.cardBackground,
|
||||
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(16))),
|
||||
builder: (context) => Container(
|
||||
padding: const EdgeInsets.all(24),
|
||||
height: MediaQuery.of(context).size.height * 0.7,
|
||||
child: Column(
|
||||
children: [
|
||||
Text(title, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||
const Divider(height: 32),
|
||||
Text(title, style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: context.appColors.textPrimary)),
|
||||
Divider(height: 32, color: context.appColors.divider),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Text("此处放置您的${title}详细内容...\n" * 20, style: const TextStyle(color: Colors.black87, height: 1.5)),
|
||||
child: Text("此处放置您的${title}详细内容...\n" * 20, style: TextStyle(color: context.appColors.textSecondary, height: 1.5)),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:cc_ui_kit/cc_ui_kit.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:maibu_satabot_v2/core/router/route_paths.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
|
||||
class RegisterPage extends StatefulWidget {
|
||||
const RegisterPage({super.key});
|
||||
@@ -29,12 +30,12 @@ class _RegisterPageState extends State<RegisterPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: context.appColors.pageBackground,
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: context.appColors.pageBackground,
|
||||
elevation: 0,
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back, color: Colors.black),
|
||||
icon: Icon(Icons.arrow_back, color: context.appColors.textPrimary),
|
||||
onPressed: () => context.go(RoutePaths.login),
|
||||
),
|
||||
),
|
||||
@@ -44,25 +45,26 @@ class _RegisterPageState extends State<RegisterPage> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(height: 40),
|
||||
const Text(
|
||||
Text(
|
||||
"账号注册",
|
||||
style: TextStyle(
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const Text(
|
||||
Text(
|
||||
"请填写以下信息完成注册",
|
||||
style: TextStyle(fontSize: 15, color: Colors.grey),
|
||||
style: TextStyle(fontSize: 15, color: context.appColors.textTertiary),
|
||||
),
|
||||
const SizedBox(height: 40),
|
||||
|
||||
_buildInputLabel("用户名"),
|
||||
TextField(
|
||||
controller: _userCtrl,
|
||||
cursorColor: Colors.black,
|
||||
style: TextStyle(fontSize: 14, color: context.appColors.textPrimary),
|
||||
cursorColor: context.appColors.textPrimary,
|
||||
decoration: _inputDecoration(hint: "请设置用户名"),
|
||||
),
|
||||
|
||||
@@ -72,7 +74,8 @@ class _RegisterPageState extends State<RegisterPage> {
|
||||
TextField(
|
||||
controller: _pwdCtrl,
|
||||
obscureText: _obscurePwd,
|
||||
cursorColor: Colors.black,
|
||||
style: TextStyle(fontSize: 14, color: context.appColors.textPrimary),
|
||||
cursorColor: context.appColors.textPrimary,
|
||||
decoration: _inputDecoration(
|
||||
hint: "请设置密码",
|
||||
suffixIcon: IconButton(
|
||||
@@ -80,7 +83,7 @@ class _RegisterPageState extends State<RegisterPage> {
|
||||
_obscurePwd
|
||||
? Icons.visibility_off_outlined
|
||||
: Icons.visibility_outlined,
|
||||
color: Colors.grey,
|
||||
color: context.appColors.textTertiary,
|
||||
size: 20,
|
||||
),
|
||||
onPressed: () => setState(() => _obscurePwd = !_obscurePwd),
|
||||
@@ -94,7 +97,8 @@ class _RegisterPageState extends State<RegisterPage> {
|
||||
TextField(
|
||||
controller: _confirmPwdCtrl,
|
||||
obscureText: _obscureConfirmPwd,
|
||||
cursorColor: Colors.black,
|
||||
style: TextStyle(fontSize: 14, color: context.appColors.textPrimary),
|
||||
cursorColor: context.appColors.textPrimary,
|
||||
decoration: _inputDecoration(
|
||||
hint: "请再次输入密码",
|
||||
suffixIcon: IconButton(
|
||||
@@ -102,7 +106,7 @@ class _RegisterPageState extends State<RegisterPage> {
|
||||
_obscureConfirmPwd
|
||||
? Icons.visibility_off_outlined
|
||||
: Icons.visibility_outlined,
|
||||
color: Colors.grey,
|
||||
color: context.appColors.textTertiary,
|
||||
size: 20,
|
||||
),
|
||||
onPressed: () => setState(
|
||||
@@ -132,17 +136,17 @@ class _RegisterPageState extends State<RegisterPage> {
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
"已有账号?",
|
||||
style: TextStyle(fontSize: 14, color: Colors.grey),
|
||||
style: TextStyle(fontSize: 14, color: context.appColors.textTertiary),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () => context.go(RoutePaths.login),
|
||||
child: const Text(
|
||||
child: Text(
|
||||
"立即登录",
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.black,
|
||||
color: context.appColors.textPrimary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
@@ -183,9 +187,10 @@ class _RegisterPageState extends State<RegisterPage> {
|
||||
padding: const EdgeInsets.only(bottom: 8.0),
|
||||
child: Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: context.appColors.textSecondary,
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -194,17 +199,17 @@ class _RegisterPageState extends State<RegisterPage> {
|
||||
InputDecoration _inputDecoration({required String hint, Widget? suffixIcon}) {
|
||||
return InputDecoration(
|
||||
hintText: hint,
|
||||
hintStyle: TextStyle(color: Colors.grey.shade400, fontSize: 14),
|
||||
hintStyle: TextStyle(color: context.appColors.textTertiary, fontSize: 14),
|
||||
filled: true,
|
||||
fillColor: Colors.grey.shade50,
|
||||
fillColor: context.appColors.fillBackground,
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: BorderSide(color: Colors.grey.shade200),
|
||||
borderSide: BorderSide(color: context.appColors.divider),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: const BorderSide(color: Colors.black, width: 1),
|
||||
borderSide: BorderSide(color: context.appColors.primary, width: 1),
|
||||
),
|
||||
suffixIcon: suffixIcon,
|
||||
);
|
||||
@@ -219,7 +224,9 @@ class _RegisterPageState extends State<RegisterPage> {
|
||||
width: 24,
|
||||
child: Checkbox(
|
||||
value: _isAgreed,
|
||||
activeColor: Colors.black,
|
||||
activeColor: context.appColors.primary,
|
||||
checkColor: Colors.white,
|
||||
side: BorderSide(color: context.appColors.divider),
|
||||
onChanged: (val) => setState(() => _isAgreed = val!),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
@@ -230,12 +237,12 @@ class _RegisterPageState extends State<RegisterPage> {
|
||||
Expanded(
|
||||
child: Wrap(
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
"我已阅读并同意 ",
|
||||
style: TextStyle(fontSize: 13, color: Colors.grey),
|
||||
style: TextStyle(fontSize: 13, color: context.appColors.textTertiary),
|
||||
),
|
||||
_protocolText("《用户协议》", () => _showProtocolDetail("用户协议")),
|
||||
const Text(" 和 ", style: TextStyle(fontSize: 13, color: Colors.grey)),
|
||||
Text(" 和 ", style: TextStyle(fontSize: 13, color: context.appColors.textTertiary)),
|
||||
_protocolText("《隐私政策》", () => _showProtocolDetail("隐私政策")),
|
||||
],
|
||||
),
|
||||
@@ -249,9 +256,9 @@ class _RegisterPageState extends State<RegisterPage> {
|
||||
onTap: onTap,
|
||||
child: Text(
|
||||
text,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: Colors.black,
|
||||
color: context.appColors.textPrimary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
@@ -262,7 +269,7 @@ class _RegisterPageState extends State<RegisterPage> {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: context.appColors.cardBackground,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
|
||||
),
|
||||
@@ -273,14 +280,14 @@ class _RegisterPageState extends State<RegisterPage> {
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: context.appColors.textPrimary),
|
||||
),
|
||||
const Divider(height: 32),
|
||||
Divider(height: 32, color: context.appColors.divider),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Text(
|
||||
"此处放置您的${title}详细内容...\n" * 20,
|
||||
style: const TextStyle(color: Colors.black87, height: 1.5),
|
||||
style: TextStyle(color: context.appColors.textSecondary, height: 1.5),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -259,7 +259,8 @@ class PathRepositoryImpl implements PathRepository {
|
||||
return records;
|
||||
}
|
||||
|
||||
/// 鏍规嵁鍦虹珯ID鏌ヨ<E98F8C>宸ヤ綔璁板綍鍒楄〃锛圶ML鏍煎紡锛?
|
||||
/// 鏍规嵁鍦虹珯ID鏌ヨ<E98F8C>宸ヤ綔璁板綍鍒楄
|
||||
/// 〃锛圶ML鏍煎紡锛?
|
||||
@override
|
||||
Future<List<WorkRecordEntity>> getWorkRecordsBySiteId({
|
||||
required int siteId,
|
||||
|
||||
@@ -18,6 +18,7 @@ import 'package:maibu_satabot_v2/features/v2/report/presentation/pages/report_pa
|
||||
import 'package:maibu_satabot_v2/features/v2/device_list/presentation/float_bar/view/float_bar_widget.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/device_list/presentation/float_bar/cubit/float_bar_setting_cubit.dart';
|
||||
import 'package:maibu_satabot_v2/core/di/injection.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
|
||||
class MainWrapper extends StatefulWidget {
|
||||
const MainWrapper({super.key});
|
||||
@@ -205,7 +206,9 @@ class _MainWrapperState extends State<MainWrapper> {
|
||||
],
|
||||
),
|
||||
bottomNavigationBar: Container(
|
||||
decoration: const BoxDecoration(color: Colors.white),
|
||||
decoration: BoxDecoration(
|
||||
color: context.appColors.cardBackground,
|
||||
),
|
||||
child: SafeArea(
|
||||
top: false,
|
||||
child: LayoutBuilder(
|
||||
@@ -217,15 +220,15 @@ class _MainWrapperState extends State<MainWrapper> {
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(25),
|
||||
border: Border.all(
|
||||
color: const Color(0xFFE5E6EB),
|
||||
color: context.appColors.divider,
|
||||
width: 1,
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -244,10 +247,10 @@ class _MainWrapperState extends State<MainWrapper> {
|
||||
width: 44,
|
||||
height: 44,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF2F3F5),
|
||||
color: context.appColors.divider,
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: const Color(0xFFE5E6EB),
|
||||
color: context.appColors.divider,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
@@ -274,8 +277,8 @@ class _MainWrapperState extends State<MainWrapper> {
|
||||
_getIconData(item.icon),
|
||||
size: 24,
|
||||
color: isSelected
|
||||
? const Color(0xFF1D2129)
|
||||
: const Color(0xFF86909C),
|
||||
? context.appColors.textPrimary
|
||||
: context.appColors.textTertiary,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
@@ -283,8 +286,8 @@ class _MainWrapperState extends State<MainWrapper> {
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: isSelected
|
||||
? const Color(0xFF1D2129)
|
||||
: const Color(0xFF86909C),
|
||||
? context.appColors.textPrimary
|
||||
: context.appColors.textTertiary,
|
||||
fontWeight: isSelected
|
||||
? FontWeight.w600
|
||||
: FontWeight.w400,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import 'package:maibu_satabot_v2/features/main_container/presentation/cubit/tab_config_cubit.dart';
|
||||
|
||||
class CustomBottomNavBar extends StatefulWidget {
|
||||
@@ -92,11 +93,11 @@ class _CustomBottomNavBarState extends State<CustomBottomNavBar>
|
||||
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(16)),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, -2),
|
||||
),
|
||||
@@ -135,11 +136,11 @@ class _CustomBottomNavBarState extends State<CustomBottomNavBar>
|
||||
width: circleDiameter,
|
||||
height: circleDiameter,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF5F5F5),
|
||||
color: context.appColors.divider,
|
||||
shape: BoxShape.circle,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.12),
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 8,
|
||||
spreadRadius: 1,
|
||||
offset: Offset.zero,
|
||||
@@ -174,7 +175,9 @@ class _CustomBottomNavBarState extends State<CustomBottomNavBar>
|
||||
children: [
|
||||
Icon(
|
||||
icon,
|
||||
color: isSelected ? Colors.black : const Color(0xFF666666),
|
||||
color: isSelected
|
||||
? context.appColors.textPrimary
|
||||
: context.appColors.textSecondary,
|
||||
size: 24,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
@@ -182,7 +185,9 @@ class _CustomBottomNavBarState extends State<CustomBottomNavBar>
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: isSelected ? Colors.black : const Color(0xFF666666),
|
||||
color: isSelected
|
||||
? context.appColors.textPrimary
|
||||
: context.appColors.textSecondary,
|
||||
fontWeight: isSelected ? FontWeight.w500 : FontWeight.w400,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -28,6 +28,7 @@ import '../../domain/entities/drone_station_entity.dart'; // 🔥 添加 DroneSt
|
||||
import 'robot_list_page.dart';
|
||||
import 'robot_control_page.dart';
|
||||
import 'drone_station_detail_page.dart';
|
||||
import '../../../../../core/network/mqtt/data/datasources/drone_osd_datasource.dart';
|
||||
import 'qr_scanner_page.dart';
|
||||
import 'bind_device_page.dart';
|
||||
import '../../../../remote_control/presentation/bloc/remote_control_cubit.dart';
|
||||
@@ -756,6 +757,12 @@ class _DeviceStatusViewState extends State<DeviceStatusView> {
|
||||
return DroneStationItemCard(
|
||||
station: station,
|
||||
onTap: () {
|
||||
// 预启动 OSD 订阅:进入详情页前就让 MQTT 数据流跑起来
|
||||
// 这样详情页一进来就能从 stream 读到数据,无需等待首帧推送
|
||||
sl<DroneOsdDataSource>().startListening(
|
||||
deviceSn: station.deviceSn,
|
||||
gatewaySn: station.gatewaySn,
|
||||
);
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
@@ -936,7 +943,8 @@ class _DeviceStatusViewState extends State<DeviceStatusView> {
|
||||
if (result != null && mounted) {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (_) => BindDevicePage(scanResult: result),
|
||||
builder: (_) =>
|
||||
BindDevicePage(scanResult: result),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -1129,6 +1137,11 @@ class _DeviceStatusViewState extends State<DeviceStatusView> {
|
||||
}
|
||||
|
||||
if (matchedStation != null) {
|
||||
// 预启动 OSD 订阅:进入详情页前就让 MQTT 数据流跑起来
|
||||
sl<DroneOsdDataSource>().startListening(
|
||||
deviceSn: matchedStation.deviceSn,
|
||||
gatewaySn: matchedStation.gatewaySn,
|
||||
);
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
|
||||
@@ -37,18 +37,22 @@ class _DroneStationDetailPageState extends State<DroneStationDetailPage> {
|
||||
late DroneOsdDataSource _osdDataSource;
|
||||
StreamSubscription<DroneOsdEntity>? _stationOsdSubscription;
|
||||
|
||||
/// 静态缓存:跨页面实例保留上次的 host 数据
|
||||
static final Map<String, dynamic> _cachedHostData = {};
|
||||
/// 静态缓存:按 gatewaySn 分区,跨页面实例保留每个机场上次的 host 数据
|
||||
/// 避免进入新机场时显示上一个机场的缓存数据
|
||||
static final Map<String, Map<String, dynamic>> _cachedHostDataBySn = {};
|
||||
|
||||
final ValueNotifier<Map<String, dynamic>> _stationHostData =
|
||||
ValueNotifier<Map<String, dynamic>>(
|
||||
// 初始化时从缓存加载,进入页面立即显示
|
||||
Map<String, dynamic>.from(_cachedHostData),
|
||||
);
|
||||
ValueNotifier<Map<String, dynamic>>({});
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// 进入页面时加载当前机场的缓存数据(切回时立即显示)
|
||||
final cached = _cachedHostDataBySn[widget.station.gatewaySn];
|
||||
if (cached != null && cached.isNotEmpty) {
|
||||
_stationHostData.value = Map<String, dynamic>.from(cached);
|
||||
}
|
||||
|
||||
_bloc = sl<DroneStationBloc>();
|
||||
_bloc.add(
|
||||
UAVDetailLoad(
|
||||
@@ -64,8 +68,10 @@ class _DroneStationDetailPageState extends State<DroneStationDetailPage> {
|
||||
}
|
||||
|
||||
void _startStationOsdListening() {
|
||||
// 使用 station 自带的 deviceSn + gatewaySn,与列表页预订阅参数一致
|
||||
// 避免因参数不同导致 DataSource 重新订阅、打断数据流
|
||||
_osdDataSource.startListening(
|
||||
deviceSn: '',
|
||||
deviceSn: widget.station.deviceSn,
|
||||
gatewaySn: widget.station.gatewaySn,
|
||||
);
|
||||
|
||||
@@ -76,18 +82,32 @@ class _DroneStationDetailPageState extends State<DroneStationDetailPage> {
|
||||
}
|
||||
|
||||
void _parseAndUpdateHostData(DroneOsdEntity osd) {
|
||||
// 防护:验证消息来源 SN 是否匹配当前机场,避免串台
|
||||
final sourceSn = osd.rawData['_sourceSn'];
|
||||
if (sourceSn != null && sourceSn != widget.station.gatewaySn) {
|
||||
debugPrint(
|
||||
'⚠️ [DetailPage] 丢弃非当前机场 OSD: source=$sourceSn, current=${widget.station.gatewaySn}',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final data = osd.rawData;
|
||||
final hostData = data['data'] is Map ? (data['data'] as Map)['host'] : null;
|
||||
if (hostData == null || hostData is! Map) return;
|
||||
|
||||
// 🔥 基于已有数据合并,只更新非 null 字段,避免 Type 2 消息覆盖已有值
|
||||
final Map<String, dynamic> merged = Map<String, dynamic>.from(_stationHostData.value);
|
||||
final Map<String, dynamic> merged = Map<String, dynamic>.from(
|
||||
_stationHostData.value,
|
||||
);
|
||||
|
||||
void _put(String key, dynamic value) {
|
||||
if (value != null) merged[key] = value;
|
||||
}
|
||||
|
||||
_put('environment_temperature', (hostData['environment_temperature'] as num?)?.toDouble());
|
||||
_put(
|
||||
'environment_temperature',
|
||||
(hostData['environment_temperature'] as num?)?.toDouble(),
|
||||
);
|
||||
_put('humidity', (hostData['humidity'] as num?)?.toDouble());
|
||||
_put('wind_speed', (hostData['wind_speed'] as num?)?.toDouble());
|
||||
_put('rainfall', hostData['rainfall']?.toString());
|
||||
@@ -95,7 +115,10 @@ class _DroneStationDetailPageState extends State<DroneStationDetailPage> {
|
||||
_put('drone_in_dock', hostData['drone_in_dock']?.toString());
|
||||
_put('temperature', (hostData['temperature'] as num?)?.toDouble());
|
||||
_put('putter_state', hostData['putter_state']?.toString());
|
||||
_put('supplement_light_state', hostData['supplement_light_state']?.toString());
|
||||
_put(
|
||||
'supplement_light_state',
|
||||
hostData['supplement_light_state']?.toString(),
|
||||
);
|
||||
_put('alarm_state', hostData['alarm_state']?.toString());
|
||||
_put('emergency_stop_state', hostData['emergency_stop_state']?.toString());
|
||||
_put('silent_mode', hostData['silent_mode']?.toString());
|
||||
@@ -104,28 +127,42 @@ class _DroneStationDetailPageState extends State<DroneStationDetailPage> {
|
||||
_put('height', (hostData['height'] as num?)?.toDouble());
|
||||
_put('latitude', (hostData['latitude'] as num?)?.toDouble());
|
||||
_put('longitude', (hostData['longitude'] as num?)?.toDouble());
|
||||
_put('home_position_is_valid', hostData['home_position_is_valid']?.toString());
|
||||
_put(
|
||||
'home_position_is_valid',
|
||||
hostData['home_position_is_valid']?.toString(),
|
||||
);
|
||||
_put('battery_store_mode', hostData['battery_store_mode']?.toString());
|
||||
_put('first_power_on', hostData['first_power_on']?.toString());
|
||||
_put('drone_charge_state', hostData['drone_charge_state']);
|
||||
_put('air_conditioner', hostData['air_conditioner']);
|
||||
_put('network_state', hostData['network_state']);
|
||||
_put('position_state', hostData['position_state']);
|
||||
_put('storage', hostData['storage']);
|
||||
_put('sub_device', hostData['sub_device']);
|
||||
_put('alternate_land_point', hostData['alternate_land_point']);
|
||||
|
||||
if (hostData['air_conditioner'] is Map) {
|
||||
final ac = hostData['air_conditioner'] as Map;
|
||||
_put('air_conditioner_state', ac['air_conditioner_state']?.toString());
|
||||
_put('air_conditioner_switch_time', ac['switch_time']?.toString());
|
||||
// 🔥 优先处理空调信息(确保第一时间解析,避免与其他卡片显示不同步)
|
||||
final acData = hostData['air_conditioner'];
|
||||
if (acData is Map) {
|
||||
_put('air_conditioner', acData);
|
||||
|
||||
// 解析空调开关状态
|
||||
final acStateVal = int.tryParse(acData['air_conditioner_state']?.toString() ?? '') ?? -1;
|
||||
if (acStateVal == 0 || acStateVal == 1) {
|
||||
_put('air_conditioner_state', acStateVal.toString());
|
||||
}
|
||||
|
||||
// 解析空调运行时间
|
||||
final switchTime = acData['switch_time'];
|
||||
if (switchTime != null) {
|
||||
_put('air_conditioner_switch_time', '$switchTime');
|
||||
}
|
||||
}
|
||||
|
||||
_stationHostData.value = merged;
|
||||
// 同步写入静态缓存
|
||||
_cachedHostData
|
||||
..clear()
|
||||
..addAll(merged);
|
||||
// 同步写入按 gatewaySn 分区的静态缓存
|
||||
_cachedHostDataBySn[widget.station.gatewaySn] = Map<String, dynamic>.from(
|
||||
merged,
|
||||
);
|
||||
}
|
||||
|
||||
/// 🔥 页面重新激活时调用(从其他页面返回时)
|
||||
@@ -161,6 +198,9 @@ class _DroneStationDetailPageState extends State<DroneStationDetailPage> {
|
||||
@override
|
||||
void dispose() {
|
||||
_stationOsdSubscription?.cancel();
|
||||
// 只调用 stopListening 减少引用计数,不调用 dispose()
|
||||
// 因为 DroneOsdDataSource 是 LazySingleton,被列表页和详情页共享
|
||||
// 详情页退出后列表页可能仍需要该订阅
|
||||
_osdDataSource.stopListening();
|
||||
_stationHostData.dispose();
|
||||
_bloc.close();
|
||||
@@ -291,11 +331,14 @@ class _DroneStationDetailPageState extends State<DroneStationDetailPage> {
|
||||
|
||||
Widget _buildContent(UAVDetailEntity detail) {
|
||||
_detail = detail;
|
||||
_droneSn = detail.deviceSn;
|
||||
final newDroneSn = detail.deviceSn;
|
||||
|
||||
if (_droneSn != null && _droneSn!.isNotEmpty) {
|
||||
// 只在 droneSn 真正变化时才重新订阅,避免 Bloc 刷新时重复 startListening
|
||||
// 导致引用计数虚增、dispose 时无法真正取消订阅
|
||||
if (newDroneSn != null && newDroneSn.isNotEmpty && newDroneSn != _droneSn) {
|
||||
_droneSn = newDroneSn;
|
||||
_osdDataSource.startListening(
|
||||
deviceSn: _droneSn!,
|
||||
deviceSn: newDroneSn,
|
||||
gatewaySn: widget.station.gatewaySn,
|
||||
);
|
||||
}
|
||||
@@ -499,13 +542,18 @@ class _DroneStationDetailPageState extends State<DroneStationDetailPage> {
|
||||
String acStr = '未知';
|
||||
Color acColor = const Color(0xFF86909C);
|
||||
if (acState != null) {
|
||||
final state = int.tryParse(acState) ?? -1;
|
||||
if (state == 1) {
|
||||
// 🔥 增强兼容性:尝试多种数据格式(int、string等)
|
||||
final acValue = acState is int ? acState : int.tryParse(acState.toString()) ?? -1;
|
||||
if (acValue == 1) {
|
||||
acStr = '开启';
|
||||
acColor = const Color(0xFF00B42A);
|
||||
} else if (state == 0) {
|
||||
} else if (acValue == 0) {
|
||||
acStr = '关闭';
|
||||
acColor = const Color(0xFF86909C);
|
||||
} else if (acValue == 2) {
|
||||
// 部分设备使用 2 表示待机或其他状态
|
||||
acStr = '待机';
|
||||
acColor = const Color(0xFFFF7D00);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
|
||||
/// 底部导航栏组件
|
||||
class DeviceBottomNavBar extends StatelessWidget {
|
||||
@@ -15,9 +16,9 @@ class DeviceBottomNavBar extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
border: Border(
|
||||
top: BorderSide(color: const Color(0xFFF2F3F5), width: 0.5),
|
||||
top: BorderSide(color: context.appColors.divider, width: 0.5),
|
||||
),
|
||||
),
|
||||
child: SafeArea(
|
||||
@@ -26,30 +27,35 @@ class DeviceBottomNavBar extends StatelessWidget {
|
||||
child: Row(
|
||||
children: [
|
||||
_buildNavItem(
|
||||
context,
|
||||
icon: Icons.home_outlined,
|
||||
label: '首页',
|
||||
isSelected: currentIndex == 0,
|
||||
onTap: () => onTap(0),
|
||||
),
|
||||
_buildNavItem(
|
||||
context,
|
||||
icon: Icons.devices,
|
||||
label: '设备',
|
||||
isSelected: currentIndex == 1,
|
||||
onTap: () => onTap(1),
|
||||
),
|
||||
_buildNavItem(
|
||||
context,
|
||||
icon: Icons.notifications_outlined,
|
||||
label: '告警',
|
||||
isSelected: currentIndex == 2,
|
||||
onTap: () => onTap(2),
|
||||
),
|
||||
_buildNavItem(
|
||||
context,
|
||||
icon: Icons.assignment_outlined,
|
||||
label: '工单',
|
||||
isSelected: currentIndex == 3,
|
||||
onTap: () => onTap(3),
|
||||
),
|
||||
_buildNavItem(
|
||||
context,
|
||||
icon: Icons.person_outlined,
|
||||
label: '我的',
|
||||
isSelected: currentIndex == 4,
|
||||
@@ -62,7 +68,8 @@ class DeviceBottomNavBar extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildNavItem({
|
||||
Widget _buildNavItem(
|
||||
BuildContext context, {
|
||||
required IconData icon,
|
||||
required String label,
|
||||
required bool isSelected,
|
||||
@@ -78,7 +85,7 @@ class DeviceBottomNavBar extends StatelessWidget {
|
||||
icon,
|
||||
color: isSelected
|
||||
? const Color(0xFF004CFD)
|
||||
: const Color(0xFF86909C),
|
||||
: context.appColors.textTertiary,
|
||||
size: 24,
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
@@ -88,7 +95,7 @@ class DeviceBottomNavBar extends StatelessWidget {
|
||||
fontSize: 11,
|
||||
color: isSelected
|
||||
? const Color(0xFF004FFF)
|
||||
: const Color(0xFF86909C),
|
||||
: context.appColors.textTertiary,
|
||||
fontWeight: isSelected ? FontWeight.w500 : FontWeight.normal,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -166,10 +166,29 @@ class _DroneOsdCardState extends State<DroneOsdCard> {
|
||||
oldWidget.gatewaySn != widget.gatewaySn ||
|
||||
oldWidget.isDroneOnline != widget.isDroneOnline) {
|
||||
_subscription?.cancel();
|
||||
// 切换机场/无人机:重置状态,避免显示上一个机场的旧数据
|
||||
_resetStateForNewDevice();
|
||||
_subscribeStream();
|
||||
}
|
||||
}
|
||||
|
||||
/// 切换到新机场/无人机时重置所有状态
|
||||
void _resetStateForNewDevice() {
|
||||
_hasReceivedData = false;
|
||||
_isWaitingForPush = droneTaskStateManager.isWaitingForOsdPush.value;
|
||||
_localWaitTimeoutTimer?.cancel();
|
||||
if (_isWaitingForPush) {
|
||||
_startLocalWaitTimeout();
|
||||
}
|
||||
// 重置所有字段为"未知"
|
||||
for (final def in _fieldDefs) {
|
||||
_valueNotifiers[def.key]?.value = '未知';
|
||||
_colorNotifiers[def.key]?.value = def.defaultColor;
|
||||
}
|
||||
// 触发一次重建以切换回离线/等待卡片
|
||||
if (mounted) setState(() {});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
droneTaskStateManager.isWaitingForOsdPush.removeListener(_onWaitingChanged);
|
||||
@@ -208,6 +227,12 @@ class _DroneOsdCardState extends State<DroneOsdCard> {
|
||||
}
|
||||
|
||||
void _parseOsdFields(DroneOsdEntity osd) {
|
||||
// 防护:验证消息来源 SN 是否匹配当前无人机,避免串台
|
||||
final sourceSn = osd.rawData['_sourceSn'];
|
||||
if (sourceSn != null && sourceSn != widget.deviceSn) {
|
||||
return;
|
||||
}
|
||||
|
||||
final data = osd.rawData;
|
||||
final dataMap = data['data'] is Map ? data['data'] as Map : null;
|
||||
Map? droneData;
|
||||
|
||||
@@ -182,9 +182,9 @@ class _DroneStationOsdCardState extends State<DroneStationOsdCard> {
|
||||
final Map<String, ValueNotifier<String>> _valueNotifiers = {};
|
||||
final Map<String, ValueNotifier<Color>> _colorNotifiers = {};
|
||||
|
||||
/// 静态缓存:跨页面实例保留上次收到的值,进入页面立即显示
|
||||
static final Map<String, String> _cachedValues = {};
|
||||
static final Map<String, Color> _cachedColors = {};
|
||||
/// 静态缓存:按 gatewaySn 分区,每个机场独立缓存
|
||||
static final Map<String, Map<String, String>> _cachedValuesBySn = {};
|
||||
static final Map<String, Map<String, Color>> _cachedColorsBySn = {};
|
||||
|
||||
/// 是否已收到过有效数据(用于首次标记)
|
||||
bool _hasReceivedData = false;
|
||||
@@ -197,17 +197,18 @@ class _DroneStationOsdCardState extends State<DroneStationOsdCard> {
|
||||
}
|
||||
|
||||
void _initNotifiers() {
|
||||
final sn = widget.gatewaySn;
|
||||
final cachedVals = _cachedValuesBySn[sn] ?? {};
|
||||
final cachedCols = _cachedColorsBySn[sn] ?? {};
|
||||
for (final def in _fieldDefs) {
|
||||
// 优先用缓存值,没有缓存则显示'未知'
|
||||
_valueNotifiers[def.key] = ValueNotifier(
|
||||
_cachedValues[def.key] ?? '未知',
|
||||
);
|
||||
// 优先用该机场的缓存值,没有缓存则显示'未知'
|
||||
_valueNotifiers[def.key] = ValueNotifier(cachedVals[def.key] ?? '未知');
|
||||
_colorNotifiers[def.key] = ValueNotifier(
|
||||
_cachedColors[def.key] ?? def.defaultColor,
|
||||
cachedCols[def.key] ?? def.defaultColor,
|
||||
);
|
||||
}
|
||||
// 如果有缓存数据,标记为已收到
|
||||
if (_cachedValues.isNotEmpty) {
|
||||
// 如果该机场有缓存数据,标记为已收到
|
||||
if (cachedVals.isNotEmpty) {
|
||||
_hasReceivedData = true;
|
||||
}
|
||||
}
|
||||
@@ -218,10 +219,39 @@ class _DroneStationOsdCardState extends State<DroneStationOsdCard> {
|
||||
if (oldWidget.gatewaySn != widget.gatewaySn ||
|
||||
oldWidget.isOnline != widget.isOnline) {
|
||||
_subscription?.cancel();
|
||||
// 切换机场:重置状态,立即清空旧机场数据
|
||||
_resetStateForNewDevice();
|
||||
_subscribeStream();
|
||||
}
|
||||
}
|
||||
|
||||
/// 切换到新机场时重置所有状态
|
||||
/// 优先从静态缓存加载该机场的历史数据(实现切回时立即显示)
|
||||
/// 无缓存则重置为"未知",避免显示上一个机场的旧数据
|
||||
void _resetStateForNewDevice() {
|
||||
final sn = widget.gatewaySn;
|
||||
final cachedVals = _cachedValuesBySn[sn] ?? {};
|
||||
final cachedCols = _cachedColorsBySn[sn] ?? {};
|
||||
|
||||
_hasReceivedData = cachedVals.isNotEmpty;
|
||||
|
||||
for (final def in _fieldDefs) {
|
||||
final newVal = cachedVals[def.key] ?? '未知';
|
||||
final newCol = cachedCols[def.key] ?? def.defaultColor;
|
||||
final vNotifier = _valueNotifiers[def.key];
|
||||
if (vNotifier != null && vNotifier.value != newVal) {
|
||||
vNotifier.value = newVal;
|
||||
}
|
||||
final cNotifier = _colorNotifiers[def.key];
|
||||
if (cNotifier != null && cNotifier.value != newCol) {
|
||||
cNotifier.value = newCol;
|
||||
}
|
||||
}
|
||||
|
||||
// 触发一次重建以切换离线/数据卡片显示
|
||||
if (mounted) setState(() {});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_subscription?.cancel();
|
||||
@@ -246,10 +276,11 @@ class _DroneStationOsdCardState extends State<DroneStationOsdCard> {
|
||||
/// 更新单个字段的值和颜色(仅当值变化时才触发 ValueNotifier 重建)
|
||||
/// 同时写入静态缓存,下次进入页面可立即显示
|
||||
void _updateField(String key, String value, [Color? color]) {
|
||||
// 写入缓存
|
||||
_cachedValues[key] = value;
|
||||
// 写入该机场的缓存
|
||||
final sn = widget.gatewaySn;
|
||||
_cachedValuesBySn.putIfAbsent(sn, () => {})[key] = value;
|
||||
if (color != null) {
|
||||
_cachedColors[key] = color;
|
||||
_cachedColorsBySn.putIfAbsent(sn, () => {})[key] = color;
|
||||
}
|
||||
final vNotifier = _valueNotifiers[key];
|
||||
if (vNotifier != null && vNotifier.value != value) {
|
||||
@@ -263,13 +294,19 @@ class _DroneStationOsdCardState extends State<DroneStationOsdCard> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _parseOsdFields(DroneOsdEntity osd) {
|
||||
// 防护:验证消息来源 SN 是否匹配当前机场,避免串台
|
||||
final sourceSn = osd.rawData['_sourceSn'];
|
||||
if (sourceSn != null && sourceSn != widget.gatewaySn) {
|
||||
return;
|
||||
}
|
||||
|
||||
final data = osd.rawData;
|
||||
final hostData = data['data'] is Map ? (data['data'] as Map)['host'] : null;
|
||||
if (hostData == null || hostData is! Map) {
|
||||
debugPrint('⚠️ [StationOsdCard] hostData 为空,rawData keys: ${data.keys.toList()}');
|
||||
debugPrint(
|
||||
'⚠️ [StationOsdCard] hostData 为空,rawData keys: ${data.keys.toList()}',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -278,17 +315,35 @@ class _DroneStationOsdCardState extends State<DroneStationOsdCard> {
|
||||
|
||||
// 🔥 调试日志:对比卡片期望的字段 vs 实际推送中存在的字段
|
||||
final expectedKeys = [
|
||||
'air_conditioner', 'cover_state', 'putter_state', 'supplement_light_state',
|
||||
'temperature', 'drone_in_dock', 'drone_charge_state', 'humidity',
|
||||
'wind_speed', 'rainfall', 'environment_temperature', 'alarm_state',
|
||||
'emergency_stop_state', 'silent_mode', 'mode_code', 'network_state',
|
||||
'position_state', 'storage', 'heading', 'height', 'sub_device',
|
||||
'air_conditioner',
|
||||
'cover_state',
|
||||
'putter_state',
|
||||
'supplement_light_state',
|
||||
'temperature',
|
||||
'drone_in_dock',
|
||||
'drone_charge_state',
|
||||
'humidity',
|
||||
'wind_speed',
|
||||
'rainfall',
|
||||
'environment_temperature',
|
||||
'alarm_state',
|
||||
'emergency_stop_state',
|
||||
'silent_mode',
|
||||
'mode_code',
|
||||
'network_state',
|
||||
'position_state',
|
||||
'storage',
|
||||
'heading',
|
||||
'height',
|
||||
'sub_device',
|
||||
'battery_store_mode',
|
||||
];
|
||||
final hostMap = hostData as Map;
|
||||
final found = expectedKeys.where((k) => hostMap.containsKey(k)).toList();
|
||||
final missing = expectedKeys.where((k) => !hostMap.containsKey(k)).toList();
|
||||
debugPrint('[StationOsdCard] host keys(${hostMap.length}): ${hostMap.keys.join(", ")}');
|
||||
debugPrint(
|
||||
'[StationOsdCard] host keys(${hostMap.length}): ${hostMap.keys.join(", ")}',
|
||||
);
|
||||
debugPrint('[StationOsdCard] matched: ${found.join(", ")}');
|
||||
if (missing.isNotEmpty) {
|
||||
debugPrint('[StationOsdCard] MISSING: ${missing.join(", ")}');
|
||||
@@ -303,9 +358,7 @@ class _DroneStationOsdCardState extends State<DroneStationOsdCard> {
|
||||
_updateField(
|
||||
'acState',
|
||||
acState == 1 ? '开启' : '关闭',
|
||||
acState == 1
|
||||
? const Color(0xFF00B42A)
|
||||
: const Color(0xFF86909C),
|
||||
acState == 1 ? const Color(0xFF00B42A) : const Color(0xFF86909C),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -322,9 +375,7 @@ class _DroneStationOsdCardState extends State<DroneStationOsdCard> {
|
||||
_updateField(
|
||||
'coverState',
|
||||
coverState == 1 ? '开启' : '关闭',
|
||||
coverState == 1
|
||||
? const Color(0xFFFF7D00)
|
||||
: const Color(0xFF00B42A),
|
||||
coverState == 1 ? const Color(0xFFFF7D00) : const Color(0xFF00B42A),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -335,23 +386,19 @@ class _DroneStationOsdCardState extends State<DroneStationOsdCard> {
|
||||
_updateField(
|
||||
'putterState',
|
||||
putterState == 1 ? '动作中' : '归位',
|
||||
putterState == 1
|
||||
? const Color(0xFFFF7D00)
|
||||
: const Color(0xFF00B42A),
|
||||
putterState == 1 ? const Color(0xFFFF7D00) : const Color(0xFF00B42A),
|
||||
);
|
||||
}
|
||||
|
||||
// 补光灯
|
||||
final lightState =
|
||||
int.tryParse(hostData['supplement_light_state']?.toString() ?? '') ??
|
||||
-1;
|
||||
-1;
|
||||
if (lightState == 0 || lightState == 1) {
|
||||
_updateField(
|
||||
'lightState',
|
||||
lightState == 1 ? '开启' : '关闭',
|
||||
lightState == 1
|
||||
? const Color(0xFFFF7D00)
|
||||
: const Color(0xFF86909C),
|
||||
lightState == 1 ? const Color(0xFFFF7D00) : const Color(0xFF86909C),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -376,9 +423,7 @@ class _DroneStationOsdCardState extends State<DroneStationOsdCard> {
|
||||
_updateField(
|
||||
'droneDock',
|
||||
droneDock == 1 ? '在库内' : '出库',
|
||||
droneDock == 1
|
||||
? const Color(0xFF00B42A)
|
||||
: const Color(0xFFFF7D00),
|
||||
droneDock == 1 ? const Color(0xFF00B42A) : const Color(0xFFFF7D00),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -391,9 +436,7 @@ class _DroneStationOsdCardState extends State<DroneStationOsdCard> {
|
||||
_updateField(
|
||||
'chargeState',
|
||||
chargeState == 1 ? '充电中' : '未充电',
|
||||
chargeState == 1
|
||||
? const Color(0xFFFF7D00)
|
||||
: const Color(0xFF86909C),
|
||||
chargeState == 1 ? const Color(0xFFFF7D00) : const Color(0xFF86909C),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -423,21 +466,18 @@ class _DroneStationOsdCardState extends State<DroneStationOsdCard> {
|
||||
}
|
||||
|
||||
// 降雨
|
||||
final rainfall =
|
||||
int.tryParse(hostData['rainfall']?.toString() ?? '') ?? -1;
|
||||
final rainfall = int.tryParse(hostData['rainfall']?.toString() ?? '') ?? -1;
|
||||
if (rainfall >= 0) {
|
||||
_updateField(
|
||||
'rainfall',
|
||||
rainfall == 1 ? '降雨中' : '无降雨',
|
||||
rainfall == 1
|
||||
? const Color(0xFF165DFF)
|
||||
: const Color(0xFF00B42A),
|
||||
rainfall == 1 ? const Color(0xFF165DFF) : const Color(0xFF00B42A),
|
||||
);
|
||||
}
|
||||
|
||||
// 外部温度
|
||||
final externalTemp =
|
||||
(hostData['environment_temperature'] as num?)?.toDouble();
|
||||
final externalTemp = (hostData['environment_temperature'] as num?)
|
||||
?.toDouble();
|
||||
if (externalTemp != null) {
|
||||
_updateField(
|
||||
'externalTemp',
|
||||
@@ -457,23 +497,18 @@ class _DroneStationOsdCardState extends State<DroneStationOsdCard> {
|
||||
_updateField(
|
||||
'alarmState',
|
||||
alarmState != 0 ? '告警中' : '无告警',
|
||||
alarmState != 0
|
||||
? const Color(0xFFF53F3F)
|
||||
: const Color(0xFF00B42A),
|
||||
alarmState != 0 ? const Color(0xFFF53F3F) : const Color(0xFF00B42A),
|
||||
);
|
||||
}
|
||||
|
||||
// 急停状态
|
||||
if (hostData.containsKey('emergency_stop_state')) {
|
||||
final emergencyStop =
|
||||
int.tryParse(hostData['emergency_stop_state']?.toString() ?? '') ??
|
||||
0;
|
||||
int.tryParse(hostData['emergency_stop_state']?.toString() ?? '') ?? 0;
|
||||
_updateField(
|
||||
'emergencyStop',
|
||||
emergencyStop == 1 ? '已触发' : '未触发',
|
||||
emergencyStop == 1
|
||||
? const Color(0xFFF53F3F)
|
||||
: const Color(0xFF00B42A),
|
||||
emergencyStop == 1 ? const Color(0xFFF53F3F) : const Color(0xFF00B42A),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -484,9 +519,7 @@ class _DroneStationOsdCardState extends State<DroneStationOsdCard> {
|
||||
_updateField(
|
||||
'silentMode',
|
||||
silentMode == 1 ? '开启' : '关闭',
|
||||
silentMode == 1
|
||||
? const Color(0xFFFF7D00)
|
||||
: const Color(0xFF86909C),
|
||||
silentMode == 1 ? const Color(0xFFFF7D00) : const Color(0xFF86909C),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -577,7 +610,6 @@ class _DroneStationOsdCardState extends State<DroneStationOsdCard> {
|
||||
: const Color(0xFF86909C),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -2,10 +2,10 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:maibu_satabot_v2/core/di/injection.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/message_center/domain/entities/message_category_entity.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/message_center/presentation/bloc/message_center_cubit.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/message_center/presentation/bloc/message_center_state.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/waring_center/presentation/constants/alarm_constants.dart';
|
||||
|
||||
/// 消息中心页面
|
||||
class MessageCenterPage extends StatelessWidget {
|
||||
@@ -28,7 +28,7 @@ class MessageCenterView extends StatelessWidget {
|
||||
final cubit = context.read<MessageCenterCubit>();
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: AlarmColors.background,
|
||||
backgroundColor: context.appColors.pageBackground,
|
||||
body: BlocConsumer<MessageCenterCubit, MessageCenterState>(
|
||||
listener: (context, state) {
|
||||
if (state is MessageCenterActionInProgress) {
|
||||
@@ -70,11 +70,11 @@ class MessageCenterView extends StatelessWidget {
|
||||
// 右侧:一键已读按钮
|
||||
GestureDetector(
|
||||
onTap: () => cubit.markAllAsRead(),
|
||||
child: const Text(
|
||||
child: Text(
|
||||
'一键已读',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: AlarmColors.primary,
|
||||
color: context.appColors.primary,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
@@ -95,15 +95,15 @@ class MessageCenterView extends StatelessWidget {
|
||||
return DropdownButton<MessageType>(
|
||||
value: selectedType,
|
||||
underline: const SizedBox(),
|
||||
icon: const Icon(
|
||||
icon: Icon(
|
||||
Icons.keyboard_arrow_down,
|
||||
size: 20,
|
||||
color: AlarmColors.textSecondary,
|
||||
color: context.appColors.textSecondary,
|
||||
),
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AlarmColors.textPrimary,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
items: MessageType.values.map((type) {
|
||||
return DropdownMenuItem<MessageType>(
|
||||
@@ -123,7 +123,7 @@ class MessageCenterView extends StatelessWidget {
|
||||
|
||||
Widget _buildContent(BuildContext context, MessageCenterState state) {
|
||||
if (state is MessageCenterLoading) {
|
||||
return _buildSkeletonScreen();
|
||||
return _buildSkeletonScreen(context);
|
||||
}
|
||||
if (state is MessageCenterError) {
|
||||
return _buildErrorState(context, state.message);
|
||||
@@ -142,9 +142,9 @@ class MessageCenterView extends StatelessWidget {
|
||||
return Center(
|
||||
child: Text(
|
||||
'暂无消息',
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: AlarmColors.textSecondary,
|
||||
color: context.appColors.textSecondary,
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -176,7 +176,7 @@ class MessageCenterView extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildSkeletonScreen() {
|
||||
Widget _buildSkeletonScreen(BuildContext context) {
|
||||
return ListView.separated(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
itemCount: 6,
|
||||
@@ -185,11 +185,11 @@ class MessageCenterView extends StatelessWidget {
|
||||
return Container(
|
||||
height: 80,
|
||||
decoration: BoxDecoration(
|
||||
color: AlarmColors.background,
|
||||
borderRadius: BorderRadius.circular(AlarmDimensions.borderRadius),
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
child: Center(
|
||||
child: CircularProgressIndicator(color: context.appColors.primary),
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -204,14 +204,14 @@ class MessageCenterView extends StatelessWidget {
|
||||
Icon(
|
||||
Icons.error_outline,
|
||||
size: 64,
|
||||
color: AlarmColors.danger,
|
||||
color: context.appColors.danger,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
message,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: AlarmColors.textSecondary,
|
||||
color: context.appColors.textSecondary,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
@@ -244,19 +244,19 @@ class MessageCenterView extends StatelessWidget {
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(24),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const CircularProgressIndicator(),
|
||||
CircularProgressIndicator(color: context.appColors.primary),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'$action中...',
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: AlarmColors.textSecondary,
|
||||
color: context.appColors.textSecondary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -288,8 +288,8 @@ class _MessageCategoryCard extends StatelessWidget {
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: AlarmColors.background,
|
||||
borderRadius: BorderRadius.circular(AlarmDimensions.borderRadius),
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
@@ -307,16 +307,16 @@ class _MessageCategoryCard extends StatelessWidget {
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: isUnread ? FontWeight.bold : FontWeight.w500,
|
||||
color: AlarmColors.textPrimary,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
// 内容摘要
|
||||
Text(
|
||||
message.content,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: AlarmColors.textSecondary,
|
||||
color: context.appColors.textSecondary,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
@@ -330,13 +330,13 @@ class _MessageCategoryCard extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
// 未读角标
|
||||
if (isUnread) _buildUnreadBadge(),
|
||||
if (isUnread) _buildUnreadBadge(context),
|
||||
// 时间
|
||||
Text(
|
||||
message.time,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: AlarmColors.textSecondary,
|
||||
color: context.appColors.textSecondary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -391,13 +391,13 @@ class _MessageCategoryCard extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildUnreadBadge() {
|
||||
Widget _buildUnreadBadge(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 4),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: AlarmColors.danger,
|
||||
color: context.appColors.danger,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Text(
|
||||
|
||||
@@ -3,6 +3,8 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:maibu_satabot_v2/core/app/app_user_cubit.dart';
|
||||
import 'package:maibu_satabot_v2/core/localization/app_localizations.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/theme_cubit.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/my/presentation/cubit/my_cubit.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/my/presentation/states/my_state.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/my/di/my_di.dart';
|
||||
@@ -38,7 +40,7 @@ class _MyPageContent extends StatelessWidget {
|
||||
),
|
||||
child: Scaffold(
|
||||
extendBodyBehindAppBar: true,
|
||||
backgroundColor: MyColors.background,
|
||||
backgroundColor: context.appColors.pageBackground,
|
||||
body: BlocConsumer<MyCubit, MyState>(
|
||||
listener: (context, state) {
|
||||
if (state is MyError) {
|
||||
@@ -59,6 +61,9 @@ class _MyPageContent extends StatelessWidget {
|
||||
final appUserState = context.watch<AppUserCubit>().state;
|
||||
final user = appUserState.user;
|
||||
|
||||
// 🔥 监听全局主题状态,夜间模式开关的真实值以 ThemeCubit 为准
|
||||
final isDarkMode = context.watch<ThemeCubit>().isDarkMode;
|
||||
|
||||
// 获取用户信息(优先使用昵称,其次用户名)
|
||||
final userName = user?.nickname ?? user?.username ?? '未知用户';
|
||||
final userRole = user?.email ?? user?.phone ?? '未设置';
|
||||
@@ -104,11 +109,11 @@ class _MyPageContent extends StatelessWidget {
|
||||
bottom: 16,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: const Color(0x0D000000),
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -123,11 +128,22 @@ class _MyPageContent extends StatelessWidget {
|
||||
itemCount: state.menuItems.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = state.menuItems[index];
|
||||
// 🔥 夜间模式开关值以全局 ThemeCubit 状态为准
|
||||
final displayItem = item.id == 'night_mode'
|
||||
? item.copyWith(switchValue: isDarkMode)
|
||||
: item;
|
||||
return MenuItemCard(
|
||||
item: item,
|
||||
item: displayItem,
|
||||
onTap: () => _handleMenuItemTap(context, cubit, item),
|
||||
onSwitchChanged: item.hasSwitch
|
||||
? (value) => cubit.toggleNightMode(value)
|
||||
? (value) {
|
||||
// 更新菜单 UI 状态
|
||||
cubit.toggleNightMode(value);
|
||||
// 🔥 真正切换全局主题
|
||||
context
|
||||
.read<ThemeCubit>()
|
||||
.toggleDarkMode(value);
|
||||
}
|
||||
: null,
|
||||
);
|
||||
},
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:maibu_satabot_v2/core/app/app_user_cubit.dart';
|
||||
import 'package:maibu_satabot_v2/core/app/app_user_state.dart';
|
||||
import 'package:maibu_satabot_v2/core/domain/entities/user_entity.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
|
||||
/// 个人信息详情页
|
||||
class ProfileDetailPage extends StatelessWidget {
|
||||
@@ -11,12 +12,11 @@ class ProfileDetailPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xFFF5F7FA),
|
||||
backgroundColor: context.appColors.pageBackground,
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.white,
|
||||
elevation: 0,
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back, color: Color(0xFF1D2129)),
|
||||
icon: Icon(Icons.arrow_back, color: context.appColors.textPrimary),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
title: const Text(
|
||||
@@ -24,7 +24,6 @@ class ProfileDetailPage extends StatelessWidget {
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFF1D2129),
|
||||
),
|
||||
),
|
||||
centerTitle: true,
|
||||
@@ -43,11 +42,11 @@ class ProfileDetailPage extends StatelessWidget {
|
||||
padding: const EdgeInsets.all(16),
|
||||
children: [
|
||||
// 头像卡片
|
||||
_buildAvatarCard(user),
|
||||
_buildAvatarCard(context, user),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 信息列表
|
||||
_buildInfoCard(user),
|
||||
_buildInfoCard(context, user),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 操作按钮
|
||||
@@ -60,15 +59,15 @@ class ProfileDetailPage extends StatelessWidget {
|
||||
}
|
||||
|
||||
/// 头像卡片
|
||||
Widget _buildAvatarCard(UserEntity user) {
|
||||
Widget _buildAvatarCard(BuildContext context, UserEntity user) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 32),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: const Color(0x0D000000),
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -95,10 +94,10 @@ class ProfileDetailPage extends StatelessWidget {
|
||||
// 昵称
|
||||
Text(
|
||||
user.nickname,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFF1D2129),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
@@ -107,7 +106,7 @@ class ProfileDetailPage extends StatelessWidget {
|
||||
'@${user.username}',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: const Color(0xFF86909C),
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -142,14 +141,14 @@ class ProfileDetailPage extends StatelessWidget {
|
||||
}
|
||||
|
||||
/// 信息卡片
|
||||
Widget _buildInfoCard(UserEntity user) {
|
||||
Widget _buildInfoCard(BuildContext context, UserEntity user) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: const Color(0x0D000000),
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -158,18 +157,21 @@ class ProfileDetailPage extends StatelessWidget {
|
||||
child: Column(
|
||||
children: [
|
||||
_buildInfoItem(
|
||||
context,
|
||||
icon: Icons.person_outline,
|
||||
label: '用户ID',
|
||||
value: user.userId,
|
||||
showDivider: true,
|
||||
),
|
||||
_buildInfoItem(
|
||||
context,
|
||||
icon: Icons.account_circle_outlined,
|
||||
label: '用户名',
|
||||
value: user.username,
|
||||
showDivider: true,
|
||||
),
|
||||
_buildInfoItem(
|
||||
context,
|
||||
icon: Icons.badge_outlined,
|
||||
label: '昵称',
|
||||
value: user.nickname,
|
||||
@@ -177,6 +179,7 @@ class ProfileDetailPage extends StatelessWidget {
|
||||
),
|
||||
if (user.email != null)
|
||||
_buildInfoItem(
|
||||
context,
|
||||
icon: Icons.email_outlined,
|
||||
label: '邮箱',
|
||||
value: user.email!,
|
||||
@@ -184,6 +187,7 @@ class ProfileDetailPage extends StatelessWidget {
|
||||
),
|
||||
if (user.phone != null)
|
||||
_buildInfoItem(
|
||||
context,
|
||||
icon: Icons.phone_outlined,
|
||||
label: '手机号',
|
||||
value: user.phone!,
|
||||
@@ -195,7 +199,8 @@ class ProfileDetailPage extends StatelessWidget {
|
||||
}
|
||||
|
||||
/// 信息项
|
||||
Widget _buildInfoItem({
|
||||
Widget _buildInfoItem(
|
||||
BuildContext context, {
|
||||
required IconData icon,
|
||||
required String label,
|
||||
required String value,
|
||||
@@ -207,13 +212,13 @@ class ProfileDetailPage extends StatelessWidget {
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(icon, size: 22, color: const Color(0xFF86909C)),
|
||||
Icon(icon, size: 22, color: context.appColors.textTertiary),
|
||||
const SizedBox(width: 12),
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
color: Color(0xFF86909C),
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
@@ -221,9 +226,9 @@ class ProfileDetailPage extends StatelessWidget {
|
||||
flex: 2,
|
||||
child: Text(
|
||||
value,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
color: Color(0xFF1D2129),
|
||||
color: context.appColors.textPrimary,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
textAlign: TextAlign.right,
|
||||
@@ -237,7 +242,7 @@ class ProfileDetailPage extends StatelessWidget {
|
||||
Divider(
|
||||
height: 1,
|
||||
thickness: 1,
|
||||
color: const Color(0xFFF2F3F5),
|
||||
color: context.appColors.divider,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:go_router/go_router.dart';
|
||||
import 'package:maibu_satabot_v2/core/localization/app_localizations.dart';
|
||||
import 'package:maibu_satabot_v2/core/localization/locale_cubit.dart';
|
||||
import 'package:maibu_satabot_v2/core/router/route_paths.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import 'package:maibu_satabot_v2/core/storage/user_storage.dart';
|
||||
import 'package:maibu_satabot_v2/features/auth/presentation/bloc/auth_cubit.dart';
|
||||
import 'package:maibu_satabot_v2/features/main_container/presentation/cubit/tab_config_cubit.dart';
|
||||
@@ -22,20 +23,19 @@ class _SystemSettingsPageState extends State<SystemSettingsPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xFFF5F6F8),
|
||||
backgroundColor: context.appColors.pageBackground,
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.white,
|
||||
elevation: 0,
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back, color: Color(0xFF1D2129)),
|
||||
icon: Icon(Icons.arrow_back, color: context.appColors.textPrimary),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
title: Text(
|
||||
AppLocalizations.of(context).translate('my.settings'),
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFF1D2129),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
centerTitle: true,
|
||||
@@ -65,11 +65,11 @@ class _SystemSettingsPageState extends State<SystemSettingsPage> {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: const [
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Color(0x0D000000),
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 8,
|
||||
offset: Offset(0, 2),
|
||||
),
|
||||
@@ -83,10 +83,10 @@ class _SystemSettingsPageState extends State<SystemSettingsPage> {
|
||||
children: [
|
||||
Text(
|
||||
AppLocalizations.of(context).translate('my_v2.suspend_bar'),
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFF1D2129),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
@@ -94,9 +94,9 @@ class _SystemSettingsPageState extends State<SystemSettingsPage> {
|
||||
AppLocalizations.of(
|
||||
context,
|
||||
).translate('my_v2.suspend_bar_desc'),
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: Color(0xFF86909C),
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -124,11 +124,11 @@ class _SystemSettingsPageState extends State<SystemSettingsPage> {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: const [
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Color(0x0D000000),
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 8,
|
||||
offset: Offset(0, 2),
|
||||
),
|
||||
@@ -139,10 +139,10 @@ class _SystemSettingsPageState extends State<SystemSettingsPage> {
|
||||
children: [
|
||||
Text(
|
||||
AppLocalizations.of(context).translate('my_v2.tab_settings'),
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFF1D2129),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
@@ -167,9 +167,9 @@ class _SystemSettingsPageState extends State<SystemSettingsPage> {
|
||||
Expanded(
|
||||
child: Text(
|
||||
tab.name,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Color(0xFF1D2129),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -197,11 +197,11 @@ class _SystemSettingsPageState extends State<SystemSettingsPage> {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: const [
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Color(0x0D000000),
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 8,
|
||||
offset: Offset(0, 2),
|
||||
),
|
||||
@@ -212,10 +212,10 @@ class _SystemSettingsPageState extends State<SystemSettingsPage> {
|
||||
children: [
|
||||
Text(
|
||||
AppLocalizations.of(context).translate('my.language'),
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFF1D2129),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
@@ -267,7 +267,7 @@ class _SystemSettingsPageState extends State<SystemSettingsPage> {
|
||||
border: Border.all(
|
||||
color: isSelected
|
||||
? const Color(0xFF165DFF)
|
||||
: const Color(0xFFE5E6EB),
|
||||
: context.appColors.divider,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
@@ -280,7 +280,7 @@ class _SystemSettingsPageState extends State<SystemSettingsPage> {
|
||||
fontSize: 14,
|
||||
color: isSelected
|
||||
? const Color(0xFF165DFF)
|
||||
: const Color(0xFF1D2129),
|
||||
: context.appColors.textPrimary,
|
||||
fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal,
|
||||
),
|
||||
),
|
||||
@@ -306,11 +306,11 @@ class _SystemSettingsPageState extends State<SystemSettingsPage> {
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: const [
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Color(0x0D000000),
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 8,
|
||||
offset: Offset(0, 2),
|
||||
),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:maibu_satabot_v2/core/localization/app_localizations.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/my/domain/entities/my_entities.dart';
|
||||
|
||||
/// 菜单项卡片组件(100% 还原设计稿)
|
||||
@@ -32,17 +33,17 @@ class MenuItemCard extends StatelessWidget {
|
||||
Icon(
|
||||
_getIconData(item.icon),
|
||||
size: 20,
|
||||
color: const Color(0xFF4E5969),
|
||||
color: context.appColors.textSecondary,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
// 标题
|
||||
Expanded(
|
||||
child: Text(
|
||||
_getLocalizedTitle(context, item),
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF1D2129),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
@@ -53,9 +54,9 @@ class MenuItemCard extends StatelessWidget {
|
||||
Flexible(
|
||||
child: Text(
|
||||
item.subTitle!,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: Color(0xFF86909C),
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
@@ -73,14 +74,14 @@ class MenuItemCard extends StatelessWidget {
|
||||
activeTrackColor: const Color(
|
||||
0xFF165DFF,
|
||||
).withOpacity(0.3),
|
||||
inactiveThumbColor: const Color(0xFFC9CDD4),
|
||||
inactiveTrackColor: const Color(0xFFE5E6EB),
|
||||
inactiveThumbColor: context.appColors.textTertiary,
|
||||
inactiveTrackColor: context.appColors.divider,
|
||||
),
|
||||
),
|
||||
],
|
||||
Icon(
|
||||
Icons.chevron_right,
|
||||
color: const Color(0xFFC9CDD4),
|
||||
color: context.appColors.textTertiary,
|
||||
size: 20,
|
||||
),
|
||||
],
|
||||
@@ -94,7 +95,7 @@ class MenuItemCard extends StatelessWidget {
|
||||
child: Divider(
|
||||
height: 1,
|
||||
thickness: 0.5,
|
||||
color: const Color(0xFFF0F0F0),
|
||||
color: context.appColors.divider,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:maibu_satabot_v2/core/localization/app_localizations.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/my/presentation/constants/my_constants.dart';
|
||||
|
||||
/// 快捷入口卡片组件(我的消息、我的收藏、我的工单)
|
||||
@@ -21,11 +22,11 @@ class QuickActionCard extends StatelessWidget {
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16),
|
||||
padding: const EdgeInsets.symmetric(vertical: 20),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: const Color(0x0D000000),
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -36,23 +37,26 @@ class QuickActionCard extends StatelessWidget {
|
||||
children: [
|
||||
// 我的消息
|
||||
_buildQuickActionItem(
|
||||
context,
|
||||
icon: Icons.notifications_outlined,
|
||||
label: AppLocalizations.of(context).translate('my_v2.message'),
|
||||
onTap: onMessageTap,
|
||||
showBadge: true,
|
||||
),
|
||||
// 分割线
|
||||
Container(width: 1, height: 40, color: const Color(0xFFF0F0F0)),
|
||||
Container(width: 1, height: 40, color: context.appColors.divider),
|
||||
// 我的收藏
|
||||
_buildQuickActionItem(
|
||||
context,
|
||||
icon: Icons.favorite_border,
|
||||
label: AppLocalizations.of(context).translate('my_v2.favorite'),
|
||||
onTap: onFavoriteTap,
|
||||
),
|
||||
// 分割线
|
||||
Container(width: 1, height: 40, color: const Color(0xFFF0F0F0)),
|
||||
Container(width: 1, height: 40, color: context.appColors.divider),
|
||||
// 我的工单
|
||||
_buildQuickActionItem(
|
||||
context,
|
||||
icon: Icons.assignment_outlined,
|
||||
label: AppLocalizations.of(context).translate('my_v2.work_order'),
|
||||
onTap: onWorkOrderTap,
|
||||
@@ -62,7 +66,8 @@ class QuickActionCard extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildQuickActionItem({
|
||||
Widget _buildQuickActionItem(
|
||||
BuildContext context, {
|
||||
required IconData icon,
|
||||
required String label,
|
||||
required VoidCallback onTap,
|
||||
@@ -98,9 +103,9 @@ class QuickActionCard extends StatelessWidget {
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: MyColors.textSecondary,
|
||||
color: context.appColors.textSecondary,
|
||||
),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
|
||||
@@ -1,18 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// 全局颜色常量
|
||||
class AppColors {
|
||||
static const Color primary = Color(0xFF165DFF);
|
||||
static const Color danger = Color(0xFFF53F3F);
|
||||
static const Color warning = Color(0xFFFF7D00);
|
||||
static const Color textPrimary = Color(0xFF1D2129);
|
||||
static const Color textSecondary = Color(0xFF4E5969);
|
||||
static const Color textHint = Color(0xFF86909C);
|
||||
static const Color background = Color(0xFFFFFFFF);
|
||||
static const Color cardBackground = Color(0xFFF8F9FA);
|
||||
static const Color borderColor = Color(0xFFE5E6EB);
|
||||
}
|
||||
|
||||
/// 全局尺寸常量
|
||||
class AppDimensions {
|
||||
static const double borderRadius = 16.0;
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import '../cubit/report_cubit.dart';
|
||||
import '../states/report_state.dart';
|
||||
import '../constants/report_constants.dart';
|
||||
@@ -30,10 +31,11 @@ class _ReportPageContent extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle.dark,
|
||||
value: isDark ? SystemUiOverlayStyle.light : SystemUiOverlayStyle.dark,
|
||||
child: Scaffold(
|
||||
backgroundColor: AppColors.cardBackground,
|
||||
backgroundColor: context.appColors.pageBackground,
|
||||
body: BlocConsumer<ReportCubit, ReportState>(
|
||||
listener: (context, state) {
|
||||
if (state is ReportFormState) {
|
||||
@@ -60,8 +62,8 @@ class _ReportPageContent extends StatelessWidget {
|
||||
},
|
||||
builder: (context, state) {
|
||||
if (state is ReportSubmitting || state is ReportDevicesLoading) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(color: AppColors.primary),
|
||||
return Center(
|
||||
child: CircularProgressIndicator(color: context.appColors.primary),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -90,7 +92,7 @@ class _ReportPageContent extends StatelessWidget {
|
||||
return PreferredSize(
|
||||
preferredSize: const Size.fromHeight(100),
|
||||
child: Container(
|
||||
color: AppColors.background,
|
||||
color: context.appColors.cardBackground,
|
||||
child: SafeArea(
|
||||
bottom: false,
|
||||
child: Padding(
|
||||
@@ -102,22 +104,22 @@ class _ReportPageContent extends StatelessWidget {
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
'现场上报',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.textPrimary,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
context.read<ReportCubit>().submitReport();
|
||||
},
|
||||
child: const Text(
|
||||
child: Text(
|
||||
'提交',
|
||||
style: TextStyle(
|
||||
color: AppColors.primary,
|
||||
color: context.appColors.primary,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
@@ -132,9 +134,9 @@ class _ReportPageContent extends StatelessWidget {
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(
|
||||
Icon(
|
||||
Icons.location_on,
|
||||
color: AppColors.primary,
|
||||
color: context.appColors.primary,
|
||||
size: 16,
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
@@ -143,7 +145,7 @@ class _ReportPageContent extends StatelessWidget {
|
||||
state.location,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: AppColors.textSecondary,
|
||||
color: context.appColors.textSecondary,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
@@ -153,7 +155,7 @@ class _ReportPageContent extends StatelessWidget {
|
||||
Icon(
|
||||
Icons.arrow_drop_down,
|
||||
size: 20,
|
||||
color: AppColors.textHint,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -327,7 +329,7 @@ class _ReportPageContent extends StatelessWidget {
|
||||
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: context.appColors.cardBackground,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
|
||||
),
|
||||
@@ -340,12 +342,12 @@ class _ReportPageContent extends StatelessWidget {
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
'选择场站',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFF1D2129),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 14),
|
||||
@@ -364,7 +366,7 @@ class _ReportPageContent extends StatelessWidget {
|
||||
? Text('站点编码: ${site.siteCode}')
|
||||
: null,
|
||||
trailing: isSelected
|
||||
? const Icon(Icons.check, color: Color(0xFF165DFF))
|
||||
? Icon(Icons.check, color: context.appColors.primary)
|
||||
: null,
|
||||
onTap: () {
|
||||
cubit.selectSite(site);
|
||||
@@ -462,12 +464,15 @@ class _ReportPageContent extends StatelessWidget {
|
||||
if (isRobotType) {
|
||||
if (newState.robots.isEmpty) {
|
||||
deviceList = [
|
||||
const Center(
|
||||
Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(32),
|
||||
child: Text(
|
||||
'暂无机器人数据',
|
||||
style: TextStyle(fontSize: 14, color: Color(0xFF86909C)),
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -492,12 +497,15 @@ class _ReportPageContent extends StatelessWidget {
|
||||
} else if (isDroneType) {
|
||||
if (newState.drones.isEmpty) {
|
||||
deviceList = [
|
||||
const Center(
|
||||
Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(32),
|
||||
child: Text(
|
||||
'暂无无人机数据',
|
||||
style: TextStyle(fontSize: 14, color: Color(0xFF86909C)),
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -520,7 +528,7 @@ class _ReportPageContent extends StatelessWidget {
|
||||
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: context.appColors.cardBackground,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
|
||||
),
|
||||
@@ -535,10 +543,10 @@ class _ReportPageContent extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
isRobotType ? '选择机器人' : '选择无人机',
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFF1D2129),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 14),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:maibu_satabot_v2/core/localization/app_localizations.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import '../constants/report_constants.dart';
|
||||
|
||||
/// 问题描述输入模块
|
||||
@@ -22,11 +23,11 @@ class DescriptionInput extends StatelessWidget {
|
||||
),
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.background,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(AppDimensions.borderRadius),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: const Color(0x0D000000),
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: AppDimensions.cardShadowBlur,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -37,10 +38,10 @@ class DescriptionInput extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
loc.translate('report.problem_description'),
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.textPrimary,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
@@ -50,37 +51,37 @@ class DescriptionInput extends StatelessWidget {
|
||||
onChanged: onChanged,
|
||||
decoration: InputDecoration(
|
||||
hintText: loc.translate('report.description_hint'),
|
||||
hintStyle: const TextStyle(color: AppColors.textHint),
|
||||
hintStyle: TextStyle(color: context.appColors.textTertiary),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
AppDimensions.borderRadiusSmall,
|
||||
),
|
||||
borderSide: const BorderSide(color: AppColors.borderColor),
|
||||
borderSide: BorderSide(color: context.appColors.divider),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
AppDimensions.borderRadiusSmall,
|
||||
),
|
||||
borderSide: const BorderSide(color: AppColors.borderColor),
|
||||
borderSide: BorderSide(color: context.appColors.divider),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
AppDimensions.borderRadiusSmall,
|
||||
),
|
||||
borderSide: const BorderSide(
|
||||
color: AppColors.primary,
|
||||
borderSide: BorderSide(
|
||||
color: context.appColors.primary,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
counterText: '',
|
||||
),
|
||||
style: const TextStyle(fontSize: 14, color: AppColors.textPrimary),
|
||||
style: TextStyle(fontSize: 14, color: context.appColors.textPrimary),
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Text(
|
||||
'${description?.length ?? 0}/200',
|
||||
style: const TextStyle(fontSize: 12, color: AppColors.textHint),
|
||||
style: TextStyle(fontSize: 12, color: context.appColors.textTertiary),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:maibu_satabot_v2/core/localization/app_localizations.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import '../constants/report_constants.dart';
|
||||
|
||||
/// 设备选择器
|
||||
@@ -19,11 +20,11 @@ class DeviceSelector extends StatelessWidget {
|
||||
),
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.background,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(AppDimensions.borderRadius),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: const Color(0x0D000000),
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: AppDimensions.cardShadowBlur,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -34,10 +35,10 @@ class DeviceSelector extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
AppLocalizations.of(context).translate('report.select_device'),
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.textPrimary,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
@@ -53,8 +54,8 @@ class DeviceSelector extends StatelessWidget {
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: selectedDevice != null
|
||||
? AppColors.textPrimary
|
||||
: AppColors.textHint,
|
||||
? context.appColors.textPrimary
|
||||
: context.appColors.textTertiary,
|
||||
),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
@@ -65,7 +66,7 @@ class DeviceSelector extends StatelessWidget {
|
||||
Icon(
|
||||
Icons.arrow_drop_down,
|
||||
size: 20,
|
||||
color: AppColors.textHint,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import '../constants/report_constants.dart';
|
||||
|
||||
class LevelSelector extends StatelessWidget {
|
||||
@@ -19,11 +20,11 @@ class LevelSelector extends StatelessWidget {
|
||||
),
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.background,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(AppDimensions.borderRadius),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: const Color(0x0D000000),
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: AppDimensions.cardShadowBlur,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -32,12 +33,12 @@ class LevelSelector extends StatelessWidget {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
'问题等级',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.textPrimary,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
@@ -53,14 +54,14 @@ class LevelSelector extends StatelessWidget {
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected
|
||||
? level.textColor.withOpacity(0.1)
|
||||
: AppColors.background,
|
||||
: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(
|
||||
AppDimensions.borderRadiusSmall,
|
||||
),
|
||||
border: Border.all(
|
||||
color: isSelected
|
||||
? level.borderColor
|
||||
: AppColors.borderColor,
|
||||
: context.appColors.divider,
|
||||
width: isSelected ? 2 : 1,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:maibu_satabot_v2/core/localization/app_localizations.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import '../constants/report_constants.dart';
|
||||
|
||||
/// 媒体上传模块
|
||||
@@ -31,11 +32,11 @@ class MediaUploader extends StatelessWidget {
|
||||
),
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.background,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(AppDimensions.borderRadius),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: const Color(0x0D000000),
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: AppDimensions.cardShadowBlur,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -46,10 +47,10 @@ class MediaUploader extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
loc.translate('report.upload_media'),
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.textPrimary,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
@@ -62,6 +63,7 @@ class MediaUploader extends StatelessWidget {
|
||||
children: [
|
||||
// 拍照按钮
|
||||
_buildUploadButton(
|
||||
context,
|
||||
icon: Icons.camera_alt,
|
||||
label: loc.translate('report.take_photo'),
|
||||
onTap: onCameraTap,
|
||||
@@ -69,6 +71,7 @@ class MediaUploader extends StatelessWidget {
|
||||
const SizedBox(width: 8),
|
||||
// 录像按钮
|
||||
_buildUploadButton(
|
||||
context,
|
||||
icon: Icons.videocam,
|
||||
label: loc.translate('report.record_video'),
|
||||
onTap: onVideoTap,
|
||||
@@ -92,7 +95,7 @@ class MediaUploader extends StatelessWidget {
|
||||
borderRadius: BorderRadius.circular(
|
||||
AppDimensions.borderRadiusSmall,
|
||||
),
|
||||
color: AppColors.cardBackground,
|
||||
color: context.appColors.fillBackground,
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(
|
||||
@@ -171,6 +174,7 @@ class MediaUploader extends StatelessWidget {
|
||||
}).toList(),
|
||||
// 添加按钮
|
||||
_buildUploadButton(
|
||||
context,
|
||||
icon: Icons.add,
|
||||
label: '',
|
||||
onTap: onAddFromGallery,
|
||||
@@ -185,7 +189,8 @@ class MediaUploader extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildUploadButton({
|
||||
Widget _buildUploadButton(
|
||||
BuildContext context, {
|
||||
required IconData icon,
|
||||
required String label,
|
||||
required VoidCallback onTap,
|
||||
@@ -197,10 +202,14 @@ class MediaUploader extends StatelessWidget {
|
||||
width: 80,
|
||||
height: 80,
|
||||
decoration: BoxDecoration(
|
||||
color: isAddButton ? AppColors.cardBackground : AppColors.background,
|
||||
color: isAddButton
|
||||
? context.appColors.fillBackground
|
||||
: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(AppDimensions.borderRadiusMedium),
|
||||
border: Border.all(
|
||||
color: isAddButton ? AppColors.borderColor : AppColors.primary,
|
||||
color: isAddButton
|
||||
? context.appColors.divider
|
||||
: context.appColors.primary,
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
@@ -208,7 +217,9 @@ class MediaUploader extends StatelessWidget {
|
||||
children: [
|
||||
Icon(
|
||||
icon,
|
||||
color: isAddButton ? AppColors.textHint : AppColors.primary,
|
||||
color: isAddButton
|
||||
? context.appColors.textTertiary
|
||||
: context.appColors.primary,
|
||||
size: 24,
|
||||
),
|
||||
if (label.isNotEmpty) ...[
|
||||
@@ -217,7 +228,9 @@ class MediaUploader extends StatelessWidget {
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: isAddButton ? AppColors.textHint : AppColors.primary,
|
||||
color: isAddButton
|
||||
? context.appColors.textTertiary
|
||||
: context.appColors.primary,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import '../constants/report_constants.dart';
|
||||
|
||||
class ReportTypeSelector extends StatelessWidget {
|
||||
@@ -33,20 +34,20 @@ class ReportTypeSelector extends StatelessWidget {
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected
|
||||
? AppColors.primary.withOpacity(0.1)
|
||||
: AppColors.background,
|
||||
? context.appColors.primary.withOpacity(0.1)
|
||||
: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(
|
||||
AppDimensions.borderRadiusSmall,
|
||||
),
|
||||
border: Border.all(
|
||||
color: isSelected
|
||||
? AppColors.primary
|
||||
: AppColors.borderColor,
|
||||
? context.appColors.primary
|
||||
: context.appColors.divider,
|
||||
width: isSelected ? 2 : 1,
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: const Color(0x0D000000),
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: AppDimensions.cardShadowBlur,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -58,8 +59,8 @@ class ReportTypeSelector extends StatelessWidget {
|
||||
Icon(
|
||||
type.icon,
|
||||
color: isSelected
|
||||
? AppColors.primary
|
||||
: AppColors.textHint,
|
||||
? context.appColors.primary
|
||||
: context.appColors.textTertiary,
|
||||
size: 24,
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
@@ -69,8 +70,8 @@ class ReportTypeSelector extends StatelessWidget {
|
||||
fontSize: 12,
|
||||
height: 1.2,
|
||||
color: isSelected
|
||||
? AppColors.primary
|
||||
: AppColors.textSecondary,
|
||||
? context.appColors.primary
|
||||
: context.appColors.textSecondary,
|
||||
fontWeight: isSelected
|
||||
? FontWeight.w600
|
||||
: FontWeight.normal,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/site/presentation/cubit/site_cubit.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/home/domain/entities/site_entity.dart';
|
||||
|
||||
@@ -74,10 +75,10 @@ class _SiteSelectorWidgetState extends State<SiteSelectorWidget> {
|
||||
text,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF1D2129),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -86,8 +87,8 @@ class _SiteSelectorWidgetState extends State<SiteSelectorWidget> {
|
||||
Icons.keyboard_arrow_down,
|
||||
size: iconSize,
|
||||
color: widget.enabled
|
||||
? const Color(0xFF4E5969)
|
||||
: const Color(0xFFC9CDD4),
|
||||
? context.appColors.textSecondary
|
||||
: context.appColors.textTertiary,
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -126,10 +127,10 @@ class _SiteSelectorWidgetState extends State<SiteSelectorWidget> {
|
||||
text,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF1D2129),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -138,8 +139,8 @@ class _SiteSelectorWidgetState extends State<SiteSelectorWidget> {
|
||||
Icons.keyboard_arrow_down,
|
||||
size: iconSize,
|
||||
color: widget.enabled
|
||||
? const Color(0xFF4E5969)
|
||||
: const Color(0xFFC9CDD4),
|
||||
? context.appColors.textSecondary
|
||||
: context.appColors.textTertiary,
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -163,7 +164,7 @@ class _SiteSelectorWidgetState extends State<SiteSelectorWidget> {
|
||||
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: context.appColors.cardBackground,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
|
||||
),
|
||||
@@ -182,21 +183,21 @@ class _SiteSelectorWidgetState extends State<SiteSelectorWidget> {
|
||||
child: Row(
|
||||
children: [
|
||||
const Spacer(),
|
||||
const Text(
|
||||
Text(
|
||||
'选择场站',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFF1D2129),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
GestureDetector(
|
||||
onTap: () => Navigator.pop(context),
|
||||
child: const Icon(
|
||||
child: Icon(
|
||||
Icons.close,
|
||||
size: 22,
|
||||
color: Color(0xFF86909C),
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -217,7 +218,7 @@ class _SiteSelectorWidgetState extends State<SiteSelectorWidget> {
|
||||
margin: const EdgeInsets.symmetric(vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected
|
||||
? const Color(0xFFE8F3FF)
|
||||
? context.appColors.primary.withOpacity(0.1)
|
||||
: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
@@ -235,15 +236,15 @@ class _SiteSelectorWidgetState extends State<SiteSelectorWidget> {
|
||||
? FontWeight.w600
|
||||
: FontWeight.w400,
|
||||
color: isSelected
|
||||
? const Color(0xFF165DFF)
|
||||
: const Color(0xFF1D2129),
|
||||
? context.appColors.primary
|
||||
: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
trailing: isSelected
|
||||
? const Icon(
|
||||
? Icon(
|
||||
Icons.check,
|
||||
size: 20,
|
||||
color: Color(0xFF165DFF),
|
||||
color: context.appColors.primary,
|
||||
)
|
||||
: null,
|
||||
onTap: () {
|
||||
|
||||
@@ -4,7 +4,6 @@ import 'package:dio/dio.dart';
|
||||
import 'package:maibu_satabot_v2/core/consts/http_api_consts.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/waring_center/data/datasources/alarm_remote_datasource.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/waring_center/data/models/alarm_model.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/waring_center/presentation/constants/alarm_constants.dart';
|
||||
|
||||
/// 告警远程数据源实现
|
||||
class AlarmRemoteDataSourceImpl implements AlarmRemoteDataSource {
|
||||
|
||||
@@ -4,7 +4,8 @@ library;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// 颜色常量
|
||||
/// 颜色常量(仅保留告警等级等模式无关的品牌语义色,
|
||||
/// UI 层颜色请使用 context.appColors 语义色)
|
||||
class AlarmColors {
|
||||
/// 主色调
|
||||
static const Color primary = Color(0xFF165DFF);
|
||||
@@ -20,24 +21,6 @@ class AlarmColors {
|
||||
|
||||
/// 提示色 - 蓝色提示
|
||||
static const Color info = Color(0xFF69b1ff);
|
||||
|
||||
/// 背景色
|
||||
static const Color background = Color(0xFFFFFFFF);
|
||||
|
||||
/// 主要文字色
|
||||
static const Color textPrimary = Color(0xFF1D2129);
|
||||
|
||||
/// 次要文字色
|
||||
static const Color textSecondary = Color(0xFF4E5969);
|
||||
|
||||
/// 辅助文字色
|
||||
static const Color textTertiary = Color(0xFF86909C);
|
||||
|
||||
/// 未处理背景色
|
||||
static const Color unprocessedBg = Color(0xFFFFF0F0);
|
||||
|
||||
/// AI诊断卡片背景色
|
||||
static const Color aiCardBg = Color(0xFFF0F7FF);
|
||||
}
|
||||
|
||||
/// 尺寸常量
|
||||
@@ -53,13 +36,6 @@ class AlarmDimensions {
|
||||
|
||||
/// 导航栏高度
|
||||
static const double appBarHeight = 44.0;
|
||||
|
||||
/// 卡片阴影
|
||||
static BoxShadow cardShadow = const BoxShadow(
|
||||
color: Color(0x0D000000),
|
||||
blurRadius: 4,
|
||||
offset: Offset(0, 2),
|
||||
);
|
||||
}
|
||||
|
||||
/// 告警等级枚举
|
||||
|
||||
@@ -5,9 +5,7 @@ import '../../domain/entities/alarm_detail_entity.dart';
|
||||
import '../../domain/usecases/dispatch_workorder_usecase.dart';
|
||||
import '../states/alarm_dispatch_state.dart';
|
||||
import '../../../report/presentation/constants/report_constants.dart';
|
||||
import '../../../home/domain/entities/site_entity.dart';
|
||||
import '../../../home/domain/usecases/get_site_list_usecase.dart';
|
||||
import '../../../home/domain/repositories/site_repository.dart';
|
||||
import '../../../home/data/repositories/site_repository_impl.dart';
|
||||
import '../../../home/data/datasources/site_datasource_impl.dart';
|
||||
import 'package:maibu_satabot_v2/core/app/app_user_cubit.dart';
|
||||
|
||||
@@ -6,6 +6,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:maibu_satabot_v2/core/localization/app_localizations.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/site/presentation/cubit/site_cubit.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/waring_center/presentation/bloc/alarm_cubit.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/waring_center/presentation/bloc/alarm_state.dart';
|
||||
@@ -71,18 +72,22 @@ class _AlarmCenterPageState extends State<AlarmCenterPage> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle.dark.copyWith(
|
||||
statusBarColor: Colors.transparent,
|
||||
statusBarIconBrightness: Brightness.dark,
|
||||
),
|
||||
value: isDark
|
||||
? SystemUiOverlayStyle.light
|
||||
: SystemUiOverlayStyle.dark,
|
||||
child: Scaffold(
|
||||
backgroundColor: const Color(0xFFF5F7FA),
|
||||
backgroundColor: context.appColors.pageBackground,
|
||||
body: SafeArea(
|
||||
child: BlocBuilder<AlarmCubit, AlarmState>(
|
||||
builder: (context, state) {
|
||||
if (state is AlarmLoading) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
return Center(
|
||||
child: CircularProgressIndicator(
|
||||
color: context.appColors.primary,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (state is AlarmError) {
|
||||
@@ -90,10 +95,10 @@ class _AlarmCenterPageState extends State<AlarmCenterPage> {
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icon(
|
||||
Icons.error_outline,
|
||||
size: 48,
|
||||
color: AlarmColors.textTertiary,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(state.message),
|
||||
@@ -192,7 +197,7 @@ class _AlarmCenterPageState extends State<AlarmCenterPage> {
|
||||
void _showFilterDialog() {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: context.appColors.cardBackground,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
|
||||
),
|
||||
@@ -207,10 +212,10 @@ class _AlarmCenterPageState extends State<AlarmCenterPage> {
|
||||
AppLocalizations.of(
|
||||
context,
|
||||
).translate('alarm_center.filter_title'),
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AlarmColors.textPrimary,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
@@ -266,7 +271,7 @@ class _AlarmCenterPageState extends State<AlarmCenterPage> {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AlarmColors.primary,
|
||||
backgroundColor: context.appColors.primary,
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
@@ -302,14 +307,14 @@ class _AlarmCenterPageState extends State<AlarmCenterPage> {
|
||||
children: [
|
||||
const Flexible(child: SiteSelectorWidget(compact: true)),
|
||||
const SizedBox(width: 8),
|
||||
Container(width: 1, height: 20, color: const Color(0xFFE5E6EB)),
|
||||
Container(width: 1, height: 20, color: context.appColors.divider),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
AppLocalizations.of(context).translate('alarm_center.title'),
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF86909C),
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -319,10 +324,10 @@ class _AlarmCenterPageState extends State<AlarmCenterPage> {
|
||||
Stack(
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
icon: Icon(
|
||||
Icons.notifications_none,
|
||||
size: 24,
|
||||
color: Color(0xFF1D2129),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
onPressed: () {
|
||||
context.push('/message_center');
|
||||
@@ -335,8 +340,8 @@ class _AlarmCenterPageState extends State<AlarmCenterPage> {
|
||||
child: Container(
|
||||
width: 8,
|
||||
height: 8,
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFFF53F3F),
|
||||
decoration: BoxDecoration(
|
||||
color: context.appColors.danger,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
@@ -345,10 +350,10 @@ class _AlarmCenterPageState extends State<AlarmCenterPage> {
|
||||
),
|
||||
// 筛选图标
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
icon: Icon(
|
||||
Icons.filter_list,
|
||||
size: 24,
|
||||
color: Color(0xFF1D2129),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
onPressed: _showFilterDialog,
|
||||
),
|
||||
@@ -360,7 +365,7 @@ class _AlarmCenterPageState extends State<AlarmCenterPage> {
|
||||
Widget _buildTabBar(AlarmLoaded state) {
|
||||
return AlarmTabBar(
|
||||
selectedFilter: state.selectedFilter,
|
||||
backgroundColor: const Color(0xFFF5F7FA),
|
||||
backgroundColor: context.appColors.pageBackground,
|
||||
onFilterChanged: (filter) {
|
||||
_cubit.changeFilter(filter);
|
||||
},
|
||||
@@ -369,16 +374,19 @@ class _AlarmCenterPageState extends State<AlarmCenterPage> {
|
||||
|
||||
Widget _buildLoadMoreIndicator(AlarmLoaded state) {
|
||||
if (state.isLoadingMore) {
|
||||
return const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 16),
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
child: Center(
|
||||
child: Column(
|
||||
children: [
|
||||
CircularProgressIndicator(strokeWidth: 2),
|
||||
SizedBox(height: 8),
|
||||
CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
color: context.appColors.primary,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'加载中...',
|
||||
style: TextStyle(fontSize: 12, color: AlarmColors.textTertiary),
|
||||
style: TextStyle(fontSize: 12, color: context.appColors.textTertiary),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -387,23 +395,23 @@ class _AlarmCenterPageState extends State<AlarmCenterPage> {
|
||||
}
|
||||
|
||||
if (!state.hasMore) {
|
||||
return const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 16),
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'已加载全部数据',
|
||||
style: TextStyle(fontSize: 12, color: AlarmColors.textTertiary),
|
||||
style: TextStyle(fontSize: 12, color: context.appColors.textTertiary),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 16),
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'上滑加载更多',
|
||||
style: TextStyle(fontSize: 12, color: AlarmColors.textTertiary),
|
||||
style: TextStyle(fontSize: 12, color: context.appColors.textTertiary),
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -415,10 +423,10 @@ class _AlarmCenterPageState extends State<AlarmCenterPage> {
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AlarmColors.textPrimary,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
@@ -429,14 +437,14 @@ class _AlarmCenterPageState extends State<AlarmCenterPage> {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: AlarmColors.textTertiary),
|
||||
border: Border.all(color: context.appColors.divider),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Text(
|
||||
option,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: AlarmColors.textSecondary,
|
||||
color: context.appColors.textSecondary,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -2,10 +2,10 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/waring_center/domain/entities/alarm_detail_entity.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/waring_center/presentation/bloc/alarm_detail_cubit.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/waring_center/presentation/bloc/alarm_detail_state.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/waring_center/presentation/constants/alarm_constants.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/waring_center/presentation/widgets/metric_trend_chart.dart';
|
||||
|
||||
/// 告警详情页面
|
||||
@@ -31,13 +31,13 @@ class _AlarmDetailPageState extends State<AlarmDetailPage> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle.dark.copyWith(
|
||||
statusBarColor: Colors.transparent,
|
||||
statusBarIconBrightness: Brightness.dark,
|
||||
),
|
||||
value: isDark
|
||||
? SystemUiOverlayStyle.light
|
||||
: SystemUiOverlayStyle.dark,
|
||||
child: Scaffold(
|
||||
backgroundColor: const Color(0xFFF5F7FA),
|
||||
backgroundColor: context.appColors.pageBackground,
|
||||
appBar: _buildAppBar(),
|
||||
body: BlocConsumer<AlarmDetailCubit, AlarmDetailState>(
|
||||
listener: (context, state) {
|
||||
@@ -49,9 +49,9 @@ class _AlarmDetailPageState extends State<AlarmDetailPage> {
|
||||
// 确认告警成功后显示提示
|
||||
if (state is AlarmDetailLoaded && state.isConfirmed) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('告警已确认,正在处理中'),
|
||||
backgroundColor: AlarmColors.success,
|
||||
SnackBar(
|
||||
content: const Text('告警已确认,正在处理中'),
|
||||
backgroundColor: context.appColors.success,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -91,26 +91,26 @@ class _AlarmDetailPageState extends State<AlarmDetailPage> {
|
||||
|
||||
PreferredSizeWidget _buildAppBar() {
|
||||
return AppBar(
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: context.appColors.cardBackground,
|
||||
elevation: 0,
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back, color: AlarmColors.textPrimary),
|
||||
icon: Icon(Icons.arrow_back, color: context.appColors.textPrimary),
|
||||
onPressed: () => context.pop(),
|
||||
),
|
||||
title: const Text(
|
||||
title: Text(
|
||||
'告警详情',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AlarmColors.textPrimary,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
centerTitle: true,
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
icon: Icon(
|
||||
Icons.share_outlined,
|
||||
color: AlarmColors.textPrimary,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
onPressed: () {
|
||||
// TODO: 分享功能
|
||||
@@ -141,11 +141,11 @@ class _AlarmDetailPageState extends State<AlarmDetailPage> {
|
||||
return Container(
|
||||
height: height,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Center(
|
||||
child: CircularProgressIndicator(color: AlarmColors.primary),
|
||||
child: CircularProgressIndicator(color: context.appColors.primary),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -156,17 +156,17 @@ class _AlarmDetailPageState extends State<AlarmDetailPage> {
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icon(
|
||||
Icons.error_outline,
|
||||
size: 64,
|
||||
color: AlarmColors.textTertiary,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
message,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: AlarmColors.textSecondary,
|
||||
color: context.appColors.textSecondary,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
@@ -176,7 +176,7 @@ class _AlarmDetailPageState extends State<AlarmDetailPage> {
|
||||
icon: const Icon(Icons.refresh),
|
||||
label: const Text('重试'),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AlarmColors.primary,
|
||||
backgroundColor: context.appColors.primary,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 12),
|
||||
),
|
||||
),
|
||||
@@ -191,18 +191,19 @@ class _AlarmDetailPageState extends State<AlarmDetailPage> {
|
||||
color: Colors.black.withOpacity(0.3),
|
||||
child: Center(
|
||||
child: Card(
|
||||
color: context.appColors.cardBackground,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
CircularProgressIndicator(color: AlarmColors.primary),
|
||||
CircularProgressIndicator(color: context.appColors.primary),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'$action...',
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: AlarmColors.textSecondary,
|
||||
color: context.appColors.textSecondary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -261,43 +262,45 @@ class _AlarmDetailPageState extends State<AlarmDetailPage> {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [AlarmDimensions.cardShadow],
|
||||
boxShadow: [
|
||||
BoxShadow(color: context.appColors.cardShadow, blurRadius: 4, offset: const Offset(0, 2)),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const Icon(
|
||||
Icon(
|
||||
Icons.warning_amber_rounded,
|
||||
color: AlarmColors.danger,
|
||||
color: context.appColors.danger,
|
||||
size: 24,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
alarm.title,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AlarmColors.textPrimary,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: AlarmColors.danger.withOpacity(0.1),
|
||||
color: context.appColors.danger.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: Text(
|
||||
alarm.level.label,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AlarmColors.danger,
|
||||
color: context.appColors.danger,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -306,17 +309,17 @@ class _AlarmDetailPageState extends State<AlarmDetailPage> {
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
alarm.deviceInfo,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: AlarmColors.textSecondary,
|
||||
color: context.appColors.textSecondary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
alarm.occurTime,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: AlarmColors.textTertiary,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -341,8 +344,8 @@ class _AlarmDetailPageState extends State<AlarmDetailPage> {
|
||||
'告警状态',
|
||||
alarm.alarmStatus,
|
||||
valueColor: alarm.alarmStatus == '待处理'
|
||||
? AlarmColors.danger
|
||||
: AlarmColors.success,
|
||||
? context.appColors.danger
|
||||
: context.appColors.success,
|
||||
);
|
||||
addRow('发生时间', alarm.occurTime);
|
||||
addRow('恢复时间', alarm.recoverTime);
|
||||
@@ -384,9 +387,11 @@ class _AlarmDetailPageState extends State<AlarmDetailPage> {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [AlarmDimensions.cardShadow],
|
||||
boxShadow: [
|
||||
BoxShadow(color: context.appColors.cardShadow, blurRadius: 4, offset: const Offset(0, 2)),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
children: infoRows
|
||||
@@ -445,9 +450,9 @@ class _AlarmDetailPageState extends State<AlarmDetailPage> {
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: AlarmColors.textSecondary,
|
||||
color: context.appColors.textSecondary,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
@@ -459,7 +464,7 @@ class _AlarmDetailPageState extends State<AlarmDetailPage> {
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: valueColor ?? AlarmColors.textPrimary,
|
||||
color: valueColor ?? context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -469,7 +474,7 @@ class _AlarmDetailPageState extends State<AlarmDetailPage> {
|
||||
}
|
||||
|
||||
Widget _buildDivider() {
|
||||
return const Divider(height: 24, thickness: 0.5, color: Color(0xFFE5E6EB));
|
||||
return Divider(height: 24, thickness: 0.5, color: context.appColors.divider);
|
||||
}
|
||||
|
||||
bool _hasHistoryData(HistoryMetrics historyData) {
|
||||
@@ -483,19 +488,21 @@ class _AlarmDetailPageState extends State<AlarmDetailPage> {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [AlarmDimensions.cardShadow],
|
||||
boxShadow: [
|
||||
BoxShadow(color: context.appColors.cardShadow, blurRadius: 4, offset: const Offset(0, 2)),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
'处理建议',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AlarmColors.textPrimary,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
@@ -507,18 +514,18 @@ class _AlarmDetailPageState extends State<AlarmDetailPage> {
|
||||
children: [
|
||||
Text(
|
||||
'${entry.key + 1}. ',
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AlarmColors.textPrimary,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
entry.value,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: AlarmColors.textSecondary,
|
||||
color: context.appColors.textSecondary,
|
||||
height: 1.5,
|
||||
),
|
||||
),
|
||||
@@ -542,10 +549,10 @@ class _AlarmDetailPageState extends State<AlarmDetailPage> {
|
||||
return Container(
|
||||
padding: const EdgeInsets.fromLTRB(16, 12, 16, 20),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, -2),
|
||||
),
|
||||
@@ -583,9 +590,9 @@ class _AlarmDetailPageState extends State<AlarmDetailPage> {
|
||||
isDisabled: true,
|
||||
onPressed: () {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('暂未开放'),
|
||||
backgroundColor: AlarmColors.warning,
|
||||
SnackBar(
|
||||
content: const Text('暂未开放'),
|
||||
backgroundColor: context.appColors.warning,
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -604,10 +611,10 @@ class _AlarmDetailPageState extends State<AlarmDetailPage> {
|
||||
_cubit.loadAlarmDetail(widget.alarmId);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.white,
|
||||
foregroundColor: AlarmColors.primary,
|
||||
backgroundColor: context.appColors.cardBackground,
|
||||
foregroundColor: context.appColors.primary,
|
||||
elevation: 0,
|
||||
side: const BorderSide(color: AlarmColors.primary),
|
||||
side: BorderSide(color: context.appColors.primary),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
@@ -639,10 +646,10 @@ class _AlarmDetailPageState extends State<AlarmDetailPage> {
|
||||
child: ElevatedButton(
|
||||
onPressed: isLoading || isDisabled ? null : onPressed,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: isPrimary ? AlarmColors.primary : Colors.white,
|
||||
foregroundColor: isPrimary ? Colors.white : AlarmColors.primary,
|
||||
backgroundColor: isPrimary ? context.appColors.primary : context.appColors.cardBackground,
|
||||
foregroundColor: isPrimary ? Colors.white : context.appColors.primary,
|
||||
elevation: 0,
|
||||
side: isPrimary ? null : const BorderSide(color: AlarmColors.primary),
|
||||
side: isPrimary ? null : BorderSide(color: context.appColors.primary),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||
),
|
||||
child: isLoading
|
||||
@@ -651,7 +658,7 @@ class _AlarmDetailPageState extends State<AlarmDetailPage> {
|
||||
width: 20,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
color: isPrimary ? Colors.white : AlarmColors.primary,
|
||||
color: isPrimary ? Colors.white : context.appColors.primary,
|
||||
),
|
||||
)
|
||||
: Text(
|
||||
@@ -671,18 +678,22 @@ class _AlarmDetailPageState extends State<AlarmDetailPage> {
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: const Text(
|
||||
backgroundColor: context.appColors.cardBackground,
|
||||
title: Text(
|
||||
'AI诊断结果',
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: context.appColors.textPrimary),
|
||||
),
|
||||
content: SingleChildScrollView(
|
||||
child: Text(
|
||||
result,
|
||||
style: const TextStyle(fontSize: 14, height: 1.6),
|
||||
style: TextStyle(fontSize: 14, height: 1.6, color: context.appColors.textSecondary),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(onPressed: () => context.pop(), child: const Text('关闭')),
|
||||
TextButton(
|
||||
onPressed: () => context.pop(),
|
||||
child: Text('关闭', style: TextStyle(color: context.appColors.primary)),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
|
||||
@@ -6,12 +6,12 @@ import 'package:go_router/go_router.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import '../../domain/entities/alarm_detail_entity.dart';
|
||||
import '../../domain/usecases/dispatch_workorder_usecase.dart';
|
||||
import '../../data/datasources/alarm_dispatch_remote_datasource.dart';
|
||||
import '../../data/datasources/impl/alarm_dispatch_remote_datasource_impl.dart';
|
||||
import '../../data/repositories/alarm_dispatch_repository_impl.dart';
|
||||
import '../cubit/alarm_dispatch_cubit.dart';
|
||||
import '../states/alarm_dispatch_state.dart';
|
||||
import '../../../report/presentation/constants/report_constants.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import '../../../report/presentation/widgets/report_type_selector.dart';
|
||||
import '../../../report/presentation/widgets/device_selector.dart';
|
||||
import '../../../report/presentation/widgets/description_input.dart';
|
||||
@@ -58,7 +58,7 @@ class _AlarmDispatchPageContent extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.cardBackground,
|
||||
backgroundColor: context.appColors.pageBackground,
|
||||
appBar: _buildAppBar(context),
|
||||
body: BlocConsumer<AlarmDispatchCubit, AlarmDispatchState>(
|
||||
listener: (context, state) {
|
||||
@@ -78,14 +78,14 @@ class _AlarmDispatchPageContent extends StatelessWidget {
|
||||
},
|
||||
builder: (context, state) {
|
||||
if (state is AlarmDispatchSubmitting) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(color: AppColors.primary),
|
||||
return Center(
|
||||
child: CircularProgressIndicator(color: context.appColors.primary),
|
||||
);
|
||||
}
|
||||
|
||||
if (state is AlarmDispatchLoading) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(color: AppColors.primary),
|
||||
return Center(
|
||||
child: CircularProgressIndicator(color: context.appColors.primary),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -101,28 +101,28 @@ class _AlarmDispatchPageContent extends StatelessWidget {
|
||||
|
||||
PreferredSizeWidget _buildAppBar(BuildContext context) {
|
||||
return AppBar(
|
||||
backgroundColor: AppColors.background,
|
||||
backgroundColor: context.appColors.cardBackground,
|
||||
elevation: 0,
|
||||
title: const Text(
|
||||
title: Text(
|
||||
'告警派发工单',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.textPrimary,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
centerTitle: true,
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back_ios, size: 20, color: Colors.black),
|
||||
icon: Icon(Icons.arrow_back_ios, size: 20, color: context.appColors.textPrimary),
|
||||
onPressed: () => context.pop(),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => context.read<AlarmDispatchCubit>().submitDispatch(),
|
||||
child: const Text(
|
||||
child: Text(
|
||||
'提交',
|
||||
style: TextStyle(
|
||||
color: AppColors.primary,
|
||||
color: context.appColors.primary,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
@@ -142,10 +142,10 @@ class _AlarmDispatchPageContent extends StatelessWidget {
|
||||
children: [
|
||||
const SizedBox(height: AppDimensions.moduleSpacing),
|
||||
// 场站信息
|
||||
_buildSiteInfoCard(state),
|
||||
_buildSiteInfoCard(context, state),
|
||||
const SizedBox(height: AppDimensions.moduleSpacing),
|
||||
// 告警关联信息条
|
||||
_buildAlarmInfoBar(state),
|
||||
_buildAlarmInfoBar(context, state),
|
||||
const SizedBox(height: AppDimensions.moduleSpacing),
|
||||
// 上报类型选择
|
||||
ReportTypeSelector(
|
||||
@@ -199,18 +199,18 @@ class _AlarmDispatchPageContent extends StatelessWidget {
|
||||
}
|
||||
|
||||
/// 场站信息卡片
|
||||
Widget _buildSiteInfoCard(AlarmDispatchFormState state) {
|
||||
Widget _buildSiteInfoCard(BuildContext context, AlarmDispatchFormState state) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.symmetric(
|
||||
horizontal: AppDimensions.horizontalPadding,
|
||||
),
|
||||
padding: const EdgeInsets.all(14),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.background,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(AppDimensions.borderRadius),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: const Color(0x0D000000),
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: AppDimensions.cardShadowBlur,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -219,16 +219,16 @@ class _AlarmDispatchPageContent extends StatelessWidget {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Row(
|
||||
Row(
|
||||
children: [
|
||||
Icon(Icons.location_on, size: 18, color: AppColors.primary),
|
||||
SizedBox(width: 6),
|
||||
Icon(Icons.location_on, size: 18, color: context.appColors.primary),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
'场站信息',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.textPrimary,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -247,7 +247,7 @@ class _AlarmDispatchPageContent extends StatelessWidget {
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(width: 24),
|
||||
_buildInfoLabel('场站名称'),
|
||||
_buildInfoLabel(context, '场站名称'),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
@@ -255,8 +255,8 @@ class _AlarmDispatchPageContent extends StatelessWidget {
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: state.siteName != null
|
||||
? AppColors.textPrimary
|
||||
: AppColors.textHint,
|
||||
? context.appColors.textPrimary
|
||||
: context.appColors.textTertiary,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
@@ -267,14 +267,14 @@ class _AlarmDispatchPageContent extends StatelessWidget {
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
_buildInfoLabel('告警编号'),
|
||||
_buildInfoLabel(context, '告警编号'),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
state.alarmNo ?? state.alarmId,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: AppColors.textPrimary,
|
||||
color: context.appColors.textPrimary,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
@@ -287,45 +287,45 @@ class _AlarmDispatchPageContent extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildInfoLabel(String label) {
|
||||
Widget _buildInfoLabel(BuildContext context, String label) {
|
||||
return Text(
|
||||
label,
|
||||
style: const TextStyle(fontSize: 12, color: AppColors.textHint),
|
||||
style: TextStyle(fontSize: 12, color: context.appColors.textTertiary),
|
||||
);
|
||||
}
|
||||
|
||||
/// 告警关联信息条
|
||||
Widget _buildAlarmInfoBar(AlarmDispatchFormState state) {
|
||||
Widget _buildAlarmInfoBar(BuildContext context, AlarmDispatchFormState state) {
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
final barColor = isDark ? const Color(0xFFE6B15A) : const Color(0xFFFA8C16);
|
||||
return Container(
|
||||
margin: const EdgeInsets.symmetric(
|
||||
horizontal: AppDimensions.horizontalPadding,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFFFF7E6),
|
||||
color: isDark ? const Color(0xFF3A2E14) : const Color(0xFFFFF7E6),
|
||||
borderRadius: BorderRadius.circular(AppDimensions.borderRadiusSmall),
|
||||
border: Border.all(color: const Color(0xFFFFD591)),
|
||||
border: Border.all(
|
||||
color: isDark ? const Color(0xFF6B5315) : const Color(0xFFFFD591),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.warning_amber_rounded,
|
||||
color: Color(0xFFFA8C16),
|
||||
size: 18,
|
||||
),
|
||||
Icon(Icons.warning_amber_rounded, color: barColor, size: 18),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'关联告警: ${state.alarmNo ?? state.alarmId}',
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: Color(0xFF8C6E1F),
|
||||
color: isDark ? const Color(0xFFE6C877) : const Color(0xFF8C6E1F),
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
const Icon(Icons.chevron_right, size: 18, color: Color(0xFFFA8C16)),
|
||||
Icon(Icons.chevron_right, size: 18, color: barColor),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -343,11 +343,11 @@ class _AlarmDispatchPageContent extends StatelessWidget {
|
||||
),
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.background,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(AppDimensions.borderRadius),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: const Color(0x0D000000),
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: AppDimensions.cardShadowBlur,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -356,16 +356,17 @@ class _AlarmDispatchPageContent extends StatelessWidget {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
'计划时间',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.textPrimary,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
_buildTimeRow(
|
||||
context,
|
||||
label: '计划开始',
|
||||
time: state.planStartTime,
|
||||
onTap: () => _pickDateTime(context, (time) {
|
||||
@@ -387,7 +388,8 @@ class _AlarmDispatchPageContent extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTimeRow({
|
||||
Widget _buildTimeRow(
|
||||
BuildContext context, {
|
||||
required String label,
|
||||
required DateTime? time,
|
||||
required VoidCallback onTap,
|
||||
@@ -398,17 +400,17 @@ class _AlarmDispatchPageContent extends StatelessWidget {
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.cardBackground,
|
||||
color: context.appColors.fillBackground,
|
||||
borderRadius: BorderRadius.circular(AppDimensions.borderRadiusSmall),
|
||||
border: Border.all(color: AppColors.borderColor),
|
||||
border: Border.all(color: context.appColors.divider),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
'$label${required ? ' *' : ''}',
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: AppColors.textSecondary,
|
||||
color: context.appColors.textSecondary,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
@@ -420,15 +422,15 @@ class _AlarmDispatchPageContent extends StatelessWidget {
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: time != null
|
||||
? AppColors.textPrimary
|
||||
: AppColors.textHint,
|
||||
? context.appColors.textPrimary
|
||||
: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
const Icon(
|
||||
Icon(
|
||||
Icons.calendar_today,
|
||||
size: 16,
|
||||
color: AppColors.textHint,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:maibu_satabot_v2/core/di/injection.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/waring_center/domain/entities/alarm_detail_entity.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/waring_center/presentation/bloc/alarm_detail_cubit.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/waring_center/presentation/bloc/alarm_detail_state.dart';
|
||||
@@ -54,7 +55,6 @@ class _AlarmHandlePageContentState extends State<_AlarmHandlePageContent> {
|
||||
'label': '确认告警',
|
||||
'icon': Icons.check_circle_outline,
|
||||
'color': const Color(0xFF52C41A),
|
||||
'bgColor': const Color(0xFFF6FFED),
|
||||
'confirmedLabel': '已确认告警',
|
||||
'confirmedTip': '确认无需',
|
||||
'unconfirmedTip': '确认无需',
|
||||
@@ -63,35 +63,30 @@ class _AlarmHandlePageContentState extends State<_AlarmHandlePageContent> {
|
||||
'label': '派发工单',
|
||||
'icon': Icons.file_copy_outlined,
|
||||
'color': const Color(0xFF1890FF),
|
||||
'bgColor': const Color(0xFFE6F7FF),
|
||||
'tip': '请填下方表格',
|
||||
},
|
||||
{
|
||||
'label': '联系负责人',
|
||||
'icon': Icons.person_outline,
|
||||
'color': const Color(0xFFFA8C16),
|
||||
'bgColor': const Color(0xFFFFF7E6),
|
||||
'tip': '暂无功能',
|
||||
},
|
||||
{
|
||||
'label': '拍照取证',
|
||||
'icon': Icons.camera_alt_outlined,
|
||||
'color': const Color(0xFF722ED1),
|
||||
'bgColor': const Color(0xFFF9F0FF),
|
||||
'tip': '暂不支持',
|
||||
},
|
||||
{
|
||||
'label': '备注记录',
|
||||
'icon': Icons.edit_note_outlined,
|
||||
'color': const Color(0xFF13C2C2),
|
||||
'bgColor': const Color(0xFFE6FFFB),
|
||||
'tip': '请填下方表格',
|
||||
},
|
||||
{
|
||||
'label': '更多操作',
|
||||
'icon': Icons.more_horiz,
|
||||
'color': const Color(0xFF8C8C8C),
|
||||
'bgColor': const Color(0xFFF5F5F5),
|
||||
'tip': '暂未开发',
|
||||
},
|
||||
];
|
||||
@@ -99,16 +94,16 @@ class _AlarmHandlePageContentState extends State<_AlarmHandlePageContent> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xFFF5F5F5),
|
||||
backgroundColor: context.appColors.pageBackground,
|
||||
appBar: _buildAppBar(),
|
||||
body: BlocConsumer<AlarmDetailCubit, AlarmDetailState>(
|
||||
listener: (context, state) {
|
||||
if (state is AlarmDetailLoaded && state.isHandleSuccess) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('处理成功'),
|
||||
backgroundColor: Color(0xFF52C41A),
|
||||
duration: Duration(seconds: 1),
|
||||
SnackBar(
|
||||
content: const Text('处理成功'),
|
||||
backgroundColor: context.appColors.success,
|
||||
duration: const Duration(seconds: 1),
|
||||
),
|
||||
);
|
||||
Future.delayed(const Duration(seconds: 1), () {
|
||||
@@ -139,17 +134,17 @@ class _AlarmHandlePageContentState extends State<_AlarmHandlePageContent> {
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icon(
|
||||
Icons.error_outline,
|
||||
size: 64,
|
||||
color: Color(0xFFBFBFBF),
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
state.message,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Color(0xFF8C8C8C),
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
@@ -161,7 +156,7 @@ class _AlarmHandlePageContentState extends State<_AlarmHandlePageContent> {
|
||||
icon: const Icon(Icons.refresh),
|
||||
label: const Text('重试'),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF1890FF),
|
||||
backgroundColor: context.appColors.primary,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 32,
|
||||
vertical: 12,
|
||||
@@ -173,7 +168,9 @@ class _AlarmHandlePageContentState extends State<_AlarmHandlePageContent> {
|
||||
);
|
||||
}
|
||||
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
return Center(
|
||||
child: CircularProgressIndicator(color: context.appColors.primary),
|
||||
);
|
||||
},
|
||||
),
|
||||
bottomNavigationBar: _buildBottomSubmitButton(),
|
||||
@@ -183,39 +180,39 @@ class _AlarmHandlePageContentState extends State<_AlarmHandlePageContent> {
|
||||
AppBar _buildAppBar() {
|
||||
return AppBar(
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back_ios, color: Colors.black, size: 20),
|
||||
icon: Icon(Icons.arrow_back_ios, color: context.appColors.textPrimary, size: 20),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
title: const Text(
|
||||
title: Text(
|
||||
'告警处理',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: context.appColors.cardBackground,
|
||||
elevation: 0,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAlarmInfoCard(AlarmDetailEntity alarm) {
|
||||
final levelColor = alarm.level == AlarmLevel.danger
|
||||
? const Color(0xFFFF4D4F)
|
||||
? context.appColors.danger
|
||||
: alarm.level == AlarmLevel.warning
|
||||
? const Color(0xFFFA8C16)
|
||||
? context.appColors.warning
|
||||
: alarm.level == AlarmLevel.low
|
||||
? const Color(0xFF1890FF)
|
||||
: const Color(0xFF52C41A);
|
||||
? context.appColors.primary
|
||||
: context.appColors.success;
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -231,10 +228,10 @@ class _AlarmHandlePageContentState extends State<_AlarmHandlePageContent> {
|
||||
Expanded(
|
||||
child: Text(
|
||||
alarm.title,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
@@ -260,7 +257,7 @@ class _AlarmHandlePageContentState extends State<_AlarmHandlePageContent> {
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'${alarm.alarmNo ?? alarm.id} | ${alarm.deviceInfo} | ${alarm.occurTime}',
|
||||
style: const TextStyle(fontSize: 13, color: Color(0xFF8C8C8C)),
|
||||
style: TextStyle(fontSize: 13, color: context.appColors.textTertiary),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -271,11 +268,11 @@ class _AlarmHandlePageContentState extends State<_AlarmHandlePageContent> {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -319,7 +316,7 @@ class _AlarmHandlePageContentState extends State<_AlarmHandlePageContent> {
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected
|
||||
? (button['color'] as Color)
|
||||
: (button['bgColor'] as Color),
|
||||
: (button['color'] as Color).withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: isSelected
|
||||
? Border.all(color: button['color'] as Color, width: 2)
|
||||
@@ -391,11 +388,11 @@ class _AlarmHandlePageContentState extends State<_AlarmHandlePageContent> {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -425,22 +422,23 @@ class _AlarmHandlePageContentState extends State<_AlarmHandlePageContent> {
|
||||
controller: _rootCauseController,
|
||||
maxLines: 4,
|
||||
maxLength: 200,
|
||||
decoration: const InputDecoration(
|
||||
decoration: InputDecoration(
|
||||
hintText: '请输入根因分析,最多200字',
|
||||
hintStyle: TextStyle(color: context.appColors.textTertiary),
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 12),
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 12),
|
||||
isDense: false,
|
||||
alignLabelWithHint: true,
|
||||
),
|
||||
style: const TextStyle(fontSize: 14, color: Colors.black),
|
||||
style: TextStyle(fontSize: 14, color: context.appColors.textPrimary),
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.bottomRight,
|
||||
child: Text(
|
||||
'${_rootCauseController.text.length}/200',
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Color(0xFFBFBFBF),
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -452,13 +450,14 @@ class _AlarmHandlePageContentState extends State<_AlarmHandlePageContent> {
|
||||
label: '处理人',
|
||||
child: TextField(
|
||||
controller: _handlerController,
|
||||
decoration: const InputDecoration(
|
||||
decoration: InputDecoration(
|
||||
hintText: '请输入处理人',
|
||||
hintStyle: TextStyle(color: context.appColors.textTertiary),
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 12),
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 12),
|
||||
isDense: false,
|
||||
),
|
||||
style: const TextStyle(fontSize: 14, color: Colors.black),
|
||||
style: TextStyle(fontSize: 14, color: context.appColors.textPrimary),
|
||||
),
|
||||
),
|
||||
_buildDivider(),
|
||||
@@ -471,22 +470,23 @@ class _AlarmHandlePageContentState extends State<_AlarmHandlePageContent> {
|
||||
controller: _remarkController,
|
||||
maxLines: 4,
|
||||
maxLength: 200,
|
||||
decoration: const InputDecoration(
|
||||
decoration: InputDecoration(
|
||||
hintText: '请输入处理备注,最多200字',
|
||||
hintStyle: TextStyle(color: context.appColors.textTertiary),
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 12),
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 12),
|
||||
isDense: false,
|
||||
alignLabelWithHint: true,
|
||||
),
|
||||
style: const TextStyle(fontSize: 14, color: Colors.black),
|
||||
style: TextStyle(fontSize: 14, color: context.appColors.textPrimary),
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.bottomRight,
|
||||
child: Text(
|
||||
'${_remarkController.text.length}/200',
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Color(0xFFBFBFBF),
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -508,7 +508,7 @@ class _AlarmHandlePageContentState extends State<_AlarmHandlePageContent> {
|
||||
width: 72,
|
||||
child: Text(
|
||||
label,
|
||||
style: const TextStyle(fontSize: 14, color: Color(0xFF8C8C8C)),
|
||||
style: TextStyle(fontSize: 14, color: context.appColors.textSecondary),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
@@ -533,7 +533,7 @@ class _AlarmHandlePageContentState extends State<_AlarmHandlePageContent> {
|
||||
item.isEmpty ? hintText ?? '' : item,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: item.isEmpty ? const Color(0xFFBFBFBF) : Colors.black,
|
||||
color: item.isEmpty ? context.appColors.textTertiary : context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -544,8 +544,8 @@ class _AlarmHandlePageContentState extends State<_AlarmHandlePageContent> {
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 12),
|
||||
isDense: false,
|
||||
),
|
||||
style: const TextStyle(fontSize: 14, color: Colors.black),
|
||||
icon: const Icon(Icons.keyboard_arrow_down, color: Color(0xFFBFBFBF)),
|
||||
style: TextStyle(fontSize: 14, color: context.appColors.textPrimary),
|
||||
icon: Icon(Icons.keyboard_arrow_down, color: context.appColors.textTertiary),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -553,11 +553,11 @@ class _AlarmHandlePageContentState extends State<_AlarmHandlePageContent> {
|
||||
return DropdownButtonFormField<String>(
|
||||
value: _handleResult.isEmpty ? null : _handleResult,
|
||||
items: [
|
||||
const DropdownMenuItem<String>(
|
||||
DropdownMenuItem<String>(
|
||||
value: '',
|
||||
child: Text(
|
||||
'请选择处理结果',
|
||||
style: TextStyle(fontSize: 14, color: Color(0xFFBFBFBF)),
|
||||
style: TextStyle(fontSize: 14, color: context.appColors.textTertiary),
|
||||
),
|
||||
),
|
||||
..._handleResultMap.entries.map((entry) {
|
||||
@@ -565,7 +565,7 @@ class _AlarmHandlePageContentState extends State<_AlarmHandlePageContent> {
|
||||
value: entry.key,
|
||||
child: Text(
|
||||
entry.value,
|
||||
style: const TextStyle(fontSize: 14, color: Colors.black),
|
||||
style: TextStyle(fontSize: 14, color: context.appColors.textPrimary),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
@@ -578,23 +578,23 @@ class _AlarmHandlePageContentState extends State<_AlarmHandlePageContent> {
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 12),
|
||||
isDense: false,
|
||||
),
|
||||
style: const TextStyle(fontSize: 14, color: Colors.black),
|
||||
icon: const Icon(Icons.keyboard_arrow_down, color: Color(0xFFBFBFBF)),
|
||||
style: TextStyle(fontSize: 14, color: context.appColors.textPrimary),
|
||||
icon: Icon(Icons.keyboard_arrow_down, color: context.appColors.textTertiary),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDivider() {
|
||||
return const Divider(height: 1, color: Color(0xFFF0F0F0));
|
||||
return Divider(height: 1, color: context.appColors.divider);
|
||||
}
|
||||
|
||||
Widget _buildBottomSubmitButton() {
|
||||
return Container(
|
||||
padding: const EdgeInsets.fromLTRB(16, 12, 16, 20),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, -2),
|
||||
),
|
||||
@@ -605,7 +605,7 @@ class _AlarmHandlePageContentState extends State<_AlarmHandlePageContent> {
|
||||
child: ElevatedButton(
|
||||
onPressed: _submitHandle,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF1890FF),
|
||||
backgroundColor: context.appColors.primary,
|
||||
foregroundColor: Colors.white,
|
||||
elevation: 0,
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/waring_center/presentation/constants/alarm_constants.dart';
|
||||
|
||||
/// AI 诊断建议卡片
|
||||
@@ -18,7 +19,7 @@ class AiDiagnosisCard extends StatelessWidget {
|
||||
margin: const EdgeInsets.all(AlarmDimensions.horizontalPadding),
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: AlarmColors.aiCardBg,
|
||||
color: context.appColors.primary.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(AlarmDimensions.borderRadius),
|
||||
),
|
||||
child: Column(
|
||||
@@ -29,8 +30,8 @@ class AiDiagnosisCard extends StatelessWidget {
|
||||
Container(
|
||||
width: 24,
|
||||
height: 24,
|
||||
decoration: const BoxDecoration(
|
||||
color: AlarmColors.primary,
|
||||
decoration: BoxDecoration(
|
||||
color: context.appColors.primary,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
@@ -40,12 +41,12 @@ class AiDiagnosisCard extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const Text(
|
||||
Text(
|
||||
'AI诊断建议',
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AlarmColors.textPrimary,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -53,9 +54,9 @@ class AiDiagnosisCard extends StatelessWidget {
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
content,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: AlarmColors.textSecondary,
|
||||
color: context.appColors.textSecondary,
|
||||
height: 1.5,
|
||||
),
|
||||
),
|
||||
@@ -67,19 +68,19 @@ class AiDiagnosisCard extends StatelessWidget {
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
'查看详情',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: AlarmColors.primary,
|
||||
color: context.appColors.primary,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
const Icon(
|
||||
Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
size: 12,
|
||||
color: AlarmColors.primary,
|
||||
color: context.appColors.primary,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:maibu_satabot_v2/core/localization/app_localizations.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/waring_center/domain/entities/alarm_count_entity.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/waring_center/presentation/constants/alarm_constants.dart';
|
||||
|
||||
class AlarmCountCard extends StatelessWidget {
|
||||
const AlarmCountCard({
|
||||
@@ -17,41 +17,46 @@ class AlarmCountCard extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.symmetric(
|
||||
horizontal: AlarmDimensions.horizontalPadding,
|
||||
horizontal: 16,
|
||||
),
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: AlarmColors.background,
|
||||
borderRadius: BorderRadius.circular(AlarmDimensions.borderRadius),
|
||||
boxShadow: [AlarmDimensions.cardShadow],
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
boxShadow: [
|
||||
BoxShadow(color: context.appColors.cardShadow, blurRadius: 4, offset: const Offset(0, 2)),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _buildCountItem(
|
||||
context,
|
||||
label: '待处理',
|
||||
value: count.unprocessed,
|
||||
color: AlarmColors.danger,
|
||||
bgColor: AlarmColors.unprocessedBg,
|
||||
labelColor: AlarmColors.danger,
|
||||
color: context.appColors.danger,
|
||||
bgColor: context.appColors.danger.withOpacity(0.1),
|
||||
labelColor: context.appColors.danger,
|
||||
),
|
||||
),
|
||||
_buildDivider(),
|
||||
_buildDivider(context),
|
||||
Expanded(
|
||||
child: _buildCountItem(
|
||||
context,
|
||||
label: '已关闭',
|
||||
value: count.confirmed,
|
||||
color: const Color(0xFF1D2129),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
_buildDivider(),
|
||||
_buildDivider(context),
|
||||
Expanded(
|
||||
child: _buildCountItem(
|
||||
context,
|
||||
label: AppLocalizations.of(
|
||||
context,
|
||||
).translate('alarm_center.today_new'),
|
||||
value: count.todayNew,
|
||||
color: const Color(0xFF1D2129),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -59,7 +64,8 @@ class AlarmCountCard extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCountItem({
|
||||
Widget _buildCountItem(
|
||||
BuildContext context, {
|
||||
required String label,
|
||||
required int value,
|
||||
required Color color,
|
||||
@@ -78,7 +84,7 @@ class AlarmCountCard extends StatelessWidget {
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: labelColor ?? AlarmColors.textSecondary,
|
||||
color: labelColor ?? context.appColors.textSecondary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
@@ -106,12 +112,12 @@ class AlarmCountCard extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDivider() {
|
||||
Widget _buildDivider(BuildContext context) {
|
||||
return Container(
|
||||
width: 1,
|
||||
height: 50,
|
||||
margin: const EdgeInsets.symmetric(horizontal: 8),
|
||||
color: const Color(0xFFE5E6EB),
|
||||
color: context.appColors.divider,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:maibu_satabot_v2/core/localization/app_localizations.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/waring_center/domain/entities/alarm_entity.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/waring_center/presentation/constants/alarm_constants.dart';
|
||||
|
||||
@@ -21,9 +22,11 @@ class AlarmItemCard extends StatelessWidget {
|
||||
),
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: AlarmColors.background,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(AlarmDimensions.borderRadius),
|
||||
boxShadow: [AlarmDimensions.cardShadow],
|
||||
boxShadow: [
|
||||
BoxShadow(color: context.appColors.cardShadow, blurRadius: 4, offset: const Offset(0, 2)),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -36,10 +39,10 @@ class AlarmItemCard extends StatelessWidget {
|
||||
Expanded(
|
||||
child: Text(
|
||||
alarm.title,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AlarmColors.textPrimary,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -67,9 +70,9 @@ class AlarmItemCard extends StatelessWidget {
|
||||
// 第二行:区域和设备
|
||||
Text(
|
||||
'${AppLocalizations.of(context).translate('alarm_center.area')}:${alarm.area} / ${AppLocalizations.of(context).translate('alarm_center.device')}:${alarm.device}',
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: AlarmColors.textSecondary,
|
||||
color: context.appColors.textSecondary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
@@ -78,9 +81,9 @@ class AlarmItemCard extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
alarm.time,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: AlarmColors.textTertiary,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
@@ -88,7 +91,7 @@ class AlarmItemCard extends StatelessWidget {
|
||||
alarm.status.label,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: _getStatusColor(alarm.status),
|
||||
color: _getStatusColor(context, alarm.status),
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
@@ -96,7 +99,7 @@ class AlarmItemCard extends StatelessWidget {
|
||||
Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
size: 12,
|
||||
color: _getStatusColor(alarm.status),
|
||||
color: _getStatusColor(context, alarm.status),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -121,14 +124,14 @@ class AlarmItemCard extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
Color _getStatusColor(AlarmStatus status) {
|
||||
Color _getStatusColor(BuildContext context, AlarmStatus status) {
|
||||
switch (status) {
|
||||
case AlarmStatus.pending:
|
||||
return AlarmColors.danger;
|
||||
return context.appColors.danger;
|
||||
case AlarmStatus.processing:
|
||||
case AlarmStatus.closed:
|
||||
case AlarmStatus.ignored:
|
||||
return AlarmColors.textTertiary;
|
||||
return context.appColors.textTertiary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:maibu_satabot_v2/core/localization/app_localizations.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/waring_center/presentation/constants/alarm_constants.dart';
|
||||
|
||||
/// 告警筛选标签栏 - 全部/未处理/已确认/已恢复
|
||||
@@ -77,8 +78,8 @@ class AlarmTabBar extends StatelessWidget {
|
||||
fontSize: 15,
|
||||
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
|
||||
color: isSelected
|
||||
? AlarmColors.primary
|
||||
: AlarmColors.textSecondary,
|
||||
? context.appColors.primary
|
||||
: context.appColors.textSecondary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
@@ -86,7 +87,7 @@ class AlarmTabBar extends StatelessWidget {
|
||||
height: 2,
|
||||
width: 20,
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected ? AlarmColors.primary : Colors.transparent,
|
||||
color: isSelected ? context.appColors.primary : Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(1),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:fl_chart/fl_chart.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/waring_center/domain/entities/alarm_detail_entity.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/waring_center/presentation/bloc/alarm_detail_state.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/waring_center/presentation/constants/alarm_constants.dart';
|
||||
|
||||
/// 指标趋势图组件
|
||||
class MetricTrendChart extends StatelessWidget {
|
||||
@@ -21,37 +21,39 @@ class MetricTrendChart extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [AlarmDimensions.cardShadow],
|
||||
boxShadow: [
|
||||
BoxShadow(color: context.appColors.cardShadow, blurRadius: 4, offset: const Offset(0, 2)),
|
||||
],
|
||||
),
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
'指标趋势',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AlarmColors.textPrimary,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
// 指标切换标签
|
||||
_buildMetricTabs(),
|
||||
_buildMetricTabs(context),
|
||||
const SizedBox(height: 16),
|
||||
// 折线图
|
||||
SizedBox(
|
||||
height: 200,
|
||||
child: _buildChart(),
|
||||
child: _buildChart(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildMetricTabs() {
|
||||
Widget _buildMetricTabs(BuildContext context) {
|
||||
return Row(
|
||||
children: MetricType.values.map((metric) {
|
||||
final isSelected = metric == selectedMetric;
|
||||
@@ -62,7 +64,7 @@ class MetricTrendChart extends StatelessWidget {
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected ? const Color(0xFFE8F3FF) : Colors.transparent,
|
||||
color: isSelected ? context.appColors.primary.withOpacity(0.1) : Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: Text(
|
||||
@@ -71,7 +73,7 @@ class MetricTrendChart extends StatelessWidget {
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal,
|
||||
color: isSelected ? AlarmColors.primary : AlarmColors.textSecondary,
|
||||
color: isSelected ? context.appColors.primary : context.appColors.textSecondary,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -81,7 +83,7 @@ class MetricTrendChart extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildChart() {
|
||||
Widget _buildChart(BuildContext context) {
|
||||
List<MetricDataPoint> dataPoints;
|
||||
double maxY;
|
||||
|
||||
@@ -101,10 +103,10 @@ class MetricTrendChart extends StatelessWidget {
|
||||
}
|
||||
|
||||
if (dataPoints.isEmpty) {
|
||||
return const Center(
|
||||
return Center(
|
||||
child: Text(
|
||||
'暂无数据',
|
||||
style: TextStyle(color: AlarmColors.textTertiary),
|
||||
style: TextStyle(color: context.appColors.textTertiary),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -123,13 +125,13 @@ class MetricTrendChart extends StatelessWidget {
|
||||
horizontalInterval: maxY / 5,
|
||||
getDrawingHorizontalLine: (value) {
|
||||
return FlLine(
|
||||
color: const Color(0xFFE5E6EB).withOpacity(0.3),
|
||||
color: context.appColors.divider.withOpacity(0.3),
|
||||
strokeWidth: 1,
|
||||
);
|
||||
},
|
||||
getDrawingVerticalLine: (value) {
|
||||
return FlLine(
|
||||
color: const Color(0xFFE5E6EB).withOpacity(0.3),
|
||||
color: context.appColors.divider.withOpacity(0.3),
|
||||
strokeWidth: 1,
|
||||
);
|
||||
},
|
||||
@@ -146,9 +148,9 @@ class MetricTrendChart extends StatelessWidget {
|
||||
if (index == 0 || index == dataPoints.length ~/ 2 || index == dataPoints.length - 1) {
|
||||
return Text(
|
||||
dataPoints[index].time,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: AlarmColors.textTertiary,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -165,9 +167,9 @@ class MetricTrendChart extends StatelessWidget {
|
||||
getTitlesWidget: (value, meta) {
|
||||
return Text(
|
||||
value.toInt().toString(),
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: AlarmColors.textTertiary,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -189,16 +191,16 @@ class MetricTrendChart extends StatelessWidget {
|
||||
LineChartBarData(
|
||||
spots: spots,
|
||||
isCurved: true,
|
||||
color: AlarmColors.primary,
|
||||
color: context.appColors.primary,
|
||||
barWidth: 2,
|
||||
dotData: FlDotData(
|
||||
show: true,
|
||||
getDotPainter: (spot, percent, barData, index) {
|
||||
return FlDotCirclePainter(
|
||||
radius: 3,
|
||||
color: AlarmColors.danger,
|
||||
color: context.appColors.danger,
|
||||
strokeWidth: 1,
|
||||
strokeColor: Colors.white,
|
||||
strokeColor: context.appColors.cardBackground,
|
||||
);
|
||||
},
|
||||
),
|
||||
@@ -206,8 +208,8 @@ class MetricTrendChart extends StatelessWidget {
|
||||
show: true,
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
AlarmColors.primary.withOpacity(0.2),
|
||||
AlarmColors.primary.withOpacity(0.0),
|
||||
context.appColors.primary.withOpacity(0.2),
|
||||
context.appColors.primary.withOpacity(0.0),
|
||||
],
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import '../../../../../core/consts/http_api_consts.dart';
|
||||
import '../../../../../core/consts/workorder_consts.dart';
|
||||
import 'workorder_remote_datasource.dart';
|
||||
import '../models/workorder_model.dart';
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import '../../../../../core/consts/workorder_consts.dart';
|
||||
import '../../../../../core/error/failure.dart';
|
||||
import '../repositories/workorder_repository.dart';
|
||||
import '../entities/workorder_entity.dart';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import '../../../../../core/app/app_user_cubit.dart';
|
||||
import '../../../../../core/network/dio_client.dart';
|
||||
import '../../../site/presentation/cubit/site_cubit.dart';
|
||||
@@ -76,8 +77,8 @@ class _TransferDialogContentState extends State<_TransferDialogContent> {
|
||||
},
|
||||
builder: (context, state) {
|
||||
return Container(
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white,
|
||||
decoration: BoxDecoration(
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
|
||||
),
|
||||
padding: EdgeInsets.only(
|
||||
@@ -107,19 +108,23 @@ class _TransferDialogContentState extends State<_TransferDialogContent> {
|
||||
Widget _buildHeader(BuildContext context) {
|
||||
return Row(
|
||||
children: [
|
||||
const Expanded(
|
||||
Expanded(
|
||||
child: Text(
|
||||
'转派工单',
|
||||
style: TextStyle(
|
||||
fontSize: 17,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF1D2129),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () => Navigator.of(context).pop(),
|
||||
child: const Icon(Icons.close, size: 24, color: Color(0xFF86909C)),
|
||||
child: Icon(
|
||||
Icons.close,
|
||||
size: 24,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -136,12 +141,15 @@ class _TransferDialogContentState extends State<_TransferDialogContent> {
|
||||
}
|
||||
|
||||
if (state.users.isEmpty) {
|
||||
return const Padding(
|
||||
return Padding(
|
||||
padding: EdgeInsets.all(24),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'暂无可转派人员',
|
||||
style: TextStyle(color: Color(0xFF86909C), fontSize: 14),
|
||||
style: TextStyle(
|
||||
color: context.appColors.textTertiary,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -167,12 +175,12 @@ class _TransferDialogContentState extends State<_TransferDialogContent> {
|
||||
margin: const EdgeInsets.only(bottom: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected
|
||||
? const Color(0xFFE8F3FF)
|
||||
: const Color(0xFFF7F8FA),
|
||||
? context.appColors.primary.withOpacity(0.1)
|
||||
: context.appColors.fillBackground,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(
|
||||
color: isSelected
|
||||
? const Color(0xFF165DFF)
|
||||
? context.appColors.primary
|
||||
: Colors.transparent,
|
||||
),
|
||||
),
|
||||
@@ -181,8 +189,8 @@ class _TransferDialogContentState extends State<_TransferDialogContent> {
|
||||
CircleAvatar(
|
||||
radius: 18,
|
||||
backgroundColor: isSelected
|
||||
? const Color(0xFF165DFF)
|
||||
: const Color(0xFFC9CDD4),
|
||||
? context.appColors.primary
|
||||
: context.appColors.textTertiary,
|
||||
child: Text(
|
||||
userName.isNotEmpty ? userName[0] : '?',
|
||||
style: const TextStyle(color: Colors.white, fontSize: 14),
|
||||
@@ -192,16 +200,16 @@ class _TransferDialogContentState extends State<_TransferDialogContent> {
|
||||
Expanded(
|
||||
child: Text(
|
||||
userName.isNotEmpty ? userName : '未知用户',
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
color: Color(0xFF1D2129),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (isSelected)
|
||||
const Icon(
|
||||
Icon(
|
||||
Icons.check_circle,
|
||||
color: Color(0xFF165DFF),
|
||||
color: context.appColors.primary,
|
||||
size: 22,
|
||||
),
|
||||
],
|
||||
@@ -217,28 +225,30 @@ class _TransferDialogContentState extends State<_TransferDialogContent> {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
'派发备注(选填)',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF1D2129),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF7F8FA),
|
||||
color: context.appColors.fillBackground,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: TextField(
|
||||
controller: _remarkController,
|
||||
maxLines: 3,
|
||||
maxLength: 200,
|
||||
style: TextStyle(color: context.appColors.textPrimary),
|
||||
onChanged: (value) =>
|
||||
context.read<TransferCubit>().updateRemark(value),
|
||||
decoration: const InputDecoration(
|
||||
decoration: InputDecoration(
|
||||
hintText: '请输入派发备注',
|
||||
hintStyle: TextStyle(color: context.appColors.textTertiary),
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.all(12),
|
||||
isDense: true,
|
||||
@@ -262,7 +272,7 @@ class _TransferDialogContentState extends State<_TransferDialogContent> {
|
||||
);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF165DFF),
|
||||
backgroundColor: context.appColors.primary,
|
||||
foregroundColor: Colors.white,
|
||||
elevation: 0,
|
||||
padding: EdgeInsets.zero,
|
||||
@@ -289,24 +299,32 @@ class _TransferDialogContentState extends State<_TransferDialogContent> {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (_) => AlertDialog(
|
||||
backgroundColor: context.appColors.cardBackground,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(Icons.error_outline, size: 48, color: Color(0xFFF53F3F)),
|
||||
Icon(
|
||||
Icons.error_outline,
|
||||
size: 48,
|
||||
color: context.appColors.danger,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const Text(
|
||||
Text(
|
||||
'转派失败',
|
||||
style: TextStyle(
|
||||
fontSize: 17,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF1D2129),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
message,
|
||||
style: const TextStyle(fontSize: 14, color: Color(0xFF86909C)),
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
@@ -317,7 +335,7 @@ class _TransferDialogContentState extends State<_TransferDialogContent> {
|
||||
child: ElevatedButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF165DFF),
|
||||
backgroundColor: context.appColors.primary,
|
||||
foregroundColor: Colors.white,
|
||||
elevation: 0,
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import 'package:video_player/video_player.dart';
|
||||
import '../../../../../core/consts/workorder_consts.dart';
|
||||
import '../cubit/workorder_detail_cubit.dart';
|
||||
@@ -29,13 +30,18 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle.dark.copyWith(
|
||||
statusBarColor: Colors.transparent,
|
||||
statusBarIconBrightness: Brightness.dark,
|
||||
),
|
||||
value: isDark
|
||||
? SystemUiOverlayStyle.light.copyWith(
|
||||
statusBarColor: Colors.transparent,
|
||||
)
|
||||
: SystemUiOverlayStyle.dark.copyWith(
|
||||
statusBarColor: Colors.transparent,
|
||||
statusBarIconBrightness: Brightness.dark,
|
||||
),
|
||||
child: Scaffold(
|
||||
backgroundColor: WorkOrderColors.pageBackground,
|
||||
backgroundColor: context.appColors.pageBackground,
|
||||
appBar: _buildAppBar(),
|
||||
body: BlocBuilder<WorkOrderDetailCubit, WorkOrderDetailState>(
|
||||
builder: (context, state) {
|
||||
@@ -61,26 +67,26 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
|
||||
PreferredSizeWidget _buildAppBar() {
|
||||
return AppBar(
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: context.appColors.cardBackground,
|
||||
elevation: 0,
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back, color: WorkOrderColors.primaryText),
|
||||
icon: Icon(Icons.arrow_back, color: context.appColors.textPrimary),
|
||||
onPressed: () => context.pop(),
|
||||
),
|
||||
title: const Text(
|
||||
title: Text(
|
||||
'工单详情',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: WorkOrderColors.primaryText,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
centerTitle: true,
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
icon: Icon(
|
||||
Icons.more_horiz,
|
||||
color: WorkOrderColors.primaryText,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
onPressed: () {},
|
||||
),
|
||||
@@ -89,9 +95,9 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
}
|
||||
|
||||
Widget _buildLoadingView() {
|
||||
return const Center(
|
||||
return Center(
|
||||
child: CircularProgressIndicator(
|
||||
valueColor: AlwaysStoppedAnimation<Color>(WorkOrderColors.primary),
|
||||
valueColor: AlwaysStoppedAnimation<Color>(context.appColors.primary),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -104,21 +110,21 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
Icon(
|
||||
Icons.error_outline,
|
||||
size: 48,
|
||||
color: WorkOrderColors.auxiliaryText,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
message,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: WorkOrderColors.auxiliaryText,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
ElevatedButton(
|
||||
onPressed: () => _cubit.loadWorkOrderDetail(widget.orderId),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: WorkOrderColors.primary,
|
||||
backgroundColor: context.appColors.primary,
|
||||
foregroundColor: Colors.white,
|
||||
),
|
||||
child: const Text('重试'),
|
||||
@@ -167,18 +173,24 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: WorkOrderColors.cardShadow,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
'工单编号',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: WorkOrderColors.auxiliaryText,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
@@ -187,10 +199,10 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
Expanded(
|
||||
child: Text(
|
||||
workOrder.orderNo,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: WorkOrderColors.primaryText,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -201,7 +213,7 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
vertical: 4,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFFF4D4F),
|
||||
color: context.appColors.danger,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: const Text(
|
||||
@@ -218,22 +230,22 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
workOrder.title,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: WorkOrderColors.primaryText,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_buildInfoRow(
|
||||
'状态',
|
||||
_getStatusLabel(workOrder.status),
|
||||
valueColor: _getStatusColor(workOrder.status),
|
||||
valueColor: _getStatusColor(context, workOrder.status),
|
||||
),
|
||||
_buildInfoRow(
|
||||
'优先级',
|
||||
_getPriorityLabel(workOrder.priority),
|
||||
valueColor: _getPriorityColor(workOrder.priority),
|
||||
valueColor: _getPriorityColor(context, workOrder.priority),
|
||||
),
|
||||
_buildInfoRow('来源', workOrder.source ?? '--'),
|
||||
_buildInfoRow(
|
||||
@@ -250,19 +262,25 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: WorkOrderColors.cardShadow,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
'基本信息',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: WorkOrderColors.primaryText,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
@@ -294,19 +312,25 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: WorkOrderColors.cardShadow,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
'设备信息',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: WorkOrderColors.primaryText,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
@@ -321,19 +345,25 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: WorkOrderColors.cardShadow,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
'时间信息',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: WorkOrderColors.primaryText,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
@@ -359,19 +389,25 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: WorkOrderColors.cardShadow,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
'任务描述',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: WorkOrderColors.primaryText,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
@@ -379,7 +415,7 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
workOrder.taskDescription!,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: WorkOrderColors.secondaryText,
|
||||
color: context.appColors.textSecondary,
|
||||
height: 1.6,
|
||||
),
|
||||
),
|
||||
@@ -392,19 +428,25 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: WorkOrderColors.cardShadow,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
'处理信息',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: WorkOrderColors.primaryText,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
@@ -428,21 +470,27 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: WorkOrderColors.cardShadow,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
'附件',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: WorkOrderColors.primaryText,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
@@ -450,7 +498,7 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
'(${hasImages ? workOrder.attachments!.length : 0}张图片${hasVideos ? ' ${workOrder.videoUrls!.length}个视频' : ''})',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: WorkOrderColors.auxiliaryText,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -482,9 +530,9 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
width: 80,
|
||||
height: 80,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF7F8FA),
|
||||
color: context.appColors.fillBackground,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: const Color(0xFFE5E6EB)),
|
||||
border: Border.all(color: context.appColors.divider),
|
||||
),
|
||||
child: attachment.url.isNotEmpty
|
||||
? ClipRRect(
|
||||
@@ -496,10 +544,10 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icon(
|
||||
Icons.image_outlined,
|
||||
size: 32,
|
||||
color: WorkOrderColors.auxiliaryText,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
@@ -508,7 +556,7 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
: '图片',
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: WorkOrderColors.auxiliaryText,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
maxLines: 2,
|
||||
@@ -522,17 +570,17 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icon(
|
||||
Icons.image_outlined,
|
||||
size: 32,
|
||||
color: WorkOrderColors.auxiliaryText,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
attachment.fileName.isNotEmpty ? attachment.fileName : '图片',
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: WorkOrderColors.auxiliaryText,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
maxLines: 2,
|
||||
@@ -551,24 +599,24 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
width: 80,
|
||||
height: 80,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF7F8FA),
|
||||
color: context.appColors.fillBackground,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: const Color(0xFFE5E6EB)),
|
||||
border: Border.all(color: context.appColors.divider),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icon(
|
||||
Icons.video_library_outlined,
|
||||
size: 32,
|
||||
color: WorkOrderColors.primary,
|
||||
color: context.appColors.primary,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
const Text(
|
||||
Text(
|
||||
'视频',
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: WorkOrderColors.auxiliaryText,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
maxLines: 2,
|
||||
@@ -644,10 +692,10 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.fromLTRB(16, 10, 16, 16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, -2),
|
||||
),
|
||||
@@ -658,8 +706,8 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
child: ElevatedButton(
|
||||
onPressed: () {},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFFF2F3F5),
|
||||
foregroundColor: const Color(0xFF86909C),
|
||||
backgroundColor: context.appColors.fillBackground,
|
||||
foregroundColor: context.appColors.textTertiary,
|
||||
elevation: 0,
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
shape: RoundedRectangleBorder(
|
||||
@@ -679,10 +727,10 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.fromLTRB(16, 10, 16, 16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, -2),
|
||||
),
|
||||
@@ -698,10 +746,10 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
_showTransferDialog(workOrder);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.white,
|
||||
foregroundColor: WorkOrderColors.primary,
|
||||
backgroundColor: context.appColors.cardBackground,
|
||||
foregroundColor: context.appColors.primary,
|
||||
elevation: 0,
|
||||
side: const BorderSide(color: WorkOrderColors.primary),
|
||||
side: BorderSide(color: context.appColors.primary),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 12,
|
||||
@@ -728,7 +776,7 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: WorkOrderColors.primary,
|
||||
backgroundColor: context.appColors.primary,
|
||||
foregroundColor: Colors.white,
|
||||
elevation: 0,
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
@@ -752,10 +800,10 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
context.push('/workorder/detail/$widget.orderId/process');
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.white,
|
||||
foregroundColor: WorkOrderColors.primary,
|
||||
backgroundColor: context.appColors.cardBackground,
|
||||
foregroundColor: context.appColors.primary,
|
||||
elevation: 0,
|
||||
side: const BorderSide(color: WorkOrderColors.primary),
|
||||
side: BorderSide(color: context.appColors.primary),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 12,
|
||||
@@ -806,7 +854,7 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: WorkOrderColors.auxiliaryText,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
@@ -818,7 +866,7 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: valueColor ?? WorkOrderColors.primaryText,
|
||||
color: valueColor ?? context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -838,14 +886,14 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
}
|
||||
}
|
||||
|
||||
Color _getPriorityColor(WorkOrderPriority priority) {
|
||||
Color _getPriorityColor(BuildContext context, WorkOrderPriority priority) {
|
||||
switch (priority) {
|
||||
case WorkOrderPriority.high:
|
||||
return const Color(0xFFFF4D4F);
|
||||
return context.appColors.danger;
|
||||
case WorkOrderPriority.medium:
|
||||
return const Color(0xFFFF7D00);
|
||||
return context.appColors.warning;
|
||||
case WorkOrderPriority.low:
|
||||
return WorkOrderColors.auxiliaryText;
|
||||
return context.appColors.textTertiary;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -862,16 +910,16 @@ class _WorkOrderDetailPageState extends State<WorkOrderDetailPage> {
|
||||
}
|
||||
}
|
||||
|
||||
Color _getStatusColor(WorkOrderStatus status) {
|
||||
Color _getStatusColor(BuildContext context, WorkOrderStatus status) {
|
||||
switch (status) {
|
||||
case WorkOrderStatus.pending:
|
||||
return const Color(0xFFFF7D00);
|
||||
return context.appColors.warning;
|
||||
case WorkOrderStatus.executing:
|
||||
return WorkOrderColors.primary;
|
||||
return context.appColors.primary;
|
||||
case WorkOrderStatus.completed:
|
||||
return const Color(0xFF00B42A);
|
||||
return context.appColors.success;
|
||||
case WorkOrderStatus.all:
|
||||
return WorkOrderColors.auxiliaryText;
|
||||
return context.appColors.textTertiary;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'package:flutter/services.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import 'package:video_player/video_player.dart';
|
||||
import '../../../../../core/consts/workorder_consts.dart';
|
||||
import '../../domain/entities/workorder_entity.dart';
|
||||
@@ -101,35 +102,43 @@ class _WorkOrderOnSitePageState extends State<WorkOrderOnSitePage> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle.dark.copyWith(
|
||||
statusBarColor: Colors.transparent,
|
||||
statusBarIconBrightness: Brightness.dark,
|
||||
),
|
||||
value: isDark
|
||||
? SystemUiOverlayStyle.light.copyWith(
|
||||
statusBarColor: Colors.transparent,
|
||||
)
|
||||
: SystemUiOverlayStyle.dark.copyWith(
|
||||
statusBarColor: Colors.transparent,
|
||||
statusBarIconBrightness: Brightness.dark,
|
||||
),
|
||||
child: Scaffold(
|
||||
backgroundColor: const Color(0xFFF5F5F5),
|
||||
backgroundColor: context.appColors.pageBackground,
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: context.appColors.cardBackground,
|
||||
elevation: 0,
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back, color: Color(0xFF1F2329)),
|
||||
icon: Icon(Icons.arrow_back, color: context.appColors.textPrimary),
|
||||
onPressed: () => context.pop(_dataChanged),
|
||||
),
|
||||
title: const Text(
|
||||
title: Text(
|
||||
'现场执行',
|
||||
style: TextStyle(
|
||||
fontSize: 17,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF1F2329),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
centerTitle: true,
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {},
|
||||
child: const Text(
|
||||
child: Text(
|
||||
'更多',
|
||||
style: TextStyle(fontSize: 15, color: Color(0xFF1890FF)),
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
color: context.appColors.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -166,7 +175,7 @@ class _WorkOrderOnSitePageState extends State<WorkOrderOnSitePage> {
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
@@ -178,10 +187,10 @@ class _WorkOrderOnSitePageState extends State<WorkOrderOnSitePage> {
|
||||
Expanded(
|
||||
child: Text(
|
||||
workOrder.orderNo,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFF1F2329),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -192,7 +201,7 @@ class _WorkOrderOnSitePageState extends State<WorkOrderOnSitePage> {
|
||||
vertical: 4,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFFF4D4F),
|
||||
color: context.appColors.danger,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: const Text(
|
||||
@@ -242,7 +251,10 @@ class _WorkOrderOnSitePageState extends State<WorkOrderOnSitePage> {
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(fontSize: 13, color: Color(0xFF86909C)),
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
@@ -250,19 +262,19 @@ class _WorkOrderOnSitePageState extends State<WorkOrderOnSitePage> {
|
||||
Expanded(
|
||||
child: Text(
|
||||
value,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: Color(0xFF1F2329),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (showArrow)
|
||||
const Padding(
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 8),
|
||||
child: Icon(
|
||||
Icons.chevron_right,
|
||||
size: 18,
|
||||
color: Color(0xFFBBBBBB),
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -279,32 +291,38 @@ class _WorkOrderOnSitePageState extends State<WorkOrderOnSitePage> {
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(fontSize: 13, color: Color(0xFF86909C)),
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
value,
|
||||
style: const TextStyle(fontSize: 13, color: Color(0xFF1F2329)),
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
if (showLocation)
|
||||
const Padding(
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 8),
|
||||
child: Icon(
|
||||
Icons.location_on,
|
||||
size: 16,
|
||||
color: Color(0xFF1890FF),
|
||||
color: context.appColors.primary,
|
||||
),
|
||||
),
|
||||
if (showArrow)
|
||||
const Padding(
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 8),
|
||||
child: Icon(
|
||||
Icons.chevron_right,
|
||||
size: 18,
|
||||
color: Color(0xFFBBBBBB),
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -327,13 +345,16 @@ class _WorkOrderOnSitePageState extends State<WorkOrderOnSitePage> {
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(fontSize: 13, color: Color(0xFF86909C)),
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
value,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: valueColor ?? const Color(0xFF1F2329),
|
||||
color: valueColor ?? context.appColors.textPrimary,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
@@ -358,13 +379,13 @@ class _WorkOrderOnSitePageState extends State<WorkOrderOnSitePage> {
|
||||
Color _getStatusColor(WorkOrderStatus status) {
|
||||
switch (status) {
|
||||
case WorkOrderStatus.pending:
|
||||
return const Color(0xFFFF7D00);
|
||||
return context.appColors.warning;
|
||||
case WorkOrderStatus.executing:
|
||||
return const Color(0xFF1890FF);
|
||||
return context.appColors.primary;
|
||||
case WorkOrderStatus.completed:
|
||||
return const Color(0xFF00B42A);
|
||||
return context.appColors.success;
|
||||
case WorkOrderStatus.all:
|
||||
return const Color(0xFF86909C);
|
||||
return context.appColors.textTertiary;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,11 +403,11 @@ class _WorkOrderOnSitePageState extends State<WorkOrderOnSitePage> {
|
||||
Color _getPriorityColor(WorkOrderPriority priority) {
|
||||
switch (priority) {
|
||||
case WorkOrderPriority.high:
|
||||
return const Color(0xFFFF4D4F);
|
||||
return context.appColors.danger;
|
||||
case WorkOrderPriority.medium:
|
||||
return const Color(0xFFFF7D00);
|
||||
return context.appColors.warning;
|
||||
case WorkOrderPriority.low:
|
||||
return const Color(0xFF86909C);
|
||||
return context.appColors.textTertiary;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,18 +446,18 @@ class _WorkOrderOnSitePageState extends State<WorkOrderOnSitePage> {
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
'检查项清单 (5/7)',
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF1F2329),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
@@ -457,10 +478,10 @@ class _WorkOrderOnSitePageState extends State<WorkOrderOnSitePage> {
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: item.checked
|
||||
? const Color(0xFF52C41A)
|
||||
? context.appColors.success
|
||||
: item.current
|
||||
? const Color(0xFF1890FF)
|
||||
: const Color(0xFF1F2329),
|
||||
? context.appColors.primary
|
||||
: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
@@ -470,16 +491,16 @@ class _WorkOrderOnSitePageState extends State<WorkOrderOnSitePage> {
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: item.checked
|
||||
? const Color(0xFF52C41A)
|
||||
? context.appColors.success
|
||||
: item.current
|
||||
? const Color(0xFF1890FF)
|
||||
: const Color(0xFFD9D9D9),
|
||||
? context.appColors.primary
|
||||
: context.appColors.divider,
|
||||
width: 2,
|
||||
),
|
||||
color: item.checked
|
||||
? const Color(0xFF52C41A)
|
||||
? context.appColors.success
|
||||
: item.current
|
||||
? const Color(0xFFE6F7FF)
|
||||
? context.appColors.primary.withOpacity(0.1)
|
||||
: Colors.transparent,
|
||||
),
|
||||
child: item.checked
|
||||
@@ -488,9 +509,9 @@ class _WorkOrderOnSitePageState extends State<WorkOrderOnSitePage> {
|
||||
? Container(
|
||||
width: 8,
|
||||
height: 8,
|
||||
decoration: const BoxDecoration(
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Color(0xFF1890FF),
|
||||
color: context.appColors.primary,
|
||||
),
|
||||
)
|
||||
: Container(),
|
||||
@@ -508,18 +529,18 @@ class _WorkOrderOnSitePageState extends State<WorkOrderOnSitePage> {
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
'现场记录',
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF1F2329),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
@@ -535,16 +556,23 @@ class _WorkOrderOnSitePageState extends State<WorkOrderOnSitePage> {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 16),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF5F7FA),
|
||||
color: context.appColors.fillBackground,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.mic_none, size: 24, color: Color(0xFFBBBBBB)),
|
||||
Icon(
|
||||
Icons.mic_none,
|
||||
size: 24,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
const Text(
|
||||
Text(
|
||||
'录音备注',
|
||||
style: TextStyle(fontSize: 13, color: Color(0xFF86909C)),
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -562,24 +590,30 @@ class _WorkOrderOnSitePageState extends State<WorkOrderOnSitePage> {
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
'现场照片',
|
||||
style: TextStyle(fontSize: 13, color: Color(0xFF86909C)),
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'(${hasImages ? workOrder.attachments!.length : 0}张图片${hasVideos ? ' ${workOrder.videoUrls!.length}个视频' : ''})',
|
||||
style: const TextStyle(fontSize: 13, color: Color(0xFF1890FF)),
|
||||
style: TextStyle(fontSize: 13, color: context.appColors.primary),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
if (!hasImages && !hasVideos)
|
||||
const Padding(
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 16),
|
||||
child: Text(
|
||||
'暂无照片或视频',
|
||||
style: TextStyle(fontSize: 13, color: Color(0xFFBBBBBB)),
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
)
|
||||
else
|
||||
@@ -613,8 +647,8 @@ class _WorkOrderOnSitePageState extends State<WorkOrderOnSitePage> {
|
||||
height: 64,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
color: const Color(0xFFF7F8FA),
|
||||
border: Border.all(color: const Color(0xFFE5E6EB)),
|
||||
color: context.appColors.fillBackground,
|
||||
border: Border.all(color: context.appColors.divider),
|
||||
),
|
||||
child: isImage
|
||||
? ClipRRect(
|
||||
@@ -623,19 +657,19 @@ class _WorkOrderOnSitePageState extends State<WorkOrderOnSitePage> {
|
||||
url,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return const Icon(
|
||||
return Icon(
|
||||
Icons.image_outlined,
|
||||
size: 24,
|
||||
color: Color(0xFFBBBBBB),
|
||||
color: context.appColors.textTertiary,
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
: const Center(
|
||||
: Center(
|
||||
child: Icon(
|
||||
Icons.video_library_outlined,
|
||||
size: 24,
|
||||
color: Color(0xFF1890FF),
|
||||
color: context.appColors.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -706,9 +740,13 @@ class _WorkOrderOnSitePageState extends State<WorkOrderOnSitePage> {
|
||||
height: 64,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: const Color(0xFFD9D9D9), width: 1),
|
||||
border: Border.all(color: context.appColors.divider, width: 1),
|
||||
),
|
||||
child: Icon(
|
||||
Icons.camera_alt,
|
||||
size: 24,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
child: const Icon(Icons.camera_alt, size: 24, color: Color(0xFFBBBBBB)),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -717,10 +755,10 @@ class _WorkOrderOnSitePageState extends State<WorkOrderOnSitePage> {
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.fromLTRB(16, 10, 16, 16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, -2),
|
||||
),
|
||||
@@ -734,7 +772,7 @@ class _WorkOrderOnSitePageState extends State<WorkOrderOnSitePage> {
|
||||
child: ElevatedButton(
|
||||
onPressed: _isOperating ? null : _handleStartWork,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF52C41A),
|
||||
backgroundColor: context.appColors.success,
|
||||
foregroundColor: Colors.white,
|
||||
elevation: 0,
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
@@ -770,7 +808,7 @@ class _WorkOrderOnSitePageState extends State<WorkOrderOnSitePage> {
|
||||
child: ElevatedButton(
|
||||
onPressed: _isOperating ? null : _handleSuspendWork,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFFFAAD14),
|
||||
backgroundColor: context.appColors.warning,
|
||||
foregroundColor: Colors.white,
|
||||
elevation: 0,
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
@@ -814,7 +852,7 @@ class _WorkOrderOnSitePageState extends State<WorkOrderOnSitePage> {
|
||||
}
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF1890FF),
|
||||
backgroundColor: context.appColors.primary,
|
||||
foregroundColor: Colors.white,
|
||||
elevation: 0,
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
|
||||
@@ -7,8 +7,8 @@ import 'package:get_it/get_it.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:maibu_satabot_v2/core/localization/app_localizations.dart';
|
||||
import 'package:maibu_satabot_v2/core/network/dio_client.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import 'package:maibu_satabot_v2/features/v2/site/presentation/cubit/site_cubit.dart';
|
||||
import '../../../../../core/consts/workorder_consts.dart';
|
||||
import '../../../site/presentation/widgets/site_selector_widget.dart';
|
||||
import '../cubit/workorder_cubit.dart';
|
||||
import '../widgets/workorder_tabbar.dart';
|
||||
@@ -79,12 +79,13 @@ class _WorkOrderPageState extends State<WorkOrderPage> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
return BlocProvider.value(
|
||||
value: _cubit,
|
||||
child: AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle.dark,
|
||||
value: isDark ? SystemUiOverlayStyle.light : SystemUiOverlayStyle.dark,
|
||||
child: Scaffold(
|
||||
backgroundColor: const Color(0xFFF7F8FA),
|
||||
backgroundColor: context.appColors.pageBackground,
|
||||
body: BlocConsumer<WorkOrderCubit, WorkOrderState>(
|
||||
listener: (context, state) {
|
||||
if (state is WorkOrderLoaded && state.errorMessage != null) {
|
||||
@@ -115,7 +116,7 @@ class _WorkOrderPageState extends State<WorkOrderPage> {
|
||||
Widget _buildLoadingView() {
|
||||
return Center(
|
||||
child: CircularProgressIndicator(
|
||||
valueColor: AlwaysStoppedAnimation<Color>(AppConstants.primaryColor),
|
||||
valueColor: AlwaysStoppedAnimation<Color>(context.appColors.primary),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -128,14 +129,14 @@ class _WorkOrderPageState extends State<WorkOrderPage> {
|
||||
Icon(
|
||||
Icons.inbox_outlined,
|
||||
size: 48,
|
||||
color: AppConstants.auxiliaryTextColor,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'无数据',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: AppConstants.auxiliaryTextColor,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -195,14 +196,18 @@ class _WorkOrderPageState extends State<WorkOrderPage> {
|
||||
children: [
|
||||
const Flexible(child: SiteSelectorWidget(compact: true)),
|
||||
const SizedBox(width: 8),
|
||||
Container(width: 1, height: 20, color: const Color(0xFFE5E6EB)),
|
||||
Container(
|
||||
width: 1,
|
||||
height: 20,
|
||||
color: context.appColors.divider,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
AppLocalizations.of(context).translate('work_order_v2.title'),
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF86909C),
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -210,10 +215,10 @@ class _WorkOrderPageState extends State<WorkOrderPage> {
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () => context.push('/workorder/report'),
|
||||
child: const Icon(
|
||||
child: Icon(
|
||||
Icons.bar_chart,
|
||||
size: 24,
|
||||
color: Color(0xFF1D2129),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -237,17 +242,23 @@ class _WorkOrderPageState extends State<WorkOrderPage> {
|
||||
child: Center(child: CircularProgressIndicator()),
|
||||
);
|
||||
} else if (state.hasMore) {
|
||||
return const Padding(
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 16),
|
||||
child: Center(
|
||||
child: Text('上滑加载更多', style: TextStyle(color: Color(0xFF86909C))),
|
||||
child: Text(
|
||||
'上滑加载更多',
|
||||
style: TextStyle(color: context.appColors.textTertiary),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return const Padding(
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 16),
|
||||
child: Center(
|
||||
child: Text('已加载全部数据', style: TextStyle(color: Color(0xFF86909C))),
|
||||
child: Text(
|
||||
'已加载全部数据',
|
||||
style: TextStyle(color: context.appColors.textTertiary),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
|
||||
class WorkOrderProcessPage extends StatelessWidget {
|
||||
final String orderId;
|
||||
@@ -9,26 +10,26 @@ class WorkOrderProcessPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xFFF5F5F5),
|
||||
backgroundColor: context.appColors.pageBackground,
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: context.appColors.cardBackground,
|
||||
elevation: 0,
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back, color: Color(0xFF1F2329)),
|
||||
icon: Icon(Icons.arrow_back, color: context.appColors.textPrimary),
|
||||
onPressed: () => context.pop(),
|
||||
),
|
||||
title: const Text(
|
||||
title: Text(
|
||||
'工单流程',
|
||||
style: TextStyle(
|
||||
fontSize: 17,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF1F2329),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
centerTitle: true,
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.share, color: Color(0xFF86909C)),
|
||||
icon: Icon(Icons.share, color: context.appColors.textTertiary),
|
||||
onPressed: () {},
|
||||
),
|
||||
],
|
||||
@@ -37,18 +38,18 @@ class WorkOrderProcessPage extends StatelessWidget {
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
children: [
|
||||
_buildProcessTimeline(),
|
||||
_buildProcessTimeline(context),
|
||||
const SizedBox(height: 24),
|
||||
_buildExecutionRecords(),
|
||||
_buildExecutionRecords(context),
|
||||
const SizedBox(height: 32),
|
||||
],
|
||||
),
|
||||
),
|
||||
bottomNavigationBar: _buildBottomIndicator(),
|
||||
bottomNavigationBar: _buildBottomIndicator(context),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildProcessTimeline() {
|
||||
Widget _buildProcessTimeline(BuildContext context) {
|
||||
final processes = [
|
||||
_ProcessStep(
|
||||
status: ProcessStatus.completed,
|
||||
@@ -92,7 +93,7 @@ class WorkOrderProcessPage extends StatelessWidget {
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
@@ -102,13 +103,14 @@ class WorkOrderProcessPage extends StatelessWidget {
|
||||
final isLast = index == processes.length - 1;
|
||||
final nextStatus = isLast ? null : processes[index + 1].status;
|
||||
|
||||
return _buildProcessItem(step, nextStatus, isLast);
|
||||
return _buildProcessItem(context, step, nextStatus, isLast);
|
||||
}).toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildProcessItem(
|
||||
BuildContext context,
|
||||
_ProcessStep step,
|
||||
ProcessStatus? nextStatus,
|
||||
bool isLast,
|
||||
@@ -120,8 +122,8 @@ class WorkOrderProcessPage extends StatelessWidget {
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
_buildStatusIcon(step.status, 0),
|
||||
if (showLine) _buildProcessLine(step.status, nextStatus!),
|
||||
_buildStatusIcon(context, step.status, 0),
|
||||
if (showLine) _buildProcessLine(context, step.status, nextStatus!),
|
||||
],
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
@@ -137,8 +139,8 @@ class WorkOrderProcessPage extends StatelessWidget {
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: step.status == ProcessStatus.completed
|
||||
? const Color(0xFF1F2329)
|
||||
: const Color(0xFFBBBBBB),
|
||||
? context.appColors.textPrimary
|
||||
: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
if (step.time.isNotEmpty) ...[
|
||||
@@ -148,8 +150,8 @@ class WorkOrderProcessPage extends StatelessWidget {
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: step.status == ProcessStatus.completed
|
||||
? const Color(0xFF86909C)
|
||||
: const Color(0xFFBBBBBB),
|
||||
? context.appColors.textTertiary
|
||||
: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -162,8 +164,8 @@ class WorkOrderProcessPage extends StatelessWidget {
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: step.status == ProcessStatus.completed
|
||||
? const Color(0xFF86909C)
|
||||
: const Color(0xFFBBBBBB),
|
||||
? context.appColors.textTertiary
|
||||
: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -175,7 +177,7 @@ class WorkOrderProcessPage extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStatusIcon(ProcessStatus status, int index) {
|
||||
Widget _buildStatusIcon(BuildContext context, ProcessStatus status, int index) {
|
||||
Widget icon;
|
||||
Color iconColor;
|
||||
Color backgroundColor;
|
||||
@@ -183,18 +185,18 @@ class WorkOrderProcessPage extends StatelessWidget {
|
||||
switch (status) {
|
||||
case ProcessStatus.completed:
|
||||
icon = const Icon(Icons.check, size: 16);
|
||||
iconColor = const Color(0xFF52C41A);
|
||||
backgroundColor = const Color(0xFFF6FFED);
|
||||
iconColor = context.appColors.success;
|
||||
backgroundColor = context.appColors.success.withOpacity(0.1);
|
||||
break;
|
||||
case ProcessStatus.current:
|
||||
icon = const Icon(Icons.check, size: 16);
|
||||
iconColor = const Color(0xFF1890FF);
|
||||
backgroundColor = const Color(0xFFE6F7FF);
|
||||
iconColor = context.appColors.primary;
|
||||
backgroundColor = context.appColors.primary.withOpacity(0.1);
|
||||
break;
|
||||
case ProcessStatus.pending:
|
||||
icon = Container();
|
||||
iconColor = const Color(0xFFBBBBBB);
|
||||
backgroundColor = const Color(0xFFFAFAFA);
|
||||
iconColor = context.appColors.textTertiary;
|
||||
backgroundColor = context.appColors.fillBackground;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -211,18 +213,19 @@ class WorkOrderProcessPage extends StatelessWidget {
|
||||
}
|
||||
|
||||
Widget _buildProcessLine(
|
||||
BuildContext context,
|
||||
ProcessStatus currentStatus,
|
||||
ProcessStatus nextStatus,
|
||||
) {
|
||||
Color lineColor;
|
||||
if (currentStatus == ProcessStatus.completed &&
|
||||
nextStatus == ProcessStatus.completed) {
|
||||
lineColor = const Color(0xFF52C41A);
|
||||
lineColor = context.appColors.success;
|
||||
} else if (currentStatus == ProcessStatus.completed &&
|
||||
nextStatus == ProcessStatus.current) {
|
||||
lineColor = const Color(0xFF1890FF);
|
||||
lineColor = context.appColors.primary;
|
||||
} else {
|
||||
lineColor = const Color(0xFFE8E8E8);
|
||||
lineColor = context.appColors.divider;
|
||||
}
|
||||
|
||||
return Container(
|
||||
@@ -233,7 +236,7 @@ class WorkOrderProcessPage extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildExecutionRecords() {
|
||||
Widget _buildExecutionRecords(BuildContext context) {
|
||||
final records = [
|
||||
_ExecutionRecord(time: '2025-05-21 09:20', action: '到达现场'),
|
||||
_ExecutionRecord(time: '2025-05-21 09:35', action: '现场定位打卡'),
|
||||
@@ -249,41 +252,47 @@ class WorkOrderProcessPage extends StatelessWidget {
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
'执行记录',
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF1F2329),
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
...records.map((record) => _buildRecordItem(record)),
|
||||
...records.map((record) => _buildRecordItem(context, record)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRecordItem(_ExecutionRecord record) {
|
||||
Widget _buildRecordItem(BuildContext context, _ExecutionRecord record) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
record.time,
|
||||
style: const TextStyle(fontSize: 12, color: Color(0xFF86909C)),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 32),
|
||||
Expanded(
|
||||
child: Text(
|
||||
record.action,
|
||||
style: const TextStyle(fontSize: 13, color: Color(0xFF1F2329)),
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -291,15 +300,15 @@ class WorkOrderProcessPage extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBottomIndicator() {
|
||||
Widget _buildBottomIndicator(BuildContext context) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.fromLTRB(16, 10, 16, 16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, -2),
|
||||
),
|
||||
@@ -309,8 +318,8 @@ class WorkOrderProcessPage extends StatelessWidget {
|
||||
height: 48,
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFF1890FF),
|
||||
decoration: BoxDecoration(
|
||||
color: context.appColors.primary,
|
||||
borderRadius: BorderRadius.all(Radius.circular(8)),
|
||||
),
|
||||
child: const Center(
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import '../../domain/entities/workorder_entity.dart';
|
||||
import '../../../work_order/domain/usecases/work_order_usecases.dart';
|
||||
|
||||
@@ -45,18 +46,18 @@ class _WorkOrderReceiptPageState extends State<WorkOrderReceiptPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xFFF7F8FA),
|
||||
backgroundColor: context.appColors.pageBackground,
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: context.appColors.cardBackground,
|
||||
elevation: 0.5,
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back, color: Color(0xFF1D2129)),
|
||||
icon: Icon(Icons.arrow_back, color: context.appColors.textPrimary),
|
||||
onPressed: () => context.pop(),
|
||||
),
|
||||
title: const Text(
|
||||
title: Text(
|
||||
'工单回执',
|
||||
style: TextStyle(
|
||||
color: Color(0xFF1D2129),
|
||||
color: context.appColors.textPrimary,
|
||||
fontSize: 17,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
@@ -65,10 +66,10 @@ class _WorkOrderReceiptPageState extends State<WorkOrderReceiptPage> {
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: _isSubmitting ? null : _handleSubmit,
|
||||
child: const Text(
|
||||
child: Text(
|
||||
'提交',
|
||||
style: TextStyle(
|
||||
color: Color(0xFF165DFF),
|
||||
color: context.appColors.primary,
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
@@ -183,19 +184,22 @@ class _WorkOrderReceiptPageState extends State<WorkOrderReceiptPage> {
|
||||
Widget _buildOrderNumberCard() {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
child: Row(
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
'工单编号',
|
||||
style: TextStyle(color: Color(0xFF4E5969), fontSize: 14),
|
||||
style: TextStyle(
|
||||
color: context.appColors.textSecondary,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
widget.workOrder.orderNo,
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF1D2129),
|
||||
style: TextStyle(
|
||||
color: context.appColors.textPrimary,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
@@ -211,7 +215,7 @@ class _WorkOrderReceiptPageState extends State<WorkOrderReceiptPage> {
|
||||
const results = ['已解决', '部分解决', '未解决'];
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@@ -228,16 +232,22 @@ class _WorkOrderReceiptPageState extends State<WorkOrderReceiptPage> {
|
||||
padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 8),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: selected ? const Color(0xFF165DFF) : Colors.white,
|
||||
color: selected
|
||||
? context.appColors.primary
|
||||
: context.appColors.cardBackground,
|
||||
border: Border.all(
|
||||
color: selected ? const Color(0xFF165DFF) : const Color(0xFFE5E6EB),
|
||||
color: selected
|
||||
? context.appColors.primary
|
||||
: context.appColors.divider,
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
results[index],
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: selected ? Colors.white : const Color(0xFF4E5969),
|
||||
color: selected
|
||||
? Colors.white
|
||||
: context.appColors.textSecondary,
|
||||
fontWeight: selected ? FontWeight.w500 : FontWeight.normal,
|
||||
),
|
||||
),
|
||||
@@ -260,7 +270,7 @@ class _WorkOrderReceiptPageState extends State<WorkOrderReceiptPage> {
|
||||
}) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@@ -268,27 +278,27 @@ class _WorkOrderReceiptPageState extends State<WorkOrderReceiptPage> {
|
||||
const SizedBox(height: 10),
|
||||
TextField(
|
||||
controller: controller,
|
||||
style: const TextStyle(fontSize: 14, color: Color(0xFF1D2129)),
|
||||
style: TextStyle(fontSize: 14, color: context.appColors.textPrimary),
|
||||
decoration: InputDecoration(
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
|
||||
filled: true,
|
||||
fillColor: const Color(0xFFF7F8FA),
|
||||
fillColor: context.appColors.fillBackground,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
borderSide: const BorderSide(color: Color(0xFFE5E6EB)),
|
||||
borderSide: BorderSide(color: context.appColors.divider),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
borderSide: const BorderSide(color: Color(0xFFE5E6EB)),
|
||||
borderSide: BorderSide(color: context.appColors.divider),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
borderSide: const BorderSide(color: Color(0xFF165DFF)),
|
||||
borderSide: BorderSide(color: context.appColors.primary),
|
||||
),
|
||||
isDense: true,
|
||||
suffixIcon: PopupMenuButton<String>(
|
||||
padding: EdgeInsets.zero,
|
||||
icon: const Icon(Icons.keyboard_arrow_down, color: Color(0xFF86909C), size: 20),
|
||||
icon: Icon(Icons.keyboard_arrow_down, color: context.appColors.textTertiary, size: 20),
|
||||
onSelected: (value) {
|
||||
controller.text = value;
|
||||
},
|
||||
@@ -310,7 +320,7 @@ class _WorkOrderReceiptPageState extends State<WorkOrderReceiptPage> {
|
||||
}) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@@ -319,24 +329,24 @@ class _WorkOrderReceiptPageState extends State<WorkOrderReceiptPage> {
|
||||
TextField(
|
||||
controller: controller,
|
||||
maxLines: maxLines,
|
||||
style: const TextStyle(fontSize: 14, color: Color(0xFF1D2129), height: 1.5),
|
||||
style: TextStyle(fontSize: 14, color: context.appColors.textPrimary, height: 1.5),
|
||||
decoration: InputDecoration(
|
||||
hintText: hintText,
|
||||
hintStyle: const TextStyle(color: Color(0xFFC9CDD4), fontSize: 14),
|
||||
hintStyle: TextStyle(color: context.appColors.textTertiary, fontSize: 14),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
|
||||
filled: true,
|
||||
fillColor: const Color(0xFFF7F8FA),
|
||||
fillColor: context.appColors.fillBackground,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
borderSide: const BorderSide(color: Color(0xFFE5E6EB)),
|
||||
borderSide: BorderSide(color: context.appColors.divider),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
borderSide: const BorderSide(color: Color(0xFFE5E6EB)),
|
||||
borderSide: BorderSide(color: context.appColors.divider),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
borderSide: const BorderSide(color: Color(0xFF165DFF)),
|
||||
borderSide: BorderSide(color: context.appColors.primary),
|
||||
),
|
||||
isDense: true,
|
||||
),
|
||||
@@ -355,16 +365,19 @@ class _WorkOrderReceiptPageState extends State<WorkOrderReceiptPage> {
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildLabel('现场照片', required: true),
|
||||
const SizedBox(height: 12),
|
||||
if (!hasImages && !hasVideos)
|
||||
const Text(
|
||||
Text(
|
||||
'暂无照片或视频',
|
||||
style: TextStyle(fontSize: 13, color: Color(0xFFBBBBBB)),
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
)
|
||||
else
|
||||
Wrap(
|
||||
@@ -394,8 +407,11 @@ class _WorkOrderReceiptPageState extends State<WorkOrderReceiptPage> {
|
||||
return Container(
|
||||
width: 72,
|
||||
height: 72,
|
||||
color: const Color(0xFFF7F8FA),
|
||||
child: const Icon(Icons.broken_image, color: Color(0xFFBBBBBB)),
|
||||
color: this.context.appColors.fillBackground,
|
||||
child: Icon(
|
||||
Icons.broken_image,
|
||||
color: this.context.appColors.textTertiary,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
@@ -407,11 +423,15 @@ class _WorkOrderReceiptPageState extends State<WorkOrderReceiptPage> {
|
||||
width: 72,
|
||||
height: 72,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF7F8FA),
|
||||
color: context.appColors.fillBackground,
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
border: Border.all(color: const Color(0xFFE5E6EB)),
|
||||
border: Border.all(color: context.appColors.divider),
|
||||
),
|
||||
child: Icon(
|
||||
Icons.video_library_outlined,
|
||||
size: 24,
|
||||
color: context.appColors.primary,
|
||||
),
|
||||
child: const Icon(Icons.video_library_outlined, size: 24, color: Color(0xFF1890FF)),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -424,11 +444,15 @@ class _WorkOrderReceiptPageState extends State<WorkOrderReceiptPage> {
|
||||
width: 72,
|
||||
height: 72,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF7F8FA),
|
||||
color: context.appColors.fillBackground,
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
border: Border.all(color: const Color(0xFFE5E6EB)),
|
||||
border: Border.all(color: context.appColors.divider),
|
||||
),
|
||||
child: Icon(
|
||||
Icons.add,
|
||||
color: context.appColors.textTertiary,
|
||||
size: 28,
|
||||
),
|
||||
child: const Icon(Icons.add, color: Color(0xFFC9CDD4), size: 28),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -437,7 +461,7 @@ class _WorkOrderReceiptPageState extends State<WorkOrderReceiptPage> {
|
||||
Widget _buildSignatureCard() {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@@ -449,9 +473,12 @@ class _WorkOrderReceiptPageState extends State<WorkOrderReceiptPage> {
|
||||
onTap: () {
|
||||
// TODO: 清除签名
|
||||
},
|
||||
child: const Text(
|
||||
child: Text(
|
||||
'清空',
|
||||
style: TextStyle(color: Color(0xFF165DFF), fontSize: 13),
|
||||
style: TextStyle(
|
||||
color: context.appColors.primary,
|
||||
fontSize: 13,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -461,14 +488,18 @@ class _WorkOrderReceiptPageState extends State<WorkOrderReceiptPage> {
|
||||
height: 100,
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF7F8FA),
|
||||
color: context.appColors.fillBackground,
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
border: Border.all(color: const Color(0xFFE5E6EB)),
|
||||
border: Border.all(color: context.appColors.divider),
|
||||
),
|
||||
child: const Center(
|
||||
child: Center(
|
||||
child: Text(
|
||||
'李建国',
|
||||
style: TextStyle(fontSize: 24, color: Color(0xFF1D2129), fontFamily: 'KaiTi'),
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
color: context.appColors.textPrimary,
|
||||
fontFamily: 'KaiTi',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -482,14 +513,14 @@ class _WorkOrderReceiptPageState extends State<WorkOrderReceiptPage> {
|
||||
return Row(
|
||||
children: [
|
||||
if (required)
|
||||
const Text(
|
||||
Text(
|
||||
'* ',
|
||||
style: TextStyle(color: Color(0xFFF53F3F), fontSize: 14),
|
||||
style: TextStyle(color: context.appColors.danger, fontSize: 14),
|
||||
),
|
||||
Text(
|
||||
text,
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF4E5969),
|
||||
style: TextStyle(
|
||||
color: context.appColors.textSecondary,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
@@ -507,16 +538,18 @@ class _WorkOrderReceiptPageState extends State<WorkOrderReceiptPage> {
|
||||
top: 12,
|
||||
bottom: 12 + MediaQuery.of(context).padding.bottom,
|
||||
),
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white,
|
||||
border: Border(top: BorderSide(color: Color(0xFFE5E6EB), width: 0.5)),
|
||||
decoration: BoxDecoration(
|
||||
color: context.appColors.cardBackground,
|
||||
border: Border(
|
||||
top: BorderSide(color: context.appColors.divider, width: 0.5),
|
||||
),
|
||||
),
|
||||
child: SizedBox(
|
||||
height: 48,
|
||||
child: ElevatedButton(
|
||||
onPressed: _isSubmitting ? null : _handleSubmit,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF165DFF),
|
||||
backgroundColor: context.appColors.primary,
|
||||
foregroundColor: Colors.white,
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:fl_chart/fl_chart.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
|
||||
class WorkOrderReportPage extends StatefulWidget {
|
||||
const WorkOrderReportPage({super.key});
|
||||
@@ -37,18 +38,18 @@ class _WorkOrderReportPageState extends State<WorkOrderReportPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xFFF7F8FA),
|
||||
backgroundColor: context.appColors.pageBackground,
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: context.appColors.cardBackground,
|
||||
elevation: 0.5,
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back, color: Color(0xFF1D2129)),
|
||||
icon: Icon(Icons.arrow_back, color: context.appColors.textPrimary),
|
||||
onPressed: () => context.pop(),
|
||||
),
|
||||
title: const Text(
|
||||
title: Text(
|
||||
'移动报表概览',
|
||||
style: TextStyle(
|
||||
color: Color(0xFF1D2129),
|
||||
color: context.appColors.textPrimary,
|
||||
fontSize: 17,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
@@ -57,10 +58,10 @@ class _WorkOrderReportPageState extends State<WorkOrderReportPage> {
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {},
|
||||
child: const Text(
|
||||
child: Text(
|
||||
'更多',
|
||||
style: TextStyle(
|
||||
color: Color(0xFF165DFF),
|
||||
color: context.appColors.primary,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
@@ -93,16 +94,27 @@ class _WorkOrderReportPageState extends State<WorkOrderReportPage> {
|
||||
Widget _buildTimeRange() {
|
||||
return Row(
|
||||
children: [
|
||||
const Icon(Icons.calendar_today, size: 16, color: Color(0xFF4E5969)),
|
||||
Icon(
|
||||
Icons.calendar_today,
|
||||
size: 16,
|
||||
color: context.appColors.textSecondary,
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
const Text(
|
||||
Text(
|
||||
'本周 05-19 ~ 05-25',
|
||||
style: TextStyle(fontSize: 14, color: Color(0xFF4E5969)),
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: context.appColors.textSecondary,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
GestureDetector(
|
||||
onTap: () {},
|
||||
child: const Icon(Icons.keyboard_arrow_down, size: 20, color: Color(0xFF86909C)),
|
||||
child: Icon(
|
||||
Icons.keyboard_arrow_down,
|
||||
size: 20,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -112,11 +124,11 @@ class _WorkOrderReportPageState extends State<WorkOrderReportPage> {
|
||||
Widget _buildMetricCards() {
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(child: _metricCard('个人工单总数', '$_totalOrders', '单', const Color(0xFFE8F3FF), const Color(0xFF165DFF))),
|
||||
Expanded(child: _metricCard('个人工单总数', '$_totalOrders', '单', context.appColors.primary.withOpacity(0.1), context.appColors.primary)),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(child: _metricCard('已完成', '$_completedOrders', '单', const Color(0xFFE8FFEA), const Color(0xFF00B42A))),
|
||||
Expanded(child: _metricCard('已完成', '$_completedOrders', '单', context.appColors.success.withOpacity(0.1), context.appColors.success)),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(child: _metricCard('完成率', '$_completionRate', '%', const Color(0xFFFFF3E0), const Color(0xFFFF7D00))),
|
||||
Expanded(child: _metricCard('完成率', '$_completionRate', '%', context.appColors.warning.withOpacity(0.1), context.appColors.warning)),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -131,7 +143,7 @@ class _WorkOrderReportPageState extends State<WorkOrderReportPage> {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(title, style: const TextStyle(fontSize: 12, color: Color(0xFF86909C))),
|
||||
Text(title, style: TextStyle(fontSize: 12, color: context.appColors.textTertiary)),
|
||||
const SizedBox(height: 8),
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
@@ -157,13 +169,13 @@ class _WorkOrderReportPageState extends State<WorkOrderReportPage> {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text('工单类型分布', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: Color(0xFF1D2129))),
|
||||
Text('工单类型分布', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: context.appColors.textPrimary)),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
@@ -204,10 +216,10 @@ class _WorkOrderReportPageState extends State<WorkOrderReportPage> {
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(child: Text(d.label, style: const TextStyle(fontSize: 13, color: Color(0xFF4E5969)))),
|
||||
Expanded(child: Text(d.label, style: TextStyle(fontSize: 13, color: context.appColors.textSecondary))),
|
||||
Text(
|
||||
'${d.value.toStringAsFixed(0)}%',
|
||||
style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w600, color: Color(0xFF1D2129)),
|
||||
style: TextStyle(fontSize: 13, fontWeight: FontWeight.w600, color: context.appColors.textPrimary),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -227,7 +239,7 @@ class _WorkOrderReportPageState extends State<WorkOrderReportPage> {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
@@ -235,11 +247,11 @@ class _WorkOrderReportPageState extends State<WorkOrderReportPage> {
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const Text('本周趋势', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: Color(0xFF1D2129))),
|
||||
Text('本周趋势', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: context.appColors.textPrimary)),
|
||||
const Spacer(),
|
||||
_legendDot(const Color(0xFF165DFF), '创建数'),
|
||||
_legendDot(context.appColors.primary, '创建数'),
|
||||
const SizedBox(width: 12),
|
||||
_legendDot(const Color(0xFF00B42A), '完成数'),
|
||||
_legendDot(context.appColors.success, '完成数'),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
@@ -255,13 +267,13 @@ class _WorkOrderReportPageState extends State<WorkOrderReportPage> {
|
||||
barRods: [
|
||||
BarChartRodData(
|
||||
toY: _createdData[i].toDouble(),
|
||||
color: const Color(0xFF165DFF),
|
||||
color: context.appColors.primary,
|
||||
width: 10,
|
||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(3)),
|
||||
),
|
||||
BarChartRodData(
|
||||
toY: _completedData[i].toDouble(),
|
||||
color: const Color(0xFF00B42A),
|
||||
color: context.appColors.success,
|
||||
width: 10,
|
||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(3)),
|
||||
),
|
||||
@@ -275,7 +287,7 @@ class _WorkOrderReportPageState extends State<WorkOrderReportPage> {
|
||||
reservedSize: 30,
|
||||
getTitlesWidget: (value, meta) {
|
||||
if (value % 6 == 0) {
|
||||
return Text('${value.toInt()}', style: const TextStyle(fontSize: 11, color: Color(0xFF86909C)));
|
||||
return Text('${value.toInt()}', style: TextStyle(fontSize: 11, color: context.appColors.textTertiary));
|
||||
}
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
@@ -289,7 +301,7 @@ class _WorkOrderReportPageState extends State<WorkOrderReportPage> {
|
||||
if (i >= 0 && i < _trendDays.length) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 6),
|
||||
child: Text(_trendDays[i], style: const TextStyle(fontSize: 10, color: Color(0xFF86909C))),
|
||||
child: Text(_trendDays[i], style: TextStyle(fontSize: 10, color: context.appColors.textTertiary)),
|
||||
);
|
||||
}
|
||||
return const SizedBox.shrink();
|
||||
@@ -304,7 +316,7 @@ class _WorkOrderReportPageState extends State<WorkOrderReportPage> {
|
||||
drawVerticalLine: false,
|
||||
horizontalInterval: 6,
|
||||
getDrawingHorizontalLine: (value) => FlLine(
|
||||
color: const Color(0xFFF0F0F0),
|
||||
color: context.appColors.divider,
|
||||
strokeWidth: 1,
|
||||
),
|
||||
),
|
||||
@@ -323,7 +335,7 @@ class _WorkOrderReportPageState extends State<WorkOrderReportPage> {
|
||||
children: [
|
||||
Container(width: 8, height: 8, decoration: BoxDecoration(color: color, borderRadius: BorderRadius.circular(2))),
|
||||
const SizedBox(width: 4),
|
||||
Text(label, style: const TextStyle(fontSize: 12, color: Color(0xFF86909C))),
|
||||
Text(label, style: TextStyle(fontSize: 12, color: context.appColors.textTertiary)),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -333,13 +345,13 @@ class _WorkOrderReportPageState extends State<WorkOrderReportPage> {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text('待处理工单 TOP5', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: Color(0xFF1D2129))),
|
||||
Text('待处理工单 TOP5', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: context.appColors.textPrimary)),
|
||||
const SizedBox(height: 12),
|
||||
...List.generate(_topPendingList.length, (i) {
|
||||
final item = _topPendingList[i];
|
||||
@@ -352,7 +364,9 @@ class _WorkOrderReportPageState extends State<WorkOrderReportPage> {
|
||||
width: 22,
|
||||
height: 22,
|
||||
decoration: BoxDecoration(
|
||||
color: i < 3 ? const Color(0xFF165DFF) : const Color(0xFFC9CDD4),
|
||||
color: i < 3
|
||||
? context.appColors.primary
|
||||
: context.appColors.fillBackground,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: Center(
|
||||
@@ -361,7 +375,9 @@ class _WorkOrderReportPageState extends State<WorkOrderReportPage> {
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: i < 3 ? Colors.white : const Color(0xFF86909C),
|
||||
color: i < 3
|
||||
? Colors.white
|
||||
: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -371,23 +387,27 @@ class _WorkOrderReportPageState extends State<WorkOrderReportPage> {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(item.title, style: const TextStyle(fontSize: 14, color: Color(0xFF1D2129))),
|
||||
Text(item.title, style: TextStyle(fontSize: 14, color: context.appColors.textPrimary)),
|
||||
const SizedBox(height: 2),
|
||||
Text(item.area, style: const TextStyle(fontSize: 12, color: Color(0xFF86909C))),
|
||||
Text(item.area, style: TextStyle(fontSize: 12, color: context.appColors.textTertiary)),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: isUrgent ? const Color(0xFFFFECE8) : const Color(0xFFF7F8FA),
|
||||
color: isUrgent
|
||||
? context.appColors.danger.withOpacity(0.1)
|
||||
: context.appColors.fillBackground,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: Text(
|
||||
'剩余${item.remainHours}h',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: isUrgent ? const Color(0xFFF53F3F) : const Color(0xFF86909C),
|
||||
color: isUrgent
|
||||
? context.appColors.danger
|
||||
: context.appColors.textTertiary,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
@@ -411,8 +431,8 @@ class _WorkOrderReportPageState extends State<WorkOrderReportPage> {
|
||||
icon: const Icon(Icons.download, size: 18),
|
||||
label: const Text('导出报表', style: TextStyle(fontSize: 14)),
|
||||
style: OutlinedButton.styleFrom(
|
||||
foregroundColor: const Color(0xFF165DFF),
|
||||
side: const BorderSide(color: Color(0xFF165DFF)),
|
||||
foregroundColor: context.appColors.primary,
|
||||
side: BorderSide(color: context.appColors.primary),
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||
),
|
||||
@@ -425,7 +445,7 @@ class _WorkOrderReportPageState extends State<WorkOrderReportPage> {
|
||||
icon: const Icon(Icons.share, size: 18),
|
||||
label: const Text('分享', style: TextStyle(fontSize: 14)),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF165DFF),
|
||||
backgroundColor: context.appColors.primary,
|
||||
foregroundColor: Colors.white,
|
||||
elevation: 0,
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:maibu_satabot_v2/core/localization/app_localizations.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import '../../../../../core/consts/workorder_consts.dart';
|
||||
import '../../domain/entities/workorder_entity.dart';
|
||||
|
||||
@@ -18,41 +19,51 @@ class WorkOrderCountCard extends StatelessWidget {
|
||||
),
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: AppConstants.backgroundColor,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(AppConstants.borderRadius),
|
||||
boxShadow: AppConstants.cardShadow,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
_buildCountItem(
|
||||
context,
|
||||
label: AppLocalizations.of(
|
||||
context,
|
||||
).translate('work_order_v2.pending'),
|
||||
value: count.pendingCount.toString(),
|
||||
valueColor: WorkOrderColors.primaryText,
|
||||
valueColor: context.appColors.textPrimary,
|
||||
),
|
||||
_buildDivider(),
|
||||
_buildDivider(context),
|
||||
_buildCountItem(
|
||||
context,
|
||||
label: AppLocalizations.of(
|
||||
context,
|
||||
).translate('work_order_v2.executing'),
|
||||
value: count.executingCount.toString(),
|
||||
valueColor: WorkOrderColors.primaryText,
|
||||
valueColor: context.appColors.textPrimary,
|
||||
),
|
||||
_buildDivider(),
|
||||
_buildDivider(context),
|
||||
_buildCountItem(
|
||||
context,
|
||||
label: AppLocalizations.of(
|
||||
context,
|
||||
).translate('work_order_v2.today_completed'),
|
||||
value: count.todayCompletedCount.toString(),
|
||||
valueColor: WorkOrderColors.primary,
|
||||
valueColor: context.appColors.primary,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCountItem({
|
||||
Widget _buildCountItem(
|
||||
BuildContext context, {
|
||||
required String label,
|
||||
required String value,
|
||||
required Color valueColor,
|
||||
@@ -64,7 +75,7 @@ class WorkOrderCountCard extends StatelessWidget {
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: AppConstants.auxiliaryTextColor,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
@@ -81,7 +92,11 @@ class WorkOrderCountCard extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDivider() {
|
||||
return Container(width: 1, height: 40, color: const Color(0xFFF0F0F0));
|
||||
Widget _buildDivider(BuildContext context) {
|
||||
return Container(
|
||||
width: 1,
|
||||
height: 40,
|
||||
color: context.appColors.divider,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:maibu_satabot_v2/core/localization/app_localizations.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import '../../../../../core/consts/workorder_consts.dart';
|
||||
import '../../domain/entities/workorder_entity.dart';
|
||||
|
||||
@@ -22,9 +23,15 @@ class WorkOrderItemCard extends StatelessWidget {
|
||||
),
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: AppConstants.backgroundColor,
|
||||
color: context.appColors.cardBackground,
|
||||
borderRadius: BorderRadius.circular(AppConstants.borderRadius),
|
||||
boxShadow: AppConstants.cardShadow,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: context.appColors.cardShadow,
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
@@ -41,7 +48,7 @@ class WorkOrderItemCard extends StatelessWidget {
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppConstants.primaryTextColor,
|
||||
color: context.appColors.textPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -52,6 +59,7 @@ class WorkOrderItemCard extends StatelessWidget {
|
||||
|
||||
// 详情信息
|
||||
_buildDetailRow(
|
||||
context,
|
||||
AppLocalizations.of(
|
||||
context,
|
||||
).translate('work_order_v2.order_no'),
|
||||
@@ -61,17 +69,19 @@ class WorkOrderItemCard extends StatelessWidget {
|
||||
|
||||
// 优先级
|
||||
_buildDetailRow(
|
||||
context,
|
||||
AppLocalizations.of(
|
||||
context,
|
||||
).translate('work_order_v2.priority'),
|
||||
_getPriorityText(context, workOrder.priority),
|
||||
valueColor: _getPriorityColor(workOrder.priority),
|
||||
valueColor: _getPriorityColor(context, workOrder.priority),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
|
||||
// 根据状态显示不同信息
|
||||
if (workOrder.status == WorkOrderStatus.pending) ...[
|
||||
_buildDetailRow(
|
||||
context,
|
||||
AppLocalizations.of(
|
||||
context,
|
||||
).translate('work_order_v2.create_time'),
|
||||
@@ -79,6 +89,7 @@ class WorkOrderItemCard extends StatelessWidget {
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
_buildDetailRow(
|
||||
context,
|
||||
AppLocalizations.of(
|
||||
context,
|
||||
).translate('work_order_v2.location'),
|
||||
@@ -86,6 +97,7 @@ class WorkOrderItemCard extends StatelessWidget {
|
||||
),
|
||||
] else if (workOrder.status == WorkOrderStatus.executing) ...[
|
||||
_buildDetailRow(
|
||||
context,
|
||||
AppLocalizations.of(
|
||||
context,
|
||||
).translate('work_order_v2.executor'),
|
||||
@@ -93,6 +105,7 @@ class WorkOrderItemCard extends StatelessWidget {
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
_buildDetailRow(
|
||||
context,
|
||||
AppLocalizations.of(
|
||||
context,
|
||||
).translate('work_order_v2.location'),
|
||||
@@ -104,6 +117,7 @@ class WorkOrderItemCard extends StatelessWidget {
|
||||
],
|
||||
] else if (workOrder.status == WorkOrderStatus.completed) ...[
|
||||
_buildDetailRow(
|
||||
context,
|
||||
AppLocalizations.of(
|
||||
context,
|
||||
).translate('work_order_v2.complete_time'),
|
||||
@@ -113,6 +127,7 @@ class WorkOrderItemCard extends StatelessWidget {
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
_buildDetailRow(
|
||||
context,
|
||||
AppLocalizations.of(
|
||||
context,
|
||||
).translate('work_order_v2.location'),
|
||||
@@ -148,23 +163,23 @@ class WorkOrderItemCard extends StatelessWidget {
|
||||
|
||||
switch (workOrder.status) {
|
||||
case WorkOrderStatus.pending:
|
||||
color = AppConstants.pendingColor;
|
||||
color = context.appColors.warning;
|
||||
text = AppLocalizations.of(context).translate('work_order_v2.pending');
|
||||
break;
|
||||
case WorkOrderStatus.executing:
|
||||
color = AppConstants.executingColor;
|
||||
color = context.appColors.primary;
|
||||
text = AppLocalizations.of(
|
||||
context,
|
||||
).translate('work_order_v2.executing');
|
||||
break;
|
||||
case WorkOrderStatus.completed:
|
||||
color = AppConstants.completedColor;
|
||||
color = context.appColors.success;
|
||||
text = AppLocalizations.of(
|
||||
context,
|
||||
).translate('work_order_v2.completed');
|
||||
break;
|
||||
default:
|
||||
color = AppConstants.auxiliaryTextColor;
|
||||
color = context.appColors.textTertiary;
|
||||
text = AppLocalizations.of(context).translate('common.unknown');
|
||||
}
|
||||
|
||||
@@ -196,7 +211,12 @@ class WorkOrderItemCard extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDetailRow(String label, String value, {Color? valueColor}) {
|
||||
Widget _buildDetailRow(
|
||||
BuildContext context,
|
||||
String label,
|
||||
String value, {
|
||||
Color? valueColor,
|
||||
}) {
|
||||
return Row(
|
||||
children: [
|
||||
Flexible(
|
||||
@@ -204,7 +224,7 @@ class WorkOrderItemCard extends StatelessWidget {
|
||||
'$label:',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: AppConstants.auxiliaryTextColor,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
@@ -215,7 +235,7 @@ class WorkOrderItemCard extends StatelessWidget {
|
||||
value,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: valueColor ?? AppConstants.secondaryTextColor,
|
||||
color: valueColor ?? context.appColors.textSecondary,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
@@ -235,15 +255,15 @@ class WorkOrderItemCard extends StatelessWidget {
|
||||
'${AppLocalizations.of(context).translate('work_order_v2.progress')}:',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: AppConstants.auxiliaryTextColor,
|
||||
color: context.appColors.textTertiary,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: LinearProgressIndicator(
|
||||
value: workOrder.progress! / 100,
|
||||
backgroundColor: const Color(0xFFF0F0F0),
|
||||
backgroundColor: context.appColors.divider,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(
|
||||
AppConstants.primaryColor,
|
||||
context.appColors.primary,
|
||||
),
|
||||
minHeight: 6,
|
||||
borderRadius: BorderRadius.circular(3),
|
||||
@@ -266,14 +286,14 @@ class WorkOrderItemCard extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
Color _getPriorityColor(WorkOrderPriority priority) {
|
||||
Color _getPriorityColor(BuildContext context, WorkOrderPriority priority) {
|
||||
switch (priority) {
|
||||
case WorkOrderPriority.high:
|
||||
return AppConstants.pendingColor;
|
||||
return context.appColors.warning;
|
||||
case WorkOrderPriority.medium:
|
||||
return AppConstants.pendingColor;
|
||||
return context.appColors.warning;
|
||||
case WorkOrderPriority.low:
|
||||
return AppConstants.auxiliaryTextColor;
|
||||
return context.appColors.textTertiary;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:maibu_satabot_v2/core/localization/app_localizations.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import '../../../../../core/consts/workorder_consts.dart';
|
||||
import '../../domain/entities/workorder_entity.dart';
|
||||
|
||||
/// 工单标签栏组件
|
||||
/// 展示待处理/执行中/已完成/全部四个静态标签
|
||||
@@ -86,8 +86,8 @@ class WorkOrderTabBar extends StatelessWidget {
|
||||
fontWeight:
|
||||
isSelected ? FontWeight.bold : FontWeight.normal,
|
||||
color: isSelected
|
||||
? AppConstants.primaryColor
|
||||
: AppConstants.secondaryTextColor,
|
||||
? context.appColors.primary
|
||||
: context.appColors.textSecondary,
|
||||
),
|
||||
),
|
||||
if (showBadge)
|
||||
@@ -111,7 +111,7 @@ class WorkOrderTabBar extends StatelessWidget {
|
||||
width: 24,
|
||||
height: 3,
|
||||
decoration: BoxDecoration(
|
||||
color: AppConstants.primaryColor,
|
||||
color: context.appColors.primary,
|
||||
borderRadius: BorderRadius.circular(1.5),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -12,6 +12,7 @@ import 'package:maibu_satabot_v2/core/app/app_user_cubit.dart';
|
||||
import 'package:maibu_satabot_v2/core/infrastructure/logging/app_bloc_observer.dart';
|
||||
import 'package:maibu_satabot_v2/core/logging/i_logger_service.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||||
import 'package:maibu_satabot_v2/core/theme/theme_cubit.dart';
|
||||
import 'package:maibu_satabot_v2/core/update/update_cubit.dart';
|
||||
import 'package:maibu_satabot_v2/core/update/version_check_service.dart';
|
||||
import 'package:maibu_satabot_v2/core/update/update_dialog.dart';
|
||||
@@ -71,6 +72,7 @@ class MyApp extends StatelessWidget {
|
||||
sl<AuthCubit>().appStarted();
|
||||
final deviceStatusBloc = sl<DeviceStatusBloc>();
|
||||
final localeCubit = sl<LocaleCubit>();
|
||||
final themeCubit = sl<ThemeCubit>();
|
||||
|
||||
return MultiBlocProvider(
|
||||
providers: [
|
||||
@@ -98,6 +100,7 @@ class MyApp extends StatelessWidget {
|
||||
),
|
||||
BlocProvider<DeviceStatusBloc>.value(value: deviceStatusBloc),
|
||||
BlocProvider<LocaleCubit>.value(value: localeCubit),
|
||||
BlocProvider<ThemeCubit>.value(value: themeCubit),
|
||||
BlocProvider<TabConfigCubit>.value(value: sl<TabConfigCubit>()),
|
||||
BlocProvider<PermissionRequestBloc>(
|
||||
create: (_) => sl<PermissionRequestBloc>(),
|
||||
@@ -113,20 +116,27 @@ class MyApp extends StatelessWidget {
|
||||
child: BlocBuilder<LocaleCubit, Locale>(
|
||||
bloc: localeCubit,
|
||||
builder: (context, locale) {
|
||||
return MaterialApp.router(
|
||||
title: 'Maibu Satabot',
|
||||
locale: locale,
|
||||
supportedLocales: const [Locale('zh', 'CN'), Locale('en', 'US')],
|
||||
localizationsDelegates: const [
|
||||
AppLocalizations.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
theme: AppTheme.lightTheme,
|
||||
routerConfig: sl<GoRouter>(),
|
||||
builder: (context, child) {
|
||||
return _LifecycleListener(child: _UpdateChecker(child: child!));
|
||||
return BlocBuilder<ThemeCubit, ThemeMode>(
|
||||
bloc: themeCubit,
|
||||
builder: (context, themeMode) {
|
||||
return MaterialApp.router(
|
||||
title: 'Maibu Satabot',
|
||||
locale: locale,
|
||||
supportedLocales: const [Locale('zh', 'CN'), Locale('en', 'US')],
|
||||
localizationsDelegates: const [
|
||||
AppLocalizations.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
theme: AppTheme.lightTheme,
|
||||
darkTheme: AppTheme.darkTheme,
|
||||
themeMode: themeMode,
|
||||
routerConfig: sl<GoRouter>(),
|
||||
builder: (context, child) {
|
||||
return _LifecycleListener(child: _UpdateChecker(child: child!));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
@@ -984,10 +984,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: mobile_scanner
|
||||
sha256: ce3f059ebd6dbfab7292bba0e893e354b46730636820d3c9ef69005ce2d55bce
|
||||
sha256: "1b60b8f9d4ce0cb0e7d7bc223c955d083a0737bee66fa1fcfe5de48225e0d5b3"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "7.4.0"
|
||||
version: "3.5.7"
|
||||
mqtt_client:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
||||
@@ -139,7 +139,7 @@ dependencies:
|
||||
markdown_widget: ^2.0.0 # 产品参数用的 markdown 渲染
|
||||
flutter_markdown: ^0.7.1
|
||||
|
||||
mobile_scanner: ^7.4.0
|
||||
mobile_scanner: ^3.4.1
|
||||
vibration: ^3.1.8
|
||||
flutter_patcher: ^0.1.2 # Add flutter_patcher here
|
||||
open_file: ^3.3.2 # 打开文件(安装 APK)
|
||||
|
||||
Reference in New Issue
Block a user