一次大的提交

This commit is contained in:
2026-08-07 08:49:29 +08:00
parent bf2fc49c19
commit db70665ced
181 changed files with 23060 additions and 2804 deletions

View File

@@ -0,0 +1,133 @@
import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../domain/usecases/transfer_workorder_usecase.dart';
import '../../../../../core/error/failure.dart';
class TransferState extends Equatable {
final bool isLoading;
final bool isSubmitting;
final List<Map<String, dynamic>> users;
final String? selectedUserId;
final String? selectedUserName;
final String? remark;
final String? errorMessage;
final bool? isSuccess;
const TransferState({
this.isLoading = false,
this.isSubmitting = false,
this.users = const [],
this.selectedUserId,
this.selectedUserName,
this.remark,
this.errorMessage,
this.isSuccess,
});
TransferState copyWith({
bool? isLoading,
bool? isSubmitting,
List<Map<String, dynamic>>? users,
String? selectedUserId,
String? selectedUserName,
String? remark,
String? errorMessage,
bool? isSuccess,
}) {
return TransferState(
isLoading: isLoading ?? this.isLoading,
isSubmitting: isSubmitting ?? this.isSubmitting,
users: users ?? this.users,
selectedUserId: selectedUserId ?? this.selectedUserId,
selectedUserName: selectedUserName ?? this.selectedUserName,
remark: remark ?? this.remark,
errorMessage: errorMessage,
isSuccess: isSuccess,
);
}
@override
List<Object?> get props => [
isLoading,
isSubmitting,
users,
selectedUserId,
selectedUserName,
remark,
errorMessage,
isSuccess,
];
}
class TransferCubit extends Cubit<TransferState> {
final FetchUsersUseCase fetchUsersUseCase;
final DispatchWorkOrderUseCase dispatchUseCase;
TransferCubit({
required this.fetchUsersUseCase,
required this.dispatchUseCase,
}) : super(const TransferState());
Future<void> loadUsers({required int orgId, required int siteId}) async {
emit(state.copyWith(isLoading: true, errorMessage: null));
final result = await fetchUsersUseCase.execute(
orgId: orgId,
siteId: siteId,
);
result.fold(
(failure) {
emit(state.copyWith(isLoading: false, errorMessage: failure.message));
},
(users) {
emit(state.copyWith(isLoading: false, users: users));
},
);
}
void selectUser(String userId, String userName) {
emit(state.copyWith(selectedUserId: userId, selectedUserName: userName));
}
void updateRemark(String remark) {
emit(state.copyWith(remark: remark));
}
Future<bool> submitTransfer({required String workOrderId}) async {
if (state.selectedUserId == null || state.selectedUserId!.isEmpty) {
emit(state.copyWith(errorMessage: '请选择接收人', isSuccess: false));
return false;
}
emit(state.copyWith(isSubmitting: true, errorMessage: null));
final result = await dispatchUseCase.execute(
orderId: workOrderId,
assigneeId: state.selectedUserId!,
assigneeName: state.selectedUserName ?? '',
dispatchRemark: state.remark,
);
return result.fold(
(failure) {
emit(
state.copyWith(
isSubmitting: false,
errorMessage: failure.message,
isSuccess: false,
),
);
return false;
},
(_) {
emit(state.copyWith(isSubmitting: false, isSuccess: true));
return true;
},
);
}
void reset() {
emit(const TransferState());
}
}

View File

