在这里插入图片描述

前言

前十篇我们已经完整搭建了工业上位机的全套核心架构:从UI模块化、DI依赖注入、业务服务分层、Repository数据持久化、HAL硬件抽象层,到可视化流程引擎、Lua脚本热更新,彻底实现了项目架构解耦、硬件适配、工艺柔性、动态拓展的核心能力。

一套能运行的上位机≠一套能量产的上位机。实验室调试通过的项目,落地到真实工业量产场景,往往会暴露诸多细节短板:设备报警混乱、无操作追溯、多设备厂区语言适配不足、生产数据无法云端汇总、离线断网数据丢失、日志杂乱无章无法排查问题。

真正的工业量产软件,核心不仅是功能能跑,而是可追溯、可管控、可运维、可适配、高安全

本篇我们集中补齐工业项目所有量产级高阶能力,手把手落地多语言国际化、分级声光报警体系、全场景操作审计日志、云端数据上报、离线缓存补传、日志分级管理全套方案,把项目从“可用版本”打磨为工业商用稳定版本

本篇核心目标:补齐工业上位机量产最后细节短板,搭建标准化运维、追溯、适配、数据同步体系,完全满足工厂量产、客户验收、设备运维标准。

一、工业量产项目的核心验收标准

在正式开发前,我们先明确工业甲方、设备厂商、自动化产线的通用验收要求,看懂本篇功能的必要性:

  • 操作可追溯:所有人工操作、参数修改、设备动作必须留痕,支持问题溯源、责任界定

  • 故障可定位:报警分级分类、实时提示、日志留存,快速排查设备故障与工艺异常

  • 多场景适配:支持中英文切换,适配出口设备、国际化厂区场景

  • 数据可汇总:生产数据、设备状态可上传云端/MES系统,支持厂区大数据统计

  • 断网不丢数:网络波动、断网离线时数据本地缓存,联网自动补传,杜绝生产数据断层

  • 日志可分级:区分普通日志、警告、错误、致命异常,避免日志泛滥难以排查问题

二、多语言国际化体系落地(中英文无缝切换)

很多工业项目仅支持中文,无法适配出口设备、外资厂区、国际化项目场景。我们搭建一套轻量化无依赖国际化方案,无需系统资源文件,支持运行时动态切换中英文、全局文本自动刷新,适配所有页面与弹窗。

1. 多语言枚举与资源模型

namespace Industrial.Core.Language
{
    /// <summary>
    /// 语言类型枚举
    /// </summary>
    public enum LangType
    {
        /// <summary>
        /// 中文
        /// </summary>
        ZhCN,
        /// <summary>
        /// 英文
        /// </summary>
        EnUS
    }
}

using System.Collections.Generic;

namespace Industrial.Core.Language
{
    /// <summary>
    /// 全局语言资源池
    /// 统一管理所有界面文本、提示语、报警文案
    /// </summary>
    public static class LangResource
    {
        // 当前选中语言
        public static LangType CurrentLang { get; set; } = LangType.ZhCN;

        // 语言字典缓存
        private static readonly Dictionary<string, Dictionary<LangType, string>> _langDict;

        static LangResource()
        {
            _langDict = new Dictionary<string, Dictionary<LangType, string>>();
            InitLangData();
        }

        /// <summary>
        /// 初始化中英文对照文案
        /// 后续所有新增文案统一在此维护
        /// </summary>
        private static void InitLangData()
        {
            // 系统通用
            AddLang("System_Start", "系统启动成功", "System Started Successfully");
            AddLang("System_Stop", "系统已停止", "System Stopped");
            AddLang("System_Offline", "设备离线", "Device Offline");
            AddLang("System_Online", "设备在线", "Device Online");

            // 生产工序
            AddLang("Product_Running", "生产运行中", "Production Running");
            AddLang("Product_Finish", "生产完成", "Production Finished");
            AddLang("Product_Error", "生产异常", "Production Error");

            // 报警提示
            AddLang("Alarm_Timeout", "设备响应超时", "Device Response Timeout");
            AddLang("Alarm_ParamError", "参数配置错误", "Parameter Configuration Error");
        }

