This commit is contained in:
zpc 2026-01-06 22:23:29 +08:00
parent 0708675fb5
commit 08aaf97f3d
12 changed files with 160 additions and 36 deletions

View File

@ -311,7 +311,7 @@ namespace WorkCameraExport.Tests
Address = $"地址{i}", Address = $"地址{i}",
Content = $"工作内容{i}", Content = $"工作内容{i}",
StatusName = "正常", StatusName = "正常",
Workers = new List<WorkerDto> { new WorkerDto { Id = i, WorkerName = $"工人{i}" } }, Workers = new List<string> { $"工人{i}" },
Images = new List<string>(), Images = new List<string>(),
CreateTime = DateTime.Now.AddDays(-i), CreateTime = DateTime.Now.AddDays(-i),
UpdateTime = DateTime.Now UpdateTime = DateTime.Now
@ -331,7 +331,7 @@ namespace WorkCameraExport.Tests
Address = "测试地址", Address = "测试地址",
Content = "测试内容", Content = "测试内容",
StatusName = "正常", StatusName = "正常",
Workers = new List<WorkerDto> { new WorkerDto { Id = 1, WorkerName = "测试工人" } }, Workers = new List<string> { "测试工人" },
Images = Enumerable.Range(1, imageCount) Images = Enumerable.Range(1, imageCount)
.Select(i => $"http://test.local/image{i}.jpg") .Select(i => $"http://test.local/image{i}.jpg")
.ToList(), .ToList(),

View File

@ -194,7 +194,7 @@ namespace WorkCameraExport.Forms
public void NavigateToMigration() public void NavigateToMigration()
{ {
_logService?.Info("导航到数据迁移界面"); _logService?.Info("导航到数据迁移界面");
using var form = new MigrationForm(_apiService); using var form = new MigrationForm(_apiService, _logService);
form.ShowDialog(this); form.ShowDialog(this);
} }

View File

@ -457,7 +457,7 @@ namespace WorkCameraExport.Forms
return; return;
} }
using var migrationForm = new MigrationForm(_apiService); using var migrationForm = new MigrationForm(_apiService, null);
migrationForm.ShowDialog(this); migrationForm.ShowDialog(this);
} }
} }

View File

@ -226,7 +226,8 @@ namespace WorkCameraExport.Forms
dgvRecords.SelectionMode = DataGridViewSelectionMode.FullRowSelect; dgvRecords.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
dgvRecords.Size = new Size(910, 315); dgvRecords.Size = new Size(910, 315);
dgvRecords.TabIndex = 0; dgvRecords.TabIndex = 0;
dgvRecords.CellContentClick += dgvRecords_CellContentClick; dgvRecords.CellValueChanged += dgvRecords_CellValueChanged;
dgvRecords.CurrentCellDirtyStateChanged += dgvRecords_CurrentCellDirtyStateChanged;
// //
// colSelect // colSelect

View File

