添加项目文件。

This commit is contained in:
admin 2025-03-16 03:17:36 +08:00
parent 47d3aca9e9
commit 34014ed142
85 changed files with 3901 additions and 0 deletions

13
.idea/.idea.Seyounth.Hyosung/.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,13 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# Rider 忽略的文件
/projectSettingsUpdater.xml
/modules.xml
/contentModel.xml
/.idea.Seyounth.Hyosung.iml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="hyosung.test" uuid="8700df22-a043-445e-8381-da146d36a9c8">
<driver-ref>sqlite.xerial</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/Seyounth.Hyosung/bin/Debug/net8.0-windows/hyosung.test</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

View File

@ -0,0 +1 @@
global using NUnit.Framework;

View File

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0"/>
<PackageReference Include="NUnit" Version="3.13.3"/>
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1"/>
<PackageReference Include="NUnit.Analyzers" Version="3.6.1"/>
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Seyounth.Hyosung.Data\Seyounth.Hyosung.Data.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,21 @@
using System.Text.Json;
using Seyounth.Hyosung.Data.Services.Hyosung;
namespace HyosungDataTester;
public class Tests
{
private IHyosungWmsService _wmsService = new HyosungWmsService();
[SetUp]
public void Setup()
{
}
[Test]
public void Test1()
{
var result = _wmsService.GetItemInfoByItemCode("TYY-JPS1843018G").Result;
Assert.Pass(JsonSerializer.Serialize(result));
}
}

View File

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Seyounth.Hyosung.Data\Seyounth.Hyosung.Data.csproj" />
</ItemGroup>
</Project>

10
HyosungTester/Program.cs Normal file
View File

@ -0,0 +1,10 @@
// See https://aka.ms/new-console-template for more information
using System.Text.Json;
using Seyounth.Hyosung.Data.Services.Hyosung;
Console.WriteLine("Hello, World!");
IHyosungWmsService wmsService=new HyosungWmsService();
var data= wmsService.GetItemInfoByItemCode("TYY-JPS1843018G").Result;
Console.WriteLine(JsonSerializer.Serialize(data));
Console.ReadLine();

View File

@ -0,0 +1,9 @@
namespace Seyounth.Core.Extensions;
public static class DateTimeExtensions
{
public static int ToTimestamp(this DateTime dateTime)
{
return (int)new DateTimeOffset(dateTime).ToUnixTimeSeconds();
}
}

View File

@ -0,0 +1,22 @@
using System.ComponentModel;
namespace Seyounth.Core.Extensions;
public static class EnumHelper
{
public static IEnumerable<T> GetValues<T>()
{
return Enum.GetValues(typeof(T)).Cast<T>();
}
// 获取枚举值的描述信息
public static string GetDescription<T>(this T enumValue) where T : Enum
{
var fieldInfo = enumValue.GetType().GetField(enumValue.ToString());
var descriptionAttributes =
fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false) as DescriptionAttribute[];
return descriptionAttributes is { Length: > 0 }
? descriptionAttributes[0].Description
: enumValue.ToString();
}
}

View File

@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,146 @@
using System.Net.Http.Json;
using Microsoft.Extensions.Logging;
using Seyounth.Hyosung.Core.Agv.HikModels;
namespace Seyounth.Hyosung.Core.Agv;
public class HikAgv(ILogger<HikAgv> logger)
{
private const string Url = "http://192.168.30.161:8181/rcms/services/rest/hikRpcService/";
private const string CancelTaskUri = "cancelTask";
private const string SchedulingTaskUri = "genAgvSchedulingTask";
private string GetRequestCode()
{
return $"Syc_{DateTimeOffset.Now.Ticks}";
}
/// <summary>
/// 取消任务
/// </summary>
/// <param name="taskCode"></param>
public async Task CancelTaskAsync(string taskCode)
{
var url = Url + CancelTaskUri;
var input = new
{
reqCode = GetRequestCode(),
taskCode
};
var result = await PostAsync<string>(url, input);
if (result is null)
{
logger.LogWarning($"task {taskCode} cancel error: result is null");
return;
}
if (result.Code != "0")
{
logger.LogWarning($"task {taskCode} cancel error: code is {result.Code}");
return;
}
logger.LogInformation($"task {taskCode} cancel succeed.");
}
public async Task CarryToAsync(AgvPosition start, AgvPosition end, string ctnrType, int priority, string taskType)
{
var url = Url + SchedulingTaskUri;
var input = new
{
reqCode = GetRequestCode(),
ctnrType,
taskType,
priority,
agvCode = "4083",
positionCodePath = new object[]
{
new { positionCode = start.PositionCode, type = start.Type },
new { positionCode = end.PositionCode, type = end.Type }
}
};
var rs = await PostAsync<string>(url, input);
if (rs is null)
{
logger.LogWarning($"{start.PositionCode} carry to {end.PositionCode} error: result is null");
return;
}
if (rs.Code != "0")
{
logger.LogWarning($"{start.PositionCode} carry to {end.PositionCode} error: code is {rs.Code}");
return;
}
logger.LogInformation($"{start.PositionCode} carry to {end.PositionCode} succeed");
}
public async Task MovingToAsync(AgvPosition des, string taskType)
{
var url = Url + SchedulingTaskUri;
var input = new
{
reqCode = GetRequestCode(),
taskType,
priority = 1,
positionCodePath =
new object[]
{
new { positionCode = des.PositionCode, type = des.Type }
}
};
var rs = await PostAsync<string>(url, input);
if (rs is null)
{
logger.LogWarning($"agv move to {des.PositionCode} error: result is null");
return;
}
if (rs.Code != "0")
{
logger.LogWarning($"agv move to {des.PositionCode} error: code is {rs.Code}");
return;
}
logger.LogInformation($"agv move to {des.PositionCode} succeed");
}
public async Task<AgvStatusInfo?> GetAgvStatus(string mapCode, string agvCode)
{
var url = "http://192.168.30.161:8181/rcms-dps/rest/queryAgvStatus";
var q = new
{
reqCode = GetRequestCode(),
mapCode
};
var rs = await PostAsync<List<AgvStatusInfo>>(url, q);
if (rs is null)
{
logger.LogWarning($"get agv {agvCode} from map {mapCode} error: result is null");
return null;
}
if (rs.Code == "0") return rs.Data.First(t => t.RobotCode == agvCode);
logger.LogWarning($"get agv {agvCode} from map {mapCode} error: code is {rs.Code}");
return null;
}
private async Task<HikApiResult<T>?> PostAsync<T>(string url, object content)
{
try
{
using var client = new HttpClient();
var json = JsonContent.Create(content);
var response = await client.PostAsync(url, json);
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<HikApiResult<T>>();
}
catch (Exception e)
{
logger.LogError(e, $"post error");
return null;
}
}
}

View File

@ -0,0 +1,8 @@
namespace Seyounth.Hyosung.Core.Agv.HikModels;
public class AgvPosition
{
public string PositionCode { get; set; }
public string Type { get; set; }
}

View File

@ -0,0 +1,27 @@
namespace Seyounth.Hyosung.Core.Agv.HikModels;
public class AgvStatusInfo
{
/// <summary>
/// 机器人编号
/// </summary>
public string RobotCode { get; set; }
public string RobotDir { get; set; }
public string RobotIp { get; set; }
public string MapCode { get; set; }
public string posX { get; set; }
public string posY { get; set; }
/// <summary>
/// 电量值
/// </summary>
public string Battery { get; set; }
public string Status { get; set; }
/// <summary>
/// 是否已被排除,被排除后不接受新任务( 1-排除, 0-正常)
public string exclType { get; set; }
/// <summary>
/// 是否暂停 0-否 1-是
/// </summary>
public string Stop { get; set; }
}

View File

@ -0,0 +1,24 @@
namespace Seyounth.Hyosung.Core.Agv.HikModels;
public class HikApiResult<TData>
{
/// <summary>
/// 返回码
/// </summary>
public string Code { get; set; }
/// <summary>
/// 返回消息
/// </summary>
public string Message { get; set; }
/// <summary>
/// 请求编号
/// </summary>
public string ReqCode { get; set; }
/// <summary>
/// 自定义返回
/// </summary>
public TData Data { get; set; }
}

View File

@ -0,0 +1,42 @@
using Microsoft.Extensions.Logging;
using Seyounth.Hyosung.Core.Agv.HikModels;
using Seyounth.Hyosung.Data.Services;
namespace Seyounth.Hyosung.Core.Agv;
public class HyosungAgvService(
ILoggerFactory loggerFactory,
IAgvBinService agvBinService,
ITrayService trayService,
IDictService dictService) : IHyosungAgvService
{
private readonly HikAgv _agv = new HikAgv(loggerFactory.CreateLogger<HikAgv>());
public async Task StorageAsync(string trayCode)
{
AgvStatusInfo? status;
do
{
status = await _agv.GetAgvStatus("BB", "4083");
await Task.Delay(1000);
} while (status is null);
var tray = await trayService.GetByCode(trayCode);
var height = (int)Math.Ceiling((double)(tray.StackHeight / 10.0)!);
var bin = await agvBinService.GetAvailableBin(height);
AgvPosition start = new AgvPosition()
{
PositionCode = "A1",
Type = "00"
};
var stop = new AgvPosition()
{
PositionCode = bin.CtnrCode,
Type = "05"
};
var ctnrType = await dictService.GetKeyAsync("AgvRackType", height.ToString());
await _agv.CarryToAsync(start, stop, ctnrType, 120, "1");
await agvBinService.BindAsync(bin);
}
}

View File

@ -0,0 +1,11 @@
namespace Seyounth.Hyosung.Core.Agv;
public interface IHyosungAgvService
{
/// <summary>
/// 入库
/// </summary>
/// <param name="trayCode"></param>
/// <returns></returns>
Task StorageAsync(string trayCode);
}

View File