        private static void AddLang(string key, string zh, string en)
        {
            _langDict[key] = new Dictionary<LangType, string>
            {
                { LangType.ZhCN, zh },
                { LangType.EnUS, en }
            };
        }

        /// <summary>
        /// 获取对应语言文本
        /// </summary>
        public static string GetText(string key)
        {
            if (_langDict.TryGetValue(key, out var dict))
            {
                return dict[CurrentLang];
            }
            return key;
        }
    }
}

2. 页面全局切换与刷新机制

封装全局语言切换工具,支持保存配置到本地,重启程序自动记忆语言,切换后所有界面实时刷新,无需重启软件。

using Industrial.Core.Utils;
using Industrial.Data.Service;

namespace Industrial.Core.Language
{
    public static class LangHelper
    {
        /// <summary>
        /// 切换语言并保存配置
        /// </summary>
        public static void SwitchLang(LangType lang)
        {
            LangResource.CurrentLang = lang;
            // 持久化保存语言配置
            var configService = ServiceLocator.GetService<DeviceDataService>();
            var config = configService.GetDeviceConfig();
            config.LangType = (int)lang;
            configService.SaveDeviceConfig(config);
        }

        /// <summary>
        /// 初始化加载语言配置
        /// </summary>
        public static void InitLang()
        {
            var configService = ServiceLocator.GetService<DeviceDataService>();
            var config = configService.GetDeviceConfig();
            LangResource.CurrentLang = (LangType)config.LangType;
        }
    }
}

三、工业分级声光报警体系落地

工业现场报警不能一概而论,我们按照工厂标准分为提示、警告、故障、致命错误四级报警,实现差异化提示、声光提醒、日志留存、故障弹窗、自动复位机制。

1. 报警等级枚举定义

namespace Industrial.Core.Alarm
{
    /// <summary>
    /// 工业报警等级
    /// 
    public enum AlarmLevel
    {
        /// 
        Info,
        /// 
        Warn,
        /// 
        Error,
        /// 
        Fatal
    }
}

2. 报警实体模型与全局管理器

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Industrial.Core.Language;

namespace Industrial.Core.Alarm
{
    /// <summary>
    /// 工业报警全局管理器
    /// 统一管控报警弹窗、声光、日志、记录留存
    /// </summary>
    public static class AlarmManager
    {
        // 报警历史缓存
        public static List<AlarmModel> AlarmHistory { get; } = new List<AlarmModel>();

        /// 
        public static void TriggerAlarm(string alarmKey, AlarmLevel level)
        {
            var alarmModel = new AlarmModel
            {
                AlarmKey = alarmKey,
                AlarmMsg = LangResource.GetText(alarmKey),
                AlarmLevel = level,
                AlarmTime = DateTime.Now,
                IsReset = false
            };

            // 加入历史记录
            AlarmHistory.Add(alarmModel);

            // 分级处理
            ProcessAlarmLevel(alarmModel);

            // 写入日志
            WriteAlarmLog(alarmModel);
        }

        /// 
        private static void ProcessAlarmLevel(AlarmModel model)
        {
            switch (model.AlarmLevel)
            {
                case AlarmLevel.Info:
                    // 仅日志提示
                    break;
                case AlarmLevel.Warn:
                    // 弹窗弱提示
                    break;
                case AlarmLevel.Error:
                    // 弹窗警告 + 声光提示
                    PlayAlarmSound();
                    break;
                case AlarmLevel.Fatal:
                    // 紧急停机 + 强弹窗 + 持续声光
                    PlayAlarmSound();
                    EmergencyStop();
                    break;
            }
        }

        // 模拟声光报警
        private static async void PlayAlarmSound()
        {
            await Task.Delay(300);
        }

        // 紧急停机逻辑
        private static void EmergencyStop()
        {
            // 调用全局急停接口
        }

        // 写入报警日志
        private static void WriteAlarmLog(AlarmModel model)
        {
            string log = $"[{model.AlarmTime:HH:mm:ss}]【{model.AlarmLevel}{model.AlarmMsg}";
            LogHelper.Error(log);
        }