@@ -1,5 +1,9 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/foundation.dart';
import 'package:get_it/get_it.dart';
import 'package:maibu_satabot_v2/features/v2/site/presentation/cubit/site_cubit.dart';
import '../../../../../core/app/app_user_cubit.dart';
import '../../../../../core/consts/workorder_consts.dart';
import '../../../../../core/error/failure.dart';
import '../../../../../core/error/workorder_failure.dart';
@@ -22,17 +26,58 @@ class WorkOrderLoading extends WorkOrderState {}
class WorkOrderLoaded extends WorkOrderState {
final List<WorkOrderEntity> workOrders;
final List<WorkOrderEntity> allWorkOrders;
final WorkOrderCountEntity? count;
final WorkOrderStatus currentStatus;
final int currentPage;
final bool hasMore;
final bool isLoadingMore;
final String? errorMessage;
const WorkOrderLoaded({
required this.workOrders,
required this.allWorkOrders,
this.count,
this.currentStatus = WorkOrderStatus.pending,
this.currentPage = 1,
this.hasMore = true,
this.isLoadingMore = false,
this.errorMessage,
});
@override
List<Object?> get props => [workOrders, count, currentStatus];
List<Object?> get props => [
workOrders,
allWorkOrders,
count,
currentStatus,
currentPage,
hasMore,
isLoadingMore,
errorMessage,
];
WorkOrderLoaded copyWith({
List<WorkOrderEntity>? workOrders,
List<WorkOrderEntity>? allWorkOrders,
WorkOrderCountEntity? count,
WorkOrderStatus? currentStatus,
int? currentPage,
bool? hasMore,
bool? isLoadingMore,
String? errorMessage,
}) {
return WorkOrderLoaded(
workOrders: workOrders ?? this.workOrders,
allWorkOrders: allWorkOrders ?? this.allWorkOrders,
count: count ?? this.count,
currentStatus: currentStatus ?? this.currentStatus,
currentPage: currentPage ?? this.currentPage,
hasMore: hasMore ?? this.hasMore,
isLoadingMore: isLoadingMore ?? this.isLoadingMore,
errorMessage: errorMessage ?? this.errorMessage,
);
}
}
class WorkOrderError extends WorkOrderState {
@@ -48,42 +93,114 @@ class WorkOrderError extends WorkOrderState {
class WorkOrderCubit extends Cubit<WorkOrderState> {
final GetWorkOrderListUseCase getWorkOrderListUseCase;
final GetWorkOrderCountUseCase getWorkOrderCountUseCase;
WorkOrderCubit({
required this.getWorkOrderListUseCase,
required this.getWorkOrderCountUseCase,
}) : super(WorkOrderInitial());
WorkOrderCubit({required this.getWorkOrderListUseCase})
: super(WorkOrderInitial());
static const int _pageSize = 100;
List<WorkOrderEntity> _filterWorkOrders(
List<WorkOrderEntity> allWorkOrders,
WorkOrderStatus status,
) {
if (status == WorkOrderStatus.all) {
return allWorkOrders;
}
return allWorkOrders.where((order) => order.status == status).toList();
}
/// 初始加载
Future<void> loadInitialData() async {
emit(WorkOrderLoading());
try {
// 并行加载工单列表和统计数据
final results = await Future.wait([
getWorkOrderListUseCase.execute(status: WorkOrderStatus.pending),
getWorkOrderCountUseCase.execute(),
]);
final siteId = GetIt.I<SiteCubit>().state.selectedSite?.id;
final orgId = GetIt.I<AppUserCubit>().state.user?.orgId;
final listResult = results[0] as Either<Failure, List<WorkOrderEntity>>;
final countResult = results[1] as Either<Failure, WorkOrderCountEntity>;
List<WorkOrderEntity> allWorkOrders = [];
String? errorMessage;
listResult.fold(
(Failure failure) => emit(WorkOrderError(failure: failure)),
(workOrders) {
countResult.fold(
(Failure failure) => emit(WorkOrderError(failure: failure)),
(count) => emit(WorkOrderLoaded(
workOrders: workOrders,
count: count,
currentStatus: WorkOrderStatus.pending,
)),
);
},
final listResult = await getWorkOrderListUseCase.execute(
page: 1,
pageSize: _pageSize,
siteId: siteId,
orgId: orgId,
);
listResult.fold((Failure failure) {
debugPrint('❌ [WorkOrder] 获取工单列表失败: ${failure.message}');
errorMessage = '暂无数据';
}, (List<WorkOrderEntity> orders) => allWorkOrders = orders);
emit(
WorkOrderLoaded(
workOrders: _filterWorkOrders(allWorkOrders, WorkOrderStatus.pending),
allWorkOrders: allWorkOrders,
count: null,
currentStatus: WorkOrderStatus.pending,
currentPage: 1,
hasMore: allWorkOrders.length >= _pageSize,
errorMessage: errorMessage,
),
);
} catch (e) {
emit(WorkOrderError(failure: UnknownFailure(message: '加载失败: $e')));
debugPrint('❌ [WorkOrder] 加载工单异常: $e');
emit(
WorkOrderLoaded(
workOrders: [],
allWorkOrders: [],
count: null,
currentStatus: WorkOrderStatus.pending,
currentPage: 1,
hasMore: false,
errorMessage: '暂无数据',
),
);
}
}
/// 加载更多
Future<void> loadMore() async {
final currentState = state;
if (currentState is WorkOrderLoaded) {
if (!currentState.hasMore || currentState.isLoadingMore) return;
emit(currentState.copyWith(isLoadingMore: true));
try {
final siteId = GetIt.I<SiteCubit>().state.selectedSite?.id;
final orgId = GetIt.I<AppUserCubit>().state.user?.orgId;
final result = await getWorkOrderListUseCase.execute(
page: currentState.currentPage + 1,
pageSize: _pageSize,
siteId: siteId,
orgId: orgId,
);
result.fold(
(Failure failure) => emit(WorkOrderError(failure: failure)),
(newWorkOrders) {
final updatedAllWorkOrders = [
...currentState.allWorkOrders,
...newWorkOrders,
];
emit(
currentState.copyWith(
allWorkOrders: updatedAllWorkOrders,
workOrders: _filterWorkOrders(
updatedAllWorkOrders,
currentState.currentStatus,
),
currentPage: currentState.currentPage + 1,
hasMore: newWorkOrders.length >= _pageSize,
isLoadingMore: false,
),
);
},
);
} catch (e) {
emit(currentState.copyWith(isLoadingMore: false));
}
}
}
@@ -93,22 +210,12 @@ class WorkOrderCubit extends Cubit<WorkOrderState> {
final currentState = state as WorkOrderLoaded;
if (currentState.currentStatus == status) return;
emit(WorkOrderLoading());
try {
final result = await getWorkOrderListUseCase.execute(status: status);
result.fold(
(Failure failure) => emit(WorkOrderError(failure: failure)),
(workOrders) => emit(WorkOrderLoaded(
workOrders: workOrders,
count: currentState.count,
currentStatus: status,
)),
);
} catch (e) {
emit(WorkOrderError(failure: UnknownFailure(message: '切换失败: $e')));
}
emit(
currentState.copyWith(
workOrders: _filterWorkOrders(currentState.allWorkOrders, status),
currentStatus: status,
),
);
}
}

View File

@@ -0,0 +1,67 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:get_it/get_it.dart';
import 'package:maibu_satabot_v2/features/v2/site/presentation/cubit/site_cubit.dart';
import '../../../../../core/app/app_user_cubit.dart';
import '../../../../../core/error/failure.dart';
import '../../../../../core/error/workorder_failure.dart';
import '../../domain/usecases/get_workorder_detail_usecase.dart';
import '../../domain/entities/workorder_entity.dart';
import 'package:fpdart/fpdart.dart';
abstract class WorkOrderDetailState extends Equatable {
const WorkOrderDetailState();
@override
List<Object?> get props => [];
}
class WorkOrderDetailInitial extends WorkOrderDetailState {}
class WorkOrderDetailLoading extends WorkOrderDetailState {}
class WorkOrderDetailLoaded extends WorkOrderDetailState {
final WorkOrderEntity workOrder;
const WorkOrderDetailLoaded({required this.workOrder});
@override
List<Object?> get props => [workOrder];
}
class WorkOrderDetailError extends WorkOrderDetailState {
final Failure failure;
const WorkOrderDetailError({required this.failure});
@override
List<Object?> get props => [failure];
}
class WorkOrderDetailCubit extends Cubit<WorkOrderDetailState> {
final GetWorkOrderDetailUseCase getWorkOrderDetailUseCase;
WorkOrderDetailCubit({required this.getWorkOrderDetailUseCase})
: super(WorkOrderDetailInitial());
Future<void> loadWorkOrderDetail(String orderId) async {
emit(WorkOrderDetailLoading());
try {
final siteId = GetIt.I<SiteCubit>().state.selectedSite?.id;
final orgId = GetIt.I<AppUserCubit>().state.user?.orgId;
final result = await getWorkOrderDetailUseCase(
orderId,
siteId: siteId,
orgId: orgId,
);
result.fold(
(Failure failure) => emit(WorkOrderDetailError(failure: failure)),
(workOrder) => emit(WorkOrderDetailLoaded(workOrder: workOrder)),
);
} catch (e) {
emit(WorkOrderDetailError(failure: UnknownFailure(message: '加载失败: $e')));
}
}
}