@ -0,0 +1,301 @@
using MCProtocol;
using Microsoft.Extensions.Logging;
using Seyounth.Hyosung.Data.Models;
using Seyounth.Hyosung.Data.Models.Plc;
namespace Seyounth.Hyosung.Core.Plc;
public class HyosungPlcService(ILogger<HyosungPlcService> logger) : IHyosungPlcService
{
private readonly McPlc _reader = new("192.168.3.10", 4060, Mitsubishi.McFrame.MC3E);
private readonly McPlc _writer = new("192.168.3.10", 4061, Mitsubishi.McFrame.MC3E);
private bool isLeaving = false;
public async Task StartAsync(CancellationToken token)
{
token = token;
List<Task<int>> ls =
[
_reader.ConnectAsync(),
_writer.ConnectAsync()
];
var codes = await Task.WhenAll(ls);
logger.LogInformation($"plc reader connect code: {codes[0]}\r\nplc writer connect code: {codes[1]}");
ReadLoop(token);
}
public async Task StopAsync()
{
List<Task<int>> ls =
[
_reader.CloseAsync(),
_writer.CloseAsync()
];
var codes = await Task.WhenAll(ls);
logger.LogInformation($"plc reader close code: {codes[0]}\r\nplc writer close code: {codes[1]}");
}
public async Task WriteVarietyAsync(Variety variety)
{
var data = variety.ToVarietyPlcData();
await _writer.WriteShortsAsync(4200, data);
logger.LogInformation($"write [{string.Join(",", data)}] data to plc address[4200]");
await _writer.WriteShortsAsync(4230, (short)variety.Id);
logger.LogInformation($"write [{variety.Id}] to plc address[4230]");
}
public async Task WriteScanYarnResultAsync(bool result, short? varietyId = null, string? yarnCode = null)
{
if (result && yarnCode != null && varietyId != null)
{
await _writer.WriteShortsAsync(4009, varietyId.Value);
await _writer.WriteStringAsync(4010, yarnCode);
logger.LogInformation($"write [{yarnCode}] to plc address[4010]");
}
await _writer.WriteShortsAsync(4000, (short)(result ? 1 : 2));
logger.LogInformation($"write [{(result ? 1 : 2)}] to plc address[4000]");
}
public async Task WriteScanFixtureResultAsync(int fixtureId, bool result, short? fixtureCode = null)
{
int flagAddress = 4000 + fixtureId;
int codeAddress = 4004 + fixtureId;
if (result && fixtureCode != null)
{
await _writer.WriteShortsAsync(codeAddress, fixtureCode.Value);
logger.LogInformation($"write [{fixtureCode}] to plc address[{codeAddress}]");
}
await _writer.WriteShortsAsync(flagAddress, (short)(result ? 1 : 2));
logger.LogInformation($"write [{(result ? 1 : 2)}] to plc address[{flagAddress}]");
}
public async Task LeaveCompletedAsync()
{
await _writer.WriteShortsAsync(4020, 0);
await _writer.WriteShortsAsync(13012, 0);
await _writer.WriteShortsAsync(4520, 1);
isLeaving = false;
}
public async Task WriteTrayCodeAsync(int index, string trayCode)
{
var address = index == 1 ? 4100 : 4110;
await _writer.WriteStringAsync(address, trayCode);
}
public async Task WriteReceivedYarnCountAsync(int count)
{
await _writer.WriteShortsAsync(4120, (short)count);
}
public async Task WritePackLineOptionAsync(PackLineOption option)
{
List<short> ls = new List<short>();
ls.Add((short)option.HeadCount);
ls.Add((short)(option.IsTop ? 1 : 2));
await _writer.WriteShortsAsync(12120, ls.ToArray());
ls.Clear();
ls.Add((short)(option.HasBox ? 1 : 2));
ls.Add((short)(option.IsPack ? 1 : 2));
ls.Add((short)(option.IsFilm ? 1 : 2));
ls.Add((short)(option.IsLam ? 1 : 2));
await _writer.WriteShortsAsync(12123, ls.ToArray());
}
public async Task WritePrintLabelResultAsync(int index, bool result)
{
var address = index == 1 ? 13060 : 13061;
await _writer.WriteShortsAsync(address, (short)(result ? 1 : 2));
}
public event Func<int, Task>? OnPlcRequestScanProduct;
public event Func<int, Task>? OnPlcRequestScanFixture;
public event Func<PlcStackInfo, Task>? OnPlcRequestLeavingProductionLine;
public event Func<int, int, Task>? OnPlcNeedNewTrayCode;
public event Func<PlcStackingInfo, Task>? OnPlcPutCompleted;
public event Func<string, Task>? OnPlcRequestPackLineOption;
public event Func<int, string, int, Task>? OnRequestPrintLabel;
private async Task ReadLoop(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
await QueryScanProductRequest();
await QueryScanFixtureRequest();
if (!isLeaving)
await QueryLeavingProductionLine();
await QueryNeedTrayCode();
await QueryPutOnceCompleted();
await QueryPackLineOption();
await QueryPrintLabel();
await Task.Delay(100, token);
}
}
/// <summary>
/// 查询请求扫描产品方法
/// </summary>
private async Task QueryScanProductRequest()
{
var requestScanProduct = await _reader.ReadShortsAsync(4500, 2);
if (requestScanProduct[0] == 1)
{
OnPlcRequestScanProduct?.Invoke(requestScanProduct[1]);
//清空请求标志位
await _writer.WriteShortsAsync(4500, 0, 0);
}
}
/// <summary>
/// 查询扫描夹具请求
/// </summary>
private async Task QueryScanFixtureRequest()
{
var requestScanFixture = await _reader.ReadShortsAsync(4505, 4);
if (requestScanFixture[0] == 1)
{
await _writer.WriteShortsAsync(4505, 0);
OnPlcRequestScanFixture?.Invoke(1);
}
if (requestScanFixture[1] == 1)
{
await _writer.WriteShortsAsync(4506, 0);
OnPlcRequestScanFixture?.Invoke(2);
}
if (requestScanFixture[2] == 1)
{
await _writer.WriteShortsAsync(4507, 0);
await OnPlcRequestScanFixture?.Invoke(3);
}
if (requestScanFixture[3] == 1)
{
await _writer.WriteShortsAsync(4508, 0);
await OnPlcRequestScanFixture?.Invoke(4);
}
}
/// <summary>
/// 查询有托盘请求下线
/// </summary>
private async Task QueryLeavingProductionLine()
{
var leavingProductionLine = await _reader.ReadShortsAsync(4020, 1);
// var stackStatus = await _reader.ReadShortsAsync(12110, 1);
if (leavingProductionLine[0] == 1)
{
var trayCode = await _reader.ReadStringAsync(12600);
if (!string.IsNullOrEmpty(trayCode))
{
PlcStackInfo info = new PlcStackInfo()
{
TrayCode = trayCode
};
isLeaving = true;
OnPlcRequestLeavingProductionLine?.Invoke(info);
}
}
}
/// <summary>
/// 查询是否需要新的托盘号
/// </summary>
private async Task QueryNeedTrayCode()
{
var n1 = await _reader.ReadShortsAsync(4600, 2);
var n2 = await _reader.ReadShortsAsync(4610, 2);
if (n1[0] == 1)
{
OnPlcNeedNewTrayCode?.Invoke(1, n1[1]);
await _writer.WriteShortsAsync(4600, 0);
}
if (n2[0] == 1)
{
OnPlcNeedNewTrayCode?.Invoke(2, n2[1]);
await _writer.WriteShortsAsync(4610, 0);
}
}
private async Task QueryPutOnceCompleted()
{
var status = await _reader.ReadShortsAsync(4691, 2);
if (status[0] == 1)
{
var trayCode = await _reader.ReadStringAsync(4620);
var yarn1 = await _reader.ReadStringAsync(4630);
var yarn2 = await _reader.ReadStringAsync(4640);
var yarn3 = await _reader.ReadStringAsync(4650);
var info = new PlcStackingInfo()
{
TrayCode = trayCode,
YarnCount = status[0],
TotalYarnCount = status[1]
};
if (!string.IsNullOrEmpty(yarn1))
info.YarnCode.Add(yarn1);
if (!string.IsNullOrEmpty(yarn2))
info.YarnCode.Add(yarn2);
if (!string.IsNullOrEmpty(yarn3))
info.YarnCode.Add(yarn3);
if (info.YarnCode.Count != info.YarnCount)
{
logger.LogWarning($"get yarn code count[{info.YarnCode.Count}]不等于YarnCount[{info.TotalYarnCount}]");
return;
}
await _writer.WriteShortsAsync(4690, 0, 0, 0);
await _writer.WriteShortsAsync(4620, new short[40]);
OnPlcPutCompleted?.Invoke(info);
}
}
/// <summary>
/// 打包线请求获取配置
/// </summary>
private async Task QueryPackLineOption()
{
var requestPackLineOption = await _reader.ReadShortsAsync(4022, 1);
if (requestPackLineOption[0] == 1)
{
var trayCode = await _reader.ReadStringAsync(12100);
await _writer.WriteShortsAsync(4022, 0);
OnPlcRequestPackLineOption?.Invoke(trayCode);
}
}
private async Task QueryPrintLabel()
{
var requestPrintLabel = await _reader.ReadShortsAsync(13010, 3);
if (requestPrintLabel[0] == 1)
{
var trayCode = await _reader.ReadStringAsync(13000);
await _writer.WriteShortsAsync(13010, 0);
await _writer.WriteShortsAsync(13012, 0);
OnRequestPrintLabel?.Invoke(1, trayCode, requestPrintLabel[2]);
}
if (requestPrintLabel[1] == 1)
{
var trayCode = await _reader.ReadStringAsync(13001);
await _writer.WriteShortsAsync(13011, 0);
await _writer.WriteShortsAsync(13012, 0);
OnRequestPrintLabel?.Invoke(2, trayCode, requestPrintLabel[2]);
}
}
}

View File

@ -0,0 +1,97 @@
using Seyounth.Hyosung.Data.Models;
using Seyounth.Hyosung.Data.Models.Plc;
namespace Seyounth.Hyosung.Core.Plc;
public interface IHyosungPlcService
{
Task StartAsync(CancellationToken token);
Task StopAsync();
/// <summary>
/// 写入品种到PLC
/// </summary>
/// <param name="variety"></param>
/// <returns></returns>
Task WriteVarietyAsync(Variety variety);
/// <summary>
/// 写入扫码结果
/// </summary>
/// <param name="result">结果</param>
/// <param name="varietyId">品类ID</param>
/// <param name="yarnCode">纱码</param>
/// <returns></returns>
Task WriteScanYarnResultAsync(bool result, short? varietyId = null, string? yarnCode = null);
/// <summary>
/// 写入治具扫码结果
/// </summary>
/// <param name="fixtureId"></param>
/// <param name="result"></param>
/// <param name="fixtureCode"></param>
/// <returns></returns>
Task WriteScanFixtureResultAsync(int fixtureId, bool result, short? fixtureCode = null);
/// <summary>
/// 下线完成
/// </summary>
/// <returns></returns>
Task LeaveCompletedAsync();
/// <summary>
/// 写入托盘号
/// </summary>
/// <param name="index"></param>
/// <param name="trayCode"></param>
/// <returns></returns>
Task WriteTrayCodeAsync(int index, string trayCode);
/// <summary>
/// 写入收到的纱数量
/// </summary>
/// <param name="count"></param>
/// <returns></returns>
Task WriteReceivedYarnCountAsync(int count);
Task WritePackLineOptionAsync(PackLineOption option);
Task WritePrintLabelResultAsync(int index, bool result);
/// <summary>
/// Plc请求扫描产品
/// </summary>
event Func<int, Task> OnPlcRequestScanProduct;
/// <summary>
/// Plc请求扫描治具
/// </summary>
event Func<int, Task> OnPlcRequestScanFixture;
/// <summary>
/// Plc请求下线
/// </summary>
event Func<PlcStackInfo, Task> OnPlcRequestLeavingProductionLine;
/// <summary>
/// Plc需要新的托盘号
/// </summary>
event Func<int, int, Task> OnPlcNeedNewTrayCode;
/// <summary>
/// Plc放入一次完成
/// </summary>
event Func<PlcStackingInfo, Task> OnPlcPutCompleted;
/// <summary>
/// Plc请求打包线选项
/// </summary>
event Func<string, Task> OnPlcRequestPackLineOption;
/// <summary>
/// 贴标站请求贴标
/// </summary>
event Func<int, string, int, Task> OnRequestPrintLabel;
}

View File