        /// 
        public static void ResetAlarm(string alarmKey)
        {
            var model = AlarmHistory.Find(x => x.AlarmKey == alarmKey && !x.IsReset);
            if (model != null) model.IsReset = true;
        }
    }

    public class AlarmModel
    {
        public string AlarmKey { get; set; }
        public string AlarmMsg { get; set; }
        public AlarmLevel AlarmLevel { get; set; }
        public DateTime AlarmTime { get; set; }
        public bool IsReset { get; set; }
    }
}

四、全场景操作审计日志体系(生产追溯核心)

工业设备、产线项目必须具备操作审计能力,用于界定人为操作失误、追溯异常原因、满足甲方合规验收。我们搭建全场景审计日志,记录所有关键操作。

1. 审计日志模型

using System;

namespace Industrial.Core.Audit
{
    /// <summary>
    /// 工业操作审计日志模型
    ///
    public class AuditLogModel
    {
        /// 
        public DateTime OperateTime { get; set; } = DateTime.Now;

        /// 
        public string OperateUser { get; set; } = "Admin";

        /// 
        public string OperateType { get; set; }

        /// 
        public string OperateDesc { get; set; }

        /// 
        public string DeviceCode { get; set; }
    }
}

2. 审计日志全局工具类

using System.IO;
using Newtonsoft.Json;
using Industrial.Core.Utils;

namespace Industrial.Core.Audit
{
    /// <summary>
    /// 全局审计日志工具
    /// 记录所有关键操作:参数修改、启停设备、工艺切换、权限操作
    /// 
    public static class AuditHelper
    {
        /// public static void WriteAuditLog(string operateType, string operateDesc)
        {
            var log = new AuditLogModel
            {
                OperateType = operateType,
                OperateDesc = operateDesc
            };

            // 保存本地文件
            string path = Path.Combine(PathHelper.AuditPath, $"{DateTime.Now:yyyyMMdd}_Audit.log");
            string content = JsonConvert.SerializeObject(log, Formatting.Indented);
            File.AppendAllText(path, content + "\r\n");
        }

        /// 
        public static void LogParamEdit(string desc) => WriteAuditLog("参数修改", desc);
        public static void LogDeviceStart() => WriteAuditLog("设备启动", "手动启动自动化设备");
        public static void LogDeviceStop() => WriteAuditLog("设备停止", "手动停止自动化设备");
        public static void LogFlowChange(string flowName) => WriteAuditLog("工艺切换", $"切换工艺流程:{flowName}");
    }
}

五、云端数据上报与离线缓存补传机制

现代工业产线均需要对接MES、ERP、云端平台,实现生产数据汇总统计。针对工业现场网络不稳定、断网频发的问题,我们实现在线实时上报、离线本地缓存、联网自动补传的工业级数据同步方案。

1. 上报数据模型

using System;

namespace Industrial.Core.Cloud
{
    /// <summary>
    /// 生产数据云端上报模型
    /// 
    public class ProductUploadModel
    {
        ///  public string DeviceSN { get; set; }

        /// 
        public string BatchNo { get; set; }

        /// 
        public int GoodNum { get; set; }

        ///  public int BadNum { get; set; }

        /// 
        public string ProductTime { get; set; }

        ///  public bool IsUploaded { get; set; }
    }
}

2. 云端上报与离线补传核心服务

using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Industrial.Core.Utils;

namespace Industrial.Core.Cloud
{
    /// <summary>
    /// 云端数据上报服务
    /// 支持在线上报、离线缓存、联网补传
    /// 
    public class CloudUploadService
    {
        private readonly string _offlineCachePath = Path.Combine(PathHelper.DataPath, "OfflineCache.json");
        private readonly string _cloudApiUrl = "http://xxx.xxx.xxx/upload";

        /// 
        public async Task SaveProductData(ProductUploadModel model)
        {
            // 优先尝试云端上报
            bool uploadResult = await UploadToCloud(model);
            if (uploadResult)
            {
                model.IsUploaded = true;
                return;
            }

            // 上报失败,离线缓存
            SaveOfflineCache(model);
        }