@ -1,5 +1,6 @@
using WorkCameraExport.Models; using WorkCameraExport.Models;
using WorkCameraExport.Services; using WorkCameraExport.Services;
using WorkCameraExport.Services.Interfaces;
namespace WorkCameraExport.Forms namespace WorkCameraExport.Forms
{ {
@ -10,6 +11,7 @@ namespace WorkCameraExport.Forms
{ {
private readonly ApiService _apiService; private readonly ApiService _apiService;
private readonly CosService _cosService; private readonly CosService _cosService;
private readonly ILogService? _logService;
private CancellationTokenSource? _migrationCts; private CancellationTokenSource? _migrationCts;
private bool _isMigrating; private bool _isMigrating;
@ -17,11 +19,12 @@ namespace WorkCameraExport.Forms
private List<MigrationRecordDto> _records = new(); private List<MigrationRecordDto> _records = new();
private int _totalRecords; private int _totalRecords;
public MigrationForm(ApiService apiService) public MigrationForm(ApiService apiService, ILogService? logService = null)
{ {
InitializeComponent(); InitializeComponent();
_apiService = apiService; _apiService = apiService;
_cosService = new CosService(); _logService = logService;
_cosService = new CosService(logService);
} }
/// <summary> /// <summary>
@ -69,12 +72,16 @@ namespace WorkCameraExport.Forms
_records.Clear(); _records.Clear();
_totalRecords = 0; _totalRecords = 0;
_logService?.Info("[迁移界面] 开始查询迁移记录");
try try
{ {
var query = BuildQuery(); var query = BuildQuery();
query.PageNum = 1; query.PageNum = 1;
query.PageSize = 50; query.PageSize = 50;
_logService?.Info($"[迁移界面] 查询条件: 开始={query.StartDate}, 结束={query.EndDate}, 状态={query.Status}");
// 获取所有记录(分页获取) // 获取所有记录(分页获取)
var allRecords = new List<MigrationRecordDto>(); var allRecords = new List<MigrationRecordDto>();
int pageNum = 1; int pageNum = 1;
@ -86,6 +93,7 @@ namespace WorkCameraExport.Forms
if (!success || data == null) if (!success || data == null)
{ {
_logService?.Error($"[迁移界面] 查询失败: {message}");
ShowError(message); ShowError(message);
return; return;
} }
@ -93,6 +101,8 @@ namespace WorkCameraExport.Forms
allRecords.AddRange(data.Result); allRecords.AddRange(data.Result);
_totalRecords = data.TotalNum; _totalRecords = data.TotalNum;
_logService?.Info($"[迁移界面] 第{pageNum}页获取 {data.Result.Count} 条, 累计 {allRecords.Count}/{_totalRecords}");
if (data.Result.Count < 50 || pageNum >= data.TotalPage) if (data.Result.Count < 50 || pageNum >= data.TotalPage)
break; break;
@ -123,6 +133,7 @@ namespace WorkCameraExport.Forms
UpdateSelectedCount(); UpdateSelectedCount();
lblStatusBar.Text = $"查询完成,共 {_totalRecords} 条记录"; lblStatusBar.Text = $"查询完成,共 {_totalRecords} 条记录";
lblStatusBar.ForeColor = Color.Green; lblStatusBar.ForeColor = Color.Green;
_logService?.Info($"[迁移界面] 查询完成, 共 {_totalRecords} 条记录");
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -188,18 +199,25 @@ namespace WorkCameraExport.Forms
} }
/// <summary> /// <summary>
/// 数据网格单元格点击事件 /// 数据网格单元格值变更事件(用于复选框)
/// </summary> /// </summary>
private void dgvRecords_CellContentClick(object sender, DataGridViewCellEventArgs e) private void dgvRecords_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{ {
if (e.ColumnIndex == 0 && e.RowIndex >= 0) if (e.ColumnIndex == 0 && e.RowIndex >= 0)
{ {
// 延迟更新,等待复选框状态变更 UpdateSelectedCount();
BeginInvoke(new Action(() => UpdateMigrateButtonState();
{ }
UpdateSelectedCount(); }
UpdateMigrateButtonState();
})); /// <summary>
/// 数据网格当前单元格脏状态变更事件(立即提交复选框编辑)
/// </summary>
private void dgvRecords_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (dgvRecords.IsCurrentCellDirty && dgvRecords.CurrentCell is DataGridViewCheckBoxCell)
{
dgvRecords.CommitEdit(DataGridViewDataErrorContexts.Commit);
} }
} }
@ -289,18 +307,24 @@ namespace WorkCameraExport.Forms
int totalRecords = records.Count; int totalRecords = records.Count;
int processedRecords = 0; int processedRecords = 0;
_logService?.Info($"[迁移界面] 开始迁移, 共 {totalRecords} 条记录");
try try
{ {
// 获取 COS 临时密钥 // 获取 COS 临时密钥
lblCurrentRecord.Text = "正在获取 COS 临时密钥..."; lblCurrentRecord.Text = "正在获取 COS 临时密钥...";
_logService?.Info("[迁移界面] 正在获取 COS 临时密钥...");
var (credSuccess, credMessage, credentials) = await _apiService.GetTempCredentialsAsync(); var (credSuccess, credMessage, credentials) = await _apiService.GetTempCredentialsAsync();
if (!credSuccess || credentials == null) if (!credSuccess || credentials == null)
{ {
_logService?.Error($"[迁移界面] 获取 COS 临时密钥失败: {credMessage}");
ShowError($"获取 COS 临时密钥失败: {credMessage}"); ShowError($"获取 COS 临时密钥失败: {credMessage}");
return; return;
} }
_logService?.Info($"[迁移界面] COS 临时密钥获取成功, Bucket={credentials.Bucket}, Region={credentials.Region}");
// 初始化 COS 服务 // 初始化 COS 服务
_cosService.Initialize(credentials); _cosService.Initialize(credentials);
@ -309,6 +333,7 @@ namespace WorkCameraExport.Forms
{ {
if (_migrationCts.Token.IsCancellationRequested) if (_migrationCts.Token.IsCancellationRequested)
{ {
_logService?.Info("[迁移界面] 迁移已取消");
lblStatusBar.Text = "迁移已取消"; lblStatusBar.Text = "迁移已取消";
lblStatusBar.ForeColor = Color.Orange; lblStatusBar.ForeColor = Color.Orange;
break; break;
@ -316,6 +341,7 @@ namespace WorkCameraExport.Forms
processedRecords++; processedRecords++;
lblCurrentRecord.Text = $"正在迁移记录 {record.Id} ({processedRecords}/{totalRecords})..."; lblCurrentRecord.Text = $"正在迁移记录 {record.Id} ({processedRecords}/{totalRecords})...";
_logService?.Info($"[迁移界面] 开始迁移记录 {record.Id}, 图片数={record.Images?.Count ?? 0}");
try try
{ {
@ -324,23 +350,26 @@ namespace WorkCameraExport.Forms
if (migrationResult) if (migrationResult)
{ {
successCount++; successCount++;
_logService?.Info($"[迁移界面] 记录 {record.Id} 迁移成功");
UpdateRowStatus(record.Id, "已迁移", Color.Green); UpdateRowStatus(record.Id, "已迁移", Color.Green);
} }
else else
{ {
failCount++; failCount++;
_logService?.Warn($"[迁移界面] 记录 {record.Id} 迁移失败");
UpdateRowStatus(record.Id, "迁移失败", Color.Red); UpdateRowStatus(record.Id, "迁移失败", Color.Red);
} }
} }
catch (OperationCanceledException) catch (OperationCanceledException)
{ {
_logService?.Info("[迁移界面] 迁移操作被取消");
break; break;
} }
catch (Exception ex) catch (Exception ex)
{ {
failCount++; failCount++;
_logService?.Error($"[迁移界面] 记录 {record.Id} 迁移异常: {ex.Message}", ex);
UpdateRowStatus(record.Id, "迁移失败", Color.Red); UpdateRowStatus(record.Id, "迁移失败", Color.Red);
System.Diagnostics.Debug.WriteLine($"迁移记录 {record.Id} 失败: {ex.Message}");
} }
// 更新进度 // 更新进度
@ -357,6 +386,7 @@ namespace WorkCameraExport.Forms
lblCurrentRecord.Text = $"迁移完成!成功: {successCount}, 失败: {failCount}"; lblCurrentRecord.Text = $"迁移完成!成功: {successCount}, 失败: {failCount}";
lblStatusBar.Text = $"迁移完成,成功 {successCount} 条,失败 {failCount} 条"; lblStatusBar.Text = $"迁移完成,成功 {successCount} 条,失败 {failCount} 条";
lblStatusBar.ForeColor = failCount > 0 ? Color.Orange : Color.Green; lblStatusBar.ForeColor = failCount > 0 ? Color.Orange : Color.Green;
_logService?.Info($"[迁移界面] 迁移完成, 成功={successCount}, 失败={failCount}");
MessageBox.Show( MessageBox.Show(
$"迁移完成!\n\n成功: {successCount} 条\n失败: {failCount} 条", $"迁移完成!\n\n成功: {successCount} 条\n失败: {failCount} 条",
@ -388,9 +418,12 @@ namespace WorkCameraExport.Forms
// 获取需要迁移的图片(未迁移的) // 获取需要迁移的图片(未迁移的)
var imagesToMigrate = record.Images.Where(img => !img.IsMigrated).ToList(); var imagesToMigrate = record.Images.Where(img => !img.IsMigrated).ToList();
_logService?.Info($"[迁移] 记录 {record.Id}: 总图片={record.Images?.Count ?? 0}, 待迁移={imagesToMigrate.Count}");
if (imagesToMigrate.Count == 0) if (imagesToMigrate.Count == 0)
{ {
// 没有需要迁移的图片,直接返回成功 // 没有需要迁移的图片,直接返回成功
_logService?.Info($"[迁移] 记录 {record.Id}: 无需迁移的图片, 跳过");
return true; return true;
} }
@ -407,31 +440,39 @@ namespace WorkCameraExport.Forms
try try
{ {
_logService?.Info($"[迁移] 记录 {record.Id} 图片 {imageIndex}/{totalImages}: 开始下载 {image.Url}");
// 1. 下载原图片 // 1. 下载原图片
var (downloadSuccess, imageData, downloadMessage) = var (downloadSuccess, imageData, downloadMessage) =
await _apiService.DownloadImageAsync(image.Url, cancellationToken); await _apiService.DownloadImageAsync(image.Url, cancellationToken);
if (!downloadSuccess || imageData == null) if (!downloadSuccess || imageData == null)
{ {
System.Diagnostics.Debug.WriteLine($"下载图片失败: {image.Url} - {downloadMessage}"); _logService?.Warn($"[迁移] 记录 {record.Id} 图片下载失败: {downloadMessage}, URL={image.Url}");
continue; // 跳过失败的图片,继续处理其他图片 continue; // 跳过失败的图片,继续处理其他图片
} }
_logService?.Info($"[迁移] 记录 {record.Id} 图片下载成功, 大小={imageData.Length} bytes");
// 2. 生成 COS 路径 // 2. 生成 COS 路径
var recordTime = record.RecordTime ?? DateTime.Now; var recordTime = record.RecordTime ?? DateTime.Now;
var fileName = CosService.GenerateFileName(".jpg"); var fileName = CosService.GenerateFileName(".jpg");
var cosKey = CosService.GenerateCosKey(recordTime, "当日照片", "", fileName); var cosKey = CosService.GenerateCosKey(recordTime, "当日照片", "", fileName);
_logService?.Info($"[迁移] 记录 {record.Id} 准备上传到 COS, Key={cosKey}");
// 3. 上传到 COS // 3. 上传到 COS
var (uploadSuccess, uploadMessage, cosUrl) = var (uploadSuccess, uploadMessage, cosUrl) =
await _cosService.UploadBytesAsync(imageData, cosKey, cancellationToken: cancellationToken); await _cosService.UploadBytesAsync(imageData, cosKey, cancellationToken: cancellationToken);
if (!uploadSuccess || string.IsNullOrEmpty(cosUrl)) if (!uploadSuccess || string.IsNullOrEmpty(cosUrl))
{ {
System.Diagnostics.Debug.WriteLine($"上传图片失败: {uploadMessage}"); _logService?.Warn($"[迁移] 记录 {record.Id} 上传COS失败: {uploadMessage}");
continue; // 跳过失败的图片,继续处理其他图片 continue; // 跳过失败的图片,继续处理其他图片
} }
_logService?.Info($"[迁移] 记录 {record.Id} 上传COS成功, NewUrl={cosUrl}");
// 4. 记录 URL 映射 // 4. 记录 URL 映射
urlPairs.Add(new MigrationUrlPair urlPairs.Add(new MigrationUrlPair
{ {
@ -445,11 +486,13 @@ namespace WorkCameraExport.Forms
} }
catch (Exception ex) catch (Exception ex)
{ {
System.Diagnostics.Debug.WriteLine($"处理图片异常: {image.Url} - {ex.Message}"); _logService?.Error($"[迁移] 记录 {record.Id} 处理图片异常: {ex.Message}, URL={image.Url}", ex);
continue; // 跳过失败的图片,继续处理其他图片 continue; // 跳过失败的图片,继续处理其他图片
} }
} }
_logService?.Info($"[迁移] 记录 {record.Id}: 成功处理 {urlPairs.Count}/{totalImages} 张图片");
// 5. 调用 API 更新 URL // 5. 调用 API 更新 URL
if (urlPairs.Count > 0) if (urlPairs.Count > 0)
{ {
@ -459,16 +502,21 @@ namespace WorkCameraExport.Forms
ImageUrls = urlPairs ImageUrls = urlPairs
}; };
_logService?.Info($"[迁移] 记录 {record.Id}: 调用API更新URL, 数量={urlPairs.Count}");
var (updateSuccess, updateMessage) = await _apiService.UpdateMigrationUrlsAsync(updateRequest); var (updateSuccess, updateMessage) = await _apiService.UpdateMigrationUrlsAsync(updateRequest);
if (!updateSuccess) if (!updateSuccess)
{ {
System.Diagnostics.Debug.WriteLine($"更新 URL 失败: {updateMessage}"); _logService?.Error($"[迁移] 记录 {record.Id} 更新URL失败: {updateMessage}");
return false; return false;
} }
_logService?.Info($"[迁移] 记录 {record.Id}: API更新URL成功");
} }
else
// 如果所有图片都成功迁移,返回成功 {
_logService?.Warn($"[迁移] 记录 {record.Id}: 没有成功迁移的图片, 不调用更新API");
} // 如果所有图片都成功迁移,返回成功
return urlPairs.Count == imagesToMigrate.Count; return urlPairs.Count == imagesToMigrate.Count;
} }

View File

@ -323,6 +323,15 @@ namespace WorkCameraExport.Services
if (response.IsSuccess && response.Data != null) if (response.IsSuccess && response.Data != null)
{ {
// 调试日志:记录反序列化后的 Workers 数据
foreach (var record in response.Data.Result.Take(3)) // 只记录前3条
{
var workersInfo = record.Workers != null
? $"Workers数量={record.Workers.Count}, 名称=[{string.Join(", ", record.Workers.Select(w => w.WorkerName ?? "null"))}]"
: "Workers=null";
_logService?.Info($"[反序列化] 记录ID={record.Id}, {workersInfo}");
}
return (true, "查询成功", response.Data); return (true, "查询成功", response.Data);
} }
@ -563,6 +572,7 @@ namespace WorkCameraExport.Services
{ {
try try
{ {
_logService?.Info($"[迁移] 开始查询迁移列表, 页码={query.PageNum}, 状态={query.Status}");
await EnsureTokenValidAsync(); await EnsureTokenValidAsync();
var queryParams = BuildQueryString(query); var queryParams = BuildQueryString(query);
var response = await ExecuteWithRetryAsync(() => var response = await ExecuteWithRetryAsync(() =>
@ -570,14 +580,16 @@ namespace WorkCameraExport.Services
if (response.IsSuccess && response.Data != null) if (response.IsSuccess && response.Data != null)
{ {
_logService?.Info($"[迁移] 查询成功, 共 {response.Data.TotalNum} 条记录");
return (true, "查询成功", response.Data); return (true, "查询成功", response.Data);
} }
_logService?.Warn($"[迁移] 查询失败: {response.Msg}, Code={response.Code}");
return (false, response.Msg ?? "查询失败", null); return (false, response.Msg ?? "查询失败", null);
} }
catch (Exception ex) catch (Exception ex)
{ {
_logService?.Error($"查询迁移列表异常: {ex.Message}", ex); _logService?.Error($"[迁移] 查询迁移列表异常: {ex.Message}", ex);
return (false, $"查询异常: {ex.Message}", null); return (false, $"查询异常: {ex.Message}", null);
} }
} }
@ -590,20 +602,23 @@ namespace WorkCameraExport.Services
{ {
try try
{ {
_logService?.Info($"[迁移] 开始更新URL, 记录ID={request.RecordId}, 图片数={request.ImageUrls?.Count ?? 0}");
await EnsureTokenValidAsync(); await EnsureTokenValidAsync();
var response = await ExecuteWithRetryAsync(() => var response = await ExecuteWithRetryAsync(() =>
PostAsync<object>("/api/workrecord/migration/update", request)); PostAsync<object>("/api/workrecord/migration/update", request));
if (response.IsSuccess) if (response.IsSuccess)
{ {
_logService?.Info($"[迁移] 更新URL成功, 记录ID={request.RecordId}");
return (true, "更新成功"); return (true, "更新成功");
} }
_logService?.Warn($"[迁移] 更新URL失败: {response.Msg}, Code={response.Code}");
return (false, response.Msg ?? "更新失败"); return (false, response.Msg ?? "更新失败");
} }
catch (Exception ex) catch (Exception ex)
{ {
_logService?.Error($"更新迁移URL异常: {ex.Message}", ex); _logService?.Error($"[迁移] 更新迁移URL异常: {ex.Message}", ex);
return (false, $"更新异常: {ex.Message}"); return (false, $"更新异常: {ex.Message}");
} }
} }
@ -769,6 +784,9 @@ namespace WorkCameraExport.Services
var content = await response.Content.ReadAsStringAsync(); var content = await response.Content.ReadAsStringAsync();
// 调试日志:记录原始 JSON 响应(完整内容)
_logService?.Info($"[API响应] {endpoint} 原始JSON: {content}");
return JsonSerializer.Deserialize<PagedResult<T>>(content, JsonOptions) return JsonSerializer.Deserialize<PagedResult<T>>(content, JsonOptions)
?? new PagedResult<T> { Code = 500, Msg = "解析响应失败" }; ?? new PagedResult<T> { Code = 500, Msg = "解析响应失败" };
} }

View File

@ -3,6 +3,7 @@ using COSXML.Auth;
using COSXML.Model.Object; using COSXML.Model.Object;
using COSXML.Transfer; using COSXML.Transfer;
using WorkCameraExport.Models; using WorkCameraExport.Models;
using WorkCameraExport.Services.Interfaces;
namespace WorkCameraExport.Services namespace WorkCameraExport.Services
{ {
@ -13,14 +14,21 @@ namespace WorkCameraExport.Services
{ {
private CosXml? _cosXml; private CosXml? _cosXml;
private CosTempCredentials? _credentials; private CosTempCredentials? _credentials;
private readonly ILogService? _logService;
private bool _disposed; private bool _disposed;
public CosService(ILogService? logService = null)
{
_logService = logService;
}
/// <summary> /// <summary>
/// 初始化 COS 客户端 /// 初始化 COS 客户端
/// </summary> /// </summary>
public void Initialize(CosTempCredentials credentials) public void Initialize(CosTempCredentials credentials)
{ {
_credentials = credentials; _credentials = credentials;
_logService?.Info($"[COS] 初始化, Region={credentials.Region}, Bucket={credentials.Bucket}");
var config = new CosXmlConfig.Builder() var config = new CosXmlConfig.Builder()
.IsHttps(true) .IsHttps(true)
@ -35,6 +43,7 @@ namespace WorkCameraExport.Services
credentials.SessionToken); credentials.SessionToken);
_cosXml = new CosXmlServer(config, credentialProvider); _cosXml = new CosXmlServer(config, credentialProvider);
_logService?.Info("[COS] 初始化完成");
} }
/// <summary> /// <summary>
@ -58,9 +67,12 @@ namespace WorkCameraExport.Services
{ {
if (!IsInitialized || _cosXml == null || _credentials == null) if (!IsInitialized || _cosXml == null || _credentials == null)
{ {
_logService?.Error("[COS] 上传失败: 服务未初始化");
return (false, "COS 服务未初始化", null); return (false, "COS 服务未初始化", null);
} }
_logService?.Info($"[COS] 开始上传文件: {localFilePath} -> {cosKey}");
try try
{ {
var transferConfig = new TransferConfig(); var transferConfig = new TransferConfig();
@ -83,27 +95,33 @@ namespace WorkCameraExport.Services
if (result.IsSuccessful()) if (result.IsSuccessful())
{ {
var cosUrl = $"https://{_credentials.Bucket}.cos.{_credentials.Region}.myqcloud.com/{cosKey}"; var cosUrl = $"https://{_credentials.Bucket}.cos.{_credentials.Region}.myqcloud.com/{cosKey}";
_logService?.Info($"[COS] 上传成功: {cosUrl}");
return (true, "上传成功", cosUrl); return (true, "上传成功", cosUrl);
} }
else else
{ {
_logService?.Warn($"[COS] 上传失败: result.IsSuccessful()=false");
return (false, "上传失败", null); return (false, "上传失败", null);
} }
} }
catch (OperationCanceledException) catch (OperationCanceledException)
{ {
_logService?.Info("[COS] 上传已取消");
return (false, "上传已取消", null); return (false, "上传已取消", null);
} }
catch (COSXML.CosException.CosClientException clientEx) catch (COSXML.CosException.CosClientException clientEx)
{ {
_logService?.Error($"[COS] 客户端异常: {clientEx.Message}", clientEx);
return (false, $"客户端异常: {clientEx.Message}", null); return (false, $"客户端异常: {clientEx.Message}", null);
} }
catch (COSXML.CosException.CosServerException serverEx) catch (COSXML.CosException.CosServerException serverEx)
{ {
_logService?.Error($"[COS] 服务端异常: {serverEx.GetInfo()}");
return (false, $"服务端异常: {serverEx.GetInfo()}", null); return (false, $"服务端异常: {serverEx.GetInfo()}", null);
} }
catch (Exception ex) catch (Exception ex)
{ {
_logService?.Error($"[COS] 上传异常: {ex.Message}", ex);
return (false, $"上传异常: {ex.Message}", null); return (false, $"上传异常: {ex.Message}", null);
} }
} }

View File

@ -201,6 +201,12 @@ namespace WorkCameraExport.Services
WorkRecordExportItem record, WorkRecordExportItem record,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
// 调试日志:记录写入 Excel 时的 Workers 数据
var workersValue = record.Workers != null
? $"Workers数量={record.Workers.Count}, 值=[{string.Join(", ", record.Workers)}]"
: "Workers=null";
_logService?.Info($"[Excel写入] 行{row}, 记录ID={record.Id}, {workersValue}");
worksheet.Cells[row, 1].Value = row - 1; // 序号 worksheet.Cells[row, 1].Value = row - 1; // 序号
worksheet.Cells[row, 2].Value = record.DeptName; worksheet.Cells[row, 2].Value = record.DeptName;
// 第3列是图片稍后处理 // 第3列是图片稍后处理

View File

@ -318,7 +318,20 @@ namespace WorkCameraExport.Services
{ {
return records.Select(r => return records.Select(r =>
{ {
// 调试日志:记录 FromDto 前的 Workers 数据
var workersInfo = r.Workers != null
? $"Workers数量={r.Workers.Count}, 值=[{string.Join(", ", r.Workers)}]"
: "Workers=null";
_logService?.Info($"[BuildExportItems] 记录ID={r.Id}, {workersInfo}");
var item = WorkRecordExportItem.FromDto(r); var item = WorkRecordExportItem.FromDto(r);
// 调试日志:记录 FromDto 后的 Workers 数据
var itemWorkersInfo = item.Workers != null
? $"Workers数量={item.Workers.Count}, 值=[{string.Join(", ", item.Workers)}]"
: "Workers=null";
_logService?.Info($"[BuildExportItems->FromDto后] 记录ID={item.Id}, {itemWorkersInfo}");
item.ImagePaths = r.Images item.ImagePaths = r.Images
.Where(url => !string.IsNullOrEmpty(url) && imagePathMap.ContainsKey(url)) .Where(url => !string.IsNullOrEmpty(url) && imagePathMap.ContainsKey(url))
.Select(url => imagePathMap[url]) .Select(url => imagePathMap[url])
@ -334,6 +347,17 @@ namespace WorkCameraExport.Services
/// </summary> /// </summary>
private WorkRecordExportDto ConvertToExportDto(WorkRecordDto dto) private WorkRecordExportDto ConvertToExportDto(WorkRecordDto dto)
{ {
// 调试日志:记录转换前的 Workers 数据
var workersBeforeConvert = dto.Workers != null
? $"Workers数量={dto.Workers.Count}, 名称=[{string.Join(", ", dto.Workers.Select(w => w.WorkerName ?? "null"))}]"
: "Workers=null";
_logService?.Info($"[转换前] 记录ID={dto.Id}, {workersBeforeConvert}");
var workerNames = dto.Workers?.Select(w => w.WorkerName).ToList() ?? new List<string>();
// 调试日志:记录转换后的 Workers 数据
_logService?.Info($"[转换后] 记录ID={dto.Id}, WorkerNames=[{string.Join(", ", workerNames)}]");
return new WorkRecordExportDto return new WorkRecordExportDto
{ {
Id = dto.Id, Id = dto.Id,
@ -344,7 +368,7 @@ namespace WorkCameraExport.Services
Address = dto.Address, Address = dto.Address,
Content = dto.Content, Content = dto.Content,
StatusName = dto.StatusName, StatusName = dto.StatusName,
Workers = dto.Workers?.Select(w => w.WorkerName).ToList() ?? new List<string>(), Workers = workerNames,
Images = dto.Images.Select(i => i.Url).ToList(), Images = dto.Images.Select(i => i.Url).ToList(),
CreateTime = dto.CreateTime, CreateTime = dto.CreateTime,
UpdateTime = dto.UpdateTime UpdateTime = dto.UpdateTime

View File

@ -105,8 +105,10 @@ namespace ZR.Admin.WebApi.Controllers.Business
var info = response.Adapt<CamWorkrecordDto>(); var info = response.Adapt<CamWorkrecordDto>();
if (info != null) if (info != null)
{ {
var names = _CamWorkerService.AsQueryable().Where(it => it.WorkrecordId == info.Id).Select(it => it.WorkerName).ToList(); // 获取工作人员列表
info.Worker = names != null && names.Count > 0 ? string.Join(",", names) : ""; var workers = _CamWorkerService.AsQueryable().Where(it => it.WorkrecordId == info.Id).ToList();
info.Workers = workers.Select(w => new CamWorkersDto { Id = w.Id, WorkerName = w.WorkerName }).ToList();
info.Worker = workers.Count > 0 ? string.Join(",", workers.Select(w => w.WorkerName)) : "";
// 获取图片列表 // 获取图片列表
var imageRecords = _CamWorkrecordImageService.GetListByWorkrecordId(info.Id); var imageRecords = _CamWorkrecordImageService.GetListByWorkrecordId(info.Id);

View File

@ -2,8 +2,8 @@
"name" : "随工水印相机", "name" : "随工水印相机",
"appid" : "__UNI__37E1E71", "appid" : "__UNI__37E1E71",
"description" : "", "description" : "",
"versionName" : "1.0.5", "versionName" : "1.0.5.03",
"versionCode" : 105, "versionCode" : 106,
"transformPx" : false, "transformPx" : false,
/* 5+App */ /* 5+App */
"app-plus" : { "app-plus" : {

View File

@ -776,10 +776,17 @@ const handleSaveImage = async () => {
await addWatermarkToImage(); await addWatermarkToImage();
// //
if (imageSrc.value) { // if (imageSrc.value) {
await saveImageToPhotosAlbum(imageSrc.value); // await saveImageToPhotosAlbum(imageSrc.value);
// }
try {
if (imageList.value.length > 0) {
const watermarkPaths = imageList.value.map(img => img.watermark);
await saveImagesToPhotosAlbum(watermarkPaths);
}
} catch (saveError) {
console.error("保存图片到相册失败:", saveError);
} }
uni.hideLoading(); uni.hideLoading();
uni.showToast({ uni.showToast({
title: "图片保存成功", title: "图片保存成功",
@ -914,8 +921,8 @@ const fallbackToV2Upload = async (_remarks, validWorkers) => {
// //
try { try {
if (imageList.value.length > 0) { if (imageList.value.length > 0) {
const watermarkPaths = imageList.value.map(img => img.watermark); //const watermarkPaths = imageList.value.map(img => img.watermark);
await saveImagesToPhotosAlbum(watermarkPaths); //await saveImagesToPhotosAlbum(watermarkPaths);
} }
} catch (saveError) { } catch (saveError) {
console.error("保存图片到相册失败:", saveError); console.error("保存图片到相册失败:", saveError);
@ -1083,8 +1090,8 @@ const handleSaveAndSubmit = async () => {
try { try {
// //
if (imageList.value.length > 0) { if (imageList.value.length > 0) {
const watermarkPaths = imageList.value.map(img => img.watermark); // const watermarkPaths = imageList.value.map(img => img.watermark);
const saveResult = await saveImagesToPhotosAlbum(watermarkPaths); // const saveResult = await saveImagesToPhotosAlbum(watermarkPaths);
console.log(`保存到相册完成: 成功${saveResult.success}张, 失败${saveResult.failed}`); console.log(`保存到相册完成: 成功${saveResult.success}张, 失败${saveResult.failed}`);
} }
} catch (error) { } catch (error) {