@ -0,0 +1,74 @@
using MCProtocol;
namespace Seyounth.Hyosung.Core.Plc;
public class McPlc(string host, int port, Mitsubishi.McFrame type)
{
private readonly Mitsubishi.McProtocolTcp _mc = new();
public async Task<int> ConnectAsync()
{
_mc.HostName = host;
_mc.PortNumber = port;
_mc.CommandFrame = type;
return await _mc.Open();
}
public Task<int> CloseAsync()
{
var code = _mc.Close();
_mc.Dispose();
return Task.FromResult(code);
}
public async Task<byte[]> ReadBytesAsync(int address, int length)
{
var code = await _mc.ReadDeviceBlock(Mitsubishi.PlcDeviceType.D, address, length / 2);
return code;
}
public async Task<short[]> ReadShortsAsync(int address, int length)
{
var code = await _mc.ReadDeviceBlock(Mitsubishi.PlcDeviceType.D, address, length);
if (code is null || code.Length < length * 2)
throw new Exception("read short error");
var shorts = new short[length];
Buffer.BlockCopy(code, 0, shorts, 0, code.Length);
return shorts;
}
public async Task WriteShortsAsync(int address, params short[] values)
{
var code = await _mc.WriteDeviceBlock(Mitsubishi.PlcDeviceType.D, address, values.Length,
values.SelectMany(BitConverter.GetBytes).ToArray());
}
public async Task WriteBytesAsync(int address, byte[] data)
{
var code = await _mc.WriteDeviceBlock(Mitsubishi.PlcDeviceType.D, address, data.Length / 2, data);
}
public async Task<string> ReadStringAsync(int address)
{
const int fixedLength = 20;
// 调用 ReadBytesAsync 方法读取字节数据,固定长度为 10
byte[] bytes = await ReadBytesAsync(address, fixedLength);
// 将字节数组使用 ASCII 编码转换为字符串
string result = System.Text.Encoding.ASCII.GetString(bytes);
// 去除字符串末尾可能存在的空字符
return result.TrimEnd('\0');
}
public async Task WriteStringAsync(int address, string value)
{
const int fixedLength = 10;
// 将字符串使用 ASCII 编码转换为字节数组
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(value);
// 确保字节数组长度为 10
byte[] fixedLengthBytes = new byte[fixedLength];
Array.Copy(bytes, fixedLengthBytes, Math.Min(bytes.Length, fixedLength));
// 调用 WriteBytesAsync 方法写入字节数组
await WriteBytesAsync(address, fixedLengthBytes);
}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,47 @@
using System.Net.Sockets;
using System.Text;
namespace Seyounth.Hyosung.Core.Printer;
public class AveryPrinter(string host, int port)
{
public string Host => host;
public int Port => port;
private readonly Socket _socket = new(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
public async Task ConnectAsync(CancellationToken token)
{
try
{
await _socket.ConnectAsync(Host, Convert.ToInt32(port), token);
}catch(Exception e)
{
Console.WriteLine($"Host[{Host}:{port}] error:{e.Message}");
}
}
public async Task CloseAsync(CancellationToken token)
{
await _socket.DisconnectAsync(true, token);
_socket.Dispose();
}
public async Task SendContentAsync(string context)
{
await _socket.SendAsync(Encoding.UTF8.GetBytes(context));
}
private const string CleanCmd = "#!A1#!CA#!P1";
private const string PrintCmd = "#!A1#!D#!P1";
public async Task CleanContextAsync()
{
await _socket.SendAsync(Encoding.UTF8.GetBytes(CleanCmd));
}
public async Task PrintAsync()
{
await _socket.SendAsync(Encoding.UTF8.GetBytes(PrintCmd));
}
}

View File

@ -0,0 +1,132 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Seyounth.Hyosung.Data.Models;
using Seyounth.Hyosung.Data.Services;
using Seyounth.Hyosung.Data.Services.Hyosung;
namespace Seyounth.Hyosung.Core.Printer;
public class HyosungPrinter(
ILogger<HyosungPrinter> logger,
IVarietyService varietyService,
ITrayService trayService,
IDictService dictService,
IYarnService yarnService,
IHyosungWmsService hyosungWmsService,
IOptions<PrintTemp> options) : IHyosungPrinter
{
private readonly AveryPrinter _masterPrinter = new("192.168.3.60", 9100);
private readonly AveryPrinter _slavePrinter = new("192.168.3.61", 9100);
public async Task StartAsync(CancellationToken token)
{
List<Task> ls = new List<Task>();
ls.Add(_masterPrinter.ConnectAsync(token)) ;
ls.Add(_slavePrinter.ConnectAsync(token)) ;
await Task.WhenAll(ls);
logger.LogInformation("printer connected");
}
public async Task StopAsync(CancellationToken token)
{
await _masterPrinter.CloseAsync(token);
await _slavePrinter.CloseAsync(token);
logger.LogInformation("printer disconnected");
}
public async Task PrintAsync(int index, string trayCode)
{
var tray = await trayService.GetByCode(trayCode);
if (index == 1)
{
await PrintLabel1Async(tray);
}
else
{
await PrintLabel2Async(tray);
}
}
private async Task PrintLabel1Async(Tray tray)
{
await _masterPrinter.CleanContextAsync();
var content = await GetPrint1Content(tray);
await _masterPrinter.SendContentAsync(content);
await _masterPrinter.PrintAsync();
}
private async Task PrintLabel2Async(Tray tray)
{
await _slavePrinter.CleanContextAsync();
var content = await GetPrint2Content(tray);
await _slavePrinter.SendContentAsync(content);
await _slavePrinter.PrintAsync();
}
private async Task<string> GetPrint1Content(Tray tray)
{
var variety = await varietyService.GetById(tray.VarietyId);
var yarns = await yarnService.GetYarnsByTrayIdAsync(tray.VarietyId);
var dic = new Dictionary<string, string>();
if (yarns.Count > 0)
{
var machineNoList = yarns
.Where(item => item.Machine.Contains('-'))
.Select(item => item.Machine.Split('-')[0])
.Distinct()
.ToList();
var machineStr = string.Join(" ", machineNoList);
dic.Add("1569", yarns[0].Lot.ToString());
dic.Add("T1 T2 T3 T4 T5", machineStr);
}
string temp;
if (variety.MasterLabelCount == 1)
temp = options.Value.Partition;
else
{
var tempName = options.Value.Sides.First(t => t.ItemCode == variety.Code).TempName;
temp = options.Value.Temps.First(t => t.Name == tempName).Code;
}
foreach (var (key, value) in dic)
{
temp = temp.Replace(key, value);
}
return temp;
}
private async Task<string> GetPrint2Content(Tray tray)
{
var variety = await varietyService.GetById(tray.VarietyId);
var labelResult =
await hyosungWmsService.GetLabelResult(variety.Code, variety.Lot.ToString(), tray.ControlNo!.Value);
var dic = new Dictionary<string, string>
{
{ "$1153", $"\"{variety.Lot}\"" },
{ "1670dtex -144F", $"\"{tray.DtexFila}\"" },
{ "1500D - 144F", $"\"{tray.DenFila}\"" },
{ "$SA", $"\"{tray.Grade}\"" },
{ "$900", $"\"{labelResult.NET_WEIGHT}\"" },
{ "25-01-01", $"\"{DateTime.Now:yy-MM-dd}\"" },
{ "$90", $"\"{variety.TotalCount}\"" },
{ "$965", $"\"{labelResult.GROSS_WEIGHT}\"" },
{
"250101J068",
$"\"{DateTime.Now.ToString("yyMMdd" + "J") + tray.ControlNo.ToString()?.PadLeft(3, '0')}\""
},
{ "DTYY-JPA11530SFG250101000900115305480", $"\"{labelResult.BAR_CODE}\"" }
};
string content = options.Value.DefaultTemp;
foreach (var (key, value) in dic)
{
content = content.Replace(key, value);
}
return content;
}
}

View File

@ -0,0 +1,15 @@
namespace Seyounth.Hyosung.Core.Printer;
public interface IHyosungPrinter
{
Task StartAsync(CancellationToken token);
Task StopAsync(CancellationToken token);
/// <summary>
/// 打印指定垛的标签
/// </summary>
/// <param name="trayCode"></param>
/// <returns></returns>
Task PrintAsync(int index,string trayCode);
}

View File

@ -0,0 +1,26 @@
namespace Seyounth.Hyosung.Core.Printer;
public class PrintTemp
{
public string DefaultTemp { get; set; }
public string Partition { get; set; }
public List<Side> Sides { get; set; }
public List<TempData> Temps { get; set; }
}
public class Side
{
public string ItemCode { get; set; }
public string TempName { get; set; }
}
public class TempData
{
public string Name { get; set; }
public string Code { get; set; }
}

View File

@ -0,0 +1,49 @@
using System.Net.Sockets;
using System.Text;
using NetTaste;
using Newtonsoft.Json.Linq;
namespace Seyounth.Hyosung.Core.Scanner;
public class HikScanner(string host, int port)
{
public string Host => host;
public int Port => port;
private Socket _socket = new(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
public async Task ConnectAsync(CancellationToken token)
{
await _socket.ConnectAsync(Host, Port, token);
Console.WriteLine($"scanner[{Host}:{Port}] connected");
}
public async Task CloseAsync(CancellationToken token)
{
await _socket.DisconnectAsync(true, token);
_socket.Dispose();
}
public async Task<string> ScanAsync()
{
try
{
byte[] cmd = "start"u8.ToArray();
await _socket.SendAsync(cmd);
byte[] buffer = new byte[1024];
int len = await _socket.ReceiveAsync(buffer).WaitAsync(TimeSpan.FromMilliseconds(2000));
cmd = "stop"u8.ToArray();
await _socket.SendAsync(cmd);
byte[] _ = new byte[1024];
while (_socket.Available > 0)
{
await _socket.ReceiveAsync(_, SocketFlags.None);
}
return Encoding.ASCII.GetString(buffer, 0, len);
}
catch (Exception e)
{
return string.Empty;
}
// 清空缓冲区 防止收到之前的数据
}
}

View File

@ -0,0 +1,135 @@
using System.Collections.Concurrent;
using Microsoft.Extensions.Logging;
using Seyounth.Hyosung.Data.Models;
namespace Seyounth.Hyosung.Core.Scanner;
public class HyosungScannerService : IHyosungScannerService
{
private readonly List<HikScanner> _yarnScanners = new();
private readonly ILogger<HyosungScannerService> _logger;
private readonly ConcurrentDictionary<int, HikScanner> _fixtureScanners = new();
public HyosungScannerService(ILogger<HyosungScannerService> logger)
{
_yarnScanners.Add(new HikScanner("192.168.3.35", 2001));
_yarnScanners.Add(new HikScanner("192.168.3.36", 2001));
_yarnScanners.Add(new HikScanner("192.168.3.37", 2001));
_yarnScanners.Add(new HikScanner("192.168.3.38", 2001));
_yarnScanners.Add(new HikScanner("192.168.3.39", 2001));
_fixtureScanners.TryAdd(1, new HikScanner("192.168.3.31", 2001));
_fixtureScanners.TryAdd(2, new HikScanner("192.168.3.32", 2001));
_fixtureScanners.TryAdd(3, new HikScanner("192.168.3.33", 2001));
_fixtureScanners.TryAdd(4, new HikScanner("192.168.3.30", 2001));
_logger = logger;
}
public async Task StartAsync(CancellationToken token)
{
// 创建一个超时任务
var timeoutTask = Task.Delay(2000, token);
// 为每个纱线扫描器创建一个带有超时的连接任务
var yarnScannerTasks = _yarnScanners.Select(scanner =>
{
var connectTask = scanner.ConnectAsync(token);
return Task.WhenAny(connectTask, timeoutTask);
}).ToList();
// 为每个夹具扫描器创建一个带有超时的连接任务
var fixtureScannerTasks = _fixtureScanners.Values.Select(scanner =>
{
var connectTask = scanner.ConnectAsync(token);
return Task.WhenAny(connectTask, timeoutTask);
}).ToList();
// 合并所有任务
var allTasks = new List<Task>();
allTasks.AddRange(yarnScannerTasks);
allTasks.AddRange(fixtureScannerTasks);
// 等待所有任务完成
await Task.WhenAll(allTasks);
// 检查每个任务是否超时
foreach (var task in yarnScannerTasks)
{
var innerTask = task as Task<Task>;
if (innerTask.Result == timeoutTask)
{
// 处理纱线扫描器连接超时的情况
Console.WriteLine($"纱线扫描器连接超时");
}
}
foreach (var task in fixtureScannerTasks)
{
var innerTask = task as Task<Task>;
if (innerTask.Result == timeoutTask)
{
// 处理夹具扫描器连接超时的情况
Console.WriteLine($"夹具扫描器连接超时");
}
}
// foreach (var scanner in _yarnScanners)
// {
// await scanner.ConnectAsync(token);
// }
//
// foreach (var fixtureScanner in _fixtureScanners)
// {
// await fixtureScanner.Value.ConnectAsync(token);
// }
}
public async Task StopAsync(CancellationToken token)
{
List<Task> ls = _yarnScanners.Select(scanner => scanner.CloseAsync(token)).ToList();
ls.AddRange(_fixtureScanners.Values.Select(scanner => scanner.CloseAsync(token)).ToList());
await Task.WhenAll(ls);
}
public async Task<Yarn?> ScanYarnAsync(int varietyId)
{
List<Task<Yarn?>> ls = _yarnScanners.Select(scanner => scanner.ScanAsync()
.ContinueWith(task =>
{
if (task.IsCompletedSuccessfully && !string.IsNullOrEmpty(task.Result))
{
_logger.LogInformation($"scanner[{scanner.Host}:{scanner.Port}] scan yarn {task.Result}");
return Yarn.Create(task.Result, varietyId);
}
return null;
}))
.ToList();
while (ls.Count > 0)
{
// 使用 Task.WhenAny 方法等待任意一个任务完成
Task<Yarn?> completedTask = await Task.WhenAny(ls);
// 移除已经完成的任务
ls.Remove(completedTask);
// 获取完成任务的结果
Yarn? result = await completedTask;
// 如果结果不为空,立即返回结果
if (result != null)
{
return result;
}
}
_logger.LogWarning($"all scanner no scan yarn");
// 如果所有任务都完成且没有找到非空结果,返回 null
return null;
}
public async Task<string> ScanFixtureAsync(int fixtureId)
{
return await _fixtureScanners[fixtureId].ScanAsync();
}
}

View File

@ -0,0 +1,24 @@
using Seyounth.Hyosung.Data.Models;
namespace Seyounth.Hyosung.Core.Scanner;
public interface IHyosungScannerService
{
Task StartAsync(CancellationToken token);
Task StopAsync(CancellationToken token);
/// <summary>
/// 扫描纱
/// </summary>
/// <param name="varietyId"></param>
/// <returns></returns>
Task<Yarn?> ScanYarnAsync(int varietyId);
/// <summary>
/// 扫描治具
/// </summary>
/// <param name="fixtureId"></param>
/// <returns></returns>
Task<string> ScanFixtureAsync(int fixtureId);
}

View File

@ -0,0 +1,20 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Seyounth.Hyosung.Core.Agv;
using Seyounth.Hyosung.Core.Plc;
using Seyounth.Hyosung.Core.Printer;
using Seyounth.Hyosung.Core.Scanner;
namespace Seyounth.Hyosung.Core;
public static class ServiceExtensions
{
public static IServiceCollection AddHyosungServices(this IServiceCollection services,ConfigurationManager configuration)
{
services.AddSingleton<IHyosungPlcService, HyosungPlcService>();
services.AddSingleton<IHyosungScannerService, HyosungScannerService>();
services.AddSingleton<IHyosungAgvService, HyosungAgvService>();
services.AddSingleton<IHyosungPrinter, HyosungPrinter>();
return services;
}
}

View File

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="McProtocol" Version="1.2.5" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Seyounth.Hyosung.Data\Seyounth.Hyosung.Data.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="PrintTemp.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@ -0,0 +1,34 @@
using SqlSugar;
namespace Seyounth.Hyosung.Data.Entities;
[SugarTable("system_agv_bin", TableDescription = "AGV库位")]
public class AgvBinEntity
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnDescription = "主键")]
public int Id { get; set; }
[SugarColumn(ColumnDescription = "库位编码")]
public string BinCode { get; set; }
[SugarColumn(ColumnDescription = "控制编码")]
public string CtnrCode { get; set; }
[SugarColumn(ColumnDescription = "控制类型")]
public int CtnrType { get; set; }
[SugarColumn(ColumnDescription = "库位类型")]
public int RackType { get; set; }
[SugarColumn(ColumnDescription = "是否空闲")]
public bool IsFree { get; set; }
[SugarColumn(ColumnDescription = "库位高度")]
public int Height { get; set; }
[SugarColumn(ColumnDescription = "上次使用时间")]
public DateTime? LastBindTime { get; set; }
[SugarColumn(ColumnDescription = "排序")]
public int Sort { get; set; }
}

View File

@ -0,0 +1,15 @@
using SqlSugar;
namespace Seyounth.Hyosung.Data.Entities;
[SugarTable("system_dict", TableDescription = "字典表")]
public class DictEntity
{
public int Id { get; set; }
public string Key { get; set; }
public string Type { get; set; }
public string Value { get; set; }
}

View File

@ -0,0 +1,26 @@
using Seyounth.Hyosung.Data.Models;
using SqlSugar;
namespace Seyounth.Hyosung.Data.Entities;
[SugarTable("system_pallet", "托盘纸盘规格表")]
public class PalletEntity
{
[SugarColumn(IsIdentity = true, IsPrimaryKey = true)]
public int Id { get; set; }
[SugarColumn(ColumnDescription = "板类型")]
public PalletType Type { get; set; }
[SugarColumn(ColumnDescription = "长")] public int Length { get; set; }
[SugarColumn(ColumnDescription = "宽")] public int Width { get; set; }
[SugarColumn(ColumnDescription = "高")] public int Height { get; set; }
[SugarColumn(ColumnDescription = "孔数量", IsNullable = true)]
public int? HoleCount { get; set; }
[SugarColumn(ColumnDescription = "是否是大孔", IsNullable = true)]
public bool? IsBigHole { get; set; }
}

View File

@ -0,0 +1,52 @@
using SqlSugar;
namespace Seyounth.Hyosung.Data.Entities;
[SugarTable("product_scanned_yarn", "扫描到的纱线信息")]
public class ScannedYarnEntity
{
[SugarColumn(IsIdentity = true, IsPrimaryKey = true, ColumnDescription = "ID")]
public int Id { get; set; }
[SugarColumn(ColumnDescription = "条码", Length = 255)]
public string QrCode { get; set; }
[SugarColumn(ColumnDescription = "纱线代码", Length = 20)]
public string ScanCode { get; set; }
[SugarColumn(ColumnDescription = "Lot")]
public int Lot { get; set; }
[SugarColumn(ColumnDescription = "DEN_FILA", IsNullable = true)]
public string? DenFila { get; set; }
[SugarColumn(ColumnDescription = "DTEX_FILA", IsNullable = true)]
public string? DtexFila { get; set; }
[SugarColumn(ColumnDescription = "生产班次")]
public string WorkShift { get; set; } = "NoData";
[SugarColumn(ColumnDescription = "生产机台")]
public string Machine { get; set; } = "NoData";
[SugarColumn(ColumnDescription = "所属品类信息")]
public int VarietyId { get; set; }
[SugarColumn(ColumnDescription = "扫描时间")]
public DateTime ScanTime { get; set; }
[SugarColumn(ColumnDescription = "生产时间")]
public string ProduceTime { get; set; }
[SugarColumn(ColumnDescription = "是否完成码垛")]
public bool IsFinished { get; set; } = false;
[SugarColumn(ColumnDescription = "所属托盘Id", IsNullable = true)]
public int? TrayId { get; set; }
[SugarColumn(ColumnDescription = "码垛时间", IsNullable = true)]
public DateTime? StackTime { get; set; }
[SugarColumn(ColumnDescription = "入库时间", IsNullable = true)]
public DateTime? StorageTime { get; set; }
}