        /// 
        private async Task<bool> UploadToCloud(ProductUploadModel model)
        {
            try
            {
                using var client = new HttpClient();
                string json = JsonConvert.SerializeObject(model);
                var content = new StringContent(json);
                var response = await client.PostAsync(_cloudApiUrl, content);
                return response.IsSuccessStatusCode;
            }
            catch
            {
                return false;
            }
        }

        /// 
        private void SaveOfflineCache(ProductUploadModel model)
        {
            var list = LoadOfflineCache();
            list.Add(model);
            string json = JsonConvert.SerializeObject(list, Formatting.Indented);
            File.WriteAllText(_offlineCachePath, json);
        }

        /// 
        public async Task RetryUploadCache()
        {
            var cacheList = LoadOfflineCache();
            if (!cacheList.Any()) return;

            // 逐条补传
            foreach (var item in cacheList)
            {
                bool res = await UploadToCloud(item);
                if (!res) return;
            }

            // 全部上传成功,清空缓存
            File.Delete(_offlineCachePath);
        }

        private List<ProductUploadModel> LoadOfflineCache()
        {
            if (!File.Exists(_offlineCachePath)) return new List<ProductUploadModel>();
            string json = File.ReadAllText(_offlineCachePath);
            return JsonConvert.DeserializeObject<List<ProductUploadModel>>(json) ?? new List<ProductUploadModel>();
        }
    }
}

六、日志分级与自动清理机制

量产项目日志不能无限堆积,我们完善日志分级(Info/Warn/Error/Fatal)、按天分割、自动过期清理,避免日志占用磁盘空间导致设备卡顿。

using System;
using System.IO;

namespace Industrial.Core.Utils
{
    public static class LogHelper
    {
        // 日志保留天数
        private const int SaveDay = 30;

        static LogHelper()
        {
            // 初始化清理过期日志
            ClearOverdueLog();
        }

        public static void Info(string msg) => WriteLog("INFO", msg);
        public static void Warn(string msg) => WriteLog("WARN", msg);
        public static void Error(string msg) => WriteLog("ERROR", msg);
        public static void Fatal(string msg) => WriteLog("FATAL", msg);

        private static void WriteLog(string level, string msg)
        {
            string path = Path.Combine(PathHelper.LogPath, $"{DateTime.Now:yyyyMMdd}.log");
            string content = $"[{DateTime.Now:HH:mm:ss}][{level}] {msg}\r\n";
            File.AppendAllText(path, content);
        }

        /// 
        private static void ClearOverdueLog()
        {
            if (!Directory.Exists(PathHelper.LogPath)) return;
            var files = Directory.GetFiles(PathHelper.LogPath);
            foreach (var file in files)
            {
                var createTime = File.GetCreationTime(file);
                if ((DateTime.Now - createTime).TotalDays > SaveDay)
                {
                    File.Delete(file);
                }
            }
        }
    }
}

七、DI全局服务注册

将本篇所有高阶能力服务统一纳入DI容器托管,程序启动自动初始化,全局可调用。

private static void RegisterAdvancedServices(ServiceCollection services)
{
    // 云端数据上报服务
    services.AddSingleton<CloudUploadService>();
}

八、本篇总结

本篇我们完成了工业上位机量产级高阶能力的全覆盖,补齐了架构之外所有商用细节短板:

  • 国际化适配:中英文动态切换,适配多场景出口设备

  • 分级报警体系:四级报警差异化处理,故障精准定位、设备安全可控

  • 全量审计日志:所有关键操作留痕,满足生产追溯、合规验收

  • 云端数据同步:断网缓存、联网补传,彻底解决现场网络不稳定丢数问题

  • 日志自动化管理:分级输出、自动清理,保证设备长期稳定运行

截至目前,整套工业上位机从底层架构、核心功能、柔性拓展、量产运维已全部完善,完全达到商业项目交付标准。

下篇预告

下一篇作为本系列最终收官第十二篇,我们将进行项目整体架构复盘、性能优化、Bug根治、打包发布与量产部署方案,手把手完成项目最终打磨、性能调优、适配量产设备,给整套12篇连载画上完整句号!

更多推荐