From 9d1660270272180cd71147d6ddd53d1382643d2e Mon Sep 17 00:00:00 2001
From: wenxiangchao <wenxiangchao@ihengxin.com.cn>
Date: 星期一, 02 十一月 2026 18:00:14 +0800
Subject: [PATCH] merge: 并入远程 Initial commit 作为历史根节点

---
 Aging.Infrastructure/Contracts/ResourceKey.cs |  134 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 134 insertions(+), 0 deletions(-)

diff --git a/Aging.Infrastructure/Contracts/ResourceKey.cs b/Aging.Infrastructure/Contracts/ResourceKey.cs
new file mode 100644
index 0000000..c250f51
--- /dev/null
+++ b/Aging.Infrastructure/Contracts/ResourceKey.cs
@@ -0,0 +1,134 @@
+using System;
+
+namespace Aging.Infrastructure.Contracts
+{
+    /// <summary>
+    /// 璧勬簮閿�煎璞★紝鍞竴鏍囪瘑涓�涓彲绠$悊鐨勭‖浠惰祫婧愩��
+    /// 鏍煎紡: "DeviceId:Channel"锛屽 "PSU024:CH1"銆�"CAN_CARD01:CH2"銆�"PLC01:OUTPUT_GROUP_A"
+    /// </summary>
+    public sealed class ResourceKey : IEquatable<ResourceKey>
+    {
+        /// <summary>
+        /// 璁惧鏍囪瘑绗�
+        /// </summary>
+        public string DeviceId { get; }
+
+        /// <summary>
+        /// 閫氶亾鏍囪瘑锛堝彲閫夛級
+        /// </summary>
+        public string? Channel { get; }
+
+        /// <summary>
+        /// 璧勬簮绫诲瀷锛圥owerSupply/CAN/PLC/Chamber绛夛級
+        /// </summary>
+        public string ResourceType { get; }
+
+        /// <summary>
+        /// 鍒濆鍖栬祫婧愰敭瀹炰緥
+        /// </summary>
+        /// <param name="deviceId">璁惧鏍囪瘑绗�</param>
+        /// <param name="resourceType">璧勬簮绫诲瀷</param>
+        /// <param name="channel">閫氶亾鏍囪瘑锛堝彲閫夛級</param>
+        public ResourceKey(string deviceId, string resourceType, string? channel = null)
+        {
+            DeviceId = deviceId ?? throw new ArgumentNullException(nameof(deviceId));
+            ResourceType = resourceType ?? throw new ArgumentNullException(nameof(resourceType));
+            Channel = channel;
+        }
+
+        /// <summary>
+        /// 浠庡瓧绗︿覆瑙f瀽璧勬簮閿紝鏍煎紡涓� "DeviceId:Channel"
+        /// </summary>
+        /// <param name="key">璧勬簮閿瓧绗︿覆</param>
+        /// <returns>瑙f瀽鍚庣殑璧勬簮閿疄渚�</returns>
+        /// <exception cref="ArgumentException">鏍煎紡鏃犳晥鏃舵姏鍑�</exception>
+        public static ResourceKey FromString(string key)
+        {
+            if (string.IsNullOrWhiteSpace(key))
+                throw new ArgumentException("璧勬簮閿笉鑳戒负绌�", nameof(key));
+
+            var parts = key.Split(':');
+            if (parts.Length < 2)
+                throw new ArgumentException($"鏃犳晥鐨勮祫婧愰敭鏍煎紡: '{key}'锛屾湡鏈涙牸寮忎负 'DeviceId:Channel'");
+
+            var deviceId = parts[0].Trim();
+            var channel = string.Join(":", parts.Skip(1)).Trim();
+
+            if (string.IsNullOrEmpty(deviceId))
+                throw new ArgumentException($"鏃犳晥鐨勮祫婧愰敭鏍煎紡: '{key}'锛孌eviceId 涓嶈兘涓虹┖");
+
+            // 鏍规嵁璁惧ID鍓嶇紑鎺ㄦ柇璧勬簮绫诲瀷
+            var resourceType = InferResourceType(deviceId);
+
+            return new ResourceKey(deviceId, resourceType, string.IsNullOrEmpty(channel) ? null : channel);
+        }
+
+        /// <summary>
+        /// 鑾峰彇鎿嶄綔璧勬簮閿紝鐢ㄤ簬鐗╃悊浼氳瘽閿�
+        /// </summary>
+        public string OperationResourceKey => $"{DeviceId}:SESSION";
+
+        /// <summary>
+        /// 鏍规嵁璁惧ID鍓嶇紑鎺ㄦ柇璧勬簮绫诲瀷
+        /// </summary>
+        private static string InferResourceType(string deviceId)
+        {
+            var upper = deviceId.ToUpperInvariant();
+            if (upper.StartsWith("PSU") || upper.StartsWith("POWER"))
+                return "PowerSupply";
+            if (upper.StartsWith("CAN"))
+                return "CAN";
+            if (upper.StartsWith("PLC"))
+                return "PLC";
+            if (upper.StartsWith("CHAMBER") || upper.StartsWith("TEMP"))
+                return "Chamber";
+            if (upper.StartsWith("DAQ"))
+                return "DAQ";
+            if (upper.StartsWith("SERIAL") || upper.StartsWith("COM"))
+                return "Serial";
+            return "Generic";
+        }
+
+        /// <inheritdoc/>
+        public bool Equals(ResourceKey? other)
+        {
+            if (other is null) return false;
+            if (ReferenceEquals(this, other)) return true;
+            return string.Equals(DeviceId, other.DeviceId, StringComparison.OrdinalIgnoreCase) &&
+                   string.Equals(Channel, other.Channel, StringComparison.OrdinalIgnoreCase) &&
+                   string.Equals(ResourceType, other.ResourceType, StringComparison.OrdinalIgnoreCase);
+        }
+
+        /// <inheritdoc/>
+        public override bool Equals(object? obj) => Equals(obj as ResourceKey);
+
+        /// <inheritdoc/>
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                int hash = 17;
+                hash = hash * 31 + (DeviceId?.ToUpperInvariant().GetHashCode() ?? 0);
+                hash = hash * 31 + (Channel?.ToUpperInvariant().GetHashCode() ?? 0);
+                hash = hash * 31 + (ResourceType?.ToUpperInvariant().GetHashCode() ?? 0);
+                return hash;
+            }
+        }
+
+        /// <inheritdoc/>
+        public override string ToString() =>
+            string.IsNullOrEmpty(Channel) ? DeviceId : $"{DeviceId}:{Channel}";
+
+        /// <summary>
+        /// 鐩哥瓑杩愮畻绗﹂噸杞�
+        /// </summary>
+        public static bool operator ==(ResourceKey? left, ResourceKey? right) =>
+            Equals(left, right);
+
+        /// <summary>
+        /// 涓嶇瓑杩愮畻绗﹂噸杞�
+        /// </summary>
+        public static bool operator !=(ResourceKey? left, ResourceKey? right) =>
+            !Equals(left, right);
+    }
+}

--
Gitblit v1.9.1