电力设备模块更换APP开发文档
一、开发背景:
根据公司指示,有一批设备要进行内置模块安装,同时设备信息要和新装的模块信息进行绑定,即在现场换装的过程中,要记录模块的信息(资产编码)与设备的信息(资产编码),通过信息上传后,到达主站,由后台人员进行信息绑定。
前期,此项工作都是由施工人员对现场的条码进行抄写、拍照上传,但由于工作过程中容易出现失误,或者施工人员书写不规范,遗漏等等问题,造成设备绑定时频频出现错误情况,因此,特开发此App,目的是减轻施工人员的工作量,同时,避免因施工人员误操作或者手写错误,造成不必要的麻烦。
二、系统框架:
系统搭设:
本系统手机端搭设APP软件一套,用于信息采集,数据临时储存、数据上传、数据查询、参数设置以及人员注册、登陆等内容。当数据采集完毕后,会在本地手机中进行存储,等网络畅通或者工作完成后,由施工人员进行上传操作,此时,数据会按照一定的格式进行编码,通过WebService提供的接口上传到服务器中。
服务器端采用WebService来进行数据的接收和处理,将现场的数据信息按照一定的编码格式进行解码,然后储存到数据库中;同时,也能够满足后台管理端的数据请求,按照一定的编码将请求的数据进行编码,提供给后台人员进行查阅和下载。
后台管理端负责将请求的数据进行解码,完成数据查阅和下载,同时,也需要完成部分系统设置,参数、人员、权限等的管理行为。
三、详细说明:
1.结构说明:
本系统采用C#编程语言,数据库为SQLServer数据库,手机本地数据库采用Sqlite数据库。
手机端采用Xamarin.Forms+MVVM形式进行开发,主要包含条形码扫描、数据信息录入、信息查询、数据编码、解码等功能。数据本地存储采用Sqlite数据库进行本地数据暂存,数据采集完毕后需要对数据进行暂存,必要时对数据进行提取,并执行上传操作。
客户机端采用WPF+MVVM的形式进行开发,同时设计C#—Excel的数据操作功能,包括信息读取和写入,数据保存、编码及解码等功能。
服务器端使用腾讯云服务器,通过IIS服务搭建Web服务,对手机端及客户机端的数据请求和数据传输进行接收和信息发送,来完成数据的转存和读取,并响应数据读取的相关请求。
2.系统特点:
2.1.本套系统主要采用MVVM模式,实现代码与界面的分离;
2.2.系统手机端采用版本更新的模式,实现版本的自主更新下载,避免版本错乱问题;
2.3.整个系统架构采用MVVM+三层架构的主要模式,后期易于代码的二次开发和漏洞修改;
2.4.系统开发语言采用C#语言,开发简单,易于维护;
2.5.远程数据库采用SqlServer数据库,可存储大容量的数据记录;
2.6.数据库部分全部采用存储过程,软件开发过程中未使用一条SQL语句;
2.7.手机端本地数据库采用Sqlite进行临时性存储,通过增删改查完成数据的基本操作;
3.软件效果:
3.1.手机端效果:
界面效果
3.2.客户端效果:
3.3.服务端效果:
WebService效果
3.4.服务端效果:
4.部分代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CommandService;
using System.Collections.ObjectModel;
using Xamarin.Forms;
using StringService;
using System.Xml.Linq;
using System.IO;
using Xamarin.Essentials;
using System.Threading;
//using SocketService;
using System.Net.Sockets;
using DataBaseService.SqliteHelper;
using PropertyChangeService;
using ModuleInstall.Services;
using AppTools_WS;
using Models;
namespace ModuleInstall.ViewModels
{
public class MainPageViewModel : PropertyChangedHelper
{
private Taiqu _tq = new Taiqu();
private Meter _meter = new Meter();
private User _User = new User();
private Recorder _recorder = new Recorder();private MainCommand _meterScanCmd, _moduleScanCmd, _saveCmd, _uploadCmd;private Action<string> _callBack;//private Dal_Module _dalModule = new Dal_Module();/// <summary>/// 用于计数功能,记录设备列表增加的行数;/// </summary>public int Count { set; get; } = 0;public int Index { set; get; } = 0;public bool IsEnabled { set; get; }public string TqName { set { _tq.Name = value; PropertyChange(nameof(TqName)); } get { return _tq.Name; } }public string MeterNum { set { _meter.MeterNum = value; PropertyChange(nameof(MeterNum)); } get { return _meter.MeterNum; } }public string ModuleNum { set { _meter.ModuleNum = value; PropertyChange(nameof(ModuleNum)); } get { return _meter.ModuleNum; } }public string Account { set { _User.Account = value; PropertyChange(nameof(Account)); } get { return _User.Account; } }public string Address { set { _recorder.Address = value; PropertyChange(nameof(Address)); } get { return _recorder.Address; } }public MainCommand MeterScanCmd { get { return _meterScanCmd; } }public MainCommand ModuleScanCmd { get { return _moduleScanCmd; } }public MainCommand SaveCmd { get { return _saveCmd; } }public MainCommand UploadCmd { get { return _uploadCmd; } }public int ScrollIndex { set; get; }public ObservableCollection<Meter> Meters { set; get; } = new ObservableCollection<Meter>();private SqliteHelper Helper;public MainPageViewModel(){}public MainPageViewModel(Action<string> action){InitDatabase();//初始化数据库;_callBack = action;//回调函数进入;_meterScanCmd = new MainCommand(MeterScan);_moduleScanCmd = new MainCommand(ModuleScan);_saveCmd = new MainCommand(Save);_uploadCmd = new MainCommand(Upload2);if (!File.Exists(SystemSettingPageViewModel.filePath) || new FileInfo(SystemSettingPageViewModel.filePath).Length == 0){_callBack("更换台区、人员操作前,请先进行系统设置!");}}/// <summary>/// Json数据读取;从字符串读取到Object(必须为Object)对象;/// </summary>/// <param name="filePath"></param>/// <returns></returns>public SettingModel JsonRead(string filePath){string jsonStr;try{using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)){using (StreamReader sr = new StreamReader(fs)){jsonStr = sr.ReadToEnd();}}return new JsonConvertHelper<SettingModel>().ToObject(jsonStr); //JsonConvert.DeserializeObject<SettingModel>(jsonStr);}catch (Exception ex){throw ex;}}public void InitDatabase(){Helper= new SqliteHelper();}/// <summary>/// 获取指定电能表资产的Id号/// </summary>/// <param name="meterNum"></param>/// <returns></returns>int GetMeterId(string meterNum){int flag;try{flag = Helper.GetMeterId(meterNum);}catch (Exception ex){throw ex;}return flag;}/// <summary>/// 获取指定台区名称的台区Id号;/// </summary>/// <param name="tqName"></param>/// <returns></returns>int GetTqId(string tqName){return Helper.GetTqId(tqName);}/// <summary>/// 获取从本地配置信息中读取的/// </summary>/// <returns></returns>int GetUserId(string Account){///从本地配置文件中获取姓名;return Helper.GetUserId(Account);}/// <summary>/// 电能表扫码方法,扫码后,将码加入到Meters集合列表;/// </summary>/// 定义电表数量,模块数量public int MeterCount = 0, ModuleCount = 0;async void MeterScan(){try{bool flag = false;//判断扫码重复的标志;string num = await new ScanToString().BoxScan();if (num.Length > 15){for (int i = 0; i < Meters.Count; i++){if (Meters[i].MeterNum == num){flag = true;//如果,Meters集合中,存在此模块条码信息,则资产重复,标志为true;}}if (!flag){//var meter = Meters.Where(m => m.ModuleNum == "").First();if (MeterCount>=ModuleCount){Meters.Insert(0,new Meter() { MeterNum = num });MeterCount++;}else{Meters[ModuleCount-MeterCount-1].MeterNum = num;//当前序号处的模块条码由空修改为当前扫描的条码;MeterCount++; //Count++;//计数指针位增加,后期删除时,指针不能小于0;//Meters.OrderBy<Meter,int>(Meter => Meter.Id).Min();}_callBack(null);//回调函数,更新ListView//num = await new ScanToString().BoxScan();}}}catch{throw;}}async void ModuleScan(){try{bool flag = false;//判断扫码重复的标志;string num = await new ScanToString().BoxScan();if (num.Length > 15){for (int i = 0; i < Meters.Count; i++){if (Meters[i].ModuleNum == num){flag = true;//如果,Meters集合中,存在此模块条码信息,则资产重复,标志为true;}}if (!flag){//var meter = Meters.Where(m => m.ModuleNum == "").First();if(MeterCount<=ModuleCount){Meters.Insert(0,new Meter() { ModuleNum = num });ModuleCount++;}else{Meters[MeterCount-ModuleCount-1].ModuleNum = num;//当前序号处的模块条码由空修改为当前扫描的条码;ModuleCount++; //Count++;//计数指针位增加,后期删除时,指针不能小于0;//Meters.OrderBy<Meter,int>(Meter => Meter.Id).Min();}_callBack(null);//回调函数,更新ListView //num = await new ScanToString().BoxScan();}}}catch{throw;}}/// <summary>/// 删除本地数据库中的表与模块信息(同时删除);如果不删除,加表,保存,或者在删除,中间回出现问题;/// </summary>/// <param name="meter"></param>public void MeterDelete(string meter){int meterid = Helper.GetMeterId(meter);int recorderId = Helper.GetRecorderId(meterid);if(meterid >0)Helper.Delete<Meter>(meterid);if(recorderId>0)Helper.Delete<Recorder>(recorderId);}/// <summary>/// 保存到本地/// </summary>void Save(){bool isSave = false;try{if (Meters.Count > 0){SettingModel setModel =null;try{setModel = JsonRead(SystemSettingPageViewModel.filePath);}catch{_callBack("更换台区、人员操作前,请先进行系统设置!");//回调函数,显示提示信息;}Account = setModel.Account;TqName = setModel.TqName;Address = setModel.Address;int tqid = GetTqId(TqName);foreach (var meter in Meters){if (meter.ModuleNum != null){meter.TqId = tqid;//判断是否在数据库中存在此表资产,如果不存在,返回结果为0,则添加资产if (GetMeterId(meter.MeterNum) == 0){Helper.Insert<Meter>(meter);Helper.Insert<Recorder>(new Recorder(){MeterId = GetMeterId(meter.MeterNum),UserId = GetUserId(Account),IsUpload = false,//上传标志为false,上传以后更改为true;SaveTime = DateTime.Now,Address = Address});}}else{_callBack("数据结构不完整,请补充完整后保存!");break;}isSave = true;}///-------------还需要确认,两种资产不能够进入//Console.WriteLine("--------------------------------------------保存成功!--------------------------------------");if(isSave){_callBack("数据保存成功!");}}else{_callBack("数据不能为空,请重试操作!");}}catch (NullReferenceException){_callBack("更换台区、人员操作前,请先进行系统设置!");}catch (Exception ex){_callBack($"{ex.ToString()}");}}/// <summary>///第一版: 上传数据到远程服务器,需要从本地数据库中读取,直接操作远程数据库插入数据/// </summary>void Upload1(){////读取本地数据库中的为上传信息,IsUpload==false,转换成Json字符串;////string meterStr=null,recorderStr = null;//ObservableCollection<Recorder> recorders = Helper.GetRecorders(false);//if (recorders.Count > 0)//{// foreach (var recorder in recorders)// {// _meter = Helper.GetMeter(recorder.MeterId);// ModuleNum = _meter.ModuleNum;// MeterNum = _meter.MeterNum;// _dalModule.ModuleAdd(ModuleNum, MeterNum, TqName, Account, recorder.SaveTime, Address);// //----------------此处需要在本地保存一下,更改一下上传状态;-------------------// recorder.IsUpload = true;// Helper.Update(recorder);//更新一下上传状态;// //recorderStr += new JsonConvertHelper<Recorder>().ToString(recorder);// //meterStr += new JsonConvertHelper<Meter>().ToString(new SqliteHelper().GetMeter(recorder.MeterId));// //Console.WriteLine($"保存时间:{recorder.SaveTime},电能表号:{MeterNum},模块号:{ModuleNum}");// }// _callBack("数据上传成功!");//}//else// _callBack("数据为空,请核实后上传!");}/// <summary>/// 通过Socketk客户端进行数据上传//第三版--服务器内存不足,socket无法使用;/// </summary>//void Upload3()//{// //读取本地数据库中的为上传信息,IsUpload==false,转换成Json字符串;// //string meterStr=null,recorderStr = null;// bool isSave=false;// SocketClient client = null;// ObservableCollection<Recorder> recorders = Helper.GetRecorders(false);// ObservableCollection<History> histories = new ObservableCollection<History>();// JsonConvertHelper<ObservableCollection<History>> jh = new JsonConvertHelper<ObservableCollection<History>>();// string Msg =string.Empty;// try// {// if (recorders.Count > 0)// {// //首先要判断是否有数据,才能进行下一步的链接;// client = new SocketClient();// foreach (var recorder in recorders)// {// _meter = Helper.GetMeter(recorder.MeterId);// ModuleNum = _meter.ModuleNum;// MeterNum = _meter.MeterNum;// //_dalModule.ModuleAdd(ModuleNum, MeterNum, TqName, Account, recorder.SaveTime, Address);// History history = new History()// {// ModuleNum = this.ModuleNum,// MeterNum = this.MeterNum,// TqName = this.TqName,// Account = this.Account,// SaveTime = recorder.SaveTime,// Address = this.Address// };// SaveTime = recorder.SaveTime,// //----------------此处需要在本地保存一下,更改一下上传状态;-------------------// recorder.IsUpload = true;// Helper.Update(recorder);//更新一下上传状态;// //recorderStr += new JsonConvertHelper<Recorder>().ToString(recorder);// //meterStr += new JsonConvertHelper<Meter>().ToString(new SqliteHelper().GetMeter(recorder.MeterId));// //Console.WriteLine($"保存时间:{recorder.SaveTime},电能表号:{MeterNum},模块号:{ModuleNum}");// histories.Add(history);// isSave = true;// }// ///将历史数据的对象集合进行序列化;然后将字符串传输到服务器;// Msg = jh.ToString(histories);// if (client.SendMsg(Msg))// _callBack("数据上传成功!");// else _callBack("数据上传失败!");//回调函数,显示上传结果;// client.Client.Close();// }// else// _callBack("数据为空,请核实后上传!");// }// catch(SocketException)// {// _callBack("上传服务器未开启,请开启后再上传数据!");// }//}/// <summary>/// 第二版:通过WebService上传,服务器端已架设Webservice成功;/// </summary>void Upload2(){//读取本地数据库中的为上传信息,IsUpload==false,转换成Json字符串;//string meterStr=null,recorderStr = null;ObservableCollection<Recorder> recorders = Helper.GetRecorders(false);ObservableCollection<History> histories = new ObservableCollection<History>();JsonConvertHelper<ObservableCollection<History>> jh = new JsonConvertHelper<ObservableCollection<History>>();string Msg = string.Empty;try{if (recorders.Count > 0){//首先要判断是否有数据,才能进行下一步的链接;foreach (var recorder in recorders){_meter = Helper.GetMeter(recorder.MeterId);ModuleNum = _meter.ModuleNum;MeterNum = _meter.MeterNum;History history = new History(){ModuleNum = this.ModuleNum,MeterNum = this.MeterNum,TqName = this.TqName,Account = this.Account,SaveTime = recorder.SaveTime,Address = this.Address};// SaveTime = recorder.SaveTime,histories.Add(history);}///将历史数据的对象集合进行序列化;然后将字符串传输到服务器;Msg = jh.ToString(histories);AppToolsSoapClient msc = new AppToolsSoapClient(AppToolsSoapClient.EndpointConfiguration.AppToolsSoap12);var rtnValue = msc.DataUpLoad(Msg);if(rtnValue==true){new Thread(() =>{foreach (var recorder in recorders){//----------------此处需要在本地保存一下,更改一下上传状态;-------------------recorder.IsUpload = true;Helper.Update(recorder);//更新一下上传状态;//recorderStr += new JsonConvertHelper<Recorder>().ToString(recorder);//meterStr += new JsonConvertHelper<Meter>().ToString(new SqliteHelper().GetMeter(recorder.MeterId));//Console.WriteLine($"保存时间:{recorder.SaveTime},电能表号:{MeterNum},模块号:{ModuleNum}");}}).Start();_callBack("数据上传成功!");}else _callBack("数据上传失败!");}else_callBack("数据为空,请核实后上传!");}catch (Exception ex){_callBack(ex.ToString ());}}
}
}
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using CommandService;
using System.Collections.ObjectModel;
using DataBaseService.SqliteHelper;
using StringService;
using AppTools_WS;
using System.Linq;
using System.Threading.Tasks;
using Models;
namespace ModuleInstall.ViewModels
{
public class SystemSettingPageViewModel:PropertyChangeService.PropertyChangedHelper
{
private AppToolsSoapClient _client;
private Company _company=new Company ();
private const string fileName = "Config.txt";
private MainCommand _writeSettingCmd;// readCmd;
private Action
private SettingModel _settingModel=new SettingModel();
private SqliteHelper sqliteHelper;
private ObservableCollection
private ObservableCollection
private ObservableCollection
private ObservableCollection
public ObservableCollection
public ObservableCollection
public ObservableCollection
public ObservableCollection
public Company Comy { get { return _company; } set { _company = value; } }
public ObservableCollection
public MainCommand WriteSettingCmd { get { return _writeSettingCmd; } }
public SettingModel SetModel { set { _settingModel = value; } get { return _settingModel; } }
public static readonly string filePath=Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), fileName);
public SystemSettingPageViewModel(Action
{
if (_client == null)
_client = new AppToolsSoapClient(AppToolsSoapClient.EndpointConfiguration.AppToolsSoap12);
GetCompanies();
GetGroupes();
if (!File.Exists(filePath))
{
File.Create(filePath);
}
_writeSettingCmd = new MainCommand(JsonWrite);
CallBack = callBack;
//readCmd = new MainCommand(Read);
}
///
/// 通过供电公司名称,获取下属单位供电所的所有内容;
///
///
///
public ObservableCollection
{
ObservableCollection
ArrayOfString strings = _client.GetGdses(companyName);
foreach (string str in strings)
{
gds.Add(str);
}
return gds;
}
public void GetGroupes()
{
try
{
ArrayOfString strings = _client.GetGroups();
foreach (string str in strings)
{
GroupCollection.Add(str);
}
//GroupCollection=new Dal_Group().GroupList();}catch (Exception ex){throw ex;}}/// <summary>/// 通过供电所名称,获取下属单位供电台区的所有内容;/// </summary>/// <param name="companyName"></param>/// <returns></returns>public ObservableCollection<string> GetTaiQues(string gdsName){try{ObservableCollection<string> taiqus = new ObservableCollection<string>();ArrayOfString strings = _client.GetTaiQues(gdsName);foreach (string str in strings){taiqus.Add(str);}return taiqus;}catch(Exception ex){ throw ex; }}/// <summary>/// 获取所有供电公司的信息;/// </summary>/// <param name="companyName"></param>/// <returns></returns>void GetCompanies(){try{ArrayOfString strings = _client.GetCompanies();foreach (string str in strings){CompanyCollection.Add(str);}}catch{throw;}}public ObservableCollection<string> GetUsers(string groupName){ObservableCollection<string> os= new ObservableCollection<string>();ArrayOfString Users = _client.GetUsers(groupName);foreach (string o in Users){os.Add(o.ToString());}return os;}/// <summary>/// 将系统设置的信息对象序列化为Json字符串;/// </summary>public void JsonWrite(){try{if(File.Exists(filePath)){File.Delete (filePath);using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Write)){using (StreamWriter sw = new StreamWriter(fs)){//向配置文件写入配置信息;string jsonStr = new JsonConvertHelper<SettingModel>().ToString(SetModel);//JsonConvert.SerializeObject(SetModel);sw.Write(jsonStr);sw.Flush();sw.Close();fs.Close();}}}sqliteHelper = new SqliteHelper();sqliteHelper.InitData(SetModel.CompanyName, SetModel.GdsName, SetModel.TqName, SetModel.Account);CallBack("保存成功!");}catch(Exception ex){CallBack($"保存失败!{ex.ToString()}");}}
}
}
using System;
using System.Collections.Generic;
using System.Text;
using Models;
using StringService;
using System.Collections.ObjectModel;
using AppTools_WS;
using System.Security.Cryptography.X509Certificates;
using System.IO;
using CommandService;
using DataBaseService.SqliteHelper;
namespace ModuleInstall.ViewModels
{
public class DataSearchViewModel
{
private AppToolsSoapClient _client;
//private Dal_History _dalHistory =new Dal_History ();
private Action
///
/// 未上传数量
///
public int UnUploadCount { set; get; }
///
/// 今日已上传数量
///
public int TodayUploadCount { set; get; }
///
/// 历史上传数量
///
public int UploadHistoryCount { set; get; }
public SettingModel SetModel { set; get; }public ObservableCollection<History> UploadHistoryList { get; set; }public DataSearchViewModel(Action<string> action){try{_action = action;if (_client == null)_client = new AppToolsSoapClient (AppToolsSoapClient.EndpointConfiguration.AppToolsSoap12);SetModel = JsonRead(SystemSettingPageViewModel.filePath);//读取配置文件;UnUploadCount = new SqliteHelper().GetUnUploadCount();//从本地获取未上传信息数量;UploadHistoryCount = _client.GetUploadedHistoryCount(SetModel.Account);//获取上传历史记录数量;TodayUploadCount = _client.GetTodayUploadedCount(SetModel.Account);//获取今天上传数量(指定操作人员);}catch {_action("应用使用前,请先进行系统设置!");}}/// <summary>/// Json数据读取;从字符串读取到Object(必须为Object)对象;/// </summary>/// <param name="filePath"></param>/// <returns></returns>public SettingModel JsonRead(string filePath){StreamReader sr = null;try{sr = new StreamReader(filePath);string jsonStr = sr.ReadToEnd();return new JsonConvertHelper<SettingModel>().ToObject(jsonStr); //JsonConvert.DeserializeObject<SettingModel>(jsonStr);}catch (Exception ex){throw ex;}finally {sr.Close();}}}
}
开发人:QQ-1009714648