Show real 0-100% download progress from transferred bytes and saved rows.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
9ee5561f3d
commit
1f6f442b21
@ -98,7 +98,13 @@ namespace Электронная_Фармация.Classes
|
|||||||
|
|
||||||
public bool IsAuthenticated => !string.IsNullOrEmpty(_token);
|
public bool IsAuthenticated => !string.IsNullOrEmpty(_token);
|
||||||
|
|
||||||
public async Task<PriceSummaryResponse> GetPriceSummaryAsync(string supplierId = null, string regionId = null, string q = null, int? limit = null, int? offset = null)
|
public async Task<PriceSummaryResponse> GetPriceSummaryAsync(
|
||||||
|
string supplierId = null,
|
||||||
|
string regionId = null,
|
||||||
|
string q = null,
|
||||||
|
int? limit = null,
|
||||||
|
int? offset = null,
|
||||||
|
IProgress<HttpTransferProgress> transferProgress = null)
|
||||||
{
|
{
|
||||||
EnsureAuthenticated();
|
EnsureAuthenticated();
|
||||||
|
|
||||||
@ -130,7 +136,10 @@ namespace Электронная_Фармация.Classes
|
|||||||
path += "?" + string.Join("&", queryParams);
|
path += "?" + string.Join("&", queryParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
var responseBody = await SendAuthorizedGetAsync(path, "загрузку прайса");
|
var responseBody = transferProgress == null
|
||||||
|
? await SendAuthorizedGetAsync(path, "загрузку прайса")
|
||||||
|
: await SendAuthorizedGetWithProgressAsync(path, "загрузку прайса", transferProgress);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var summary = JsonSerializer.Deserialize<PriceSummaryResponse>(responseBody, JsonOptions);
|
var summary = JsonSerializer.Deserialize<PriceSummaryResponse>(responseBody, JsonOptions);
|
||||||
@ -174,6 +183,14 @@ namespace Электронная_Фармация.Classes
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async Task<string> SendAuthorizedGetAsync(string path, string operationName)
|
private async Task<string> SendAuthorizedGetAsync(string path, string operationName)
|
||||||
|
{
|
||||||
|
return await SendAuthorizedGetWithProgressAsync(path, operationName, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string> SendAuthorizedGetWithProgressAsync(
|
||||||
|
string path,
|
||||||
|
string operationName,
|
||||||
|
IProgress<HttpTransferProgress> transferProgress)
|
||||||
{
|
{
|
||||||
var fullUrl = BuildFullUrl(path);
|
var fullUrl = BuildFullUrl(path);
|
||||||
var stopwatch = Stopwatch.StartNew();
|
var stopwatch = Stopwatch.StartNew();
|
||||||
@ -185,8 +202,8 @@ namespace Электронная_Фармация.Classes
|
|||||||
using (var httpRequest = new HttpRequestMessage(HttpMethod.Get, fullUrl))
|
using (var httpRequest = new HttpRequestMessage(HttpMethod.Get, fullUrl))
|
||||||
{
|
{
|
||||||
httpRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _token);
|
httpRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _token);
|
||||||
var response = await _httpClient.SendAsync(httpRequest);
|
var response = await _httpClient.SendAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead);
|
||||||
var responseBody = await response.Content.ReadAsStringAsync();
|
var responseBody = await ReadContentWithProgressAsync(response, transferProgress);
|
||||||
stopwatch.Stop();
|
stopwatch.Stop();
|
||||||
|
|
||||||
AppDebugLog.ApiResponse("GET", fullUrl, (int)response.StatusCode, stopwatch.ElapsedMilliseconds, responseBody);
|
AppDebugLog.ApiResponse("GET", fullUrl, (int)response.StatusCode, stopwatch.ElapsedMilliseconds, responseBody);
|
||||||
@ -243,6 +260,29 @@ namespace Электронная_Фармация.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static async Task<string> ReadContentWithProgressAsync(
|
||||||
|
HttpResponseMessage response,
|
||||||
|
IProgress<HttpTransferProgress> transferProgress)
|
||||||
|
{
|
||||||
|
var totalBytes = response.Content.Headers.ContentLength;
|
||||||
|
using (var stream = await response.Content.ReadAsStreamAsync())
|
||||||
|
using (var memory = new System.IO.MemoryStream())
|
||||||
|
{
|
||||||
|
var buffer = new byte[81920];
|
||||||
|
long received = 0;
|
||||||
|
int read;
|
||||||
|
while ((read = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) > 0)
|
||||||
|
{
|
||||||
|
memory.Write(buffer, 0, read);
|
||||||
|
received += read;
|
||||||
|
transferProgress?.Report(new HttpTransferProgress(received, totalBytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
transferProgress?.Report(new HttpTransferProgress(received, totalBytes ?? received));
|
||||||
|
return Encoding.UTF8.GetString(memory.ToArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private string ParseLoginResponse(HttpResponseMessage response, string responseBody)
|
private string ParseLoginResponse(HttpResponseMessage response, string responseBody)
|
||||||
{
|
{
|
||||||
if (response.IsSuccessStatusCode)
|
if (response.IsSuccessStatusCode)
|
||||||
@ -333,4 +373,29 @@ namespace Электронная_Фармация.Classes
|
|||||||
public string InvoiceSum { get; set; }
|
public string InvoiceSum { get; set; }
|
||||||
public string RefuseSum { get; set; }
|
public string RefuseSum { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sealed class HttpTransferProgress
|
||||||
|
{
|
||||||
|
public HttpTransferProgress(long bytesReceived, long? totalBytes)
|
||||||
|
{
|
||||||
|
BytesReceived = bytesReceived;
|
||||||
|
TotalBytes = totalBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long BytesReceived { get; }
|
||||||
|
public long? TotalBytes { get; }
|
||||||
|
|
||||||
|
public int Percent
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!TotalBytes.HasValue || TotalBytes.Value <= 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int)Math.Max(0, Math.Min(100, (100.0 * BytesReceived) / TotalBytes.Value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,10 +52,10 @@
|
|||||||
// progressDownload
|
// progressDownload
|
||||||
//
|
//
|
||||||
this.progressDownload.Location = new System.Drawing.Point(25, 52);
|
this.progressDownload.Location = new System.Drawing.Point(25, 52);
|
||||||
this.progressDownload.MarqueeAnimationSpeed = 30;
|
|
||||||
this.progressDownload.Name = "progressDownload";
|
this.progressDownload.Name = "progressDownload";
|
||||||
this.progressDownload.Size = new System.Drawing.Size(630, 22);
|
this.progressDownload.Size = new System.Drawing.Size(630, 22);
|
||||||
this.progressDownload.Style = System.Windows.Forms.ProgressBarStyle.Marquee;
|
this.progressDownload.Style = System.Windows.Forms.ProgressBarStyle.Continuous;
|
||||||
|
this.progressDownload.Maximum = 100;
|
||||||
this.progressDownload.TabIndex = 6;
|
this.progressDownload.TabIndex = 6;
|
||||||
//
|
//
|
||||||
// lblProgress
|
// lblProgress
|
||||||
|
|||||||
@ -12,6 +12,11 @@ namespace Электронная_Фармация.HelpForms
|
|||||||
{
|
{
|
||||||
public partial class HF_DownloadDataFromServer : Form
|
public partial class HF_DownloadDataFromServer : Form
|
||||||
{
|
{
|
||||||
|
// Доли общего прогресса 0..100.
|
||||||
|
private const int DownloadPhaseEnd = 45;
|
||||||
|
private const int BuildPhaseEnd = 55;
|
||||||
|
private const int SavePhaseEnd = 100;
|
||||||
|
|
||||||
public HF_DownloadDataFromServer()
|
public HF_DownloadDataFromServer()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@ -30,7 +35,7 @@ namespace Электронная_Фармация.HelpForms
|
|||||||
rtxtDebug.Visible = true;
|
rtxtDebug.Visible = true;
|
||||||
rtxtDebug.ReadOnly = true;
|
rtxtDebug.ReadOnly = true;
|
||||||
_isDownloading = true;
|
_isDownloading = true;
|
||||||
SetMarqueeProgress("Подключение к серверу...");
|
SetOverallProgress(0, "Подключение к серверу...");
|
||||||
|
|
||||||
var client = new ApiClient();
|
var client = new ApiClient();
|
||||||
AppendStatus($"Сервер: {client.BaseUrl}");
|
AppendStatus($"Сервер: {client.BaseUrl}");
|
||||||
@ -39,43 +44,58 @@ namespace Электронная_Фармация.HelpForms
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
SetMarqueeProgress("Авторизация...");
|
SetOverallProgress(1, "Авторизация...");
|
||||||
await EnsureAuthenticatedAsync(client);
|
await EnsureAuthenticatedAsync(client);
|
||||||
|
|
||||||
SetMarqueeProgress("Загрузка прайса с сервера...");
|
SetOverallProgress(3, "Загрузка прайса с сервера...");
|
||||||
AppendStatus("Загружаю сводный прайс (постранично, весь)...");
|
AppendStatus("Загружаю сводный прайс...");
|
||||||
var allSuppliersSummary = await GetFullPriceSummaryPagedAsync(client);
|
var allSuppliersSummary = await GetFullPriceSummaryPagedAsync(client);
|
||||||
AppendStatus($"Получено {allSuppliersSummary.Summary?.Count ?? 0} позиций");
|
int totalItems = allSuppliersSummary.Summary?.Count ?? 0;
|
||||||
|
AppendStatus($"Получено {totalItems} позиций");
|
||||||
|
SetOverallProgress(DownloadPhaseEnd, $"Получено {totalItems} / {totalItems} позиций (100%)");
|
||||||
|
|
||||||
SetMarqueeProgress("Подготовка таблицы...");
|
SetOverallProgress(DownloadPhaseEnd, "Подготовка таблицы...");
|
||||||
var tablePrice = await Task.Run(() => BuildPriceTable(allSuppliersSummary));
|
var buildProgress = new Progress<CountProgress>(p =>
|
||||||
|
{
|
||||||
|
int phasePercent = MapPhasePercent(p.Current, p.Total, DownloadPhaseEnd, BuildPhaseEnd);
|
||||||
|
SetOverallProgress(
|
||||||
|
phasePercent,
|
||||||
|
$"Обработка: {p.Current} / {p.Total} ({PercentOf(p.Current, p.Total)}%)");
|
||||||
|
});
|
||||||
|
var tablePrice = await Task.Run(() => BuildPriceTable(allSuppliersSummary, buildProgress));
|
||||||
|
|
||||||
SetDeterminateProgress(0, Math.Max(tablePrice.Rows.Count, 1), "Сохранение в локальную базу...");
|
SetOverallProgress(BuildPhaseEnd, "Сохранение в локальную базу...");
|
||||||
var progress = new Progress<SaveProgress>(ReportSaveProgress);
|
var saveProgress = new Progress<CountProgress>(p =>
|
||||||
await Task.Run(() => SavePriceTable(tablePrice, progress));
|
{
|
||||||
|
int phasePercent = MapPhasePercent(p.Current, p.Total, BuildPhaseEnd, SavePhaseEnd);
|
||||||
|
SetOverallProgress(
|
||||||
|
phasePercent,
|
||||||
|
$"Сохранение: {p.Current} / {p.Total} ({PercentOf(p.Current, p.Total)}%)");
|
||||||
|
});
|
||||||
|
await Task.Run(() => SavePriceTable(tablePrice, saveProgress));
|
||||||
|
|
||||||
SetDeterminateProgress(100, 100, "Готово");
|
SetOverallProgress(100, $"Готово: {tablePrice.Rows.Count} / {tablePrice.Rows.Count} (100%)");
|
||||||
DialogResult = DialogResult.OK;
|
DialogResult = DialogResult.OK;
|
||||||
AppendStatus($"Готово. Сохранено {tablePrice.Rows.Count} позиций в локальную базу.");
|
AppendStatus($"Готово. Сохранено {tablePrice.Rows.Count} позиций в локальную базу.");
|
||||||
ToastNotification.ShowSuccess($"Прайс обновлён: {tablePrice.Rows.Count} позиций");
|
ToastNotification.ShowSuccess($"Прайс обновлён: {tablePrice.Rows.Count} позиций");
|
||||||
}
|
}
|
||||||
catch (UnauthorizedAccessException ex)
|
catch (UnauthorizedAccessException ex)
|
||||||
{
|
{
|
||||||
SetMarqueeProgress("Ошибка авторизации");
|
SetOverallProgress(0, "Ошибка авторизации");
|
||||||
AppendStatus($"Ошибка авторизации: {ex.Message}");
|
AppendStatus($"Ошибка авторизации: {ex.Message}");
|
||||||
AppDebugLog.Error("Download", "Ошибка авторизации при загрузке прайса", ex);
|
AppDebugLog.Error("Download", "Ошибка авторизации при загрузке прайса", ex);
|
||||||
ToastNotification.ShowError($"Ошибка авторизации: {ex.Message}");
|
ToastNotification.ShowError($"Ошибка авторизации: {ex.Message}");
|
||||||
}
|
}
|
||||||
catch (HttpRequestException ex)
|
catch (HttpRequestException ex)
|
||||||
{
|
{
|
||||||
SetMarqueeProgress("Ошибка сети");
|
SetOverallProgress(0, "Ошибка сети");
|
||||||
AppendStatus($"Ошибка сети: {ex.Message}");
|
AppendStatus($"Ошибка сети: {ex.Message}");
|
||||||
AppDebugLog.Error("Download", "Ошибка сети при загрузке прайса", ex);
|
AppDebugLog.Error("Download", "Ошибка сети при загрузке прайса", ex);
|
||||||
ToastNotification.ShowError($"Ошибка сети: {ex.Message}");
|
ToastNotification.ShowError($"Ошибка сети: {ex.Message}");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
SetMarqueeProgress("Ошибка загрузки");
|
SetOverallProgress(0, "Ошибка загрузки");
|
||||||
AppendStatus($"Ошибка загрузки прайса: {ex.Message}");
|
AppendStatus($"Ошибка загрузки прайса: {ex.Message}");
|
||||||
AppDebugLog.Error("Download", "Неожиданная ошибка при загрузке прайса", ex);
|
AppDebugLog.Error("Download", "Неожиданная ошибка при загрузке прайса", ex);
|
||||||
ToastNotification.ShowError($"Ошибка загрузки прайса: {ex.Message}");
|
ToastNotification.ShowError($"Ошибка загрузки прайса: {ex.Message}");
|
||||||
@ -114,45 +134,51 @@ namespace Электронная_Фармация.HelpForms
|
|||||||
AppendStatus("Авторизация успешно пройдена");
|
AppendStatus("Авторизация успешно пройдена");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Тянем весь прайс постранично: сервер отдаёт максимум 5000 за запрос,
|
|
||||||
// поэтому идём offset'ом, пока страница не окажется неполной.
|
|
||||||
private async Task<PriceSummaryResponse> GetFullPriceSummaryPagedAsync(ApiClient client)
|
private async Task<PriceSummaryResponse> GetFullPriceSummaryPagedAsync(ApiClient client)
|
||||||
{
|
{
|
||||||
var regionId = string.IsNullOrWhiteSpace(Settings.Default.RegionId)
|
var regionId = string.IsNullOrWhiteSpace(Settings.Default.RegionId)
|
||||||
? null
|
? null
|
||||||
: Settings.Default.RegionId;
|
: Settings.Default.RegionId;
|
||||||
|
|
||||||
// Тянем весь прайс одним запросом: постраничный OFFSET на тяжёлом
|
// Один крупный запрос (OFFSET на больших страницах валит сервер).
|
||||||
// сводном запросе валит сервер на глубоких страницах. Один запрос =
|
|
||||||
// один расчёт выборки. Страховка-цикл остаётся на случай, если позиций
|
|
||||||
// окажется больше pageSize.
|
|
||||||
const int pageSize = 200000;
|
const int pageSize = 200000;
|
||||||
const int maxPages = 100;
|
const int maxPages = 100;
|
||||||
|
|
||||||
var combined = new PriceSummaryResponse { Summary = new List<PriceSummaryItem>() };
|
var combined = new PriceSummaryResponse { Summary = new List<PriceSummaryItem>() };
|
||||||
|
var transferProgress = new Progress<HttpTransferProgress>(ReportTransferProgress);
|
||||||
|
|
||||||
for (int page = 0; page < maxPages; page++)
|
for (int page = 0; page < maxPages; page++)
|
||||||
{
|
{
|
||||||
int offset = page * pageSize;
|
int offset = page * pageSize;
|
||||||
SetMarqueeProgress(page == 0
|
SetOverallProgress(
|
||||||
? "Ожидание ответа сервера..."
|
Math.Min(DownloadPhaseEnd - 1, 3 + page),
|
||||||
: $"Загрузка страницы {page + 1}...");
|
page == 0 ? "Скачивание прайса с сервера..." : $"Скачивание страницы {page + 1}...");
|
||||||
|
|
||||||
PriceSummaryResponse chunk;
|
PriceSummaryResponse chunk;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
chunk = await client.GetPriceSummaryAsync(supplierId: null, regionId: regionId, limit: pageSize, offset: offset);
|
chunk = await client.GetPriceSummaryAsync(
|
||||||
|
supplierId: null,
|
||||||
|
regionId: regionId,
|
||||||
|
limit: pageSize,
|
||||||
|
offset: offset,
|
||||||
|
transferProgress: transferProgress);
|
||||||
}
|
}
|
||||||
catch (UnauthorizedAccessException)
|
catch (UnauthorizedAccessException)
|
||||||
{
|
{
|
||||||
AppendStatus("Токен недействителен, повторная авторизация...");
|
AppendStatus("Токен недействителен, повторная авторизация...");
|
||||||
SetMarqueeProgress("Повторная авторизация...");
|
SetOverallProgress(2, "Повторная авторизация...");
|
||||||
Settings.Default.stringToken = string.Empty;
|
Settings.Default.stringToken = string.Empty;
|
||||||
Settings.Default.Save();
|
Settings.Default.Save();
|
||||||
client.SetToken(null);
|
client.SetToken(null);
|
||||||
await LoginAndSaveTokenAsync(client);
|
await LoginAndSaveTokenAsync(client);
|
||||||
SetMarqueeProgress("Повторная загрузка прайса...");
|
SetOverallProgress(3, "Повторная загрузка прайса...");
|
||||||
chunk = await client.GetPriceSummaryAsync(supplierId: null, regionId: regionId, limit: pageSize, offset: offset);
|
chunk = await client.GetPriceSummaryAsync(
|
||||||
|
supplierId: null,
|
||||||
|
regionId: regionId,
|
||||||
|
limit: pageSize,
|
||||||
|
offset: offset,
|
||||||
|
transferProgress: transferProgress);
|
||||||
}
|
}
|
||||||
|
|
||||||
int got = chunk?.Summary?.Count ?? 0;
|
int got = chunk?.Summary?.Count ?? 0;
|
||||||
@ -160,19 +186,37 @@ namespace Электронная_Фармация.HelpForms
|
|||||||
{
|
{
|
||||||
combined.Summary.AddRange(chunk.Summary);
|
combined.Summary.AddRange(chunk.Summary);
|
||||||
AppendStatus($"Загружено {combined.Summary.Count} позиций...");
|
AppendStatus($"Загружено {combined.Summary.Count} позиций...");
|
||||||
SetMarqueeProgress($"Получено {combined.Summary.Count} позиций...");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (got < pageSize)
|
if (got < pageSize)
|
||||||
{
|
{
|
||||||
break; // последняя (неполная) страница — дальше данных нет
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return combined;
|
return combined;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DataTable BuildPriceTable(PriceSummaryResponse allSuppliersSummary)
|
private void ReportTransferProgress(HttpTransferProgress transfer)
|
||||||
|
{
|
||||||
|
if (transfer.TotalBytes.HasValue && transfer.TotalBytes.Value > 0)
|
||||||
|
{
|
||||||
|
int phasePercent = MapPhasePercent(transfer.BytesReceived, transfer.TotalBytes.Value, 3, DownloadPhaseEnd);
|
||||||
|
SetOverallProgress(
|
||||||
|
phasePercent,
|
||||||
|
$"Скачивание: {FormatBytes(transfer.BytesReceived)} / {FormatBytes(transfer.TotalBytes.Value)} ({transfer.Percent}%)");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetOverallProgress(
|
||||||
|
Math.Min(DownloadPhaseEnd - 1, 5),
|
||||||
|
$"Скачивание: получено {FormatBytes(transfer.BytesReceived)}...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DataTable BuildPriceTable(
|
||||||
|
PriceSummaryResponse allSuppliersSummary,
|
||||||
|
IProgress<CountProgress> progress = null)
|
||||||
{
|
{
|
||||||
var tablePrice = new DataTable();
|
var tablePrice = new DataTable();
|
||||||
tablePrice.Columns.Add("supplier_price_id");
|
tablePrice.Columns.Add("supplier_price_id");
|
||||||
@ -215,6 +259,8 @@ namespace Электронная_Фармация.HelpForms
|
|||||||
return tablePrice;
|
return tablePrice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int total = allSuppliersSummary.Summary.Count;
|
||||||
|
int current = 0;
|
||||||
foreach (var item in allSuppliersSummary.Summary)
|
foreach (var item in allSuppliersSummary.Summary)
|
||||||
{
|
{
|
||||||
var row = tablePrice.NewRow();
|
var row = tablePrice.NewRow();
|
||||||
@ -233,12 +279,18 @@ namespace Электронная_Фармация.HelpForms
|
|||||||
row["TradeName"] = string.IsNullOrWhiteSpace(item.TradeName) ? (object)DBNull.Value : item.TradeName.Trim();
|
row["TradeName"] = string.IsNullOrWhiteSpace(item.TradeName) ? (object)DBNull.Value : item.TradeName.Trim();
|
||||||
row["Dosage"] = string.IsNullOrWhiteSpace(item.Dosage) ? (object)DBNull.Value : item.Dosage.Trim();
|
row["Dosage"] = string.IsNullOrWhiteSpace(item.Dosage) ? (object)DBNull.Value : item.Dosage.Trim();
|
||||||
tablePrice.Rows.Add(row);
|
tablePrice.Rows.Add(row);
|
||||||
|
|
||||||
|
current++;
|
||||||
|
if (progress != null && (current % 500 == 0 || current == total))
|
||||||
|
{
|
||||||
|
progress.Report(new CountProgress(current, total));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return tablePrice;
|
return tablePrice;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SavePriceTable(DataTable tablePrice, IProgress<SaveProgress> progress = null)
|
private void SavePriceTable(DataTable tablePrice, IProgress<CountProgress> progress = null)
|
||||||
{
|
{
|
||||||
const string commandToDelete = "delete from [PriceList]";
|
const string commandToDelete = "delete from [PriceList]";
|
||||||
const string commandToDeleteTempOrder = "delete from [TempOrderItems]";
|
const string commandToDeleteTempOrder = "delete from [TempOrderItems]";
|
||||||
@ -315,7 +367,7 @@ VALUES
|
|||||||
saved++;
|
saved++;
|
||||||
if (progress != null && (saved % 250 == 0 || saved == total))
|
if (progress != null && (saved % 250 == 0 || saved == total))
|
||||||
{
|
{
|
||||||
progress.Report(new SaveProgress(saved, total));
|
progress.Report(new CountProgress(saved, total));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,21 +376,43 @@ VALUES
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReportSaveProgress(SaveProgress state)
|
private static int MapPhasePercent(long current, long total, int phaseStart, int phaseEnd)
|
||||||
{
|
{
|
||||||
if (IsDisposed)
|
if (total <= 0)
|
||||||
{
|
{
|
||||||
return;
|
return phaseStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
int percent = state.Total <= 0 ? 0 : (int)(100.0 * state.Current / state.Total);
|
double ratio = Math.Max(0.0, Math.Min(1.0, (double)current / total));
|
||||||
SetDeterminateProgress(
|
return phaseStart + (int)((phaseEnd - phaseStart) * ratio);
|
||||||
percent,
|
|
||||||
100,
|
|
||||||
$"Сохранение в базу: {state.Current} / {state.Total} ({percent}%)");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetMarqueeProgress(string text)
|
private static int PercentOf(long current, long total)
|
||||||
|
{
|
||||||
|
if (total <= 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int)Math.Max(0, Math.Min(100, (100.0 * current) / total));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string FormatBytes(long bytes)
|
||||||
|
{
|
||||||
|
if (bytes < 1024)
|
||||||
|
{
|
||||||
|
return $"{bytes} Б";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes < 1024 * 1024)
|
||||||
|
{
|
||||||
|
return $"{bytes / 1024.0:0.0} КБ";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"{bytes / (1024.0 * 1024.0):0.00} МБ";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetOverallProgress(int percent, string text)
|
||||||
{
|
{
|
||||||
if (IsDisposed)
|
if (IsDisposed)
|
||||||
{
|
{
|
||||||
@ -347,27 +421,7 @@ VALUES
|
|||||||
|
|
||||||
if (InvokeRequired)
|
if (InvokeRequired)
|
||||||
{
|
{
|
||||||
BeginInvoke(new Action<string>(SetMarqueeProgress), text);
|
BeginInvoke(new Action<int, string>(SetOverallProgress), percent, text);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
progressDownload.Style = ProgressBarStyle.Marquee;
|
|
||||||
progressDownload.MarqueeAnimationSpeed = 30;
|
|
||||||
lblProgress.Text = text ?? string.Empty;
|
|
||||||
lblProgress.Refresh();
|
|
||||||
progressDownload.Refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetDeterminateProgress(int value, int maximum, string text)
|
|
||||||
{
|
|
||||||
if (IsDisposed)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (InvokeRequired)
|
|
||||||
{
|
|
||||||
BeginInvoke(new Action<int, int, string>(SetDeterminateProgress), value, maximum, text);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,9 +430,10 @@ VALUES
|
|||||||
progressDownload.Style = ProgressBarStyle.Continuous;
|
progressDownload.Style = ProgressBarStyle.Continuous;
|
||||||
}
|
}
|
||||||
|
|
||||||
progressDownload.Maximum = Math.Max(maximum, 1);
|
progressDownload.Minimum = 0;
|
||||||
progressDownload.Value = Math.Max(0, Math.Min(value, progressDownload.Maximum));
|
progressDownload.Maximum = 100;
|
||||||
lblProgress.Text = text ?? string.Empty;
|
progressDownload.Value = Math.Max(0, Math.Min(100, percent));
|
||||||
|
lblProgress.Text = $"{Math.Max(0, Math.Min(100, percent))}% — {text}";
|
||||||
lblProgress.Refresh();
|
lblProgress.Refresh();
|
||||||
progressDownload.Refresh();
|
progressDownload.Refresh();
|
||||||
}
|
}
|
||||||
@ -411,9 +466,9 @@ VALUES
|
|||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class SaveProgress
|
private sealed class CountProgress
|
||||||
{
|
{
|
||||||
public SaveProgress(int current, int total)
|
public CountProgress(int current, int total)
|
||||||
{
|
{
|
||||||
Current = current;
|
Current = current;
|
||||||
Total = total;
|
Total = total;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user