View File

@ -0,0 +1,43 @@
using SqlSugar;
namespace Seyounth.Hyosung.Data.Entities;
[SugarTable("product_tray", "生产托盘数据")]
public class TrayEntity
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
[SugarColumn(ColumnDescription = "托盘唯一号")]
public string TrayCode { get; set; }
[SugarColumn(ColumnDescription = "所属的品类信息")]
public int VarietyId { get; set; }
[SugarColumn(ColumnDescription = "垛高")]
public int? StackHeight { get; set; }
[SugarColumn(ColumnDescription = "是否为双号")]
public bool IsEven { get; set; }
[SugarColumn(ColumnDescription = "控制号 为空时说明尚未入库", IsNullable = true,
IndexGroupNameList = ["idx_ControlNo_CreateTime"])]
public int? ControlNo { get; set; }
[SugarColumn(ColumnDescription = "生成时间", IndexGroupNameList = ["idx_ControlNo_CreateTime"])]
public DateTime CreateTime { get; set; }
[SugarColumn(ColumnDescription = "入库时间", IsNullable = true)]
public DateTime? FinishTime { get; set; }
[SugarColumn(IsNullable = true)] public string? Grade { get; set; }
[SugarColumn(IsNullable = true)] public string? Type { get; set; }
[SugarColumn(IsNullable = true)] public string? DenFila { get; set; }
[SugarColumn(IsNullable = true)] public string? DtexFila { get; set; }
[SugarColumn(IsNullable = true)] public int? Unit { get; set; }
[SugarColumn(IsNullable = true)] public double NetWeight { get; set; }
[SugarColumn(IsNullable = true)] public double GrossWeight { get; set; }
[SugarColumn(IsNullable = true)] public int? AgvBinId { get; set; }
}

View File

@ -0,0 +1,87 @@
using Seyounth.Hyosung.Data.Models;
using SqlSugar;
namespace Seyounth.Hyosung.Data.Entities;
[SugarTable("system_variety", TableDescription = "品种表")]
public class VarietyEntity
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnDescription = "主键")]
public int Id { get; set; }
[SugarColumn(ColumnDescription = "品种代码")]
public string Code { get; set; }
[SugarColumn(ColumnDescription = "Lot")]
public int Lot { get; set; }
[SugarColumn(ColumnDescription = "规格")]
public string Specifications { get; set; }
[SugarColumn(ColumnDescription = "纸管内径")]
public int InnerDiameter { get; set; }
[SugarColumn(ColumnDescription = "纸管外径")]
public int OuterDiameter { get; set; }
[SugarColumn(ColumnDescription = "纱直径")]
public int YarnDiameter { get; set; }
[SugarColumn(ColumnDescription = "纸筒高度")]
public int PaperTubeHeight { get; set; }
[SugarColumn(ColumnDescription = "纱丝厚度")]
public int YarnThickness { get; set; }
[SugarColumn(ColumnDescription = "单筒重量")]
public double SingleWeight { get; set; }
[SugarColumn(ColumnDescription = "码垛层数")]
public int StackingLayers { get; set; }
[SugarColumn(ColumnDescription = "总数量")]
public int TotalCount { get; set; }
[SugarColumn(ColumnDescription = "中间蜂窝板ID")]
public int MiddlePalletId { get; set; }
[SugarColumn(ColumnDescription = "上下蜂窝板ID")]
public int TopAndBottomPalletId { get; set; }
[SugarColumn(ColumnDescription = "托盘ID")]
public int TrayId { get; set; }
[SugarColumn(ColumnDescription = "垛头尺寸")]
public string? StackHeadSpec { get; set; }
[SugarColumn(ColumnDescription = "垛头数量")]
public int? StackHeadCount { get; set; }
[SugarColumn(ColumnDescription = "纸托Id")]
public int? PaperTrayId { get; set; }
[SugarColumn(ColumnDescription = "是否需要纸箱")]
public bool HasBox { get; set; }
[SugarColumn(ColumnDescription = "是否需要顶板")]
public NeedType NeedTopBoard { get; set; }
[SugarColumn(ColumnDescription = "是否需要护角")]
public NeedType NeedAngleBeam { get; set; }
[SugarColumn(ColumnDescription = "是否需要打包带")]
public NeedType NeedPackStrap { get; set; }
[SugarColumn(ColumnDescription = "是否需要缠膜")]
public NeedType NeedFilmWrapping { get; set; }
[SugarColumn(ColumnDescription = "是否需要覆膜")]
public NeedType NeedFilmCoating { get; set; }
[SugarColumn(ColumnDescription = "主标签数量")]
public int MasterLabelCount { get; set; }
[SugarColumn(ColumnDescription = "副标签数量")]
public int SubLabelCount { get; set; }
}

View File

@ -0,0 +1,17 @@
using System.ComponentModel;
namespace Seyounth.Hyosung.Data.Models;
public enum NeedType
{
[Description("需要")] Need,
[Description("不需要")] NotNeed,
[Description("单号需要")] OddNeed,
[Description("双号需要")] EvenNeed
}
public class NeedTypeEnumItem
{
public NeedType Value { get; set; }
public string Description { get; set; }
}

View File

@ -0,0 +1,5 @@
using Seyounth.Hyosung.Data.Entities;
namespace Seyounth.Hyosung.Data.Models;
public class Pallet : PalletEntity;

View File

@ -0,0 +1,19 @@
namespace Seyounth.Hyosung.Data.Models;
public enum PalletType
{
/// <summary>
/// 纸板托盘
/// </summary>
Paper=0,
/// <summary>
/// 胶合板托盘
/// </summary>
Plywood = 1,
/// <summary>
/// 木板托盘
/// </summary>
Wood = 2
}

View File

@ -0,0 +1,18 @@
namespace Seyounth.Hyosung.Data.Models.Plc;
public class PackLineOption
{
public int HeadCount { get; set; }
public bool HasBox { get; set; }
public bool IsTop { get; set; }
public bool IsPack { get; set; }
public bool IsFilm { get; set; }
public bool IsLam { get; set; }
}

View File

@ -0,0 +1,10 @@
namespace Seyounth.Hyosung.Data.Models.Plc;
/// <summary>
/// Plc侧整垛信息
/// </summary>
public class PlcStackInfo
{
public string TrayCode { get; set; }
}

View File

@ -0,0 +1,12 @@
namespace Seyounth.Hyosung.Data.Models.Plc;
public class PlcStackingInfo
{
public string TrayCode { get; set; }
public List<string> YarnCode { get; set; } = new List<string>();
public int YarnCount { get; set; }
public int TotalYarnCount { get; set; }
}

View File

@ -0,0 +1,84 @@
using Seyounth.Hyosung.Data.Entities;
namespace Seyounth.Hyosung.Data.Models;
public class Tray
{
public int Id { get; set; }
public string TrayCode { get; set; }
public int VarietyId { get; set; }
public int? ControlNo { get; set; } = null;
public DateTime CreateTime { get; set; }
public DateTime? FinishTime { get; set; }
public bool IsEven { get; set; }
public string? Grade { get; set; }
public string? Type { get; set; }
public string? DenFila { get; set; }
public string? DtexFila { get; set; }
public int? Unit { get; set; }
public double NetWeight { get; set; }
public double GrossWeight { get; set; }
public int? StackHeight { get; set; }
public int? AgvBinId { get; set; }
public TrayEntity ToEntity()
{
return new TrayEntity()
{
Id = Id,
TrayCode = TrayCode,
VarietyId = VarietyId,
ControlNo = ControlNo,
FinishTime = FinishTime,
StackHeight = StackHeight,
IsEven = IsEven,
GrossWeight = GrossWeight,
NetWeight = NetWeight,
CreateTime = CreateTime,
DenFila = DenFila,
DtexFila = DtexFila,
Grade = Grade,
Type = Type,
Unit = Unit,
AgvBinId = AgvBinId
};
}
public static Tray FromEntity(TrayEntity entity)
{
return new Tray()
{
Id = entity.Id,
TrayCode = entity.TrayCode,
VarietyId = entity.VarietyId,
ControlNo = entity.ControlNo,
StackHeight = entity.StackHeight,
FinishTime = entity.FinishTime,
IsEven = entity.IsEven,
GrossWeight = entity.GrossWeight,
NetWeight = entity.NetWeight,
CreateTime = entity.CreateTime,
DenFila = entity.DenFila,
DtexFila = entity.DtexFila,
Grade = entity.Grade,
Type = entity.Type,
Unit = entity.Unit,
AgvBinId = entity.AgvBinId
};
}
}

View File

@ -0,0 +1,179 @@
using Seyounth.Hyosung.Data.Entities;
namespace Seyounth.Hyosung.Data.Models;
public class Variety
{
public int Id { get; set; }
public string Code { get; set; }
public int Lot { get; set; }
public int YarnCarType { get; set; }
public int YarnCarSide { get; set; }
public string Specifications { get; set; }
public int InnerDiameter { get; set; }
public int OuterDiameter { get; set; }
public int YarnDiameter { get; set; }
public int PaperTubeHeight { get; set; }
public int YarnThickness { get; set; }
public double SingleWeight { get; set; }
public int StackingLayers { get; set; }
public int TotalCount { get; set; }
public Pallet MiddlePallet { get; set; }
public Pallet TopAndBottomPallet { get; set; }
public Pallet Tray { get; set; }
public string? StackHeadSpec { get; set; }
public int? StackHeadCount { get; set; }
public Pallet? PaperTray { get; set; }
public bool HasBox { get; set; }
public NeedType NeedTopBoard { get; set; }
public NeedType NeedAngleBeam { get; set; }
public NeedType NeedPackStrap { get; set; }
public NeedType NeedFilmWrapping { get; set; }
public NeedType NeedFilmCoating { get; set; }
public int MasterLabelCount { get; set; }
public int SubLabelCount { get; set; }
public bool IsTurn { get; set; }
public static Variety Create(VarietyEntity entity, List<PalletEntity> pallets)
{
var variety = new Variety()
{
Id = entity.Id,
Code = entity.Code,
Lot = entity.Lot,
Specifications = entity.Specifications,
InnerDiameter = entity.InnerDiameter,
OuterDiameter = entity.OuterDiameter,
YarnDiameter = entity.YarnDiameter,
PaperTubeHeight = entity.PaperTubeHeight,
YarnThickness = entity.YarnThickness,
SingleWeight = entity.SingleWeight,
StackingLayers = entity.StackingLayers,
TotalCount = entity.TotalCount,
StackHeadSpec = entity.StackHeadSpec,
StackHeadCount = entity.StackHeadCount,
NeedTopBoard = entity.NeedTopBoard,
NeedAngleBeam = entity.NeedAngleBeam,
NeedPackStrap = entity.NeedPackStrap,
NeedFilmWrapping = entity.NeedFilmWrapping,
NeedFilmCoating = entity.NeedFilmCoating,
MasterLabelCount = entity.MasterLabelCount,
SubLabelCount = entity.SubLabelCount,
MiddlePallet = (Pallet)pallets.First(x => x.Id == entity.MiddlePalletId),
TopAndBottomPallet = (Pallet)pallets.First(x => x.Id == entity.TopAndBottomPalletId),
Tray = (Pallet)pallets.First(x => x.Id == entity.TrayId),
HasBox = entity.HasBox
};
if (entity.PaperTrayId != null && entity.PaperTrayId != 0)
variety.PaperTray = (Pallet)pallets.First(x => x.Id == entity.PaperTrayId);
return variety;
}
public VarietyEntity ToEntity()
{
var entity = new VarietyEntity()
{
Id = Id,
Code = Code,
Lot = Lot,
Specifications = Specifications,
InnerDiameter = InnerDiameter,
OuterDiameter = OuterDiameter,
YarnDiameter = YarnDiameter,
PaperTubeHeight = PaperTubeHeight,
YarnThickness = YarnThickness,
SingleWeight = SingleWeight,
StackingLayers = StackingLayers,
TotalCount = TotalCount,
StackHeadSpec = StackHeadSpec,
StackHeadCount = StackHeadCount,
PaperTrayId = PaperTray?.Id,
NeedTopBoard = NeedTopBoard,
NeedAngleBeam = NeedAngleBeam,
NeedPackStrap = NeedPackStrap,
NeedFilmWrapping = NeedFilmWrapping,
NeedFilmCoating = NeedFilmCoating,
MasterLabelCount = MasterLabelCount,
SubLabelCount = SubLabelCount,
MiddlePalletId = MiddlePallet.Id,
TopAndBottomPalletId = TopAndBottomPallet.Id,
TrayId = Tray.Id,
HasBox = HasBox,
};
return entity;
}
public short[] ToVarietyPlcData()
{
List<short> ls = new List<short>();
ls.Add((short)YarnCarSide);
ls.Add((short)YarnCarType);
ls.Add((short)InnerDiameter);
ls.Add((short)OuterDiameter);
ls.Add((short)YarnDiameter);
ls.Add((short)PaperTubeHeight);
ls.Add((short)YarnThickness);
ls.Add((short)Tray.Type);
ls.Add((short)Tray.Length);
ls.Add((short)Tray.Width);
ls.Add((short)Tray.Height);
if (PaperTray is null)
{
ls.Add(0);
ls.Add(0);
ls.Add(0);
ls.Add(0);
}
else
{
ls.Add(1);
ls.Add((short)PaperTray.Length);
ls.Add((short)PaperTray.Width);
ls.Add((short)PaperTray.Height);
}
ls.Add((short)TopAndBottomPallet.HoleCount);
ls.Add((short)(TopAndBottomPallet.IsBigHole.Value ? 1 : 2));
ls.Add((short)TopAndBottomPallet.Length);
ls.Add((short)TopAndBottomPallet.Width);
ls.Add((short)TopAndBottomPallet.Height);
ls.Add((short)MiddlePallet.HoleCount);
ls.Add((short)(MiddlePallet.IsBigHole.Value ? 1 : 2));
ls.Add((short)MiddlePallet.Length);
ls.Add((short)MiddlePallet.Width);
ls.Add((short)MiddlePallet.Height);
ls.Add((short)(IsTurn ? 1 : 2));
ls.Add((short)TotalCount);
ls.Add((short)StackingLayers);
return ls.ToArray();
}
}

