diff --git a/AksWebBrowser.sln b/AksWebBrowser.sln new file mode 100644 index 0000000..2d69e9e --- /dev/null +++ b/AksWebBrowser.sln @@ -0,0 +1,37 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34622.214 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AKS.EnterpriseLibrary.WebBrowser", "CPF_Cef\AKS.EnterpriseLibrary.WebBrowser.csproj", "{76142658-6E83-4A1C-8CC9-C2574865CA7D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {76142658-6E83-4A1C-8CC9-C2574865CA7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {76142658-6E83-4A1C-8CC9-C2574865CA7D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {76142658-6E83-4A1C-8CC9-C2574865CA7D}.Debug|x64.ActiveCfg = Debug|x64 + {76142658-6E83-4A1C-8CC9-C2574865CA7D}.Debug|x64.Build.0 = Debug|x64 + {76142658-6E83-4A1C-8CC9-C2574865CA7D}.Debug|x86.ActiveCfg = Debug|x86 + {76142658-6E83-4A1C-8CC9-C2574865CA7D}.Debug|x86.Build.0 = Debug|x86 + {76142658-6E83-4A1C-8CC9-C2574865CA7D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {76142658-6E83-4A1C-8CC9-C2574865CA7D}.Release|Any CPU.Build.0 = Release|Any CPU + {76142658-6E83-4A1C-8CC9-C2574865CA7D}.Release|x64.ActiveCfg = Release|x64 + {76142658-6E83-4A1C-8CC9-C2574865CA7D}.Release|x64.Build.0 = Release|x64 + {76142658-6E83-4A1C-8CC9-C2574865CA7D}.Release|x86.ActiveCfg = Release|x86 + {76142658-6E83-4A1C-8CC9-C2574865CA7D}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {BDDA2FFD-1C83-470F-82EE-DE0E448EEB6D} + EndGlobalSection +EndGlobal diff --git a/CPF_Cef/AKS.EnterpriseLibrary.WebBrowser.csproj b/CPF_Cef/AKS.EnterpriseLibrary.WebBrowser.csproj new file mode 100644 index 0000000..9e4a5de --- /dev/null +++ b/CPF_Cef/AKS.EnterpriseLibrary.WebBrowser.csproj @@ -0,0 +1,51 @@ + + + + WinExe + net6.0 + Recent.ico + + AksWebBrowser + AksWebBrowser + AnyCPU;x64;x86 + + + + true + + AnyCPU + + + + true + + AnyCPU + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CPF_Cef/AssistEntity.cs b/CPF_Cef/AssistEntity.cs new file mode 100644 index 0000000..bc200c8 --- /dev/null +++ b/CPF_Cef/AssistEntity.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AksWebBrowser +{ + public enum LightTypeModel + { + FingerLight, + IDCardLight, + BottomLight, + BurnLight + } +} diff --git a/CPF_Cef/Common/COMUtils.cs b/CPF_Cef/Common/COMUtils.cs new file mode 100644 index 0000000..708e29a --- /dev/null +++ b/CPF_Cef/Common/COMUtils.cs @@ -0,0 +1,321 @@ +using AKS.EnterpriseLibrary.WebBrowser; +using AksWebBrowser; +using AKSWebBrowser.Commen; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.IO.Ports; +using System.Text; +using System.Threading.Tasks; +using System.Timers; +using Timer = System.Timers.Timer; +namespace AKSWebBrowser.Common +{ + public class COMUtils + { + private static SerialPort serialPort = new SerialPort(); + public string jsonstr = string.Empty; + public string jsontemp = string.Empty; + public int maxCHunkSize = 1024; + public string callback = string.Empty; + public string ml = "COM4"; + public COMUtils() + { + OpenCOM(); + } + + //打开COM口 + public void OpenCOM() + { + + try + { + //要执行的Linux命令 + string[] cmd = LinuxCmdArea("ls /dev"); + if (cmd.Length > 0) + { + string parm = string.Empty; + foreach (string line in cmd) + { + if (line.Contains("ttyCH341USB")) + { + parm = line; + break; + } + } + if (!string.IsNullOrEmpty(parm)) + { + ml = "/dev/" + parm; + Log.Info("输出结果:" + ml); + //给管理权限 + LinuxCmd(ml); + //打开串口 + // 设置COM口,波特率,奇偶校验,数据位,停止位 + serialPort.PortName = ml; // 请替换为你的串口名称 + serialPort.BaudRate = 115200; // 设置波特率 + serialPort.Parity = Parity.None; + serialPort.DataBits = 8; + serialPort.StopBits = StopBits.One; + serialPort.Handshake = Handshake.None; + serialPort.DtrEnable = true; //启用控制终端就续信号 + //serialPort.ReadTimeout = 18000; + //serialPort.RtsEnable = true; //启用请求发送信号 + serialPort.NewLine = "\n"; + serialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler); + if (!serialPort.IsOpen) + { + serialPort.Open(); + } + Timer timer = new Timer(3000);//1秒钟的时间间隔 + timer.Elapsed += OnTimedEvent; + timer.AutoReset = true;//重复执行 + timer.Enabled = true;//启动定时器 + Log.Info("浏览器COM服务启动成功"); + } + else + { + Log.Info("串口类型不匹配"); + } + } + else + { + Log.Info("当前设备没有串口设备"); + } + } + catch (Exception ex) + { + Log.Info("服务启动异常ex: " + ex.Message + ""); + } + + } + + //接受数据 + public static string bsid = string.Empty; + public static string bsext = string.Empty; + public static string bspath = string.Empty; + public static bool sfjswc = false; + private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e) + { + try + { + SerialPort sp = (SerialPort)sender; + string _jsonstr = sp.ReadExisting(); + if (!string.IsNullOrEmpty(_jsonstr)) + { + if (_jsonstr.Contains("\n")) + { + jsonstr = jsontemp + _jsonstr; + //向js发送数据 + //CShaseBJavaScript(jsonstr); + //jsontemp = string.Empty; + //jsonstr = string.Empty; + } + else + { + jsontemp = jsontemp + _jsonstr; + } + } + } + catch (Exception ex) + { + Log.Info("接受数据数据异常: " + ex.Message + ""); + jsonstr = MainModel.str2Base64("{\"callback\":\"" + this.callback + "\",\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + "接受数据数据超时:" + ex.Message + "\"}"); + // CShaseBJavaScript(jsonstr); + } + } + + //打开串口 + private void OnTimedEvent(Object source, ElapsedEventArgs e) + { + try + { + if (!serialPort.IsOpen) + { + serialPort.Open(); + } + } + catch (Exception ex) + { + Log.Info("定时任务打开串口异常: " + ex.Message + ""); + } + } + + //发送数据 + public string SendData(string data, string callback) + { + try + { + this.callback = callback; + if (serialPort.IsOpen) + { + jsontemp = string.Empty; + jsonstr = string.Empty; + //写入数据并以换行符结束 + serialPort.WriteLine(data); + Log.Info("发送数据成功: " + data + ""); + while (string.IsNullOrEmpty(jsonstr)) + { + Task.Delay(10).Wait(); + } + } + else + { + //重新打开串口 + OpenCOM(); + if (serialPort.IsOpen) + { + jsontemp = string.Empty; + jsonstr = string.Empty; + //写入数据并以换行符结束 + serialPort.WriteLine(data); + Log.Info("发送数据成功: " + data + ""); + while (string.IsNullOrEmpty(jsonstr)) + { + Task.Delay(10).Wait(); + } + } + else + { + jsontemp = string.Empty; + jsonstr = string.Empty; + Log.Info("发送数据失败"); + jsonstr = MainModel.str2Base64("{\"callback\":\"" + this.callback + "\",\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + "串口未打开" + "\"}"); + //CShaseBJavaScript(jsonstr); + } + } + } + catch (Exception ex) + { + jsontemp = string.Empty; + jsonstr = string.Empty; + Log.Info("发送数据异常3: " + ex.Message + ""); + jsonstr = MainModel.str2Base64("{\"callback\":\"" + this.callback + "\",\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + "发送数据异常:" + ex.Message + "\"}"); + //CShaseBJavaScript(jsonstr); + } + return jsonstr; + } + + //关闭 + public void ClosePort() + { + try + { + if (serialPort.IsOpen) + { + serialPort.Close(); // 关闭串口 + } + } + catch (Exception ex) + { + Log.Error("关闭异常: " + ex.Message + ""); + } + } + + /// + /// COM接收文件 + /// + public void NewMethod1(SerialPort sp, string path) + { + byte[] buffer = new byte[sp.ReadBufferSize]; + int bytesRead = sp.Read(buffer, 0, buffer.Length); + using (FileStream fileStream = new FileStream(path, FileMode.Append)) + { + fileStream.Write(buffer, 0, bytesRead); + fileStream.Close(); + fileStream.Dispose(); + } + } + + + /// + /// COM口公共发送文件 + /// + /// + public void NewMethod(string url, string id) + { + string ext = Path.GetExtension(url); + serialPort.WriteLine("Start_" + id + "_" + ext); + // 发送端 + byte[] documentBytes = File.ReadAllBytes(url); + serialPort.Write(documentBytes, 0, documentBytes.Length); + serialPort.WriteLine("End"); + } + + + //向js传输数据 + public void CShaseBJavaScript(string param) + { + Task.Run(async () => + { + param = MainModel.Base64str2(param); + Log.Info("返回数据:" + param); + JObject jo = (JObject)JsonConvert.DeserializeObject(param); + bool fieldExists = jo.ContainsKey("callback"); + if (fieldExists) + { + string callback = jo["callback"].ToString(); + Log.Info("回调js方法:" + callback); + string _parm = callback + "('" + param + "')"; + await Parame.webBrowser.ExecuteJavaScript(_parm); + } + else + { + Log.Info("回调js方法为空"); + } + }); + } + + //执行命令 + public void LinuxCmd(string command) + { + command = $"echo 'aks@123456' sudo -S chmod 777 {command}"; + Log.Info("执行命令:" + command); + // 启动进程 + var process = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = "/bin/bash", + Arguments = $"-c \"{command}\"", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true + } + }; + process.Start(); + string output = process.StandardOutput.ReadToEnd(); + string error = process.StandardError.ReadToEnd(); + process.WaitForExit(); + Log.Info("执行命令结果返回:" + output); + Log.Info("执行命令错误结果返回:" + error); + } + + //执行命令返回数组 + public string[] LinuxCmdArea(string command) + { + // 使用ProcessStartInfo设置启动参数 + ProcessStartInfo startInfo = new ProcessStartInfo + { + FileName = "/bin/bash", // 指定bash shell + Arguments = $"-c \"{command}\"", // 要执行的命令 + RedirectStandardOutput = true, // 重定向标准输出 + UseShellExecute = false, // 不使用系统外壳程序启动 + CreateNoWindow = true // 不创建新窗口 + }; + + // 启动进程 + using (Process process = Process.Start(startInfo)) + { + using (System.IO.StreamReader reader = process.StandardOutput) + { + string result = reader.ReadToEnd(); // 读取全部输出 + return result.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); // 转换为字符串数组 + } + } + } + } +} diff --git a/CPF_Cef/Common/ChunkedUpload.cs b/CPF_Cef/Common/ChunkedUpload.cs new file mode 100644 index 0000000..f6f9759 --- /dev/null +++ b/CPF_Cef/Common/ChunkedUpload.cs @@ -0,0 +1,58 @@ +using Newtonsoft.Json.Linq; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; +using System.Threading.Tasks; +using CPF.Controls; + +namespace AksWebBrowser.Common +{ + public class ChunkedUpload + { + private readonly HttpClient _httpClient; + + public ChunkedUpload(HttpClient httpClient) + { + _httpClient = httpClient; + } + + public async Task UploadFileAsync(string url, string filePath) + { + string ret = string.Empty; + using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) + { + FileInfo fileInfo = new FileInfo(filePath); + int totalParts = 1; + int chunkNumber = 1; + // 读取文件流其实位置 + var fileStreamPos = 0; + var uploadUrl = $"{url}?partNumber={chunkNumber}&chunks={totalParts}&size={fileInfo.Length}&start={fileStreamPos}&end={fileInfo.Length}&total={fileInfo.Length}&FileName={Path.GetFileName(filePath)}"; + + using (var client = new HttpClient()) + { + + var formData = new MultipartFormDataContent(); + formData.Add(new StreamContent(fileStream, (int)fileStream.Length), "file", Path.GetFileName(filePath) + ".partNumber-1"); + var response = await client.PostAsync(uploadUrl, formData); + var responseString = await response.Content.ReadAsStringAsync(); + fileStream.Close(); + fileStream.Dispose(); + ret = responseString; + JObject jo = (JObject)JsonConvert.DeserializeObject(ret); + if (Convert.ToBoolean(jo["IsSucceed"].ToString()) == true) + { + string result = jo["result"].ToString(); + JObject jo1 = (JObject)JsonConvert.DeserializeObject(result); + ret = jo1["url"].ToString(); + } + } + } + return ret; + } + } +} diff --git a/CPF_Cef/Common/Log.cs b/CPF_Cef/Common/Log.cs new file mode 100644 index 0000000..adc6668 --- /dev/null +++ b/CPF_Cef/Common/Log.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AKSWebBrowser.Commen +{ + public class Log + { + private static StreamWriter streamWriter; //写文件 + + public static void Error(string message) + { + try + { + //DateTime dt = new DateTime(); + string directPath = AppDomain.CurrentDomain.BaseDirectory + @"/logs/error"; //在获得文件夹路径 + if (!Directory.Exists(directPath)) //判断文件夹是否存在,如果不存在则创建 + { + Directory.CreateDirectory(directPath); + } + directPath += string.Format(@"/{0}.log", DateTime.Now.ToString("yyyy-MM-dd")); + if (streamWriter == null) + { + streamWriter = !File.Exists(directPath) ? File.CreateText(directPath) : File.AppendText(directPath); + } + streamWriter.WriteLine("***********************************************************************"); + streamWriter.WriteLine(DateTime.Now.ToString("HH:mm:ss")); + streamWriter.WriteLine("输出信息:错误信息"); + if (message != null) + { + streamWriter.WriteLine("异常信息:\r\n" + message); + } + } + finally + { + if (streamWriter != null) + { + streamWriter.Flush(); + streamWriter.Dispose(); + streamWriter = null; + } + } + } + + public static void Info(string message) + { + try + { + //DateTime dt = new DateTime(); + string directPath = AppDomain.CurrentDomain.BaseDirectory + @"/logs/Info"; //在获得文件夹路径 + if (!Directory.Exists(directPath)) //判断文件夹是否存在,如果不存在则创建 + { + Directory.CreateDirectory(directPath); + } + directPath += string.Format(@"/{0}.log", DateTime.Now.ToString("yyyy-MM-dd")); + if (streamWriter == null) + { + streamWriter = !File.Exists(directPath) ? File.CreateText(directPath) : File.AppendText(directPath); + } + streamWriter.WriteLine("***********************************************************************"); + streamWriter.WriteLine(DateTime.Now.ToString("HH:mm:ss")); + streamWriter.WriteLine("输出信息:信息"); + if (message != null) + { + streamWriter.WriteLine("信息:\r\n" + message); + } + } + finally + { + if (streamWriter != null) + { + streamWriter.Flush(); + streamWriter.Dispose(); + streamWriter = null; + } + } + } + } +} diff --git a/CPF_Cef/Common/Utils.cs b/CPF_Cef/Common/Utils.cs new file mode 100644 index 0000000..5616b15 --- /dev/null +++ b/CPF_Cef/Common/Utils.cs @@ -0,0 +1,21 @@ +using CPF.Controls; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AksWebBrowser.Common +{ + public class Utils + { + /// + /// 消息弹框 + /// + /// + public static void MessagesBox(string mes) { + MessageBox.ShowSync(mes); + + } + } +} diff --git a/CPF_Cef/CusWebBrowser.cs b/CPF_Cef/CusWebBrowser.cs new file mode 100644 index 0000000..d51b8b7 --- /dev/null +++ b/CPF_Cef/CusWebBrowser.cs @@ -0,0 +1,77 @@ +using CPF; +using CPF.Cef; +using CPF.Cef.JSExtenstions; +using CPF.Mac.CoreText; +using CPF.Reflection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.ConstrainedExecution; +using System.Text; +using System.Threading.Tasks; + +namespace AKS.EnterpriseLibrary.WebBrowser +{ + + public class CusWebBrowser : CPF.Cef.WebBrowser + { + public CusCefRequestHandler CusRequest = new CusCefRequestHandler(); + public CusWebBrowser() { } + + protected override CpfCefClient OnCreateWebBrowser(CefBrowserSettings settings) + { + CpfCefClient cefClient = base.OnCreateWebBrowser(settings); + cefClient.RequestHandler = CusRequest; + cefClient.ContextMenuHandler = new MenuHandler(); + cefClient.DragHandler = new DragHandler(); + return cefClient; + } + } + + public class CusCefRequestHandler : CpfCefRequestHandler + { + public delegate void CusResquestDelegate(CefPostData postData, CefRequest request); + public event CusResquestDelegate CusResquestEvent; + + public CusCefRequestHandler() { } + + protected override CefResourceRequestHandler GetResourceRequestHandler(CefBrowser browser, CefFrame frame, CefRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling) + { + CusResquestEvent(request.PostData, request); + return null; + } + } + + public class DragHandler : CpfCefDragHandler + { + protected override bool OnDragEnter(CefBrowser browser, CefDragData dragData, CefDragOperationsMask mask) + { + return true; + } + protected override void OnDraggableRegionsChanged(CefBrowser browser, CefFrame frame, CefDraggableRegion[] regions) + { + + } + } + + public class MenuHandler : CpfCefContextMenuHandler + { + protected override void OnBeforeContextMenu(CefBrowser browser, CefFrame frame, CefContextMenuParams state, CefMenuModel model) + { + model.Clear(); + } + protected override bool OnContextMenuCommand(CefBrowser browser, CefFrame frame, CefContextMenuParams state, int commandId, CefEventFlags eventFlags) + { + return false; + } + protected override void OnContextMenuDismissed(CefBrowser browser, CefFrame frame) + { + + } + protected override bool RunContextMenu(CefBrowser browser, CefFrame frame, CefContextMenuParams parameters, CefMenuModel model, CefRunContextMenuCallback callback) + { + return false; + } + } + +} diff --git a/CPF_Cef/FrmMain.cs b/CPF_Cef/FrmMain.cs new file mode 100644 index 0000000..cae73a7 --- /dev/null +++ b/CPF_Cef/FrmMain.cs @@ -0,0 +1,202 @@ +using AksWebBrowser; +using CPF; +using CPF.Cef; +using CPF.Controls; +using CPF.Platform; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json; +using System; +using System.IO; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using AKSWebBrowser.Commen; +using System.Collections.Generic; +using System.Reflection.Metadata; +using AksWebBrowser.Common; + +namespace AKS.EnterpriseLibrary.WebBrowser +{ + public class FrmMain : Window + { + + protected override void InitializeComponent() + { + LoadStyleFile("res://AksWebBrowser/StyleSheet.css"); + //加载样式文件,文件需要设置为内嵌资源 + Title = "控申业务专用浏览器"; + CanResize = false; + ShowInTaskbar = true; + WindowState = WindowState.Maximized; + Children.Add( + new Border + { + Width = "100%", + Height = "100%", + Child = new Panel + { + Size = SizeField.Fill, + Children = + { + new CusWebBrowser + { + PresenterFor = this, + Name = nameof(Parame.webBrowser), + Bindings = + { + { + nameof(CusWebBrowser.Title), + "Title", + this, + BindingMode.OneWayToSource + }, + }, + MarginTop=0, + MarginLeft=0, + MarginRight=0, + MarginBottom=0, + }, + } + } + } + ); + } + private TextBox textBox; + protected override async void OnInitialized() + { + //窗体大小 + this.Width = 1080; + this.Height = 1920; + //SetTaskStatus.Hidetask(); + base.OnInitialized(); + Parame.webBrowser = FindPresenterByName(nameof(Parame.webBrowser)); + textBox = FindPresenterByName(nameof(textBox)); + Parame.webBrowser.CusRequest.CusResquestEvent += CusRequest_CusResquestEvent; + //浏览器大小 + Parame.webBrowser.Width = 1080; + Parame.webBrowser.Height = 1920; + Parame.webBrowser.Url = "http://192.168.0.34:8078/#/main-out"; + //Parame.webBrowser.Url = Application.StartupPath + @"\html\index.html"; + //开发者工具暂时只能支持Windows + //webBrowser.ShowDev(); + //SetTaskStatus.Showtask(); + Parame.webBrowser.LoadEnd += WebBrowser_LoadEnd; + this.Closing += MainWindow_Closing; + } + + //关闭事件 + private void MainWindow_Closing(object sender, ClosingEventArgs e) + { + new MainModel().CLoseCOM(); + MainModel.KillProcessByName("AksWebBrowser"); + } + bool showDev = false; + private void WebBrowser_LoadEnd(object sender, LoadEndEventArgs e) + { + if (!showDev) + { + showDev = true; + Parame.webBrowser.ShowDev(); + } + //获取授权 + GetSQObject(); + } + + public void Writelog(string str, string dirName = @"logs") + { + try + { + if (string.IsNullOrEmpty(str)) return; + + var baseDir = AppDomain.CurrentDomain.BaseDirectory + dirName; + if (!Directory.Exists(baseDir)) + { + Directory.CreateDirectory(baseDir); + } + string filePath = System.IO.Path.Combine(baseDir, DateTime.Now.ToString("yyyy-MM-dd") + "_log.txt"); + using (StreamWriter sw = File.AppendText(filePath)) + { + sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "[" + str + "]" + "\r\n"); + sw.Flush(); + } + } + catch { } + } + private void CusRequest_CusResquestEvent(CefPostData postData, CefRequest request) + { + string postParams = string.Empty; + if (postData != null) + { + //取提交的参数 + CefPostData cefPostData = postData; + var elements = cefPostData.GetElements(); + foreach (var element in elements) + { + if (element.ElementType == CefPostDataElementType.Bytes) + { + var bytes = element.GetBytes(); + postParams = Encoding.UTF8.GetString(bytes); + Console.WriteLine("请求参数:" + postParams); + } + } + } + + Console.WriteLine("请求地址:" + request.Url.ToString()); + } + + //调用JS内的JS方法 + async void InvokeJS(CpfObject obj, RoutedEventArgs eventArgs) + { + var r = await Parame.webBrowser.ExecuteJavaScript("callback('调用绑定到JS里的C#方法')"); + } + + /// + /// 或者可以用授权接口 + /// + public void GetSQObject() + { + Task.Run(async () => + { + var client = new HttpClient(); + var request = new HttpRequestMessage(HttpMethod.Get, $"{Parame.apiUrl}/api/Interface/Getlist?Ytjbm={Parame.key}"); + var response = await client.SendAsync(request); + List list = new List(); + if (response.StatusCode.ToString() == "200") + { + response.EnsureSuccessStatusCode(); + var body = await response.Content.ReadAsStringAsync(); + JObject jo = (JObject)JsonConvert.DeserializeObject(body); + if (jo["IsSucceed"].ToString() == "True") + { + string result = jo["result"].ToString(); + if (!string.IsNullOrEmpty("result")) + { + JArray array = (JArray)JsonConvert.DeserializeObject(result); + foreach (JObject item in array) + { + Func func = new Func() + { + Id = item["Id"].ToString(), + Platform = item["Platform"].ToString(), + Interfaceaddress = item["Interfaceaddress"].ToString(), + }; + list.Add(func); + } + } + else + { + Log.Info("未获取授权"); + Utils.MessagesBox("未获取授权"); + } + } + else + { + Log.Info("未获取授权"); + Utils.MessagesBox("未获取授权"); + } + } + Parame.FuncObject = list; + }); + } + } +} diff --git a/CPF_Cef/MainModel.cs b/CPF_Cef/MainModel.cs new file mode 100644 index 0000000..0dcd33e --- /dev/null +++ b/CPF_Cef/MainModel.cs @@ -0,0 +1,1206 @@ +using AksWebBrowser; +using AksWebBrowser.Common; +using AKSWebBrowser.Commen; +using AKSWebBrowser.Common; +using CPF.Cef; +using CPF.Mac.AppKit; +using NAudio.Wave; +using NAudio.Wave.SampleProviders; +using SkiaSharp; +using System; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using System.Web; +using System.Xml.Linq; + +namespace AKS.EnterpriseLibrary.WebBrowser +{ + public class MainModel : CPF.CpfObject + { + public COMUtils com = new COMUtils(); + public string callback = string.Empty; + public string PrinterName = "Lexmark-MS430-Series"; + public static Process recordingProcess; + public static Process Typrocess; + + /// + /// 读取身份证卡号 + /// + /// + /// + [JSFunction] + public string IDCardRead(string paramsString) + { + try + { + if (!isFuncisFuncObject("IDCardRead")) + { + Utils.MessagesBox("读取身份证设备未授权使用"); + return "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + "读取身份证设备未授权使用" + "\"}"; + } + else + { + paramsString = "{\"callback\":\"" + callback + "\",\"type\":\"1\",\"param\":{\"data\":\"" + "" + "\"}}"; + Log.Info("读取身份证卡号: " + paramsString + ""); + string base64 = str2Base64(paramsString); + string str = com.SendData(base64, callback); + string result = Base64str2(str); + SubmitLogs(result, "IDCardRead"); + return result; + } + } + catch (Exception ex) + { + Log.Error("读取身份证卡号异常: " + ex.Message + ""); + string result = "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + ex.Message + "\"}"; + SubmitLogs(result, "IDCardRead"); + return result; + } + } + + /// + /// 打印排队票据 + /// + /// 排号 + /// 等待人数 + /// 二维码 + /// 办理业务名称 + /// + [JSFunction] + public string SendByPrint(string ph, string ddrs, string qrcode, string ywmc) + { + try + { + if (!isFuncisFuncObject("SendByPrint")) + { + Utils.MessagesBox("打印排队票据设备未授权使用"); + return "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + "打印排队票据设备未授权使用" + "\"}"; + } + else + { + string paramsString = "{\"callback\":\"" + callback + "\",\"type\":\"2\",\"param\":{\"ph\":\"" + ph + "\",\"ddrs\":\"" + ddrs + "\",\"qrcode\":\"" + qrcode + "\",\"ywmc\":\"" + ywmc + "\"}}"; + Log.Info("打印排队票据: " + paramsString + ""); + string base64 = str2Base64(paramsString); + string str = com.SendData(base64, callback); + string result = Base64str2(str); + SubmitLogs(result, "SendByPrint"); + return result; + } + } + catch (Exception ex) + { + Log.Error("打印排队票据异常: " + ex.Message + ""); + string result = "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + ex.Message + "\"}"; + SubmitLogs(result, "SendByPrint"); + return result; + } + } + + /// + /// 文字语音播报 + /// apt install sox + /// apt install libsox-fmt-all + /// + /// + /// + /// + public WaveOutEvent playerTxt = null; + public static string tempWav = string.Empty; + [JSFunction] + public string payleText(string text, bool ispaye) + { + try + { + if (!isFuncisFuncObject("payleText")) + { + Utils.MessagesBox("文字语音播报设备未授权使用"); + return "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + "文字语音播报设备未授权使用" + "\"}"; + } + else + { + string paramsString = "{\"callback\":\"" + callback + "\",\"type\":\"3\",\"param\":{\"text\":\"" + text + "\",\"ispaye\":\"" + ispaye + "\"}}"; + Log.Info("文字语音播报: " + paramsString + ""); + //string base64 = str2Base64(paramsString); + //if (base64.Length > 1024) + //{ + // //形成临时文件 + // DateTime dateTime = DateTime.Now; + // string time = DateTime.Now.ToString( + // "yyyyMMddHHmmss", DateTimeFormatInfo.InvariantInfo); + // var dirpath = System.IO.Path.Combine(Environment.CurrentDirectory, "wwwroot", "TempFile"); + // if (!Directory.Exists(dirpath)) + // { + // Directory.CreateDirectory(dirpath); + // } + // var filepath = System.IO.Path.Combine(dirpath, time); + // string path = dirpath + @"/" + time + ".txt"; + // base64 = str2Base64(text); + // byte[] bytes = Convert.FromBase64String(base64); + // System.IO.FileStream stream = new System.IO.FileStream(path, System.IO.FileMode.CreateNew); + // System.IO.BinaryWriter writer = new System.IO.BinaryWriter(stream); + // writer.Write(bytes, 0, bytes.Length); + // writer.Close(); + // Log.Info("文字语音播报临时文件: " + path + ""); + // string id = Guid.NewGuid().ToString(); + // //通过文件发送数据 + // com.NewMethod(path, ".txt"); + + // //正式执行命令 + // string url = "http://192.168.0.34:92/api/UploadFP/UploadFP"; + // Regex re = new Regex(@"(((?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(:[0-9]+)?|(?:ww‌​w.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?‌​(?:[\w]*))?)"); + // MatchCollection mc = re.Matches(url);//获取的是一个数组 + // string pdfurl = mc[0].ToString() + "://" + mc[1].ToString() + urlpath; + // paramsString = "{\"callback\":\"" + callback + "\",\"bsid\":\"" + id + "\",\"type\":\"3\",\"param\":{\"text\":\"" + pdfurl + "\",\"ispaye\":\"" + ispaye + "\"}}"; + // Log.Info("文字语音播报: " + paramsString + ""); + // base64 = str2Base64(paramsString); + //} + //string str = com.SendData(base64, callback); + //return Base64str2(str); + if (ispaye) + { + Task.Run(() => + { + if (Typrocess != null) + { + // 如果进程还在运行 + if (!Typrocess.HasExited) + { + // 发送SIGTERM信号来停止进程 + Typrocess.Kill(); + // 等待进程真正停止 + Typrocess.WaitForExit(); + } + } + }); + string result = "{\"callback\":\"" + callback + "\",\"message\":\"success\",\"code\":\"200\",\"status\":true,\"data\":" + "停止播放成功" + "}"; + SubmitLogs(result, "payleText"); + return result; + } + else + { + Task.Run(() => + { + //形成语音 + tempWav = GenerateWavFromText(text); + //开始播放 + string command = $"sox {tempWav} -d"; + ShllCommad(command); + }); + string result = "{\"callback\":\"" + callback + "\",\"message\":\"success\",\"code\":\"200\",\"status\":true,\"data\":" + "开始播放" + "}"; + SubmitLogs(result, "payleText"); + return result; + } + } + } + catch (Exception ex) + { + Log.Error("文字语音播报异常2: " + ex.Message + ""); + string result = "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + ex.Message + "\"}"; + SubmitLogs(result, "payleText"); + return result; + } + } + + /// + /// 发送短信 + /// + /// + /// + /// + [JSFunction] + public string SendSSM(string content, string phone) + { + try + { + if (!isFuncisFuncObject("SendSSM")) + { + Utils.MessagesBox("发送短信设备未授权使用"); + return "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + "发送短信设备未授权使用" + "\"}"; + } + else + { + string paramsString = "{\"callback\":\"" + callback + "\",\"type\":\"4\",\"param\":{\"content\":\"" + content + "\",\"phone\":\"" + phone + "\"}}"; + Log.Info("发送短信: " + paramsString + ""); + string base64 = str2Base64(paramsString); + string str = com.SendData(base64, callback); + string result = Base64str2(str); + SubmitLogs(result, "SendSSM"); + return result; + } + } + catch (Exception ex) + { + Log.Error("发送短信异常: " + ex.Message + ""); + string result = "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + ex.Message + "\"}"; + SubmitLogs(result, "SendSSM"); + return result; + } + } + + /// + /// 打开高拍仪并且进行快速扫描文件 + /// + /// + /// + [JSFunction] + public string openCamera(string url) + { + try + { + if (!isFuncisFuncObject("openCamera")) + { + Utils.MessagesBox("高拍仪设备未授权使用"); + return "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + "高拍仪设备未授权使用" + "\"}"; + } + else + { + string paramsString = "{\"callback\":\"" + callback + "\",\"type\":\"5\",\"param\":{\"url\":\"" + url + "\"}}"; + Log.Info("打开高拍仪并且进行快速扫描文件: " + paramsString + ""); + string base64 = str2Base64(paramsString); + string str = com.SendData(base64, callback); + string data = Base64str2(str); + if (data == "400") + { + string result = "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + "获取签字失败" + "\"}"; + SubmitLogs(result, "openCamera"); + return result; + } + else + { + string result = "{\"callback\":\"" + callback + "\",\"message\":\"success\",\"code\":\"200\",\"status\":true,\"suffix\":\"jpg\",\"data\":\"" + str + "\"}"; + SubmitLogs(result, "openCamera"); + return result; + } + } + } + catch (Exception ex) + { + Log.Error("打开高拍仪并且进行快速扫描文件异常: " + ex.Message + ""); + string result = "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + ex.Message + "\"}"; + SubmitLogs(result, "openCamera"); + return result; + } + } + + /// + /// 打开签字版 + /// + /// + /// + [JSFunction] + public string OpenSign(string paramsString) + { + try + { + if (!isFuncisFuncObject("OpenSign")) + { + Utils.MessagesBox("签字版设备未授权使用"); + return "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + "签字版设备未授权使用" + "\"}"; + } + else + { + paramsString = "{\"callback\":\"" + callback + "\",\"type\":\"6\",\"param\":{\"data\":\"" + "" + "\"}}"; + Log.Info("打开签字版: " + paramsString + ""); + string base64 = str2Base64(paramsString); + string str = com.SendData(base64, callback); + string result = Base64str2(str); + SubmitLogs(result, "OpenSign"); + return result; + } + } + catch (Exception ex) + { + Log.Error("打开签字版异常: " + ex.Message + ""); + string result = "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + ex.Message + "\"}"; + SubmitLogs(result, "OpenSign"); + return result; + } + } + + /// + /// 关闭签字版 + /// + /// + /// + [JSFunction] + public string CloseSign(string paramsString) + { + try + { + if (!isFuncisFuncObject("OpenSign")) + { + Utils.MessagesBox("签字版设备未授权使用"); + return "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + "签字版设备未授权使用" + "\"}"; + } + else + { + paramsString = "{\"callback\":\"" + callback + "\",\"type\":\"7\",\"param\":{\"data\":\"" + "" + "\"}}"; + Log.Info("关闭签字版: " + paramsString + ""); + string base64 = str2Base64(paramsString); + string str = com.SendData(base64, callback); + string result = Base64str2(str); + SubmitLogs(result, "OpenSign"); + return result; + } + } + catch (Exception ex) + { + Log.Error("关闭签字版异常: " + ex.Message + ""); + string result = "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + ex.Message + "\"}"; + SubmitLogs(result, "OpenSign"); + return result; + } + } + + /// + /// 获取签字版数据 + /// + /// + /// + [JSFunction] + public string GetSignData(string url) + { + try + { + if (!isFuncisFuncObject("OpenSign")) + { + Utils.MessagesBox("签字版设备未授权使用"); + return "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + "签字版设备未授权使用" + "\"}"; + } + else + { + string paramsString = "{\"callback\":\"" + callback + "\",\"type\":\"8\",\"param\":{\"url\":\"" + url + "\"}}"; + Log.Info("获取签字版数据: " + paramsString + ""); + string base64 = str2Base64(paramsString); + string str = com.SendData(base64, callback); + string data = Base64str2(str); + if (data == "400") + { + string result = "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + "获取签字失败" + "\"}"; + SubmitLogs(result, "OpenSign"); + return result; + } + else + { + string result = "{\"callback\":\"" + callback + "\",\"message\":\"success\",\"code\":\"200\",\"status\":true,\"suffix\":\"png\",\"data\":\"" + str + "\"}"; + SubmitLogs(result, "OpenSign"); + return result; + } + } + } + catch (Exception ex) + { + Log.Error("获取签字版数据异常: " + ex.Message + ""); + string result = "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + ex.Message + "\"}"; + SubmitLogs(result, "OpenSign"); + return result; + } + } + + /// + /// 开始录音、取消录音、结束录音 + /// sudo apt-get update + /// sudo apt-get install alsa-utils + /// + /// + /// + /// + [JSFunction] + public string SoundRecording(bool isopen, string url) + { + try + { + if (!isFuncisFuncObject("SoundRecording")) + { + Utils.MessagesBox("录音设备未授权使用"); + return "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + "录音设备未授权使用" + "\"}"; + } + else + { + //结束录音上传文件 + if (!string.IsNullOrEmpty(url) && !isopen) + { + if (StopRecording()) + { + Task.Run(async () => + { + UploadInfo(url, srpath); + }); + @event2.WaitOne(); + Regex re = new Regex(@"(((?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(:[0-9]+)?|(?:ww‌​w.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?‌​(?:[\w]*))?)"); + MatchCollection mc = re.Matches(url);//获取的是一个数组 + string reurl = mc[0].ToString() + "://" + mc[1].ToString() + urlpath; + string result = "{\"callback\":\"" + callback + "\",\"message\":\"success\",\"code\":\"200\",\"status\":true,\"suffix\":\"wav\",\"data\":\"" + reurl + "\"}"; + SubmitLogs(result, "SoundRecording"); + return result; + } + else + { + string result = "{\"callback\":\"" + callback + "\",\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"suffix\":\"wav\",\"data\":\"" + "结束录音失败" + "\"}"; + SubmitLogs(result, "SoundRecording"); + return result; + } + } + else if (isopen)//开始录音 + { + if (StartRecording()) + { + string result = "{\"callback\":\"" + callback + "\",\"message\":\"success\",\"code\":\"200\",\"status\":true,\"suffix\":\"wav\",\"data\":\"" + "开始录音" + "\"}"; + SubmitLogs(result, "SoundRecording"); + return result; + } + else + { + string result = "{\"callback\":\"" + callback + "\",\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"suffix\":\"wav\",\"data\":\"" + "录音失败" + "\"}"; + SubmitLogs(result, "SoundRecording"); + return result; + } + } + else //取消录音 + { + if (StopRecording()) + { + srpath = string.Empty; + string result = "{\"callback\":\"" + callback + "\",\"message\":\"success\",\"code\":\"200\",\"status\":true,\"suffix\":\"wav\",\"data\":\"" + "取消录音" + "\"}"; + SubmitLogs(result, "SoundRecording"); + return result; + } + else + { + srpath = string.Empty; + string result = "{\"callback\":\"" + callback + "\",\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"suffix\":\"wav\",\"data\":\"" + "取消录音失败" + "\"}"; + SubmitLogs(result, "SoundRecording"); + return result; + } + + } + } + } + catch (Exception ex) + { + Log.Error("开始录音、取消录音、结束录音异常: " + ex.Message + ""); + string result = "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + ex.Message + "\"}"; + SubmitLogs(result, "SoundRecording"); + return result; + } + } + + /// + /// 根据文件地址在线打印 + /// + /// + /// + [JSFunction] + public string PrintFile(string url, string ext) + { + try + { + if (!isFuncisFuncObject("PrintFile")) + { + Utils.MessagesBox("打印机设备未授权使用"); + return "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + "打印机设备未授权使用" + "\"}"; + } + else + { + Task.Run(async () => + { + DateTime dateTime = DateTime.Now; + string time = DateTime.Now.ToString( + "yyyyMMddHHmmss", DateTimeFormatInfo.InvariantInfo); + var dirpath = System.IO.Path.Combine(Environment.CurrentDirectory, "wwwroot", "PrintFile"); + if (!Directory.Exists(dirpath)) + { + Directory.CreateDirectory(dirpath); + } + var filepath = System.IO.Path.Combine(dirpath, time); + string path = dirpath + "\\" + time + "." + ext; + WebRequest request = WebRequest.Create(url); + WebResponse response = request.GetResponse(); + using (Stream stream = response.GetResponseStream()) + { + using (FileStream fileStream = new FileStream(path, FileMode.Create)) + { + stream.CopyTo(fileStream); + } + } + response.Close(); + Log.Info("根据文件base64打印: " + path + ""); + string command = $"lp -d {PrinterName} {path}"; + ShllCommad(command); + }); + + //string id = Guid.NewGuid().ToString(); + ////通过文件发送数据 + //com.NewMethod(path, id); + //string paramsString = "{\"callback\":\"" + callback + "\",\"bsid\":\"" + id + "\",\"type\":\"9\",\"param\":{\"url\":\"" + url + "\",\"ext\":\"" + ext + "\"}}"; + //Log.Info("根据文件地址在线打印: " + paramsString + ""); + //string base64_1 = str2Base64(paramsString); + //string str = com.SendData(base64_1, callback); + //return Base64str2(str); + string result = "{\"callback\":\"" + callback + "\",\"message\":\"success\",\"code\":\"200\",\"status\":true,\"data\":\"" + "打印成功" + "\"}"; + SubmitLogs(result, "PrintFile"); + return result; + } + } + catch (Exception ex) + { + Log.Error("根据文件地址在线打印异常: " + ex.Message + ""); + string result = "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + ex.Message + "\"}"; + SubmitLogs(result, "PrintFile"); + return result; + } + + } + + /// + /// 根据文件base64打印 + /// + /// + /// + /// + [JSFunction] + public string PrintBase64(string url, string base64, string ext) + { + try + { + if (!isFuncisFuncObject("PrintBase64")) + { + Utils.MessagesBox("打印机设备未授权使用"); + return "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + "打印机设备未授权使用" + "\"}"; + } + else + { + Task.Run(async () => + { + DateTime dateTime = DateTime.Now; + string time = DateTime.Now.ToString( + "yyyyMMddHHmmss", DateTimeFormatInfo.InvariantInfo); + var dirpath = System.IO.Path.Combine(Environment.CurrentDirectory, "wwwroot", "PrintFile"); + if (!Directory.Exists(dirpath)) + { + Directory.CreateDirectory(dirpath); + } + var filepath = System.IO.Path.Combine(dirpath, time); + string path = dirpath + @"/" + time + "." + ext; + byte[] bytes = Convert.FromBase64String(base64); + System.IO.FileStream stream = new System.IO.FileStream(path, System.IO.FileMode.CreateNew); + System.IO.BinaryWriter writer = new System.IO.BinaryWriter(stream); + writer.Write(bytes, 0, bytes.Length); + writer.Close(); + Log.Info("根据文件base64打印: " + path + ""); + string command = $"lp -d {PrinterName} {path}"; + ShllCommad(command); + }); + //string id = Guid.NewGuid().ToString(); + ////通过文件发送数据 + //com.NewMethod(path, ext); + //Regex re = new Regex(@"(((?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(:[0-9]+)?|(?:ww‌​w.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?‌​(?:[\w]*))?)"); + //MatchCollection mc = re.Matches(url);//获取的是一个数组 + //string pdfurl = mc[0].ToString() + "://" + mc[1].ToString() + urlpath; + //Log.Info("根据文件base64打印: " + pdfurl + ""); + //try + //{ + // string paramsString = "{\"callback\":\"" + callback + "\",\"bsid\":\"" + id + "\",\"type\":\"9\",\"param\":{\"url\":\"" + pdfurl + "\",\"ext\":\"" + ext + "\"}}"; + // Log.Info("根据文件base64打印: " + paramsString + ""); + // string base64_1 = str2Base64(paramsString); + // string str = com.SendData(base64_1, callback); + // return Base64str2(str); + //} + //catch (Exception ex) + //{ + // Log.Error("根据文件base64打印异常: " + ex.Message + ""); + // return "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + ex.Message + "\"}"; + //} + string result = "{\"callback\":\"" + callback + "\",\"message\":\"success\",\"code\":\"200\",\"status\":true,\"data\":\"" + "打印成功" + "\"}"; + SubmitLogs(result, "PrintBase64"); + return result; + } + } + catch (Exception ex) + { + string result = "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + ex.Message + "\"}"; + SubmitLogs(result, "PrintBase64"); + return result; + } + } + + /// + /// 播放音频文件 + /// + /// + /// + public static WaveOutEvent player = null; + public static AudioFileReader audioFileReader = null; + public static string WaveOutPath = string.Empty; + [JSFunction] + public string PalyFile(string url, bool ispaly) + { + try + { + if (!isFuncisFuncObject("PalyFile")) + { + Utils.MessagesBox("音频设备未授权使用"); + return "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + "音频设备未授权使用" + "\"}"; + } + else + { + if (ispaly) + { + Task.Run(() => + { + Uri uri = new Uri(url); + //返回 123.xlsx + var filename = HttpUtility.UrlDecode(uri.Segments.Last()); + //获取文件后缀 + string ext = System.IO.Path.GetExtension(filename); + DateTime dateTime = DateTime.Now; + string time = DateTime.Now.ToString( + "yyyyMMddHHmmss", DateTimeFormatInfo.InvariantInfo); + var dirpath = System.IO.Path.Combine(Environment.CurrentDirectory, "wwwroot", "WaveOutFile"); + if (!Directory.Exists(dirpath)) + { + Directory.CreateDirectory(dirpath); + } + string path = dirpath + @"/" + time + "." + ext; + WebRequest request = WebRequest.Create(url); + WebResponse response = request.GetResponse(); + using (Stream stream = response.GetResponseStream()) + { + using (FileStream fileStream = new FileStream(WaveOutPath, FileMode.Create)) + { + stream.CopyTo(fileStream); + } + } + response.Close(); + + //开始播放 + string command = $"sox {path} -d"; + ShllCommad(command); + }); + string result = "{\"callback\":\"" + callback + "\",\"message\":\"success\",\"code\":\"200\",\"status\":true,\"data\":" + "开始播放" + "}"; + SubmitLogs(result, "PalyFile"); + return result; + } + else + { + Task.Run(() => + { + if (Typrocess != null) + { + // 如果进程还在运行 + if (!Typrocess.HasExited) + { + // 发送SIGTERM信号来停止进程 + Typrocess.Kill(); + // 等待进程真正停止 + Typrocess.WaitForExit(); + } + } + }); + string result = "{\"callback\":\"" + callback + "\",\"message\":\"success\",\"code\":\"200\",\"status\":true,\"data\":" + "停止播放成功" + "}"; + SubmitLogs(result, "PalyFile"); + return result; + } + } + } + catch (Exception ex) + { + string result = "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + ex.Message + "\"}"; + SubmitLogs(result, "PalyFile"); + return result; + } + } + + /// + /// 播放音频公共方法 + /// + /// + private void NewMethod(string url) + { + Uri uri = new Uri(url); + //返回 123.xlsx + var filename = HttpUtility.UrlDecode(uri.Segments.Last()); + //获取文件后缀 + string ext = System.IO.Path.GetExtension(filename); + DateTime dateTime = DateTime.Now; + string time = DateTime.Now.ToString( + "yyyyMMddHHmmss", DateTimeFormatInfo.InvariantInfo); + var dirpath = System.IO.Path.Combine(Environment.CurrentDirectory, "wwwroot", "WaveOutFile"); + if (!Directory.Exists(dirpath)) + { + Directory.CreateDirectory(dirpath); + } + string path = dirpath + @"/" + time + "." + ext; + WebRequest request = WebRequest.Create(url); + WebResponse response = request.GetResponse(); + using (Stream stream = response.GetResponseStream()) + { + using (FileStream fileStream = new FileStream(WaveOutPath, FileMode.Create)) + { + stream.CopyTo(fileStream); + } + } + response.Close(); + + + using (player = new WaveOutEvent()) + { + player.PlaybackStopped += waveOut_PlaybackStopped; + using (audioFileReader = new AudioFileReader(WaveOutPath)) + { + // 创建一个增益效果器对象 + var volumeProvider = new VolumeSampleProvider(audioFileReader.ToSampleProvider()); + // 将音频文件添加到WaveOutEvent对象中 + player.Init(volumeProvider); + // 设置音量增益为2倍 + volumeProvider.Volume = 2.0f; + // 开始播放音频 + player.Play(); + while (player.PlaybackState == PlaybackState.Playing) + { + Thread.Sleep(1000); + } + } + } + Log.Info("开始播放"); + } + + /// + /// 播放完成 + /// + /// + /// + private void waveOut_PlaybackStopped(object sender, StoppedEventArgs e) + { + try + { + player.Stop(); + // 释放资源 + player.Dispose(); + audioFileReader.Dispose(); + player = null; + File.Delete(WaveOutPath); + Log.Info("播放完成"); + } + catch (Exception ex) + { + Log.Info("播放完成,清除本地文件异常" + ex.Message); + } + } + + /// + /// 唤醒键盘 + /// + /// + /// + [JSFunction] + public string openKey(string paramsString) + { + try + { + Task.Run(() => + { + Bash("/usr/bin/python3 /usr/bin/onboard"); + }); + return "{\"message\":\"seccse\",\"code\":\"200\",\"status\":true,\"data\":\"" + "唤醒键盘成功" + "\"}"; + } + catch (Exception ex) + { + Log.Error("唤醒键盘异常: " + ex.Message + ""); + return "{\"message\":\"fali\",\"code\":\"400\",\"status\":false,\"data\":\"" + ex.Message + "\"}"; + } + } + + /// + /// 执行文件 + /// + /// + /// + public static string Bash(string command) + { + var escapedArgs = command.Replace("\"", "\\\""); + var process = new Process() + { + StartInfo = new ProcessStartInfo + { + FileName = "/bin/bash", + Arguments = $"-c \"{escapedArgs}\"", + RedirectStandardOutput = true, + UseShellExecute = false, + CreateNoWindow = true, + } + }; + process.Start(); + string result = process.StandardOutput.ReadToEnd(); + process.WaitForExit(); + process.Dispose(); + return result; + } + + /// + /// 初始文件上传 + /// + private string urlpath = string.Empty; + private AutoResetEvent @event2 = new AutoResetEvent(false); + private async void UploadInfo(string url, string srpath) + { + var httpClient = new HttpClient(); + var uploader = new ChunkedUpload(httpClient); + urlpath = await uploader.UploadFileAsync(url, srpath); + @event2.Set(); + } + + + //上传本地文件中转 + private string urlP = string.Empty; + private AutoResetEvent @event5 = new AutoResetEvent(false); + private async void UploadInfoByFile(string url, string strpath) + { + var httpClient = new HttpClient(); + var uploader = new ChunkedUpload(httpClient); + urlP = await uploader.UploadFileAsync(url, strpath); + File.Delete(strpath); + @event5.Set(); + } + + /// + /// string 转换为 base64 + /// + /// + public static string str2Base64(string str) + { + byte[] b = System.Text.Encoding.UTF8.GetBytes(str); + string result = Convert.ToBase64String(b); + return result; + } + + /// + /// base64 转换为 string + /// + /// + public static string Base64str2(string data) + { + byte[] c = Convert.FromBase64String(data); + string result = System.Text.Encoding.UTF8.GetString(c); + Log.Info("接收返回数据:" + result); + return result; + } + + //根据程序名称杀死进程 + public static void KillProcessByName(string processName) + { + Process[] processes = Process.GetProcessesByName(processName); + + foreach (Process process in processes) + { + try + { + process.Kill(); + process.WaitForExit(); // 等待进程退出 + } + catch (Exception ex) { } + } + } + + //关闭串口 + public void CLoseCOM() + { + com.ClosePort(); + } + + /// + /// 开始录音 + /// + /// + public bool StartRecording() + { + try + { + if (recordingProcess != null) + { + // 如果进程还在运行 + if (!recordingProcess.HasExited) + { + // 发送SIGTERM信号来停止arecord进程 + recordingProcess.Kill(); + recordingProcess.WaitForExit(); // 等待进程真正停止 + } + } + string time = DateTime.Now.ToString( + "yyyyMMddHHmmss", DateTimeFormatInfo.InvariantInfo); + var dirpath = System.IO.Path.Combine(Environment.CurrentDirectory, "wwwroot", "Record"); + if (!Directory.Exists(dirpath)) + { + Directory.CreateDirectory(dirpath); + } + srpath = dirpath + "/" + time + ".wav"; + string outputFile = srpath; // 输出文件名 + string device = "default"; // 音频设备,可以通过arecord -l来列出所有设备 + // 构建arecord命令 + string command = $"arecord --device={device} --file-type=wav --duration=10 --quiet {outputFile}"; + // 启动进程 + recordingProcess = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = "/bin/bash", + Arguments = $"-c \"{command}\"", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true + } + }; + recordingProcess.Start(); + return true; + } + catch (Exception ex) + { + Log.Error("开始录音异常:" + ex.Message); + return false; + } + } + + /// + /// 结束录音 + /// + public bool StopRecording() + { + try + { + // 如果进程还在运行 + if (!recordingProcess.HasExited) + { + // 发送SIGTERM信号来停止arecord进程 + recordingProcess.Kill(); + recordingProcess.WaitForExit(); // 等待进程真正停止 + } + return true; + } + catch (Exception ex) + { + Log.Error("结束录音异常:" + ex.Message); + return false; + } + } + + + public static WaveFileWriter writer; + public static StreamWriter mStreamWriter; + public static WaveInEvent waveIn = null; + private string srpath = string.Empty; + //开启录音 + private bool StateSoundRecor() + { + if (waveIn != null) + { + waveIn.StopRecording(); + waveIn.Dispose(); + writer.Close(); + mStreamWriter.Close(); + waveIn = null; + } + // 录音对象 + waveIn = new WaveInEvent(); + int sampleRate = 48000; //采样率 + int channels = 2; //录音通道数 + int bitsPerSample = 16; //位深 + WaveFormat waveFormat = new WaveFormat(sampleRate, bitsPerSample, channels); + waveIn.WaveFormat = waveFormat; //设置录音格式 + DateTime dateTime = DateTime.Now; + string time = DateTime.Now.ToString( + "yyyyMMddHHmmss", DateTimeFormatInfo.InvariantInfo); + var dirpath = System.IO.Path.Combine(Environment.CurrentDirectory, "wwwroot", "Record"); + if (!Directory.Exists(dirpath)) + { + Directory.CreateDirectory(dirpath); + } + srpath = dirpath + "/" + time + ".wav"; + string pathfile = dirpath + "/" + time + ".txt"; + // 创建WaveFileWriter对象来保存录音数据 路径在bin文件下 + writer = new WaveFileWriter(srpath, waveFormat); + //编写器 + mStreamWriter = new StreamWriter(pathfile, false, new System.Text.UTF8Encoding(false)); + // 设置录音回调函数 + int bitIndex = bitsPerSample / 8; + waveIn.DataAvailable += (sender, e) => + { + // 将录音数据写入文件 + writer.Write(e.Buffer, 0, e.BytesRecorded); + for (int i = 0; i < e.BytesRecorded / bitIndex; i++) + { + //24bit,导出的数据 + //int sample = (int)((e.Buffer[i * bitIndex + 2] << 16) | (e.Buffer[i * bitIndex + 1] << 8) | e.Buffer[i * bitIndex]); + //16bit 将两个byte数据组合成一个short数据 + short sample = (short)((e.Buffer[i * bitIndex + 1] << 8) | e.Buffer[i * bitIndex]); + mStreamWriter.Write("{0},", sample); + } + }; + try + { + //尝试打开录音设备,如果设备支持设置的WaveFormat,则能够成功打开 + waveIn.StartRecording(); + return true; + } + catch (Exception ex) + { + Log.Info("录音开启失败:" + ex.Message); + srpath = ""; + return false; + } + } + + /// + /// 停止录音、取消录音 + /// + /// + private bool StopSoundRecor() + { + + try + { + //停止录音 + waveIn.StopRecording(); + waveIn.Dispose(); + writer.Close(); + mStreamWriter.Close(); + waveIn = null; + return true; + } + catch (Exception ex) + { + Log.Info("停止录音、取消录音失败:" + ex.Message); + srpath = ""; + return false; + } + } + + /// + /// 执行命令 + /// + public static void ShllCommad(string command) + { + Log.Info("执行命令:" + command); + // 启动进程 + Typrocess = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = "/bin/bash", + Arguments = $"-c \"{command}\"", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true + } + }; + Typrocess.Start(); + Typrocess.WaitForExit(); + } + + /// + /// 开源文字转语音 + /// sudo apt-get install espeak + /// + /// + /// + static string GenerateWavFromText(string text) + { + string time = DateTime.Now.ToString( + "yyyyMMddHHmmss", DateTimeFormatInfo.InvariantInfo); + var dirpath = System.IO.Path.Combine(Environment.CurrentDirectory, "wwwroot", "WavFile"); + if (!Directory.Exists(dirpath)) + { + Directory.CreateDirectory(dirpath); + } + var tempFile = dirpath + "/" + time + ".wav"; + text = text.Replace("(", "").Replace(")", "、"); + ProcessStartInfo startInfo = new ProcessStartInfo + { + FileName = "espeak", + Arguments = $" -vzh -s 150 \"{text}\" -w {tempFile}", // 设置语速为150,输出为WAV文件 + UseShellExecute = false, + RedirectStandardOutput = true, + CreateNoWindow = true + }; + using (Process process = Process.Start(startInfo)) + { + process.WaitForExit(); // 等待进程结束 + process.Close(); + process.Dispose(); + } + return tempFile; + } + + /// + /// 是否已获取收取 + /// + /// + /// + public bool isFuncisFuncObject(string funcName) + { + bool isFunc = false; + if (Parame.FuncObject.Count > 0) + { + foreach (Func func in Parame.FuncObject) + { + if (func.Interfaceaddress.Contains(funcName)) + { + isFunc = true; + break; + } + } + } + return isFunc; + } + + //提交设备操作日志 + public static void SubmitLogs(string Describer, string funcName) + { + Task.Run(async () => + { + string ApiId = string.Empty; + string Name = string.Empty; + string Interfaceaddress = string.Empty; + bool isFunc = false; + if (Parame.FuncObject.Count > 0) + { + foreach (Func func in Parame.FuncObject) + { + if (func.Interfaceaddress.Contains(funcName)) + { + isFunc = true; + ApiId = func.Id; + Name = func.Platform; + Interfaceaddress = func.Interfaceaddress; + break; + } + } + } + if (isFunc) + { + var client = new HttpClient(); + var request = new HttpRequestMessage(HttpMethod.Post, $"{Parame.apiUrl}/api/Interface/JournalAdd"); + var content = new StringContent("{\"Name\": \"" + Name + "\",\"Describer\": \"" + str2Base64(Describer) + "\", \"Interfaceaddress\": \"" + Interfaceaddress + "\", \"ApiId\": \"" + ApiId + "\"}", null, "application/json"); + request.Content = content; + var response = await client.SendAsync(request); + if (response.StatusCode.ToString() == "200") + { + response.EnsureSuccessStatusCode(); + var body = await response.Content.ReadAsStringAsync(); + Log.Info(body); + } + } + }); + } + + + } +} diff --git a/CPF_Cef/Parame.cs b/CPF_Cef/Parame.cs new file mode 100644 index 0000000..834aeb6 --- /dev/null +++ b/CPF_Cef/Parame.cs @@ -0,0 +1,25 @@ +using AKS.EnterpriseLibrary.WebBrowser; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AksWebBrowser +{ + public class Parame + { + public static CusWebBrowser webBrowser { get; set; } + public static List FuncObject { get; set; } + //接口地址 + public static string apiUrl = "http://192.168.0.34:92"; + //授权key + public static string key = "1"; + } + public struct Func + { + public string Id { get; set; } + public string Platform { get; set; } + public string Interfaceaddress { get; set; } + }; +} diff --git a/CPF_Cef/Program.cs b/CPF_Cef/Program.cs new file mode 100644 index 0000000..9f15228 --- /dev/null +++ b/CPF_Cef/Program.cs @@ -0,0 +1,38 @@ +using CPF.Cef; +using CPF.Linux;//如果需要支持Linux才需要 +using CPF.Mac;//如果需要支持Mac才需要 +using CPF.Platform; +using CPF.Skia; +using CPF.Windows; +using System; + +namespace AKS.EnterpriseLibrary.WebBrowser +{ + class Program + { + [STAThread] + static void Main(string[] args) + { + Application.Initialize( + (OperatingSystemType.Windows, new WindowsPlatform(), new SkiaDrawingFactory()) + , (OperatingSystemType.OSX, new MacPlatform(), new SkiaDrawingFactory())//如果需要支持Mac才需要 + , (OperatingSystemType.Linux, new LinuxPlatform(), new SkiaDrawingFactory())//如果需要支持Linux才需要 + ); + + CefRuntime.Load(); + var mainArgs = new CpfCefMainArgs(args); + var app = new CpfCefApp(); + var exitCode = CefRuntime.ExecuteProcess(mainArgs, app, IntPtr.Zero); + if (exitCode != -1) + { + return; + } + CefRuntime.Initialize(mainArgs, new CefSettings{ }, app, IntPtr.Zero); + + var model = new MainModel(); + Application.Run(new FrmMain { DataContext = model, CommandContext = model }); + + CefRuntime.Shutdown(); + } + } +} diff --git a/CPF_Cef/Recent.ico b/CPF_Cef/Recent.ico new file mode 100644 index 0000000..a05686b Binary files /dev/null and b/CPF_Cef/Recent.ico differ diff --git a/CPF_Cef/SetTaskStatus.cs b/CPF_Cef/SetTaskStatus.cs new file mode 100644 index 0000000..9d28f48 --- /dev/null +++ b/CPF_Cef/SetTaskStatus.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace AksWebBrowser +{ + public class SetTaskStatus + { + private const int SW_HIDE = 0; //隐藏任务栏 + private const int SW_RESTORE = 9;//显示任务栏 + + [DllImport("user32.dll")] + private static extern int ShowWindow(int hwnd, int nCmdShow); + [DllImport("user32.dll")] + private static extern int FindWindow(string lpClassName, string lpWindowName); + + /// + /// 显示任务栏 + /// + public static void Showtask() + { + ShowWindow(FindWindow("Shell_TrayWnd", null), SW_RESTORE); + } + /// + /// 隐藏任务栏 + /// + public static void Hidetask() + { + ShowWindow(FindWindow("Shell_TrayWnd", null), SW_HIDE); + } + + + + // 设置窗体的显示状态 + [DllImport("user32.dll", SetLastError = true)] + public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, + int X, int Y, int cx, int cy, uint uFlags); + + // 窗体的句柄 + [DllImport("user32.dll")] + public static extern IntPtr GetForegroundWindow(); + + public const uint SWP_SHOWWINDOW = 0x0040; + public const uint SWP_NOSIZE = 0x0001; + public const uint SWP_NOMOVE = 0x0002; + public const uint TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW; + } +} diff --git a/CPF_Cef/StyleSheet.css b/CPF_Cef/StyleSheet.css new file mode 100644 index 0000000..db1d459 --- /dev/null +++ b/CPF_Cef/StyleSheet.css @@ -0,0 +1,473 @@ + +@media windows { + * { + FontFamily: '微软雅黑'; /*不同系统的字体不同,自己根据情况改或者使用内嵌字体*/ + } +} + +@media osx { + * { + FontFamily: '苹方-简'; + } +} + +@media linux { + * { + FontFamily: '文泉驿正黑'; + } +} +/*设置窗体标题栏背景颜色圆角*/ +/*#caption { + IsAntiAlias: true; + Background: #2c2c2c; + CornerRadius:5,5,0,0; +} +#frame { + CornerRadius: 5; + IsAntiAlias: true; +}*/ +Button { + BorderFill: #DCDFE6; + IsAntiAlias: True; + CornerRadius: 4,4,4,4; + Background: #FFFFFF; +} + + Button[IsMouseOver=true] { + BorderFill: rgb(198,226,255); + Background: rgb(236,245,255); + Foreground: rgb(64,158,255); + } + + Button[IsPressed=true] { + BorderFill: rgb(58,142,230); + } + + Button.primary { + BorderFill: rgb(64,158,255); + CornerRadius: 4,4,4,4; + Background: rgb(64,158,255); + Foreground: #FFFFFF; + } + + Button.primary[IsMouseOver=true] { + BorderFill: rgb(102,177,255); + Background: rgb(102,177,255); + Foreground: #FFFFFF; + } + + Button.primary[IsPressed=true] { + BorderFill: rgb(58,142,230); + Background: rgb(58,142,230); + } + + Button.success { + BorderFill: rgb(103,194,58); + CornerRadius: 4,4,4,4; + Background: rgb(103,194,58); + Foreground: #FFFFFF; + } + + Button.success[IsMouseOver=true] { + BorderFill: rgb(133,206,97); + Background: rgb(133,206,97); + Foreground: #FFFFFF; + } + + Button.success[IsPressed=true] { + BorderFill: rgb(93,175,52); + Background: rgb(93,175,52); + } + + Button.danger { + BorderFill: rgb(245,108,108); + Background: rgb(245,108,108); + CornerRadius: 4,4,4,4; + Foreground: #FFFFFF; + } + + Button.danger[IsMouseOver=true] { + BorderFill: rgb(247,137,137); + Background: rgb(247,137,137); + Foreground: #FFFFFF; + } + + Button.danger[IsPressed=true] { + BorderFill: rgb(221,97,97); + Background: rgb(221,97,97); + } + + +TextBox, .textBox, DatePicker { + Background: #fff; + IsAntiAlias: true; + BorderFill: #DCDFE6; + CornerRadius: 4,4,4,4; + BorderStroke: 1; +} + + .groupPanel TextBox, DatePicker TextBox, .textBox TextBox { + BorderStroke: 0; + } + + .textBox[IsKeyboardFocusWithin=true] { + BorderFill: #1E9FFF; + } + +.singleLine { /*单行文本框*/ + AcceptsReturn: false; + HScrollBarVisibility: Hidden; + VScrollBarVisibility: Hidden; +} + + .singleLine #contentPresenter { + Padding: 3; + } + +.multiline { /*多行文本框*/ +} + + +.slotLeft { + CornerRadius: 0,4,4,0; + BorderFill: #DCDFE6; + Background: #F5F7FA; + BorderThickness: 1,0,0,0; + BorderType: BorderThickness; + MarginTop: 0; + MarginBottom: 0; + MarginRight: 0; +} + +RadioButton #radioButtonBorder { + StrokeFill: rgb(220,223,230); +} + +RadioButton[IsChecked=true] #radioButtonBorder { + StrokeFill: #1E9FFF; + Fill: #1E9FFF; +} + +RadioButton #optionMark { + StrokeFill: #1E9FFF; + Fill: #fff; +} + +CheckBox #indeterminateMark { + Fill: #1E9FFF; +} + +CheckBox #checkBoxBorder { + Background: #fff; + BorderFill: rgb(220,223,230); +} + +CheckBox[IsChecked=true] #checkBoxBorder { + Background: #1E9FFF; + BorderFill: #1E9FFF; +} + +CheckBox Polyline { + StrokeFill: #fff; +} + +.radioGroup { + BorderType: BorderThickness; + BorderFill: rgb(220,223,230); + BorderThickness: 1,1,0,1; +} + + .radioGroup RadioButton { + BorderType: BorderThickness; + BorderFill: rgb(220,223,230); + BorderThickness: 0,0,1,0; + } + + .radioGroup RadioButton #markPanel { + Visibility: Collapsed; + } + + .radioGroup RadioButton TextBlock { + Margin: 5; + } + + .radioGroup RadioButton[IsChecked=true] { + Background: rgb(64,158,255); + Foreground: #fff; + } + +.error { + Foreground: #f00; + Visibility: Collapsed; +} + + .error[DesignMode=true] { + Visibility: Visible; + } + +.twoLine[AttachedExtenstions.IsError=true] .error { + Visibility: Visible; +} + +.twoLine[AttachedExtenstions.IsError=true] .textBox { + BorderFill: #f00; +} + +ScrollBar { + Background: null; +} + + ScrollBar Thumb { + IsAntiAlias: true; + CornerRadius: 5; + } + + ScrollBar[Orientation=Horizontal] { + Height: 12; + } + + ScrollBar[Orientation=Vertical] { + Width: 12; + } + + ScrollBar #PART_LineUpButton, ScrollBar #PART_LineDownButton { + Visibility: Collapsed; + } + +ComboBox { + Background: #fff; + IsAntiAlias: true; + BorderFill: #DCDFE6; + CornerRadius: 4,4,4,4; + BorderStroke: 1; +} + + ComboBox[IsKeyboardFocusWithin=true] { + BorderFill: #1E9FFF; + } + +#DropDownPanel TextBlock { + MarginLeft: 5; + MarginTop: 2; + MarginBottom: 2; + font-size: 14; +} + +#dropDownBorder { + ShadowBlur: 2; + ShadowColor: rgba(0, 0, 0, 0.4); + BorderStroke: 0; +} + +#DropDownPanel[IsMouseOver=false] ScrollBar { + Visibility: Collapsed; +} + +#DropDownPanel ScrollBar[Orientation=Horizontal] { + Height: 10; +} + +#DropDownPanel ScrollBar[Orientation=Vertical] { + Width: 10; +} + +Slider { + IsAntiAlias: true; +} + + Slider Thumb { + IsAntiAlias: true; + Width: 16; + Height: 16; + CornerRadius: 7; + BorderFill: rgb(64,158,255); + BorderStroke: 2; + Background: #fff; + ZIndex: 1; + } + + + Slider Thumb[IsMouseOver=true] { + animation-name: sliderMouseOver; + animation-duration: 0.1s; + animation-iteration-count: 1; + animation-fill-mode: forwards; + } + + Slider #TrackBackground { + CornerRadius: 2; + Background: rgb(228,231,237); + BorderStroke: 0; + } + + Slider #decreaseRepeatButton { + Background: rgb(64,158,255); + CornerRadius: 2; + } + + Slider[Orientation=Horizontal] #decreaseRepeatButton { + Height: 4; + MarginLeft: 5; + } + + Slider[Orientation=Vertical] #decreaseRepeatButton { + Width: 4; + MarginBottom: 5; + } + +ProgressBar { + CornerRadius: 5; + IsAntiAlias: true; + BorderFill: null; + Background: rgb(235,238,245); +} + + ProgressBar #Indicator, ProgressBar #Animation { + CornerRadius: 5; + } + +NumericUpDown { + Background: #fff; + IsAntiAlias: true; + BorderFill: #DCDFE6; + CornerRadius: 4,4,4,4; + BorderStroke: 1; +} + + NumericUpDown RepeatButton { + Width: 20; + Background: rgb(245,247,250); + } + + NumericUpDown #decreaseBtn { + CornerRadius: 4,0,0,4; + } + + NumericUpDown #increaseBtn { + CornerRadius: 0,4,4,0; + } + + NumericUpDown #textBoxBorder { + BorderFill: #DCDFE6; + } + + NumericUpDown TextBox { + BorderStroke: 0; + } + +.widget { + IsAntiAlias: true; + BorderFill: #DCDFE6; + CornerRadius: 4,4,4,4; + BorderStroke: 1; +} + +.widgetHead { + Background: linear-gradient(0 0,0 100%,#F7F7F7 0,#F0F0F0 1); + BorderType: BorderThickness; + BorderThickness: 0,0,0,1; + BorderFill: #DCDFE6; +} + +DataGrid { + Foreground: #7a7a7a; +} + +DataGridCellTemplate, DataGridRow, DataGrid, .DataGridCell { + BorderFill: rgb(235,238,245); +} + +DataGridRow { + Height: 36; +} + + DataGridRow[IsMouseOver=true] { + Background: rgb(245,247,250); + } + + DataGridRow[IsSelected=true] { + Background: rgb(245,247,250); + } + +DataGridColumnTemplate { + Height: 38; + FontSize: 15; + FontStyle: Bold; + Background: #fff; + BorderFill: rgb(235,238,245); +} + +TabControl #headBorder { + Background: #fff; +} + +TabItem > Border { + BorderThickness: 0,0,0,2; +} + +TabItem[IsSelected=true] > Border { + BorderFill: #1E9FFF; +} + +TabItem[IsSelected=true] { + Foreground: #1E9FFF; +} + +TabControl[TabStripPlacement=Left] TabItem, TabControl[TabStripPlacement=Right] TabItem { + Width: 100%; + BorderType: BorderThickness; + BorderThickness: 0,0,0,1; + BorderFill: #e8e8e8; +} + + TabControl[TabStripPlacement=Left] TabItem TextBlock { + MarginRight: 0; + } + + TabControl[TabStripPlacement=Left] TabItem > Border { + Width: 100%; + } + +TabControl[TabStripPlacement=Left] #headerPanel, TabControl[TabStripPlacement=Right] #headerPanel { + Width: 100; + Background: rgb(245,247,250); +} + +.closeBtn[IsMouseOver=true] { + Fill: #171717; +} + +.placeholder { + IsHitTestVisible: false; + Foreground: "192,196,204"; + Visibility: Collapsed; +} + +.textBox[AttachedExtenstions.IsEmpty=true] .placeholder { + Visibility: Visible; +} + +.loginBox TextBox, .loginBox .placeholder { + FontSize: 16; +} + +.loginBox CheckBox { + Foreground: #757575; +} + +.searchBox Button { + CornerRadius: 0,4,4,0, +} + +#MenuPop #menuPanel > Border, #MenuPop ContextMenu > Border { + Background: #fff; + ShadowColor: rgba(0, 0, 0, 0.4); +} + +#MenuPop MenuItem[IsMouseOver=true] { + Background: #DCDFE6; +} + +ListBoxItem { + Width: 100%; +} \ No newline at end of file