feat(programs): Excel 导入改为全量覆盖模式
已存在 code 的程序不再跳过,而是: - 用 Excel 中的字段更新 program(保留 id) - 删除该 program 的全部旧步骤 - 按 Excel 中的步骤重新写入 返回值变量名 importedCount -> processedCount 更准确。 Toast 文案同步:成功处理 / Excel 无有效数据。
This commit is contained in:
@@ -441,9 +441,9 @@ class _ProgramsPageState extends ConsumerState<ProgramsPage> {
|
|||||||
|
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
if (importedCount > 0) {
|
if (importedCount > 0) {
|
||||||
ToastService.showSuccess(context, '成功导入 $importedCount 个程序');
|
ToastService.showSuccess(context, '成功处理 $importedCount 个程序');
|
||||||
} else {
|
} else {
|
||||||
ToastService.showWarning(context, '未导入新程序(编号可能已存在)');
|
ToastService.showWarning(context, 'Excel 中无有效程序数据');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
|
|||||||
@@ -18,7 +18,11 @@ class ExcelImportService {
|
|||||||
|
|
||||||
ExcelImportService._internal();
|
ExcelImportService._internal();
|
||||||
|
|
||||||
/// 从 .xlsx 文件导入程序,返回成功导入的程序数量
|
/// 从 .xlsx 文件导入程序,返回成功处理的程序数量(新建 + 覆盖)
|
||||||
|
///
|
||||||
|
/// 行为:
|
||||||
|
/// - code 不存在:新建程序 + 写入步骤
|
||||||
|
/// - code 已存在:全量覆盖程序字段,并删除旧步骤后写入新步骤
|
||||||
Future<int> importFromExcel(File file) async {
|
Future<int> importFromExcel(File file) async {
|
||||||
final bytes = await file.readAsBytes();
|
final bytes = await file.readAsBytes();
|
||||||
final excel = Excel.decodeBytes(bytes);
|
final excel = Excel.decodeBytes(bytes);
|
||||||
@@ -33,9 +37,11 @@ class ExcelImportService {
|
|||||||
throw const ExcelImportException('Programs 表无有效数据');
|
throw const ExcelImportException('Programs 表无有效数据');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 读取已有 code,避免重复
|
// 已有 code → 完整 Program(用于覆盖时取 id)
|
||||||
final existing = await _programService.getAllPrograms();
|
final existing = await _programService.getAllPrograms();
|
||||||
final existingCodes = existing.map((p) => p.code).toSet();
|
final existingByCode = <String, Program>{
|
||||||
|
for (final p in existing) p.code: p,
|
||||||
|
};
|
||||||
|
|
||||||
// 解析步骤
|
// 解析步骤
|
||||||
final stepsSheet = _findSheet(excel, ExcelTemplateService.sheetSteps);
|
final stepsSheet = _findSheet(excel, ExcelTemplateService.sheetSteps);
|
||||||
@@ -43,17 +49,37 @@ class ExcelImportService {
|
|||||||
? <String, List<_RawStep>>{}
|
? <String, List<_RawStep>>{}
|
||||||
: _parseSteps(stepsSheet);
|
: _parseSteps(stepsSheet);
|
||||||
|
|
||||||
int importedCount = 0;
|
int processedCount = 0;
|
||||||
for (final program in programs) {
|
for (final program in programs) {
|
||||||
try {
|
try {
|
||||||
if (existingCodes.contains(program.code)) {
|
final existingProgram = existingByCode[program.code];
|
||||||
continue;
|
final int programId;
|
||||||
|
if (existingProgram == null) {
|
||||||
|
programId = await _programService.addProgram(program);
|
||||||
|
} else {
|
||||||
|
// 全量覆盖:保留 id,其余字段取 Excel
|
||||||
|
programId = existingProgram.id!;
|
||||||
|
await _programService.updateProgram(
|
||||||
|
existingProgram.copyWith(
|
||||||
|
name: program.name,
|
||||||
|
temperature: program.temperature,
|
||||||
|
airflowTime: program.airflowTime,
|
||||||
|
status: program.status,
|
||||||
|
createdAt: program.createdAt,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
// 清空旧步骤
|
||||||
|
final oldSteps =
|
||||||
|
await _programService.getStepsByProgramId(programId);
|
||||||
|
if (oldSteps.isNotEmpty) {
|
||||||
|
await _programService.deleteSteps(
|
||||||
|
oldSteps.map((s) => s.id!).toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final programId = await _programService.addProgram(program);
|
// 写入新步骤(按 step_no 排序后重新编号为 1..N)
|
||||||
|
|
||||||
final rawSteps = stepsByCode[program.code] ?? const <_RawStep>[];
|
final rawSteps = stepsByCode[program.code] ?? const <_RawStep>[];
|
||||||
// 按 step_no 排序后写入
|
|
||||||
rawSteps.sort((a, b) => a.stepNo.compareTo(b.stepNo));
|
rawSteps.sort((a, b) => a.stepNo.compareTo(b.stepNo));
|
||||||
for (var i = 0; i < rawSteps.length; i++) {
|
for (var i = 0; i < rawSteps.length; i++) {
|
||||||
final raw = rawSteps[i];
|
final raw = rawSteps[i];
|
||||||
@@ -71,14 +97,14 @@ class ExcelImportService {
|
|||||||
await _programService.addStep(step);
|
await _programService.addStep(step);
|
||||||
}
|
}
|
||||||
|
|
||||||
importedCount++;
|
processedCount++;
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
// 单条失败不影响其他程序
|
// 单条失败不影响其他程序
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return importedCount;
|
return processedCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
Sheet? _findSheet(Excel excel, String name) {
|
Sheet? _findSheet(Excel excel, String name) {
|
||||||
|
|||||||
Reference in New Issue
Block a user