View File

@ -0,0 +1,143 @@
using Seyounth.Core.Extensions;
using Seyounth.Hyosung.Data.Entities;
namespace Seyounth.Hyosung.Data.Models;
public class Yarn
{
public int Id { get; set; }
public string QrCode { get; set; }
public string ScanCode { get; set; }
public int Lot { get; set; }
public string? DenFila { get; set; }
public string? DtexFila { get; set; }
public string WorkShift { get; set; } = "NoData";
public string Machine { get; set; } = "NoData";
public int VarietyId { get; set; }
public DateTime ScanTime { get; set; }
public string ProduceTime { get; set; }
public bool IsFinished { get; set; } = false;
public int? TrayId { get; set; }
public DateTime? StackTime { get; set; }
public DateTime? StorageTime { get; set; }
public static Yarn? Create(string qrCode, int varietyId)
{
try
{
Yarn yarn;
if (!qrCode.Contains('\n'))
{
var parts = qrCode.Split(' ');
yarn = new Yarn()
{
QrCode = qrCode,
Lot = int.Parse(parts[0].Replace("Lot:", "")),
Machine = parts[2],
ProduceTime = parts[3],
ScanTime = DateTime.Now,
VarietyId = varietyId,
ScanCode = DateTime.Now.ToTimestamp().ToString(),
TrayId = null
};
yarn.WorkShift = parts[1] switch
{
"0" => "早班",
"1" => "中班",
"2" => "晚班",
_ => yarn.WorkShift
};
return yarn;
}
else
{
var parts = qrCode.Split('\n');
yarn = new Yarn()
{
QrCode = qrCode,
Lot = int.Parse(parts[0].Replace("Lot:", "")),
DenFila = parts[1],
DtexFila = parts[2],
ProduceTime = parts[3],
Machine = parts[4],
ScanTime = DateTime.Now,
VarietyId = varietyId,
TrayId = null,
ScanCode = DateTime.Now.ToTimestamp().ToString().PadLeft(10, '0'),
};
yarn.WorkShift = parts[5] switch
{
"0" => "早班",
"1" => "中班",
"2" => "晚班",
_ => yarn.WorkShift
};
return yarn;
}
}
catch (Exception e)
{
return null;
}
}
public static Yarn FromEntity(ScannedYarnEntity entity)
{
return new Yarn
{
Id = entity.Id,
ScanCode = entity.ScanCode,
DenFila = entity.DenFila,
DtexFila = entity.DtexFila,
IsFinished = entity.IsFinished,
Lot = entity.Lot,
Machine = entity.Machine,
ProduceTime = entity.ProduceTime,
QrCode = entity.QrCode,
ScanTime = entity.ScanTime,
VarietyId = entity.VarietyId,
WorkShift = entity.WorkShift,
TrayId = entity.TrayId,
StorageTime = entity.StorageTime,
StackTime = entity.StackTime
};
}
public ScannedYarnEntity ToEntity()
{
return new ScannedYarnEntity
{
Id = Id,
ScanCode = ScanCode,
DenFila = DenFila,
DtexFila = DtexFila,
IsFinished = IsFinished,
Lot = Lot,
Machine = Machine,
ProduceTime = ProduceTime,
QrCode = QrCode,
ScanTime = ScanTime,
VarietyId = VarietyId,
WorkShift = WorkShift,
TrayId = TrayId,
StackTime = StackTime,
StorageTime = StorageTime
};
}
}

View File

@ -0,0 +1,7 @@
using SqlSugar;
namespace Seyounth.Hyosung.Data.Repositories;
public interface IRepository<T> : ISimpleClient<T> where T : class, new()
{
}

View File

@ -0,0 +1,11 @@
using SqlSugar;
namespace Seyounth.Hyosung.Data.Repositories;
public class Repository<T> : SimpleClient<T>, IRepository<T> where T : class, new()
{
public Repository(ISqlSugarClient db)
{
base.Context = db;
}
}

View File

@ -0,0 +1,49 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Seyounth.Hyosung.Data.Entities;
using Seyounth.Hyosung.Data.Repositories;
using Seyounth.Hyosung.Data.Services;
using Seyounth.Hyosung.Data.Services.Hyosung;
using SqlSugar;
namespace Seyounth.Hyosung.Data;
public static class ServiceExtensions
{
public static IServiceCollection AddHyosungData(this IServiceCollection services,
ConfigurationManager configuration)
{
var connectionString = configuration.GetConnectionString("DefaultConnection");
services.AddSingleton<ISqlSugarClient>(s =>
{
SqlSugarScope sqlSugar = new SqlSugarScope(new ConnectionConfig()
{
DbType = DbType.SqlServer,
ConnectionString = connectionString,
IsAutoCloseConnection = true,
}
);
return sqlSugar;
});
services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
services.AddSingleton<IVarietyService, VarietyService>();
services.AddSingleton<IYarnService, YarnService>();
services.AddSingleton<ITrayService, TrayService>();
services.AddSingleton<IAgvBinService, AgvBinService>();
services.AddSingleton<IDictService, DictService>();
services.AddSingleton<IHyosungWmsService, HyosungWmsService>();
return services;
}
public static void UseHyosungData(this IServiceProvider provider)
{
var db = provider.GetRequiredService<ISqlSugarClient>();
db.DbMaintenance.CreateDatabase();
db.CodeFirst.InitTables(typeof(VarietyEntity),
typeof(PalletEntity),
typeof(ScannedYarnEntity),
typeof(TrayEntity),
typeof(AgvBinEntity),
typeof(DictEntity));
}
}

View File

@ -0,0 +1,45 @@
using Microsoft.Extensions.DependencyInjection;
using Seyounth.Hyosung.Data.Entities;
using Seyounth.Hyosung.Data.Repositories;
namespace Seyounth.Hyosung.Data.Services;
public class AgvBinService : IAgvBinService
{
private readonly List<AgvBinEntity> _cache;
private readonly IRepository<AgvBinEntity> repository;
public AgvBinService(IServiceProvider provider)
{
repository = provider.CreateScope().ServiceProvider.GetRequiredService<IRepository<AgvBinEntity>>();
_cache = repository.GetList();
}
public async Task<AgvBinEntity> GetAvailableBin(int height)
{
if (height < 180)
{
return _cache
.Where(x =>
x is { CtnrType: 1, IsFree: true } ||
x is { CtnrType: 2, IsFree: true } &&
_cache.Any(y =>
y is { CtnrType: 1, IsFree: false } && y.BinCode == x.BinCode &&
y is { Height: < 180 })
)
.OrderByDescending(x => x.CtnrType)
.ThenBy(x => x.Sort)
.First();
}
return _cache.Where(a => a is { IsFree: true }).OrderBy(a => a.CtnrType).First();
}
public Task BindAsync(AgvBinEntity entity)
{
entity.IsFree = false;
_cache.First(e => e.Id == entity.Id).IsFree = false;
return repository.UpdateAsync(entity);
}
}

View File

@ -0,0 +1,31 @@
using Microsoft.Extensions.DependencyInjection;
using Seyounth.Hyosung.Data.Entities;
using Seyounth.Hyosung.Data.Repositories;
using SqlSugar;
namespace Seyounth.Hyosung.Data.Services;
public class DictService : IDictService
{
private readonly IRepository<DictEntity> _repository;
private readonly List<DictEntity> _cache;
public DictService(IServiceProvider provider)
{
_repository = provider.CreateScope()
.ServiceProvider.GetRequiredService<IRepository<DictEntity>>();
_cache = _repository.GetList();
}
public async Task<string> GetKeyAsync(string type, string name)
{
return _cache.FirstOrDefault(d => d.Type == type && d.Value == name)?.Value ?? "";
}
public async Task<List<DictEntity>> GetDictsByTypeAsync(string type)
{
return _cache.Where(d => d.Type == type).ToList();
}
}

View File

@ -0,0 +1,38 @@
using SqlSugar;
namespace Seyounth.Hyosung.Data.Services.Hyosung.Entities;
[SugarTable("LABEL_RESULT")]
public class LabelResult
{
public int BE_ID { get; set; }
public string BAR_CODE { get; set; }
public string ITEM_CODE { get; set; }
public string LABEL_ID { get; set; }
public string WMS_UOM { get; set; }
public string ERP_UOM { get; set; }
public string MFG_DATE { get; set; }
public decimal NET_WEIGHT { get; set; }
public double GROSS_WEIGHT { get; set; }
public string MFG_LINE { get; set; }
public string GRADE { get; set; }
public string LOT { get; set; }
public string BOX_NO { get; set; }
public string DENIER { get; set; }
public string FILA { get; set; }
public string CUSTOMER_NAME { get; set; }
public string REMARKS { get; set; }
public string TRI_INTERFACE_YN { get; set; }
public string TRI_TYPE { get; set; }
public string COMMON_S1 { get; set; }
public string COMMON_S2 { get; set; }
public string COMMON_S3 { get; set; }
public string COMMON_S4 { get; set; }
public string COMMON_S5 { get; set; }
public string COMMON_N1 { get; set; }
public string TRI_YN { get; set; }
public string CREATED_BY { get; set; }
public string CREATED_ON { get; set; }
public string MODIFIED_BY { get; set; }
public string MODIFIED_ON { get; set; }
}

View File

@ -0,0 +1,32 @@
using SqlSugar;
namespace Seyounth.Hyosung.Data.Services.Hyosung.Entities;
/// <summary>
/// 晓星 控制号表
/// </summary>
public class MST_BOXNO_SEQ_NON_DATE
{
[SugarColumn(ColumnName = "LAST_NO", IsNullable = true)]
public int? LastNo { get; set; }
[SugarColumn(ColumnName = "BE_ID")] public string BeId { get; set; }
[SugarColumn(ColumnName = "ITEM_CODE")]
public string ItemCode { get; set; }
[SugarColumn(ColumnName = "CHECK_CHAR")]
public string CheckCode { get; set; }
[SugarColumn(ColumnName = "CREATED_ON", IsNullable = true)]
public DateTime CreatedTime { get; set; }
[SugarColumn(ColumnName = "MODIFIED_ON", IsNullable = true)]
public DateTime ModifiedTime { get; set; }
[SugarColumn(ColumnName = "CREATED_BY", IsNullable = true)]
public string CreatedBy { get; set; }
[SugarColumn(ColumnName = "MODIFIED_BY", IsNullable = true)]
public string ModifiedBy { get; set; }
}

View File

@ -0,0 +1,24 @@
namespace Seyounth.Hyosung.Data.Services.Hyosung.Entities;
public class MST_ITEM_2240_V
{
public string BE_ID { get; set; }
public string ITEM_CODE { get; set; }
public string TYPE { get; set; }
public string DEN_FILA { get; set; }
public string DTEX_FILA { get; set; }
public string LOTNO { get; set; }
public string GRADE { get; set; }
public int UNIT { get; set; }
public double NET_WEIGHT { get; set; }
public double GROSS_WEIGHT { get; set; }
}

View File

@ -0,0 +1,77 @@
using Seyounth.Hyosung.Data.Models;
using Seyounth.Hyosung.Data.Services.Hyosung.Entities;
using SqlSugar;
namespace Seyounth.Hyosung.Data.Services.Hyosung;
public class HyosungWmsService : IHyosungWmsService
{
private ISqlSugarClient _db = new SqlSugarClient(new ConnectionConfig
{
DbType = DbType.SqlServer,
ConnectionString =
$"Data Source=192.168.2.11;User Id=TY_ACP;Password=ty@_acp20y;database=HSWMS;Encrypt=True;TrustServerCertificate=True;Pooling=true;Min Pool Size=1",
IsAutoCloseConnection = true,
});
public async Task<int> GetControlNo(Variety variety, string grade)
{
var checkCode = $"02025{grade}{variety.Lot.ToString().Substring(1, 3)}";
var x = await _db.Queryable<MST_BOXNO_SEQ_NON_DATE>().Where(x =>
x.BeId == "2240" && x.ItemCode == variety.Code && x.CheckCode == checkCode).FirstAsync();
if (x?.LastNo is null)
return 1;
return x.LastNo.Value + 1;
}
public async Task<MST_ITEM_2240_V> GetItemInfoByItemCode(string itemCode)
{
return await _db.Queryable<MST_ITEM_2240_V>()
.FirstAsync(t => t.ITEM_CODE == itemCode);
}
public async Task UpdateControlNo(Variety variety, int controlNo)
{
var checkCode = $"02025{variety.Lot}";
if (controlNo is 1)
{
var entity = new MST_BOXNO_SEQ_NON_DATE()
{
BeId = "2240",
CheckCode = checkCode,
LastNo = 1,
CreatedBy = "seyounth",
CreatedTime = DateTime.Now,
ModifiedBy = "seyounth",
ModifiedTime = DateTime.Now,
ItemCode = variety.Code
};
await _db.Insertable(entity).ExecuteCommandAsync();
}
else
{
await _db.Updateable<MST_BOXNO_SEQ_NON_DATE>()
.SetColumns(i => i.LastNo == controlNo
&& i.ModifiedTime == DateTime.Now
&& i.ModifiedBy == "seyounth")
.Where(i => i.BeId == "2240" &&
i.ItemCode == variety.Code &&
i.CheckCode == checkCode).ExecuteCommandAsync();
}
}
public async Task<LabelResult> GetLabelResult(string itemCode, string lot, int controlNo)
{
string code = $"{itemCode.Trim()} {DateTime.Now.AddDays(0):yyMMdd}";
string code2 = $"{lot.Trim()}{controlNo.ToString().PadLeft(4, '0')}0";
// 使用 SqlSugar 进行查询
return await _db.Queryable<LabelResult>()
.Where(x =>
x.BAR_CODE.Substring(0, 24) == code &&
x.BAR_CODE.Substring(x.BAR_CODE.Length - 9, 9) == code2 &&
x.BE_ID == 2240
)
.FirstAsync();
}
}

