33
This commit is contained in:
parent
914cda7219
commit
0e5e9fb140
|
|
@ -30,6 +30,11 @@ namespace WorkCameraExport.Forms
|
||||||
{
|
{
|
||||||
components = new System.ComponentModel.Container();
|
components = new System.ComponentModel.Container();
|
||||||
|
|
||||||
|
// 图片右键菜单
|
||||||
|
contextMenuImage = new ContextMenuStrip(components);
|
||||||
|
menuItemDownloadImage = new ToolStripMenuItem();
|
||||||
|
menuItemCopyUrl = new ToolStripMenuItem();
|
||||||
|
|
||||||
// 主面板
|
// 主面板
|
||||||
panelMain = new Panel();
|
panelMain = new Panel();
|
||||||
|
|
||||||
|
|
@ -365,6 +370,7 @@ namespace WorkCameraExport.Forms
|
||||||
btnAdd.Text = "➕ 新增";
|
btnAdd.Text = "➕ 新增";
|
||||||
btnAdd.UseVisualStyleBackColor = false;
|
btnAdd.UseVisualStyleBackColor = false;
|
||||||
btnAdd.Click += btnAdd_Click;
|
btnAdd.Click += btnAdd_Click;
|
||||||
|
btnAdd.Enabled = false; // 禁用新增按钮
|
||||||
|
|
||||||
//
|
//
|
||||||
// btnExportAll
|
// btnExportAll
|
||||||
|
|
@ -471,6 +477,7 @@ namespace WorkCameraExport.Forms
|
||||||
dgvWorkRecords.CellClick += dgvWorkRecords_CellClick;
|
dgvWorkRecords.CellClick += dgvWorkRecords_CellClick;
|
||||||
dgvWorkRecords.CellContentClick += dgvWorkRecords_CellContentClick;
|
dgvWorkRecords.CellContentClick += dgvWorkRecords_CellContentClick;
|
||||||
dgvWorkRecords.CellPainting += dgvWorkRecords_CellPainting;
|
dgvWorkRecords.CellPainting += dgvWorkRecords_CellPainting;
|
||||||
|
dgvWorkRecords.CellMouseClick += dgvWorkRecords_CellMouseClick;
|
||||||
|
|
||||||
//
|
//
|
||||||
// colSelect - 选择列
|
// colSelect - 选择列
|
||||||
|
|
@ -560,6 +567,7 @@ namespace WorkCameraExport.Forms
|
||||||
colOperations.Text = "编辑";
|
colOperations.Text = "编辑";
|
||||||
colOperations.UseColumnTextForButtonValue = true;
|
colOperations.UseColumnTextForButtonValue = true;
|
||||||
colOperations.Width = 70;
|
colOperations.Width = 70;
|
||||||
|
colOperations.ReadOnly = true; // 禁用编辑列
|
||||||
|
|
||||||
//
|
//
|
||||||
// panelPaging - 分页控件区域
|
// panelPaging - 分页控件区域
|
||||||
|
|
@ -760,6 +768,29 @@ namespace WorkCameraExport.Forms
|
||||||
|
|
||||||
//
|
//
|
||||||
// WorkRecordForm
|
// WorkRecordForm
|
||||||
|
//
|
||||||
|
// contextMenuImage
|
||||||
|
//
|
||||||
|
contextMenuImage.Items.AddRange(new ToolStripItem[] { menuItemDownloadImage, menuItemCopyUrl });
|
||||||
|
contextMenuImage.Name = "contextMenuImage";
|
||||||
|
contextMenuImage.Size = new Size(150, 48);
|
||||||
|
|
||||||
|
//
|
||||||
|
// menuItemDownloadImage
|
||||||
|
//
|
||||||
|
menuItemDownloadImage.Name = "menuItemDownloadImage";
|
||||||
|
menuItemDownloadImage.Size = new Size(149, 22);
|
||||||
|
menuItemDownloadImage.Text = "下载图片";
|
||||||
|
menuItemDownloadImage.Click += menuItemDownloadImage_Click;
|
||||||
|
|
||||||
|
//
|
||||||
|
// menuItemCopyUrl
|
||||||
|
//
|
||||||
|
menuItemCopyUrl.Name = "menuItemCopyUrl";
|
||||||
|
menuItemCopyUrl.Size = new Size(149, 22);
|
||||||
|
menuItemCopyUrl.Text = "复制URL";
|
||||||
|
menuItemCopyUrl.Click += menuItemCopyUrl_Click;
|
||||||
|
|
||||||
//
|
//
|
||||||
AutoScaleDimensions = new SizeF(7F, 17F);
|
AutoScaleDimensions = new SizeF(7F, 17F);
|
||||||
AutoScaleMode = AutoScaleMode.Font;
|
AutoScaleMode = AutoScaleMode.Font;
|
||||||
|
|
@ -782,6 +813,7 @@ namespace WorkCameraExport.Forms
|
||||||
panelPaging.ResumeLayout(false);
|
panelPaging.ResumeLayout(false);
|
||||||
panelPaging.PerformLayout();
|
panelPaging.PerformLayout();
|
||||||
panelProgress.ResumeLayout(false);
|
panelProgress.ResumeLayout(false);
|
||||||
|
contextMenuImage.ResumeLayout(false);
|
||||||
ResumeLayout(false);
|
ResumeLayout(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -850,5 +882,10 @@ namespace WorkCameraExport.Forms
|
||||||
private ProgressBar progressBar;
|
private ProgressBar progressBar;
|
||||||
private Label lblProgress;
|
private Label lblProgress;
|
||||||
private Button btnCancelExport;
|
private Button btnCancelExport;
|
||||||
|
|
||||||
|
// 图片右键菜单
|
||||||
|
private ContextMenuStrip contextMenuImage;
|
||||||
|
private ToolStripMenuItem menuItemDownloadImage;
|
||||||
|
private ToolStripMenuItem menuItemCopyUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -249,7 +249,7 @@ namespace WorkCameraExport.Forms
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 单元格绘制事件 - 用于绘制图片缩略图
|
/// 单元格绘制事件 - 用于绘制图片缩略图
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private async void dgvWorkRecords_CellPainting(object? sender, DataGridViewCellPaintingEventArgs e)
|
private void dgvWorkRecords_CellPainting(object? sender, DataGridViewCellPaintingEventArgs e)
|
||||||
{
|
{
|
||||||
// 只处理图片列
|
// 只处理图片列
|
||||||
if (e.ColumnIndex != colImages.Index || e.RowIndex < 0)
|
if (e.ColumnIndex != colImages.Index || e.RowIndex < 0)
|
||||||
|
|
@ -272,7 +272,6 @@ namespace WorkCameraExport.Forms
|
||||||
var startX = cellBounds.X + 5;
|
var startX = cellBounds.X + 5;
|
||||||
var startY = cellBounds.Y + (cellBounds.Height - ThumbnailHeight) / 2;
|
var startY = cellBounds.Y + (cellBounds.Height - ThumbnailHeight) / 2;
|
||||||
|
|
||||||
// 绘制缩略图占位符
|
|
||||||
using var placeholderBrush = new SolidBrush(Color.FromArgb(230, 230, 230));
|
using var placeholderBrush = new SolidBrush(Color.FromArgb(230, 230, 230));
|
||||||
using var borderPen = new Pen(Color.FromArgb(200, 200, 200));
|
using var borderPen = new Pen(Color.FromArgb(200, 200, 200));
|
||||||
using var textBrush = new SolidBrush(Color.FromArgb(102, 102, 102));
|
using var textBrush = new SolidBrush(Color.FromArgb(102, 102, 102));
|
||||||
|
|
@ -283,16 +282,35 @@ namespace WorkCameraExport.Forms
|
||||||
var x = startX + i * (ThumbnailWidth + ThumbnailSpacing);
|
var x = startX + i * (ThumbnailWidth + ThumbnailSpacing);
|
||||||
var rect = new Rectangle(x, startY, ThumbnailWidth, ThumbnailHeight);
|
var rect = new Rectangle(x, startY, ThumbnailWidth, ThumbnailHeight);
|
||||||
|
|
||||||
// 绘制占位符背景
|
var imageUrl = record.Images[i].ImageUrl;
|
||||||
e.Graphics.FillRectangle(placeholderBrush, rect);
|
|
||||||
e.Graphics.DrawRectangle(borderPen, rect);
|
|
||||||
|
|
||||||
// 绘制图片序号
|
// 检查缓存中是否有图片
|
||||||
var text = $"图{i + 1}";
|
if (_thumbnailCache.TryGetValue(imageUrl, out var cachedImage) && cachedImage != null)
|
||||||
var textSize = e.Graphics.MeasureString(text, font);
|
{
|
||||||
var textX = x + (ThumbnailWidth - textSize.Width) / 2;
|
// 绘制缓存的图片
|
||||||
var textY = startY + (ThumbnailHeight - textSize.Height) / 2;
|
e.Graphics.DrawImage(cachedImage, rect);
|
||||||
e.Graphics.DrawString(text, font, textBrush, textX, textY);
|
e.Graphics.DrawRectangle(borderPen, rect);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 绘制占位符背景
|
||||||
|
e.Graphics.FillRectangle(placeholderBrush, rect);
|
||||||
|
e.Graphics.DrawRectangle(borderPen, rect);
|
||||||
|
|
||||||
|
// 绘制加载中文字
|
||||||
|
var text = "加载中";
|
||||||
|
var textSize = e.Graphics.MeasureString(text, font);
|
||||||
|
var textX = x + (ThumbnailWidth - textSize.Width) / 2;
|
||||||
|
var textY = startY + (ThumbnailHeight - textSize.Height) / 2;
|
||||||
|
e.Graphics.DrawString(text, font, textBrush, textX, textY);
|
||||||
|
|
||||||
|
// 异步加载图片(只触发一次)
|
||||||
|
if (!_thumbnailCache.ContainsKey(imageUrl))
|
||||||
|
{
|
||||||
|
_thumbnailCache[imageUrl] = null; // 标记为正在加载
|
||||||
|
_ = LoadThumbnailAsync(imageUrl, e.RowIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 绘制徽章(显示剩余图片数量)
|
// 绘制徽章(显示剩余图片数量)
|
||||||
|
|
@ -316,6 +334,58 @@ namespace WorkCameraExport.Forms
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步加载缩略图
|
||||||
|
/// </summary>
|
||||||
|
private async Task LoadThumbnailAsync(string imageUrl, int rowIndex)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var (success, imageData, _) = await _apiService.DownloadImageAsync(imageUrl);
|
||||||
|
if (success && imageData != null && imageData.Length > 0)
|
||||||
|
{
|
||||||
|
using var ms = new MemoryStream(imageData);
|
||||||
|
var originalImage = Image.FromStream(ms);
|
||||||
|
|
||||||
|
// 创建缩略图
|
||||||
|
var thumbnail = new Bitmap(ThumbnailWidth, ThumbnailHeight);
|
||||||
|
using (var g = Graphics.FromImage(thumbnail))
|
||||||
|
{
|
||||||
|
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
|
||||||
|
g.DrawImage(originalImage, 0, 0, ThumbnailWidth, ThumbnailHeight);
|
||||||
|
}
|
||||||
|
originalImage.Dispose();
|
||||||
|
|
||||||
|
_thumbnailCache[imageUrl] = thumbnail;
|
||||||
|
|
||||||
|
// 刷新对应行
|
||||||
|
if (InvokeRequired)
|
||||||
|
{
|
||||||
|
Invoke(() => InvalidateRow(rowIndex));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
InvalidateRow(rowIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logService?.Warn($"加载缩略图失败: {imageUrl}, {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 刷新指定行
|
||||||
|
/// </summary>
|
||||||
|
private void InvalidateRow(int rowIndex)
|
||||||
|
{
|
||||||
|
if (rowIndex >= 0 && rowIndex < dgvWorkRecords.Rows.Count)
|
||||||
|
{
|
||||||
|
dgvWorkRecords.InvalidateRow(rowIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 单元格点击事件 - 处理图片点击打开查看器
|
/// 单元格点击事件 - 处理图片点击打开查看器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -345,6 +415,128 @@ namespace WorkCameraExport.Forms
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 当前右键选中的图片信息
|
||||||
|
private string? _contextMenuImageUrl;
|
||||||
|
private int _contextMenuRowIndex = -1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 单元格鼠标点击事件 - 处理右键菜单
|
||||||
|
/// </summary>
|
||||||
|
private void dgvWorkRecords_CellMouseClick(object? sender, DataGridViewCellMouseEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.RowIndex < 0 || e.Button != MouseButtons.Right)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 只处理图片列的右键
|
||||||
|
if (e.ColumnIndex == colImages.Index)
|
||||||
|
{
|
||||||
|
var row = dgvWorkRecords.Rows[e.RowIndex];
|
||||||
|
var record = row.Tag as WorkRecordDto;
|
||||||
|
|
||||||
|
if (record?.Images != null && record.Images.Count > 0)
|
||||||
|
{
|
||||||
|
// 计算点击的是哪张图片
|
||||||
|
var cellBounds = dgvWorkRecords.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, false);
|
||||||
|
var clickX = e.X;
|
||||||
|
var imageIndex = clickX / (ThumbnailWidth + ThumbnailSpacing);
|
||||||
|
|
||||||
|
if (imageIndex >= 0 && imageIndex < record.Images.Count)
|
||||||
|
{
|
||||||
|
_contextMenuImageUrl = record.Images[imageIndex].ImageUrl;
|
||||||
|
_contextMenuRowIndex = e.RowIndex;
|
||||||
|
|
||||||
|
// 显示右键菜单
|
||||||
|
var screenPoint = dgvWorkRecords.PointToScreen(new Point(
|
||||||
|
cellBounds.X + e.X,
|
||||||
|
cellBounds.Y + e.Y));
|
||||||
|
contextMenuImage.Show(screenPoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 下载图片菜单项点击
|
||||||
|
/// </summary>
|
||||||
|
private async void menuItemDownloadImage_Click(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(_contextMenuImageUrl))
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 创建 image 目录
|
||||||
|
var imageDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "image");
|
||||||
|
if (!Directory.Exists(imageDir))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(imageDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成文件名
|
||||||
|
var fileName = Path.GetFileName(_contextMenuImageUrl);
|
||||||
|
if (string.IsNullOrEmpty(fileName) || !fileName.Contains('.'))
|
||||||
|
{
|
||||||
|
fileName = $"image_{DateTime.Now:yyyyMMdd_HHmmss}.jpg";
|
||||||
|
}
|
||||||
|
var savePath = Path.Combine(imageDir, fileName);
|
||||||
|
|
||||||
|
// 确保文件名唯一
|
||||||
|
var counter = 1;
|
||||||
|
var baseName = Path.GetFileNameWithoutExtension(savePath);
|
||||||
|
var ext = Path.GetExtension(savePath);
|
||||||
|
while (File.Exists(savePath))
|
||||||
|
{
|
||||||
|
savePath = Path.Combine(imageDir, $"{baseName}_{counter}{ext}");
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
lblStatusBar.Text = "正在下载图片...";
|
||||||
|
lblStatusBar.ForeColor = Color.Blue;
|
||||||
|
|
||||||
|
var (success, imageData, message) = await _apiService.DownloadImageAsync(_contextMenuImageUrl);
|
||||||
|
|
||||||
|
if (success && imageData != null)
|
||||||
|
{
|
||||||
|
await File.WriteAllBytesAsync(savePath, imageData);
|
||||||
|
lblStatusBar.Text = $"图片已保存: {savePath}";
|
||||||
|
lblStatusBar.ForeColor = Color.Green;
|
||||||
|
_logService?.Info($"图片下载成功: {savePath}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lblStatusBar.Text = $"下载失败: {message}";
|
||||||
|
lblStatusBar.ForeColor = Color.Red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
lblStatusBar.Text = $"下载失败: {ex.Message}";
|
||||||
|
lblStatusBar.ForeColor = Color.Red;
|
||||||
|
_logService?.Error($"下载图片失败: {ex.Message}", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 复制URL菜单项点击
|
||||||
|
/// </summary>
|
||||||
|
private void menuItemCopyUrl_Click(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(_contextMenuImageUrl))
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Clipboard.SetText(_contextMenuImageUrl);
|
||||||
|
lblStatusBar.Text = "URL已复制到剪贴板";
|
||||||
|
lblStatusBar.ForeColor = Color.Green;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
lblStatusBar.Text = $"复制失败: {ex.Message}";
|
||||||
|
lblStatusBar.ForeColor = Color.Red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 单元格内容点击事件 - 处理操作按钮
|
/// 单元格内容点击事件 - 处理操作按钮
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user