2025-04-18 11:01:56 +08:00
|
|
|
|
@page "/stock/check"
|
|
|
|
|
@using MasaBlazorApp3.Pojo.Config
|
|
|
|
|
@using MasaBlazorApp3.Util
|
|
|
|
|
@using Microsoft.Extensions.Options
|
|
|
|
|
@using Newtonsoft.Json
|
|
|
|
|
@using log4net
|
|
|
|
|
|
|
|
|
|
<style>
|
|
|
|
|
.rz-custom-header {
|
|
|
|
|
width: 100%;
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
<RadzenStack Orientation="Orientation.Horizontal">
|
|
|
|
|
<div class="row justify-content-center">
|
|
|
|
|
<div class="col-12 row justify-content-center align-items-center text-center" style="background: url('/images/box.png') no-repeat; background-size: 100% 100%; width: 380px; height:650px">
|
|
|
|
|
@* <RadzenStack AlignItems="AlignItems.Center" JustifyContent="JustifyContent.Center" Orientation="Orientation.Vertical" Style="margin-top: 220px"> *@
|
|
|
|
|
<div class="row justify-content-around align-items-center" style="margin-top: 220px; height: 430px;">
|
|
|
|
|
@foreach (int i in DrawerNos)
|
|
|
|
|
{
|
|
|
|
|
<RadzenButton class="col-5" Click="@(() => SelectDrawer(i))" Text="@i.ToString()" Disabled="@(status > 0)" Shade="Shade.Light" Variant="@(drawerNo !=i ? Variant.Outlined : Variant.Flat)" />
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
</div>
|
|
|
|
|
@* </RadzenStack> *@
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<RadzenDataGrid @ref="grid"
|
|
|
|
|
LoadData="@LoadData"
|
|
|
|
|
IsLoading="@isLoading"
|
|
|
|
|
Count="@count"
|
2025-08-11 14:58:39 +08:00
|
|
|
|
EmptyText="@myText.NoDate"
|
2025-04-18 11:01:56 +08:00
|
|
|
|
Data="@channels"
|
|
|
|
|
AllowColumnResize="true" AllowAlternatingRows="false"
|
|
|
|
|
CellClick="@((DataGridCellMouseEventArgs<ChannelStock> args) => OnCellClick(args))"
|
|
|
|
|
AllowPaging="true" PageSize="10" PagerHorizontalAlign="HorizontalAlign.Left" ShowPagingSummary="true" PagingSummaryFormat="{0}/{1} 共{2}条数据">
|
|
|
|
|
<HeaderTemplate>
|
|
|
|
|
<RadzenRow JustifyContent="JustifyContent.End">
|
|
|
|
|
@if (status < 3)
|
|
|
|
|
{
|
2025-08-11 14:58:39 +08:00
|
|
|
|
<RadzenButton IsBusy="@(status > 0)" BusyText="@myText.Checking" ButtonStyle="ButtonStyle.Warning" Variant="Variant.Flat" Shade="Shade.Light" Text="@myText.Check" Click="@OpenDrawer" />
|
2025-04-18 11:01:56 +08:00
|
|
|
|
}
|
|
|
|
|
@if (status == 3)
|
|
|
|
|
{
|
2025-08-11 14:58:39 +08:00
|
|
|
|
<RadzenButton ButtonStyle="ButtonStyle.Warning" Variant="Variant.Flat" Shade="Shade.Light" Text="@myText.Complete" Click="@CheckFinish" />
|
2025-04-18 11:01:56 +08:00
|
|
|
|
}
|
|
|
|
|
@if (status > 0 && status <= 3)
|
|
|
|
|
{
|
2025-08-11 14:58:39 +08:00
|
|
|
|
<RadzenButton Variant="Variant.Flat" Shade="Shade.Light" Text="@myText.Cancel" Click="@Cancel" Style="width: 120px" />
|
2025-04-18 11:01:56 +08:00
|
|
|
|
}
|
|
|
|
|
</RadzenRow>
|
|
|
|
|
</HeaderTemplate>
|
|
|
|
|
<Columns>
|
2025-08-11 14:58:39 +08:00
|
|
|
|
<RadzenDataGridColumn Width="70px" Title="@myText.StorageLocation" Property="ColNo"></RadzenDataGridColumn>
|
|
|
|
|
<RadzenDataGridColumn Title="@myText.DrugName" Property="Drug.DrugName">
|
2025-04-18 11:01:56 +08:00
|
|
|
|
<Template Context="channel">
|
|
|
|
|
<RadzenText TextStyle="TextStyle.Subtitle2" class="mb-0">@channel.Drug?.DrugName</RadzenText>
|
|
|
|
|
<RadzenText TextStyle="TextStyle.Caption">@channel.Drug?.DrugSpec</RadzenText>
|
|
|
|
|
</Template>
|
|
|
|
|
</RadzenDataGridColumn>
|
2025-08-11 14:58:39 +08:00
|
|
|
|
<RadzenDataGridColumn Title="@myText.Batch" Property="ManuNo">
|
2025-04-18 11:01:56 +08:00
|
|
|
|
<Template Context="channel">
|
|
|
|
|
<RadzenText TextStyle="TextStyle.Subtitle2" class="mb-0">@channel.drugManuNo?.ManuNo</RadzenText>
|
|
|
|
|
<RadzenText TextStyle="TextStyle.Caption">@channel.drugManuNo?.EffDate</RadzenText>
|
|
|
|
|
</Template>
|
|
|
|
|
<EditTemplate Context="channel">
|
|
|
|
|
|
|
|
|
|
@if (channel.Quantity == 0 && !String.IsNullOrEmpty(channel.DrugId))
|
|
|
|
|
{
|
|
|
|
|
<RadzenDropDown TValue="DrugManuNo" Name="ManuNo" @bind-Value="channel.drugManuNo" Data="@channel.Drug?.Manus" Style="width:100%; display: block;">
|
|
|
|
|
<Template>
|
|
|
|
|
<RadzenText TextStyle="TextStyle.Subtitle2" class="mb-0">@((context as DrugManuNo)?.ManuNo)</RadzenText>
|
|
|
|
|
<RadzenText TextStyle="TextStyle.Caption">@((context as DrugManuNo)?.EffDate)</RadzenText>
|
|
|
|
|
</Template>
|
|
|
|
|
<ValueTemplate>
|
|
|
|
|
<RadzenStack Orientation="Orientation.Horizontal">
|
|
|
|
|
<RadzenText TextStyle="TextStyle.Subtitle2" class="mb-0">@((context as DrugManuNo)?.ManuNo)</RadzenText>
|
|
|
|
|
<RadzenText TextStyle="TextStyle.Caption">@((context as DrugManuNo)?.EffDate)</RadzenText>
|
|
|
|
|
</RadzenStack>
|
|
|
|
|
</ValueTemplate>
|
|
|
|
|
</RadzenDropDown>
|
2025-08-11 14:58:39 +08:00
|
|
|
|
<RadzenRequiredValidator Text="@myText.SelectBatch" Component="ManuNo" Popup="true" />
|
2025-04-18 11:01:56 +08:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
<RadzenText TextStyle="TextStyle.Subtitle2" class="mb-0">@channel.drugManuNo?.ManuNo</RadzenText>
|
|
|
|
|
<RadzenText TextStyle="TextStyle.Caption">@channel.drugManuNo?.EffDate</RadzenText>
|
|
|
|
|
}
|
|
|
|
|
</EditTemplate>
|
|
|
|
|
</RadzenDataGridColumn>
|
2025-08-11 14:58:39 +08:00
|
|
|
|
<RadzenDataGridColumn Title="@myText.Inventory" Property="Quantity">
|
2025-04-18 11:01:56 +08:00
|
|
|
|
<Template Context="cs">
|
|
|
|
|
<RadzenButton ButtonStyle="ButtonStyle.Info" Variant="Variant.Flat" Shade="Shade.Lighter" class="m-1" Text="@cs.Quantity.ToString()" />
|
|
|
|
|
</Template>
|
|
|
|
|
</RadzenDataGridColumn>
|
2025-08-11 14:58:39 +08:00
|
|
|
|
<RadzenDataGridColumn MinWidth="120px" Title="@myText.CheckQuantity" Property="CheckQuantity">
|
2025-04-18 11:01:56 +08:00
|
|
|
|
<EditTemplate Context="cs">
|
2025-06-24 08:55:34 +08:00
|
|
|
|
@if (cs.BoardType.ToString().Contains("2") || cs.BoardType.ToString().Contains("3"))
|
2025-04-18 11:01:56 +08:00
|
|
|
|
{
|
|
|
|
|
@cs.CheckQuantity
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2025-06-24 08:55:34 +08:00
|
|
|
|
<RadzenNumeric Style="display: block" Name="CheckQuantity" @bind-Value=@cs.CheckQuantity>
|
2025-08-11 14:58:39 +08:00
|
|
|
|
<RadzenNumericRangeValidator Style="position: absolute;z-index: 9999;" Min="1" Max="100" Text="@myText.InputTips" Component="CheckQuantity" />
|
2025-06-24 08:55:34 +08:00
|
|
|
|
</RadzenNumeric>
|
2025-04-18 11:01:56 +08:00
|
|
|
|
}
|
|
|
|
|
</EditTemplate>
|
|
|
|
|
</RadzenDataGridColumn>
|
|
|
|
|
</Columns>
|
|
|
|
|
</RadzenDataGrid>
|
|
|
|
|
|
|
|
|
|
</RadzenStack>
|
|
|
|
|
@code {
|
|
|
|
|
@inject IChannelListDao channelListDao;
|
|
|
|
|
@inject NavigationManager na;
|
|
|
|
|
@inject PortUtil PortUtil;
|
|
|
|
|
@inject NotificationService _message
|
|
|
|
|
@inject IOptions<DrawerConfig> setting;
|
2025-08-11 14:58:39 +08:00
|
|
|
|
@inject Toolbelt.Blazor.I18nText.I18nText I18nText;
|
|
|
|
|
private I18nText.local myText = new I18nText.local();
|
2025-04-18 11:01:56 +08:00
|
|
|
|
int status = 0;
|
|
|
|
|
int drawerNo = 1;
|
|
|
|
|
RadzenDataGrid<ChannelStock> grid;
|
|
|
|
|
private List<ChannelStock>? channels;
|
|
|
|
|
bool isLoading;
|
|
|
|
|
int count;
|
|
|
|
|
int[] DrawerNos = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
|
|
|
|
|
int[] BeforeQuantity = new int[9];
|
|
|
|
|
int[] AfterQuantity = new int[9];
|
|
|
|
|
private readonly ILog logger = LogManager.GetLogger(typeof(DrawerAdd));
|
2025-08-11 14:58:39 +08:00
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
|
|
|
{
|
|
|
|
|
myText = await I18nText.GetTextTableAsync<I18nText.local>(this);
|
|
|
|
|
await base.OnInitializedAsync();
|
|
|
|
|
}
|
2025-04-18 11:01:56 +08:00
|
|
|
|
|
|
|
|
|
async Task LoadData(LoadDataArgs args)
|
|
|
|
|
{
|
|
|
|
|
isLoading = true;
|
|
|
|
|
|
|
|
|
|
var result = await channelListDao.GetChannelStockByDrawerNoWithDrawers(drawerNo);
|
|
|
|
|
// var result = await channelListDao.GetChannelStockByDrawerNo(drawerNo);
|
|
|
|
|
// Update the Data property
|
|
|
|
|
DrawerNos = result.DrawerArray;
|
|
|
|
|
// for (int i = 0; i < result.ChannelStocks.Count; i++)
|
|
|
|
|
// {
|
|
|
|
|
// result.ChannelStocks[i].CheckQuantity = result.ChannelStocks[i].Quantity;
|
|
|
|
|
// }
|
|
|
|
|
result.ChannelStocks.ForEach(cs => cs.CheckQuantity = cs.Quantity);
|
|
|
|
|
channels = result.ChannelStocks;
|
|
|
|
|
// Update the count
|
|
|
|
|
count = result.ChannelStocks.Count;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
isLoading = false;
|
|
|
|
|
}
|
|
|
|
|
async Task OpenDrawer()
|
|
|
|
|
{
|
|
|
|
|
this.status = 1;
|
|
|
|
|
// 根据抽屉类型来决定打开前是否需要查询数量
|
|
|
|
|
var promiseUtil = new PromiseUtil<object>();
|
|
|
|
|
await promiseUtil.taskAsyncLoop(500, null, async (data, next, stop) =>
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (this.status == 0)
|
|
|
|
|
{
|
|
|
|
|
stop();
|
|
|
|
|
}
|
|
|
|
|
// 开启抽屉
|
|
|
|
|
else if (this.status == 1)
|
|
|
|
|
{
|
|
|
|
|
// 判断是否为单支抽屉
|
|
|
|
|
if (setting.Value.single.Contains(this.drawerNo))
|
|
|
|
|
{
|
|
|
|
|
byte[] quantity = await PortUtil.CheckQuantityByDrawer(this.drawerNo);
|
|
|
|
|
BeforeQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray();
|
|
|
|
|
logger.Info($"单支抽屉,开抽屉前检测数量【{string.Join(",", BeforeQuantity)}】");
|
|
|
|
|
}
|
|
|
|
|
var b = await PortUtil.OpenDrawerStatus(this.drawerNo);
|
|
|
|
|
if (b)
|
|
|
|
|
{
|
2025-05-28 14:48:38 +08:00
|
|
|
|
PortUtil.speechSynthesizer.SpeakAsyncCancelAll();
|
2025-04-18 11:01:56 +08:00
|
|
|
|
PortUtil.SpeakAsync($"{drawerNo}号抽屉已经打开,请,盘点");
|
|
|
|
|
this.status = 2;
|
|
|
|
|
next();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_message.Notify(
|
|
|
|
|
new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"抽屉【{drawerNo}】打开失败,请检测硬件", Duration = 4000 }
|
|
|
|
|
);
|
|
|
|
|
logger.Info($"抽屉打开失败");
|
|
|
|
|
RestData();
|
|
|
|
|
stop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
// 检测状态
|
|
|
|
|
else if (this.status == 2)
|
|
|
|
|
{
|
|
|
|
|
// 查询抽屉是否为关闭状态
|
|
|
|
|
var b = await PortUtil.CheckDrawerStatus2(drawerNo);
|
|
|
|
|
// 关闭则改变状态并终止循环
|
|
|
|
|
if (b)
|
|
|
|
|
{
|
2025-05-28 14:48:38 +08:00
|
|
|
|
PortUtil.speechSynthesizer.SpeakAsyncCancelAll();
|
2025-04-18 11:01:56 +08:00
|
|
|
|
PortUtil.SpeakAsync($"盘点完成,请,核对,或,录入,正确的,盘点数量");
|
|
|
|
|
this.status = 3;
|
|
|
|
|
stop();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (setting.Value.single.Contains(this.drawerNo))
|
|
|
|
|
{
|
|
|
|
|
byte[] quantity = await PortUtil.CheckQuantityByDrawer(this.drawerNo);
|
|
|
|
|
AfterQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray();
|
|
|
|
|
logger.Info($"单支抽屉,抽屉未关检测数量【{string.Join(",", AfterQuantity)}】");
|
|
|
|
|
|
|
|
|
|
channels.ForEach(cl =>
|
|
|
|
|
{
|
|
|
|
|
cl.CheckQuantity = this.AfterQuantity[cl.ColNo - 1];// - this.BeforeQuantity[cl.ColNo - 1];
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
next(); // continue iteration
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
logger.Info($"抽屉盘点发生错误,{e.Message}");
|
|
|
|
|
_message.Notify(
|
|
|
|
|
new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"发生错误,{e.Message}", Duration = 4000 }
|
|
|
|
|
);
|
|
|
|
|
if (setting.Value.single.Contains(this.drawerNo))
|
|
|
|
|
{
|
|
|
|
|
PortUtil.AllLightOff();
|
|
|
|
|
}
|
|
|
|
|
RestData();
|
|
|
|
|
stop();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RestData()
|
|
|
|
|
{
|
2025-05-28 14:48:38 +08:00
|
|
|
|
PortUtil.speechSynthesizer.SpeakAsyncCancelAll();
|
2025-04-18 11:01:56 +08:00
|
|
|
|
this.status = 0;
|
|
|
|
|
this.BeforeQuantity = new int[9];
|
|
|
|
|
this.AfterQuantity = new int[9];
|
|
|
|
|
}
|
|
|
|
|
async Task CheckFinish()
|
|
|
|
|
{
|
|
|
|
|
if (channels.Any(cl => cl.CheckQuantity != cl.Quantity && cl.DrugId != null && cl.drugManuNo != null))
|
|
|
|
|
{
|
|
|
|
|
// 保存账册、操作记录
|
|
|
|
|
var b = await channelListDao.DrawerCheckFinish(channels.Where(cl => cl.CheckQuantity != cl.Quantity).ToList());
|
|
|
|
|
if (!b)
|
|
|
|
|
{
|
|
|
|
|
_message.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"数据保存失败", Duration = 4000 });
|
|
|
|
|
logger.Error($"盘点保存数据库失败,数据{JsonConvert.SerializeObject(channels)}");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2025-06-24 08:55:34 +08:00
|
|
|
|
_message.Notify(new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "提示", Detail = $"盘点完成", Duration = 4000 });
|
2025-05-28 14:48:38 +08:00
|
|
|
|
logger.Info($"盘点完成");
|
2025-04-18 11:01:56 +08:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//重置状态
|
|
|
|
|
this.RestData();
|
|
|
|
|
// 重新查询库存
|
|
|
|
|
await grid.Reload();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Cancel()
|
|
|
|
|
{
|
2025-05-28 14:48:38 +08:00
|
|
|
|
RestData();
|
2025-04-18 11:01:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SelectDrawer(int drawerNo)
|
|
|
|
|
{
|
|
|
|
|
this.drawerNo = drawerNo;
|
|
|
|
|
grid.Reload();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OnCellClick(DataGridCellMouseEventArgs<ChannelStock> args)
|
|
|
|
|
{
|
|
|
|
|
grid.EditRow(args.Data);
|
|
|
|
|
}
|
|
|
|
|
private IDisposable? registration;
|
|
|
|
|
protected override void OnAfterRender(bool firstRender)
|
|
|
|
|
{
|
|
|
|
|
if (firstRender)
|
|
|
|
|
{
|
|
|
|
|
registration = na.RegisterLocationChangingHandler(OnLocationChanging);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private ValueTask OnLocationChanging(LocationChangingContext context)
|
|
|
|
|
{
|
|
|
|
|
// 操作中不可跳转页面
|
|
|
|
|
if (status > 0)
|
|
|
|
|
{
|
|
|
|
|
context.PreventNavigation(); //阻止导航
|
|
|
|
|
}
|
|
|
|
|
return ValueTask.CompletedTask;
|
|
|
|
|
}
|
|
|
|
|
//在生命周期函数Dispose中,移除订阅的事件,并销毁非托管资源registration===========================================
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
registration?.Dispose();
|
|
|
|
|
}
|
|
|
|
|
}
|