View File

@ -0,0 +1,15 @@
using Seyounth.Hyosung.Data.Models;
using Seyounth.Hyosung.Data.Services.Hyosung.Entities;
namespace Seyounth.Hyosung.Data.Services.Hyosung;
public interface IHyosungWmsService
{
Task<int> GetControlNo(Variety variety, string grade);
Task<MST_ITEM_2240_V> GetItemInfoByItemCode(string itemCode);
Task UpdateControlNo(Variety variety, int controlNo);
Task<LabelResult> GetLabelResult(string itemCode,string lot,int controlNo);
}

View File

@ -0,0 +1,21 @@
using Seyounth.Hyosung.Data.Entities;
using Seyounth.Hyosung.Data.Models;
namespace Seyounth.Hyosung.Data.Services;
public interface IAgvBinService
{
/// <summary>
/// 获取可用的库位信息
/// </summary>
/// <param name="height"></param>
/// <returns></returns>
Task<AgvBinEntity> GetAvailableBin(int height);
/// <summary>
/// 绑定相应的库
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
Task BindAsync(AgvBinEntity entity);
}

View File

@ -0,0 +1,10 @@
using Seyounth.Hyosung.Data.Entities;
namespace Seyounth.Hyosung.Data.Services;
public interface IDictService
{
Task<string> GetKeyAsync(string type, string value);
Task<List<DictEntity>> GetDictsByTypeAsync(string type);
}

View File

@ -0,0 +1,45 @@
using Seyounth.Hyosung.Data.Models;
using Seyounth.Hyosung.Data.Services.Hyosung.Entities;
namespace Seyounth.Hyosung.Data.Services;
public interface ITrayService
{
/// <summary>
/// 生成一个新的托盘
/// </summary>
/// <param name="varietyId">品类ID</param>
/// <returns></returns>
Task<Tray> GeneraNewTray(int varietyId);
/// <summary>
/// 通过Code查找ID
/// </summary>
/// <param name="code"></param>
/// <returns></returns>
Task<int> GetIdByCode(string code);
/// <summary>
///
/// </summary>
/// <param name="code"></param>
/// <returns></returns>
Task<Tray> GetByCode(string code);
/// <summary>
/// 生成控制号
/// </summary>
/// <param name="trayCode"></param>
/// <returns></returns>
Task StorageAsync(string trayCode);
/// <summary>
/// 打印托盘
/// </summary>
/// <param name="trayCode"></param>
/// <param name="stackHeight"></param>
/// <param name="controlNo"></param>
/// <param name="itemInfo"></param>
/// <returns></returns>
Task PrintTrayAsync(string trayCode, int stackHeight, int controlNo, MST_ITEM_2240_V itemInfo);
}

View File

@ -0,0 +1,36 @@
using Seyounth.Hyosung.Data.Models;
namespace Seyounth.Hyosung.Data.Services;
public interface IVarietyService
{
/// <summary>
/// 通过品种代码获取品种信息
/// </summary>
/// <param name="code">品种代码</param>
/// <param name="layers">码垛层数</param>
/// <returns></returns>
Task<Variety?> GetVarietyByCodeAsync(string code, int? layers = null);
Task<Variety> GetById(int id);
/// <summary>
/// 添加品种信息
/// </summary>
/// <param name="variety"></param>
/// <returns></returns>
Task AddVarietyAsync(Variety variety);
/// <summary>
/// 获取所有托盘信息
/// </summary>
/// <returns></returns>
Task<List<Pallet>> GetPalletsAsync();
/// <summary>
/// 添加托盘信息
/// </summary>
/// <param name="pallet"></param>
/// <returns></returns>
Task AddPalletAsync(Pallet pallet);
}

View File

@ -0,0 +1,31 @@
using System.Collections.Concurrent;
using Seyounth.Hyosung.Data.Models;
namespace Seyounth.Hyosung.Data.Services;
public interface IYarnService
{
ConcurrentDictionary<string, Yarn> NoFinished { get; }
Task<Yarn?> AddYarnAsync(Yarn yarn);
Task<List<Yarn>> GetYarnsByTrayIdAsync(int trayId);
Task<Yarn> GetYarnByCodeAsync(string code);
/// <summary>
/// 完成指定纱
/// </summary>
/// <param name="yarnCode"></param>
/// <returns></returns>
Task FinishYarnAsync(string yarnCode);
/// <summary>
/// 绑定托盘号
/// </summary>
/// <param name="yarnCode"></param>
/// <param name="trayId"></param>
/// <returns></returns>
Task BindTrayAsync(string yarnCode, int trayId);
}

View File

@ -0,0 +1,79 @@
using System.Collections.Concurrent;
using Microsoft.Extensions.DependencyInjection;
using Seyounth.Hyosung.Data.Entities;
using Seyounth.Hyosung.Data.Models;
using Seyounth.Hyosung.Data.Repositories;
using Seyounth.Hyosung.Data.Services.Hyosung;
using Seyounth.Hyosung.Data.Services.Hyosung.Entities;
namespace Seyounth.Hyosung.Data.Services;
public class TrayService : ITrayService
{
private readonly ConcurrentDictionary<string, Tray> _cache = new();
private readonly IRepository<TrayEntity> _repository;
private readonly IHyosungWmsService _hyosungWmsService;
public TrayService(IServiceProvider provider, IHyosungWmsService hyosungWmsService)
{
_repository = provider.CreateScope().ServiceProvider.GetRequiredService<IRepository<TrayEntity>>();
var trays = _repository.GetList(t => t.ControlNo == null);
_hyosungWmsService = hyosungWmsService;
foreach (var tray in trays)
{
_cache.TryAdd(tray.TrayCode, Tray.FromEntity(tray));
}
}
public async Task<Tray> GeneraNewTray(int varietyId)
{
var tray = new Tray()
{
TrayCode = DateTime.Now.ToString("yyMMddHHmmss"),
VarietyId = varietyId,
CreateTime = DateTime.Now
};
var count = await _repository.CountAsync(t => t.VarietyId == tray.VarietyId);
tray.IsEven = count % 2 == 0;
var identity = await _repository.InsertReturnIdentityAsync(tray.ToEntity());
tray.Id = identity;
_cache.TryAdd(tray.TrayCode, tray);
return tray;
}
public async Task<int> GetIdByCode(string code)
{
return _cache[code].Id;
}
public async Task<Tray> GetByCode(string code)
{
return Tray.FromEntity(await _repository.GetSingleAsync(t => t.TrayCode == code));
}
public Task StorageAsync(string trayCode, int stackHeight, int controlNo, MST_ITEM_2240_V itemInfo)
{
throw new NotImplementedException();
}
public async Task PrintTrayAsync(string trayCode, int stackHeight, int controlNo, MST_ITEM_2240_V itemInfo)
{
var tray = _cache[trayCode];
tray.ControlNo = controlNo;
tray.StackHeight = stackHeight;
tray.Grade = itemInfo.GRADE;
tray.Type = itemInfo.TYPE;
tray.DenFila = itemInfo.DEN_FILA;
tray.DtexFila = itemInfo.DTEX_FILA;
tray.Unit = itemInfo.UNIT;
tray.NetWeight = itemInfo.NET_WEIGHT;
tray.GrossWeight = itemInfo.GROSS_WEIGHT;
await _repository.UpdateAsync(tray.ToEntity());
_cache.Remove(tray.TrayCode, out _);
}
public async Task StorageAsync(string trayCode)
{
}
}

View File

@ -0,0 +1,61 @@
using System.Collections.Concurrent;
using Microsoft.Extensions.DependencyInjection;
using Seyounth.Hyosung.Data.Entities;
using Seyounth.Hyosung.Data.Models;
using Seyounth.Hyosung.Data.Repositories;
namespace Seyounth.Hyosung.Data.Services;
public class VarietyService : IVarietyService
{
private readonly IRepository<VarietyEntity> _varietyRepository;
private readonly IRepository<PalletEntity> _palletRepository;
private readonly ConcurrentBag<VarietyEntity> _varietiesCache;
private readonly ConcurrentBag<PalletEntity> _palletsCache;
public VarietyService(IServiceProvider provider)
{
try
{
_varietyRepository = provider.CreateScope().ServiceProvider.GetRequiredService<IRepository<VarietyEntity>>();
_palletRepository = provider.CreateScope().ServiceProvider.GetRequiredService<IRepository<PalletEntity>>();
_varietiesCache = new ConcurrentBag<VarietyEntity>(_varietyRepository.GetList());
_palletsCache = new ConcurrentBag<PalletEntity>(_palletRepository.GetList());
}catch(Exception e)
{
Console.WriteLine(e.Message);
}
}
public async Task<Variety?> GetVarietyByCodeAsync(string code, int? layers = null)
{
var entity = layers != null
? _varietiesCache.FirstOrDefault(p => p.Code == code && p.StackingLayers == layers)
: _varietiesCache.FirstOrDefault(v => v.Code == code);
return entity is null ? null : Variety.Create(entity, _palletsCache.ToList());
}
public Task<Variety> GetById(int id)
{
var entity = _varietiesCache.FirstOrDefault(p => p.Id == id);
return Task.FromResult(Variety.Create(entity, _palletsCache.ToList()));
}
public async Task AddVarietyAsync(Variety variety)
{
var entity = await _varietyRepository.InsertReturnEntityAsync(variety.ToEntity());
_varietiesCache.Add(entity);
}
public async Task<List<Pallet>> GetPalletsAsync()
{
return _palletsCache.Select(p => (Pallet)p).ToList();
}
public async Task AddPalletAsync(Pallet pallet)
{
var entity = await _palletRepository.InsertReturnEntityAsync(pallet);
_palletsCache.Add(entity);
}
}

View File

@ -0,0 +1,63 @@
using System.Collections.Concurrent;
using Microsoft.Extensions.DependencyInjection;
using Seyounth.Hyosung.Data.Entities;
using Seyounth.Hyosung.Data.Models;
using Seyounth.Hyosung.Data.Repositories;
namespace Seyounth.Hyosung.Data.Services;
public class YarnService : IYarnService
{
private readonly IRepository<ScannedYarnEntity> _yarnRepository;
public YarnService(IServiceProvider provider)
{
_yarnRepository = provider.CreateScope().ServiceProvider.GetRequiredService<IRepository<ScannedYarnEntity>>();
NoFinished = new ConcurrentDictionary<string, Yarn>();
var yarns = _yarnRepository.GetList(y => !y.IsFinished);
foreach (var yarn in yarns)
{
NoFinished.TryAdd(yarn.ScanCode, Yarn.FromEntity(yarn));
}
}
public ConcurrentDictionary<string, Yarn> NoFinished { get; }
public async Task<Yarn?> AddYarnAsync(Yarn yarn)
{
var id = await _yarnRepository.InsertReturnIdentityAsync(yarn.ToEntity());
yarn.Id = id;
NoFinished.TryAdd(yarn.ScanCode, yarn);
return yarn;
}
public async Task<List<Yarn>> GetYarnsByTrayIdAsync(int trayId)
{
return (await _yarnRepository.GetListAsync(y => y.TrayId == trayId))
.Select(Yarn.FromEntity).ToList();
}
public async Task<Yarn> GetYarnByCodeAsync(string code)
{
return NoFinished[code];
}
public async Task FinishYarnAsync(string yarnCode)
{
var yarn = NoFinished[yarnCode];
yarn.IsFinished = true;
await _yarnRepository.UpdateAsync(yarn.ToEntity());
NoFinished.TryRemove(yarnCode, out _);
}
public async Task BindTrayAsync(string yarnCode, int trayId)
{
var yarn = NoFinished[yarnCode];
yarn.TrayId = trayId;
yarn.StackTime = DateTime.Now;
yarn.IsFinished = true;
yarn.IsFinished = true;
await _yarnRepository.UpdateAsync(yarn.ToEntity());
NoFinished.TryRemove(yarnCode, out _);
}
}

View File

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="McProtocol" Version="1.2.5" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.3" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.3" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.182" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Seyounth.Core\Seyounth.Core.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,212 @@
using System.Collections.Concurrent;
using Microsoft.Extensions.Logging;
using Seyounth.Hyosung.Core.Agv;
using Seyounth.Hyosung.Core.Plc;
using Seyounth.Hyosung.Core.Printer;
using Seyounth.Hyosung.Core.Scanner;
using Seyounth.Hyosung.Data.Models;
using Seyounth.Hyosung.Data.Models.Plc;
using Seyounth.Hyosung.Data.Services;
using Seyounth.Hyosung.Data.Services.Hyosung;
namespace Seyounth.Hyosung.Runtime;
public class HyosungRuntime(
ILogger<HyosungRuntime> logger,
IHyosungPlcService hyosungPlcService,
IHyosungScannerService hyosungScannerService,
IHyosungPrinter printer,
IYarnService yarnService,
ITrayService trayService,
IVarietyService varietyService,
IHyosungAgvService hyosungAgvService,
IHyosungWmsService hyosungWmsService) : IHyosungRuntime
{
public async Task StartAsync(CancellationToken token)
{
//启动扫码服务
await hyosungScannerService.StartAsync(token);
await printer.StartAsync(token);
//最后启动PLC服务
hyosungPlcService.OnPlcRequestScanProduct += OnPlcRequestScanProduct;
hyosungPlcService.OnPlcRequestScanFixture += OnPlcRequestScanFixture;
hyosungPlcService.OnPlcRequestLeavingProductionLine += OnPlcRequestLeavingProductionLine;
hyosungPlcService.OnPlcNeedNewTrayCode += OnPlcNeedNewTrayCode;
hyosungPlcService.OnPlcPutCompleted += OnPlcPutCompleted;
hyosungPlcService.OnPlcRequestPackLineOption += OnPlcRequestPackLineOption;
hyosungPlcService.OnRequestPrintLabel += OnPlcRequestPrintLabel;
await hyosungPlcService.StartAsync(token);
}
public async Task StopAsync(CancellationToken token)
{
//先停止扫码服务
// await hyosungScannerService.StopAsync(token);
await printer.StopAsync(token);
//先停止PLC服务
//解绑相关事件
hyosungPlcService.OnPlcRequestScanProduct -= OnPlcRequestScanProduct;
hyosungPlcService.OnPlcRequestScanFixture -= OnPlcRequestScanFixture;
hyosungPlcService.OnPlcRequestLeavingProductionLine -= OnPlcRequestLeavingProductionLine;
hyosungPlcService.OnPlcNeedNewTrayCode -= OnPlcNeedNewTrayCode;
hyosungPlcService.OnPlcPutCompleted -= OnPlcPutCompleted;
await hyosungPlcService.StopAsync();
}
public async Task SendVarietyToPlcAsync(Variety variety)
{
await hyosungPlcService.WriteVarietyAsync(variety);
logger.LogInformation($"send variety to plc success: {variety.Id}");
}
/// <summary>
/// 处理PLC请求扫描治具事件
/// </summary>
/// <param name="fixtureId">治具ID</param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
private async Task OnPlcRequestScanFixture(int fixtureId)
{
var fix = await hyosungScannerService.ScanFixtureAsync(fixtureId);
if (string.IsNullOrEmpty(fix))
{
await hyosungPlcService.WriteScanFixtureResultAsync(fixtureId, false);
logger.LogInformation($"scan fixture{fixtureId} fail");
}
else
{
await hyosungPlcService.WriteScanFixtureResultAsync(fixtureId, true, (short)Convert.ToInt32(fix));
logger.LogInformation($"scan fixture{fixtureId} success: {fix}");
}
}
/// <summary>
/// 处理PLC请求扫描纱事件
/// </summary>
/// <param name="varietyId"></param>
private async Task OnPlcRequestScanProduct(int varietyId)
{
logger.LogInformation($"plc request scan yarn qrcode");
var yarn = await hyosungScannerService.ScanYarnAsync(varietyId);
if (yarn is null)
{
await hyosungPlcService.WriteScanYarnResultAsync(false);
logger.LogInformation($"scan yarn fail");
return;
}
await yarnService.AddYarnAsync(yarn);
await hyosungPlcService.WriteScanYarnResultAsync(true, (short)varietyId, yarn.ScanCode);
logger.LogInformation($"scan yarn {yarn.ScanCode} success: qrcode[{yarn.QrCode}]");
}
/// <summary>
/// 处理PLC请求下线事件
/// </summary>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
private async Task OnPlcRequestLeavingProductionLine(PlcStackInfo info)
{
//使托盘完成
await trayService.StorageAsync(info.TrayCode);
await hyosungAgvService.StorageAsync(info.TrayCode);
//标志下线已完成
await hyosungPlcService.LeaveCompletedAsync();
}
/// <summary>
/// 处理Plc需要新的托盘号事件
/// </summary>
/// <param name="index"></param>
/// <param name="varietyId"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
private async Task OnPlcNeedNewTrayCode(int index, int varietyId)
{
var tray = await trayService.GeneraNewTray(varietyId);
await hyosungPlcService.WriteTrayCodeAsync(index, tray.TrayCode);
}
/// <summary>
/// PLC码垛一次完成
/// </summary>
/// <param name="arg"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
private async Task OnPlcPutCompleted(PlcStackingInfo arg)
{
foreach (var yarnCode in arg.YarnCode)
{
await yarnService.BindTrayAsync(yarnCode, await trayService.GetIdByCode(arg.TrayCode));
}
await hyosungPlcService.WriteReceivedYarnCountAsync(arg.YarnCode.Count);
}
/// <summary>
/// 处理PLC请求打包线配置事件
/// </summary>
/// <param name="arg"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
private async Task OnPlcRequestPackLineOption(string arg)
{
var tray = await trayService.GetByCode(arg);
var variety = await varietyService.GetById(tray.VarietyId);
var option = new PackLineOption()
{
HeadCount = variety.StackHeadCount ?? 0,
HasBox = variety.HasBox,
IsTop = variety.NeedTopBoard is NeedType.Need or NeedType.NotNeed
? variety.NeedTopBoard == NeedType.Need
: tray.IsEven && variety.NeedTopBoard == NeedType.EvenNeed,
IsPack = variety.NeedPackStrap is NeedType.Need or NeedType.NotNeed
? variety.NeedPackStrap == NeedType.Need
: tray.IsEven && variety.NeedPackStrap == NeedType.EvenNeed,
IsFilm = variety.NeedFilmWrapping is NeedType.Need or NeedType.NotNeed
? variety.NeedFilmWrapping == NeedType.Need
: tray.IsEven && variety.NeedFilmWrapping == NeedType.EvenNeed,
IsLam = variety.NeedFilmCoating is NeedType.Need or NeedType.NotNeed
? variety.NeedFilmCoating == NeedType.Need
: tray.IsEven && variety.NeedFilmCoating == NeedType.EvenNeed,
};
await hyosungPlcService.WritePackLineOptionAsync(option);
}
/// <summary>
/// 处理贴标站请求贴标事件
/// </summary>
/// <param name="arg1"></param>
/// <param name="arg2"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
private async Task OnPlcRequestPrintLabel(int arg1, string trayCode, int height)
{
try
{
if (arg1 == 1)
{
var tray = await trayService.GetByCode(trayCode);
var variety = await varietyService.GetById(tray.VarietyId);
var mod = await hyosungWmsService.GetItemInfoByItemCode(variety.Code);
var grade = "1";
if (mod.GRADE != "AA") grade = mod.GRADE;
var controlNo = await hyosungWmsService.GetControlNo(variety, grade);
await trayService.PrintTrayAsync(trayCode, height, controlNo, mod);
await printer.PrintAsync(1, trayCode);
await hyosungWmsService.UpdateControlNo(variety, controlNo);
}
else
await printer.PrintAsync(1, trayCode);
await hyosungPlcService.WritePrintLabelResultAsync(arg1, true);
}
catch (Exception e)
{
await hyosungPlcService.WritePrintLabelResultAsync(arg1, false);
logger.LogError(e, "print label fail");
}
}
}

View File

@ -0,0 +1,26 @@
using Microsoft.Extensions.Hosting;
namespace Seyounth.Hyosung.Runtime;
public class HyosungWorker(IHyosungRuntime runtime) : BackgroundService
{
public override async Task StopAsync(CancellationToken cancellationToken)
{
await runtime.StopAsync(cancellationToken);
await base.StopAsync(cancellationToken);
}
public override async Task StartAsync(CancellationToken cancellationToken)
{
await runtime.StartAsync(cancellationToken);
await base.StartAsync(cancellationToken);
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (stoppingToken.IsCancellationRequested)
{
await Task.Delay(1000, stoppingToken);
}
}
}

View File

@ -0,0 +1,29 @@
using System.Collections.Concurrent;
using Seyounth.Hyosung.Data.Models;
namespace Seyounth.Hyosung.Runtime;
public interface IHyosungRuntime
{
/// <summary>
/// 启动运行
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
Task StartAsync(CancellationToken token);
/// <summary>
/// 停止运行
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
Task StopAsync(CancellationToken token);
/// <summary>
/// 发布品类信息到PLC
/// </summary>
/// <param name="variety"></param>
/// <returns></returns>
Task SendVarietyToPlcAsync(Variety variety);
}

View File

@ -0,0 +1,23 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Seyounth.Hyosung.Core;
using Seyounth.Hyosung.Data;
namespace Seyounth.Hyosung.Runtime;
public static class ServiceExtensions
{
public static IServiceCollection AddHyosung(this IServiceCollection services, ConfigurationManager configuration)
{
services.AddHyosungData(configuration);
services.AddHyosungServices(configuration);
services.AddHostedService<HyosungWorker>();
services.AddSingleton<IHyosungRuntime, HyosungRuntime>();
return services;
}
public static void UseHyosung(this IServiceProvider provider)
{
provider.UseHyosungData();
}
}

View File

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Seyounth.Hyosung.Core\Seyounth.Hyosung.Core.csproj" />
<ProjectReference Include="..\Seyounth.Hyosung.Data\Seyounth.Hyosung.Data.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.3" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.3" />
</ItemGroup>
</Project>

58
Seyounth.Hyosung.sln Normal file
View File

@ -0,0 +1,58 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Seyounth.Hyosung.Core", "Seyounth.Hyosung.Core\Seyounth.Hyosung.Core.csproj", "{B6FCBC79-2C82-4915-BE52-16F4F22F2650}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Seyounth.Hyosung.Data", "Seyounth.Hyosung.Data\Seyounth.Hyosung.Data.csproj", "{BC51516E-38D1-482C-913B-CE8F514CF978}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Seyounth.Hyosung.Runtime", "Seyounth.Hyosung.Runtime\Seyounth.Hyosung.Runtime.csproj", "{CB32CBA4-8760-490A-8E48-91CB10AD3965}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Seyounth.Core", "Seyounth.Core\Seyounth.Core.csproj", "{BC139001-2C26-4E95-982F-DA90DC0CFB4A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tester", "Tester", "{F94CF5F9-01E3-4159-BC91-1EC9D8112837}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HyosungDataTester", "HyosungDataTester\HyosungDataTester.csproj", "{6D6BC0D1-1460-42A7-8A47-81B22B2C7A07}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HyosungTester", "HyosungTester\HyosungTester.csproj", "{95193F01-653D-4664-84F3-1956994703D6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Seyounth.Hyosung", "Seyounth.Hyosung\Seyounth.Hyosung.csproj", "{16C5CC9B-FEA9-4B1E-805F-C6DBF5865DC0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B6FCBC79-2C82-4915-BE52-16F4F22F2650}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B6FCBC79-2C82-4915-BE52-16F4F22F2650}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B6FCBC79-2C82-4915-BE52-16F4F22F2650}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B6FCBC79-2C82-4915-BE52-16F4F22F2650}.Release|Any CPU.Build.0 = Release|Any CPU
{BC51516E-38D1-482C-913B-CE8F514CF978}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BC51516E-38D1-482C-913B-CE8F514CF978}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BC51516E-38D1-482C-913B-CE8F514CF978}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BC51516E-38D1-482C-913B-CE8F514CF978}.Release|Any CPU.Build.0 = Release|Any CPU
{CB32CBA4-8760-490A-8E48-91CB10AD3965}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CB32CBA4-8760-490A-8E48-91CB10AD3965}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CB32CBA4-8760-490A-8E48-91CB10AD3965}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CB32CBA4-8760-490A-8E48-91CB10AD3965}.Release|Any CPU.Build.0 = Release|Any CPU
{BC139001-2C26-4E95-982F-DA90DC0CFB4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BC139001-2C26-4E95-982F-DA90DC0CFB4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BC139001-2C26-4E95-982F-DA90DC0CFB4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BC139001-2C26-4E95-982F-DA90DC0CFB4A}.Release|Any CPU.Build.0 = Release|Any CPU
{6D6BC0D1-1460-42A7-8A47-81B22B2C7A07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6D6BC0D1-1460-42A7-8A47-81B22B2C7A07}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6D6BC0D1-1460-42A7-8A47-81B22B2C7A07}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6D6BC0D1-1460-42A7-8A47-81B22B2C7A07}.Release|Any CPU.Build.0 = Release|Any CPU
{95193F01-653D-4664-84F3-1956994703D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{95193F01-653D-4664-84F3-1956994703D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{95193F01-653D-4664-84F3-1956994703D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{95193F01-653D-4664-84F3-1956994703D6}.Release|Any CPU.Build.0 = Release|Any CPU
{16C5CC9B-FEA9-4B1E-805F-C6DBF5865DC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{16C5CC9B-FEA9-4B1E-805F-C6DBF5865DC0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{16C5CC9B-FEA9-4B1E-805F-C6DBF5865DC0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{16C5CC9B-FEA9-4B1E-805F-C6DBF5865DC0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{6D6BC0D1-1460-42A7-8A47-81B22B2C7A07} = {F94CF5F9-01E3-4159-BC91-1EC9D8112837}
{95193F01-653D-4664-84F3-1956994703D6} = {F94CF5F9-01E3-4159-BC91-1EC9D8112837}
EndGlobalSection
EndGlobal

22
Seyounth.Hyosung/App.xaml Normal file
View File

@ -0,0 +1,22 @@
<Application x:Class="Seyounth.Hyosung.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Seyounth.Hyosung"
DispatcherUnhandledException="OnDispatcherUnhandledException"
Exit="OnExit"
Startup="OnStartup">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/materialdesigntheme.dark.xaml" />
<ResourceDictionary
Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
<ResourceDictionary
Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.DeepPurple.xaml" />
<ResourceDictionary
Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Lime.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>

View File

@ -0,0 +1,68 @@
using System.Configuration;
using System.Data;
using System.IO;
using System.Reflection;
using System.Windows;
using System.Windows.Threading;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Seyounth.Hyosung.Core.Printer;
using Seyounth.Hyosung.Runtime;
using Seyounth.Hyosung.Services;
using Seyounth.Hyosung.ViewModels;
using Seyounth.Hyosung.Views;
using Seyounth.Hyosung.Views.Pages;
namespace Seyounth.Hyosung;
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
private static IHost _host;
public App()
{
var builder = Host
.CreateApplicationBuilder();
builder.Configuration.AddJsonFile("PrintTemp.json", true, true);
builder.Configuration.AddJsonFile("appsettings.json", true, true);
builder.Services.Configure<PrintTemp>(builder.Configuration.GetSection("Print"));
builder.Services.AddHostedService<ApplicationHostService>();
builder.Services.AddSingleton<MainWindow>();
builder.Services.AddSingleton<MainWindowViewModel>();
builder.Services.AddSingleton<VarietyPage>();
builder.Services.AddSingleton<VarietyViewModel>();
builder.Services.AddHyosung(builder.Configuration);
_host = builder.Build();
}
private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
var logger = _host.Services.GetRequiredService<ILogger<App>>();
logger.LogError(e.Exception, "Unhandled exception");
}
private async void OnExit(object sender, ExitEventArgs e)
{
await _host.StopAsync();
_host.Dispose();
}
private void OnStartup(object sender, StartupEventArgs e)
{
try
{
_host.Services.UseHyosung();
_host.StartAsync();
}catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}

View File

@ -0,0 +1,10 @@
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]

View File

@ -0,0 +1,40 @@
using System.Windows;
using Microsoft.Extensions.Hosting;
using Seyounth.Hyosung.Views;
namespace Seyounth.Hyosung.Services;
public class ApplicationHostService(IServiceProvider serviceProvider) : IHostedService
{
/// <summary>
/// Triggered when the application host is ready to start the service.
/// </summary>
/// <param name="cancellationToken">Indicates that the start process has been aborted.</param>
public async Task StartAsync(CancellationToken cancellationToken)
{
await HandleActivationAsync();
}
/// <summary>
/// Triggered when the application host is performing a graceful shutdown.
/// </summary>
/// <param name="cancellationToken">Indicates that the shutdown process should no longer be graceful.</param>
public async Task StopAsync(CancellationToken cancellationToken)
{
await Task.CompletedTask;
}
/// <summary>
/// Creates main window during activation.
/// </summary>
private async Task HandleActivationAsync()
{
if (!Application.Current.Windows.OfType<MainWindow>().Any())
{
Application.Current.MainWindow = serviceProvider.GetService(typeof(MainWindow)) as MainWindow;
Application.Current.MainWindow.Show();
}
await Task.CompletedTask;
}
}

View File

@ -0,0 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
<PackageReference Include="MaterialDesignThemes" Version="4.9.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Seyounth.Hyosung.Runtime\Seyounth.Hyosung.Runtime.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<Page Update="Views\MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<XamlRuntime>Wpf</XamlRuntime>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
</Project>

View File

@ -0,0 +1,23 @@
using System.Diagnostics.Metrics;
using System.Windows;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
namespace Seyounth.Hyosung.ViewModels;
public partial class MainWindowViewModel : ObservableObject
{
[ObservableProperty] private string _applicationTitle = "Hyosung - Seyounth Auto";
[RelayCommand]
private void OnExit()
{
Application.Current.Shutdown();
}
[RelayCommand]
private void OnMinimize()
{
Application.Current.MainWindow.WindowState = WindowState.Minimized;
}
}

View File

@ -0,0 +1,25 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Seyounth.Core.Extensions;
using Seyounth.Hyosung.Data.Entities;
using Seyounth.Hyosung.Data.Models;
namespace Seyounth.Hyosung.ViewModels;
public partial class VarietyViewModel : ObservableObject
{
[ObservableProperty] private List<VarietyEntity> _varieties;
public IEnumerable<NeedTypeEnumItem> NeedTypeItems { get; }
public VarietyViewModel()
{
_varieties = new List<VarietyEntity>();
var needTypes = EnumHelper.GetValues<NeedType>();
NeedTypeItems = needTypes.Select(nt => new NeedTypeEnumItem
{
Value = nt,
Description = nt.GetDescription()
});
}
}

View File

@ -0,0 +1,62 @@
<UserControl x:Class="Seyounth.Hyosung.Views.Controls.AddVarietyControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Seyounth.Hyosung.Views.Controls"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<StackPanel
Margin="16">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="产品编号:" VerticalAlignment="Center" Margin="0,0,10,0"/>
<TextBox Grid.Column="1"
x:Name="VarietyCodeTextBox">
</TextBox>
</Grid>
<TextBox Grid.Row="1"
x:Name="LotTextBox"
materialDesign:HintAssist.Hint="Lot">
</TextBox>
</Grid>
<StackPanel
HorizontalAlignment="Right"
Orientation="Horizontal">
<Button
Margin="0,8,8,0"
Content="ACCEPT"
IsDefault="True"
Style="{StaticResource MaterialDesignFlatButton}">
<Button.CommandParameter>
<system:Boolean
xmlns:system="clr-namespace:System;assembly=mscorlib">
True
</system:Boolean>
</Button.CommandParameter>
</Button>
<Button
Margin="0,8,8,0"
Content="CANCEL"
IsCancel="True"
Style="{StaticResource MaterialDesignFlatButton}">
<Button.CommandParameter>
<system:Boolean
xmlns:system="clr-namespace:System;assembly=mscorlib">
False
</system:Boolean>
</Button.CommandParameter>
</Button>
</StackPanel>
</StackPanel>
</UserControl>

View File

@ -0,0 +1,22 @@
using System.Windows;
using System.Windows.Controls;
namespace Seyounth.Hyosung.Views.Controls;
public partial class AddVarietyControl : UserControl
{
public AddVarietyControl()
{
InitializeComponent();
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
throw new NotImplementedException();
}
private void OkButton_Click(object sender, RoutedEventArgs e)
{
throw new NotImplementedException();
}
}

View File

@ -0,0 +1,129 @@
<Window x:Class="Seyounth.Hyosung.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Seyounth.Hyosung"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:views="clr-namespace:Seyounth.Hyosung.Views"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance views:MainWindow,
IsDesignTimeCreatable=True}"
Title="{Binding ViewModel.ApplicationTitle, Mode=OneWay}"
Height="1080" Width="1920"
WindowStartupLocation="CenterScreen"
WindowStyle="None"
AllowsTransparency="True"
WindowState="Maximized"
Background="Transparent">
<Border Background="{DynamicResource MaterialDesignPaper}"
CornerRadius="4"
Margin="10"
materialDesign:ElevationAssist.Elevation="Dp2">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<materialDesign:ColorZone Padding="16"
materialDesign:ElevationAssist.Elevation="Dp4"
DockPanel.Dock="Top"
Mode="PrimaryMid">
<DockPanel>
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal">
<Button x:Name="One" Margin="-20,-20,10,-20"
Content="_"
Command="{Binding ViewModel.MinimizeCommand}" />
<Button x:Name="Exit"
Content="X"
Command="{Binding ViewModel.ExitCommand}" />
</StackPanel>
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="22"
Text="Hyosung -- Seyounth Auto" />
</DockPanel>
</materialDesign:ColorZone>
<materialDesign:Card Grid.Row="1">
<TabControl
x:Name="MenuTab"
materialDesign:ColorZoneAssist.Mode="Standard"
materialDesign:ElevationAssist.Elevation="Dp8"
Style="{StaticResource MaterialDesignNavigationRailTabControl}">
<TabItem x:Name="Home">
<TabItem.Header>
<StackPanel
Width="auto"
Height="auto">
<materialDesign:PackIcon
Width="24"
Height="24"
HorizontalAlignment="Center"
Kind="Home" />
<TextBlock
HorizontalAlignment="Center"
Text="仪表盘" />
</StackPanel>
</TabItem.Header>
<Grid
Width="100" />
</TabItem>
<TabItem x:Name="VarietyTabItem">
<TabItem.Header>
<StackPanel
Width="auto"
Height="auto">
<materialDesign:PackIcon
Width="24"
Height="24"
HorizontalAlignment="Center"
Kind="ListBox" />
<TextBlock
HorizontalAlignment="Center"
Text="产品信息" />
</StackPanel>
</TabItem.Header>
<Frame Padding="16" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" x:Name="VarietyFrame" />
</TabItem>
<TabItem>
<TabItem.Header>
<StackPanel
Width="auto"
Height="auto">
<materialDesign:PackIcon
Width="24"
Height="24"
HorizontalAlignment="Center"
Kind="Info" />
<TextBlock
HorizontalAlignment="Center"
Text="运行状态" />
</StackPanel>
</TabItem.Header>
</TabItem>
<TabItem>
<TabItem.Header>
<StackPanel
Width="auto"
Height="auto">
<materialDesign:PackIcon
Width="24"
Height="24"
HorizontalAlignment="Center"
Kind="Settings" />
<TextBlock
HorizontalAlignment="Center"
Text="系统设置" />
</StackPanel>
</TabItem.Header>
</TabItem>
</TabControl>
</materialDesign:Card>
</Grid>
</Border>
</Window>

View File

@ -0,0 +1,21 @@
using System.Windows;
using Seyounth.Hyosung.ViewModels;
using Seyounth.Hyosung.Views.Pages;
namespace Seyounth.Hyosung.Views;
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow
{
public MainWindowViewModel ViewModel { get; }
public MainWindow(MainWindowViewModel viewModel, VarietyPage varietyPage)
{
ViewModel = viewModel;
DataContext = this;
InitializeComponent();
VarietyFrame.Content = varietyPage;
}
}

View File

@ -0,0 +1,142 @@
<Page x:Class="Seyounth.Hyosung.Views.Pages.VarietyPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Seyounth.Hyosung.Views.Pages"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d"
Width="Auto"
Height="Auto"
d:DataContext="{d:DesignInstance local:VarietyPage,
IsDesignTimeCreatable=True}">
<materialDesign:DialogHost x:Name="Root"
DialogMargin="8"
Style="{StaticResource MaterialDesignEmbeddedDialogHost}" >
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="Auto" Height="Auto">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ToolBarTray>
<ToolBar ClipToBounds="False"
Style="{StaticResource MaterialDesignToolBar}">
<Button
Content="{materialDesign:PackIcon Kind=Add}"
Click="ButtonBase_OnClick"
ToolTip="新增" />
<Button
Content="{materialDesign:PackIcon Kind=Edit}"
ToolTip="编辑" />
<Button
Content="{materialDesign:PackIcon Kind=Delete}"
ToolTip="删除" />
<Separator />
<ComboBox Margin="8"
Width="400"
materialDesign:HintAssist.Hint="品类编号"
materialDesign:TextFieldAssist.HasClearButton="False"
IsEditable="False"
ItemsSource="{Binding ViewModel.Varieties}"
DisplayMemberPath="Code"
Style="{StaticResource MaterialDesignFilledComboBox}">
</ComboBox>
<Button
Content="{materialDesign:PackIcon Kind=Search}"
ToolTip="搜索" />
</ToolBar>
</ToolBarTray>
<materialDesign:Card Margin="0,10,0,0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Width="Auto"
Height="Auto"
Grid.Row="1">
<DataGrid x:Name="VarietyDataGrid"
CanUserAddRows="True"
AutoGenerateColumns="False"
HeadersVisibility="All"
ItemsSource="{Binding ViewModel.Varieties, Mode=OneWay}"
SelectionUnit="{Binding ElementName=selectionUnitComboBox, Path=SelectedValue}">
<DataGrid.Columns>
<DataGridTextColumn
Binding="{Binding Code}"
Header="代码"
Width="Auto" />
<DataGridTextColumn
Binding="{Binding Lot }"
Header="LOT"
Width="Auto" />
<DataGridTextColumn
Binding="{Binding Specifications }"
Header="规格"
Width="Auto" />
<DataGridTextColumn
Binding="{Binding InnerDiameter }"
Header="内径(D1)"
Width="Auto" />
<DataGridTextColumn
Binding="{Binding OuterDiameter }"
Header="外径(D2)"
Width="Auto" />
<DataGridTextColumn
Binding="{Binding YarnDiameter }"
Header="直径(D3)"
Width="Auto" />
<DataGridTextColumn
Binding="{Binding PaperTubeHeight }"
Header="纸管高(H1)"
Width="Auto" />
<DataGridTextColumn
Binding="{Binding YarnThickness }"
Header="纱线厚(H2)"
Width="Auto" />
<DataGridTextColumn
Binding="{Binding SingleWeight }"
Header="单筒重"
Width="Auto" />
<DataGridTextColumn
Binding="{Binding StackingLayers }"
Header="码层数"
Width="Auto" />
<DataGridTextColumn
Binding="{Binding TotalCount }"
Header="个/托"
Width="Auto" />
<DataGridTextColumn
Binding="{Binding StackHeadSpec }"
Header="垛头尺寸"
Width="Auto" />
<DataGridTextColumn
Binding="{Binding StackHeadCount }"
Header="垛头数量"
Width="Auto" />
<DataGridComboBoxColumn
TextBinding="{Binding NeedTopBoard }"
ItemsSource="{Binding }"
Header="顶板"
Width="Auto" />
<DataGridComboBoxColumn
TextBinding="{Binding NeedAngleBeam }"
Header="护角"
Width="Auto" />
<DataGridComboBoxColumn
TextBinding="{Binding NeedFilmWrapping }"
Header="缠膜"
Width="Auto" />
<DataGridComboBoxColumn
TextBinding="{Binding NeedFilmCoating }"
Header="覆膜"
Width="Auto" />
<DataGridTextColumn
Binding="{Binding MasterLabelCount }"
Header="主标签数量"
Width="Auto" />
<DataGridTextColumn
Binding="{Binding SubLabelCount }"
Header="副标签数量"
Width="Auto" />
</DataGrid.Columns>
</DataGrid>
</materialDesign:Card>
</Grid>
</materialDesign:DialogHost>
</Page>

View File

@ -0,0 +1,36 @@
using System.Windows;
using System.Windows.Controls;
using MaterialDesignThemes.Wpf;
using Seyounth.Hyosung.Data.Entities;
using Seyounth.Hyosung.Data.Models;
using Seyounth.Hyosung.ViewModels;
using Seyounth.Hyosung.Views.Controls;
namespace Seyounth.Hyosung.Views.Pages;
public partial class VarietyPage : Page
{
public VarietyViewModel ViewModel { get; set; }
public VarietyPage(VarietyViewModel viewModel)
{
ViewModel = viewModel;
DataContext = this;
InitializeComponent();
}
private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var blankVariety = new VarietyEntity()
;
// 将空白对象添加到数据源中
ViewModel.Varieties.Add(blankVariety);
// 滚动到新添加的行并使其进入编辑状态
VarietyDataGrid.ScrollIntoView(blankVariety);
var index = ViewModel.Varieties.IndexOf(blankVariety);
VarietyDataGrid.SelectedIndex = index;
VarietyDataGrid.BeginEdit();
}
}

View File

@ -0,0 +1,5 @@
{
"ConnectionStrings": {
"DefaultConnection": "server=DESKTOP-AJ6K895;database=seyounth.hyosung;Trusted_Connection=SSPI;Encrypt=True;TrustServerCertificate=True;"
}
}

7
global.json Normal file
View File

@ -0,0 +1,7 @@
{
"sdk": {
"version": "8.0.0",
"rollForward": "latestMinor",
"allowPrerelease": false
}
}