Explorar o código

update:优化页面逻辑,优化配置管理模块;

Bigpang_1 hai 1 mes
pai
achega
a53284f70c
Modificáronse 100 ficheiros con 6696 adicións e 1440 borrados
  1. 3744 0
      cfg/POSLinkUPT.html
  2. 11 2
      cfg/tcu_config.json
  3. BIN=BIN
      docs/充电桩终端UI软件需求详解.docx
  4. BIN=BIN
      docs/充电系统页面需求详解.pdf
  5. 3 0
      rec/Resource.qrc
  6. BIN=BIN
      rec/icons/information.png
  7. BIN=BIN
      rec/icons/question.png
  8. BIN=BIN
      rec/icons/warning.png
  9. 7 0
      rec/styles/Dark.qss
  10. 6 18
      src/MainWindow.cpp
  11. 6 5
      src/main.cpp
  12. 98 0
      src/utils/AsyncInitManager.cpp
  13. 61 0
      src/utils/AsyncInitManager.h
  14. 62 17
      src/utils/ConfigManager.cpp
  15. 12 3
      src/utils/ConfigManager.h
  16. 19 8
      src/utils/DataTypeDef.h
  17. 31 0
      src/utils/FunctionTimer.h
  18. 261 1
      src/utils/GeneralInterface.cpp
  19. 34 1
      src/utils/GeneralInterface.h
  20. 14 4
      src/utils/Globals.cpp
  21. 17 16
      src/utils/NFCReaderWorker.cpp
  22. 2 2
      src/utils/NFCReaderWorker.h
  23. 1 1
      src/utils/TcpServerThread.cpp
  24. 1 1
      src/utils/TcpServerThread.h
  25. 269 0
      src/utils/TouchScrollerHelper.cpp
  26. 77 0
      src/utils/TouchScrollerHelper.h
  27. 27 1
      src/widgets/custom/BaseWidget.cpp
  28. 18 0
      src/widgets/custom/BaseWidget.h
  29. 441 58
      src/widgets/custom/CustomComboBox.cpp
  30. 37 5
      src/widgets/custom/CustomComboBox.h
  31. 3 0
      src/widgets/custom/CustomCommandLinkButton.cpp
  32. 2 1
      src/widgets/custom/CustomDoubleSpinBox.cpp
  33. 1 0
      src/widgets/custom/CustomLineEdit.cpp
  34. 3 2
      src/widgets/custom/CustomNavigationBar.cpp
  35. 1 0
      src/widgets/custom/CustomQDateTimeEdit.cpp
  36. 3 0
      src/widgets/custom/CustomSpinBox.cpp
  37. 12 1
      src/widgets/custom/CustomSpinBox.h
  38. 35 36
      src/widgets/home/FormHome.cpp
  39. 14 1
      src/widgets/home/FormHome.h
  40. 12 3
      src/widgets/home/FormStartUp.cpp
  41. 3 0
      src/widgets/home/FormStartUp.h
  42. 25 9
      src/widgets/label/CircleProgressLabel.cpp
  43. 9 0
      src/widgets/label/CircleProgressLabel.h
  44. 36 28
      src/widgets/login/FormLogin.cpp
  45. 20 11
      src/widgets/workspace/home/FormAuthentication.cpp
  46. 4 4
      src/widgets/workspace/home/FormAuthentication.h
  47. 3 1
      src/widgets/workspace/home/FormChargeSettings.cpp
  48. 171 197
      src/widgets/workspace/home/FormChargeSettings.ui
  49. 4 0
      src/widgets/workspace/home/FormCharging.cpp
  50. 1 0
      src/widgets/workspace/home/FormCharging.h
  51. 73 45
      src/widgets/workspace/home/FormGunDetail.cpp
  52. 2 0
      src/widgets/workspace/home/FormGunDetail.h
  53. 7 3
      src/widgets/workspace/home/FormPlugIn.cpp
  54. 1 0
      src/widgets/workspace/home/FormPlugIn.h
  55. 4 22
      src/widgets/workspace/home/FormPrice.cpp
  56. 6 0
      src/widgets/workspace/home/FormStandby.cpp
  57. 1 0
      src/widgets/workspace/home/FormStandby.h
  58. 4 22
      src/widgets/workspace/settings/CcuSettings/DialogPriceDetail.cpp
  59. 34 12
      src/widgets/workspace/settings/CcuSettings/FormCcuSetting.cpp
  60. 4 1
      src/widgets/workspace/settings/CcuSettings/FormCcuSetting.h
  61. 146 272
      src/widgets/workspace/settings/CcuSettings/FormCcuSetting.ui
  62. 67 46
      src/widgets/workspace/settings/CcuSettings/FormChargeGunDetail.cpp
  63. 6 0
      src/widgets/workspace/settings/CcuSettings/FormChargeGunDetail.h
  64. 237 313
      src/widgets/workspace/settings/CcuSettings/FormChargeGunDetail.ui
  65. 2 1
      src/widgets/workspace/settings/CcuSettings/FormChargeGunType.cpp
  66. 2 1
      src/widgets/workspace/settings/CcuSettings/FormChargeGunType.h
  67. 61 8
      src/widgets/workspace/settings/CcuSettings/FormOcppGeneralSettings.cpp
  68. 4 1
      src/widgets/workspace/settings/CcuSettings/FormOcppGeneralSettings.h
  69. 13 9
      src/widgets/workspace/settings/CcuSettings/FormOfflinePrice.cpp
  70. 2 1
      src/widgets/workspace/settings/CcuSettings/FormOfflinePrice.h
  71. 6 6
      src/widgets/workspace/settings/CcuSettings/FormOfflinePrice.ui
  72. 16 3
      src/widgets/workspace/settings/CcuSettings/FormPcuhwSettings.cpp
  73. 2 1
      src/widgets/workspace/settings/CcuSettings/FormPcuhwSettings.h
  74. 15 3
      src/widgets/workspace/settings/CcuSettings/FormPcutcSettings.cpp
  75. 2 1
      src/widgets/workspace/settings/CcuSettings/FormPcutcSettings.h
  76. 15 5
      src/widgets/workspace/settings/CcuSettings/FormQttcuSettings.cpp
  77. 2 1
      src/widgets/workspace/settings/CcuSettings/FormQttcuSettings.h
  78. 24 2
      src/widgets/workspace/settings/CcuSettings/OcppGeneralSetting/FormOCPP16GeneralSettings.cpp
  79. 11 2
      src/widgets/workspace/settings/CcuSettings/OcppGeneralSetting/FormOCPP16GeneralSettings.h
  80. 3 3
      src/widgets/workspace/settings/CcuSettings/OcppGeneralSetting/FormOCPP16GeneralSettings.ui
  81. 24 2
      src/widgets/workspace/settings/CcuSettings/OcppGeneralSetting/FormOCPP21GeneralSettings.cpp
  82. 10 2
      src/widgets/workspace/settings/CcuSettings/OcppGeneralSetting/FormOCPP21GeneralSettings.h
  83. 3 3
      src/widgets/workspace/settings/CcuSettings/OcppGeneralSetting/FormOCPP21GeneralSettings.ui
  84. 181 79
      src/widgets/workspace/settings/FormSettings.cpp
  85. 9 1
      src/widgets/workspace/settings/FormSettings.h
  86. 4 21
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogChargingProfileEdit.cpp
  87. 4 21
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogLimitEdit.cpp
  88. 4 21
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogSelectChargingProfiles.cpp
  89. 5 23
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogWeekDayDetail.cpp
  90. 10 3
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormChargingPointMaxProfile.cpp
  91. 2 1
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormChargingPointMaxProfile.h
  92. 6 5
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormChargingProfilesSettings.cpp
  93. 1 1
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormChargingProfilesSettings.h
  94. 10 4
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxDefaultProfileDetail.cpp
  95. 1 0
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxDefaultProfileDetail.h
  96. 11 5
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxDufaultProfile.cpp
  97. 2 1
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxDufaultProfile.h
  98. 10 4
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxProfile.cpp
  99. 2 1
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxProfile.h
  100. 4 21
      src/widgets/workspace/settings/OcppSettings/DialogAddCard.cpp

+ 3744 - 0
cfg/POSLinkUPT.html

@@ -0,0 +1,3744 @@
+<html>
+  <head>
+	  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+        <title>PAX_UPT_Integration_Interface</title>

+		<link href="toc/style/github-bf51422f4bb36427d391e4b75a1daa083c2d840e.css" media="all" rel="stylesheet" type="text/css"/>
+		<link href="toc/style/github2-d731afd4f624c99a4b19ad69f3083cd6d02b81d5.css" media="all" rel="stylesheet" type="text/css"/>
+		<link href="toc/css/zTreeStyle/zTreeStyle.css" media="all" rel="stylesheet" type="text/css"/>
+	  <style>
+		pre {
+		    counter-reset: line-numbering;
+		    border: solid 1px #d9d9d9;
+		    border-radius: 0;
+		    background: #fff;
+		    padding: 0;
+		    line-height: 23px;
+		    margin-bottom: 30px;
+		    white-space: pre;
+		    overflow-x: auto;
+		    word-break: inherit;
+		    word-wrap: inherit;
+		}
+
+		pre a::before {
+		  content: counter(line-numbering);
+		  counter-increment: line-numbering;
+		  padding-right: 1em; /* space after numbers */
+		  width: 25px;
+		  text-align: right;
+		  opacity: 0.7;
+		  display: inline-block;
+		  color: #aaa;
+		  background: #eee;
+		  margin-right: 16px;
+		  padding: 2px 10px;
+		  font-size: 13px;
+		  -webkit-touch-callout: none;
+		  -webkit-user-select: none;
+		  -khtml-user-select: none;
+		  -moz-user-select: none;
+		  -ms-user-select: none;
+		  user-select: none;
+		}
+
+		pre a:first-of-type::before {
+		  padding-top: 10px;
+		}
+
+		pre a:last-of-type::before {
+		  padding-bottom: 10px;
+		}
+
+		pre a:only-of-type::before {
+		  padding: 10px;
+		}
+
+		.highlight { background-color: #ffffcc } /* RIGHT */
+		</style>
+  </head>
+  <body>
+	  <div>
+				<div style='width:25%;'>
+						<ul id="tree" class="ztree" style='width:100%'>
+
+						</ul>
+				</div>
+        <div id='readme' style='width:70%;margin-left:20%;'>
+          	<article class='markdown-body'>
+            	<div style="color:black;"><font size="6"><strong>Copyright Notice</strong></font></div>
+
+<p>Copyright © 2021 PAX Computer Technology (Shenzhen) Co., Ltd. All Rights Reserved.</p>
+<p>The Programs (which include both the software and documentation) contain proprietary information. Such programs are provided by copyright holders under the limited license and are also protected by copyright, patent, and other intellectual and industrial property laws. Please respect the ownership rights of us and others. In no event shall you copy, modify, distribute and disassemble the software and/or documentation, except to the extent required to obtain interoperability with other independently created software or as specified by law.</p>
+<p>The programs are provided &quot;as is,&quot; and copyright holders make no representations or warranties, express or implied, including, but not limited to, warranties of merchantability, fitness for a particular purpose, non-infringement, or title; that the contents of the document are suitable for any purpose; nor that the implementation of such contents will not infringe any third party patents, copyrights, trademarks or other rights.</p>
+<p>Copyright holders will not be liable for any direct, indirect, special or consequential damages arising out of any use of the document or the performance or implementation of the contents thereof.</p>
+<p>The name and trademarks of copyright holders cannot be used in advertising or publicity pertaining to this document or its contents without specific, written prior permission. Title to copyright in this document will at all times remain with copyright holders. </p>
+<p>The information contained in this Copyright Notice is subject to change without notice. If you find any problems in this Copyright Notice, please report them to us in writing. This Copyright Notice is not warranted to be error-free. </p>
+<h1 id="-">修订历史记录</h1>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">时间</th>
+<th style="text-align:left">版本</th>
+<th style="text-align:left">作者</th>
+<th style="text-align:left">内容</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">2025/03/06</td>
+<td style="text-align:left">V1.02.03</td>
+<td style="text-align:left">Ben.J</td>
+<td style="text-align:left">1. 添加110133 PIN KEY MISSING和110134 PIN KEY AND P2PE KEY MISSING到响应码和响应消息。<br>2. 修改hostReferenceNumber的属性为ans…64。<br>3. 更新了Ping命令中timeout的描述。<br>4. 添加detectCardTimeout到GConfigurationNames和SConfigurationNames中。<br>5. 添加amountInformation到GetTransactionInfo命令的response中。</td>
+</tr>
+<tr>
+<td style="text-align:left">2024/09/09</td>
+<td style="text-align:left">V1.02.02</td>
+<td style="text-align:left">Ben.J</td>
+<td style="text-align:left">1. 添加amountInformation到TransactionStartRsp、TransactionIncrementalRsp和TransactionCompletionRsp。<br>2. 添加enableCardUniqueIdentifier到TransactionStartReq、GetCardStatusReq和GetCardInfoReq。<br>3. 添加110225 NEED READ CARD FIRST和110300 PARTIALLY APPROVED到响应码和响应消息。<br>4. 添加cardUniqueIdentifier到AccountRsp。</td>
+</tr>
+<tr>
+<td style="text-align:left">2024/04/30</td>
+<td style="text-align:left">V1.02.01</td>
+<td style="text-align:left">Ben.J</td>
+<td style="text-align:left">1. 添加ipAddress、subnetMask、defaultGateway、dnsServer和backgroundMode到SConfigurationNames类。<br>2. 添加110131 IP CONFIGURATION DISABLED IN DHCP和110132 IP CONFIGURATION PARAMETER ERROR到响应码和响应消息。<br>3. 添加transactionAmount到GetCardInfoReq类。<br>4. 添加appVersion、appUpdateTimeStamp和ipAddress到GetTerminalInfoRsp类。</td>
+</tr>
+<tr>
+<td style="text-align:left">2023/11/21</td>
+<td style="text-align:left">V1.02.00</td>
+<td style="text-align:left">Ben.J</td>
+<td style="text-align:left">1. 添加TransactionIncremental命令。<br>2. 添加hostGateway和accountInformation到TransactionStart的request。<br>3. 添加hostInformation到TransactionStart的response。<br>4. 添加110002 EXP DATE INVALID,110002 TOKEN REQUEST FLAG INVALID,110222 CARD EXPIRE DATE MISSING和110223 SERVICE BUSY到响应码和响应消息。</td>
+</tr>
+<tr>
+<td style="text-align:left">2023/10/18</td>
+<td style="text-align:left">V1.01.09</td>
+<td style="text-align:left">Ben.J</td>
+<td style="text-align:left">1. 添加displayMode到GConfigurationNames和SConfigurationNames。<br>2. 添加110224 PARAMETERS FILE CORRUPTION到响应码和响应消息。</td>
+</tr>
+<tr>
+<td style="text-align:left">2023/07/24</td>
+<td style="text-align:left">V1.01.08</td>
+<td style="text-align:left">Ben.J</td>
+<td style="text-align:left">1. 添加110221 AUTOMATIC REBOOT COUNTDOWN到响应码和响应消息。</td>
+</tr>
+<tr>
+<td style="text-align:left">2023/07/04</td>
+<td style="text-align:left">V1.01.07</td>
+<td style="text-align:left">Ben.J</td>
+<td style="text-align:left">1. 更新了一些描述.<br>2. 新增AccountRsp到TransactionStart/GetCardStatus/GetCardInfo的response中.<br>3. 新增CardType到AccountRsp中。</td>
+</tr>
+<tr>
+<td style="text-align:left">2023/05/25</td>
+<td style="text-align:left">V1.01.06</td>
+<td style="text-align:left">Ben.J</td>
+<td style="text-align:left">1. 增加tapPromptMsgLine1/tapPromptMsgLine2/cardReadSuccessMsg/tapImageName到GConfigurationNames和SConfigurationNames中。<br>2. 修改registerReferenceNumber的属性为ans…32。<br>3. 修改STX相关描述。</td>
+</tr>
+<tr>
+<td style="text-align:left">2023/04/12</td>
+<td style="text-align:left">V1.01.05</td>
+<td style="text-align:left">Ben.J</td>
+<td style="text-align:left">1. 增加InputText命令。<br>2. 增加InputText相关响应码和响应消息。</td>
+</tr>
+<tr>
+<td style="text-align:left">2023/02/20</td>
+<td style="text-align:left">V1.01.04</td>
+<td style="text-align:left">Ben.J</td>
+<td style="text-align:left">1. 将一些属性的是否必需修改成O或C。<br>2. 添加responseMessage的描述链接。<br>3. 修复一些语法错误。<br>4. 增加新机型IM15到Terminal。</td>
+</tr>
+<tr>
+<td style="text-align:left">2023/01/30</td>
+<td style="text-align:left">V1.01.03</td>
+<td style="text-align:left">Ben.J</td>
+<td style="text-align:left">1. 添加cardType到GetCardStatus Response中。<br>2. 修改GetCardStatus Response中的account的描述。</td>
+</tr>
+<tr>
+<td style="text-align:left">2023/01/09</td>
+<td style="text-align:left">V1.01.02</td>
+<td style="text-align:left">Ben.J</td>
+<td style="text-align:left">1. 添加currencyCode于GConfigurationNames中。</td>
+</tr>
+<tr>
+<td style="text-align:left">2022/09/16</td>
+<td style="text-align:left">V1.01.01</td>
+<td style="text-align:left">Ben.J</td>
+<td style="text-align:left">1. 修复GConfigurationNames没有超链接的问题。<br>2. 重命名“通信头”为“报文头”。<br>3. 增加GetCardInfo命令。</td>
+</tr>
+<tr>
+<td style="text-align:left">2022/09/02</td>
+<td style="text-align:left">V1.01.00</td>
+<td style="text-align:left">Jerry.Z</td>
+<td style="text-align:left">1. 第一个中文版本。</td>
+</tr>
+</tbody>
+</table>
+<p><a id="id.introduction"></a></p>
+<h1 id="-">序言</h1>
+<h2 id="-">目的</h2>
+<p>本文档致力于提供自助服务终端以及PAX终端之间的通信接口定义,本文档将包含以下主题。</p>
+<ul>
+<li><a href="#id.introduction">序言</a></li>
+<li><a href="#id.overallDescription">概述</a></li>
+<li><a href="#id.communicationProtocol">通信协议</a></li>
+<li><a href="#id.communicationScenarios">通信场景</a></li>
+<li><a href="#id.normalTransactionFlow">一般交易流程</a></li>
+<li><a href="#id.commandDataAttribute">命令数据属性</a></li>
+<li><a href="#id.commandDefinition">命令定义</a></li>
+<li><a href="#id.commandObjectDefinition">命令对象定义</a></li>
+<li><a href="#id.valueReference">常量值定义</a></li>
+<li><a href="#id.appendix">附录</a></li>
+</ul>
+<h2 id="-">预期读者</h2>
+<p>本文档的预期读者如下:</p>
+<ul>
+<li>自助服务终端设备应用开发人员</li>
+<li>PAX 终端应用开发人员</li>
+</ul>
+<h2 id="-">文档约定</h2>
+<ul>
+<li>RFU:预留给未来使用。</li>
+</ul>
+<p><a id="id.overallDescription"></a></p>
+<h1 id="-">概述</h1>
+<h2 id="-">简介</h2>
+<p>PAX为自助服务终端和支付终端进行通信提供了一个简单的集成方案,操作员可以通过使用交易命令来避免数据和通信过程中的监控。目前有四种类型的命令Admin,Transaction,Batch,Device,Report。 其中Admin系列负责终端管理,Transaction系列负责交易处理, Batch负责和后台的清结算,Device负责操作硬件相关功能,Report负责报告交易的执行结果。</p>
+<h3 id="-">通信方式</h3>
+<p>自助服务终端可以通过UART/USB 或者 TCP/SSL 和支付终端进行通信。</p>
+<ul>
+<li>UART/USB<ul>
+<li>对于UART,自助服务终端可以用以下默认参数。</li>
+<li>波特率: 115200, 数据位: 8 停止位: 1, 奇偶校验位: None。</li>
+</ul>
+</li>
+<li>TCP/SSL<ul>
+<li>对于网络通信,支付终端将作为服务端,自助服务终端将作为客户端进行通信。 默认的端口号为10009。</li>
+</ul>
+</li>
+</ul>
+<h2 id="-">操作环境</h2>
+<h3 id="-">支付终端</h3>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">IM系列</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">IM30</td>
+</tr>
+<tr>
+<td style="text-align:left">IM700</td>
+</tr>
+<tr>
+<td style="text-align:left">IM15</td>
+</tr>
+</tbody>
+</table>
+<p><a id="id.communicationProtocol"></a></p>
+<h1 id="-">通信协议</h1>
+<h2 id="-">通信交互设计</h2>
+<p>该协议设计分为两层,一层为应用层,另一层为通信层。</p>
+<ul>
+<li>应用层 (基于JSON,适用于所有通信方法)</li>
+<li>通信层(不同的通信方式采用不同的逻辑)</li>
+</ul>
+<h2 id="-">应用层</h2>
+<p>采用JSON格式,命令的具体内容将放到该层实现</p>
+<h3 id="-">格式范例</h3>
+<p>一条发自自助服务终端的请求报文的一般如下:</p>
+<pre><code>{
+    &quot;version&quot;: &quot;2.xx&quot;,
+    &quot;request&quot;: [
+        {
+            &quot;command&quot;: &quot;CMD&quot;,
+            &quot;properties&quot;: {
+                &quot;name1&quot;: &quot;Value1&quot;,
+                &quot;name2&quot;: &quot;Value2&quot;
+            }
+        }
+    ]
+}
+</code></pre><p>一条来自支付终端的响应报文的一般如下:</p>
+<pre><code>{
+    &quot;version&quot;: &quot;2.xx&quot;,
+    &quot;response&quot;: [
+        {
+            &quot;command&quot;: &quot;CMD&quot;,
+            &quot;properties&quot;: {
+                &quot;name1&quot;: &quot;Value1&quot;,
+                &quot;name2&quot;: &quot;Value2&quot;
+            }
+        }
+    ]
+} 
+</code></pre><h2 id="-">通信层</h2>
+<p>在本章节中, &quot;报文体&quot; 指应用层数据内容。</p>
+<h3 id="-">通信方式</h3>
+<h4 id="tcp-ssl">TCP/SSL</h4>
+<p>TCP/SSL完整报文包由报文头和报文体两部分组成。
+报文头由协议标记,报文头长度,报文体长度等组成. 详细请参考 <a href="#Communication Header">报文头格式</a>。  </p>
+<p>格式:  </p>
+<table>
+<thead>
+<tr>
+<th>报文头</th>
+<th>报文体</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>PJ****</td>
+<td>{****}</td>
+</tr>
+</tbody>
+</table>
+<h4 id="uart-usb">UART/USB</h4>
+<p>UART/USB 完整报文包由起始符,报文头,报文体以及校验码组成。 
+报文头由协议标记,报文头长度,报文体长度等组成. 详细请参考 <a href="#Communication Header">报文头格式</a>。  </p>
+<p>格式:  </p>
+<table>
+<thead>
+<tr>
+<th>起始符</th>
+<th>报文头</th>
+<th>报文体</th>
+<th>校验码</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>STX</td>
+<td>PJ****</td>
+<td>{****}</td>
+<td>LRC</td>
+</tr>
+</tbody>
+</table>
+<p>起始符: 固定值为&#39;\x02&#39;。单字节,ASCII码控制字符STX(标记有效数据的开始)。  </p>
+<p>校验码: 单字节。用来判断报文是否有效,计算方式为从报文头到报文体逐字节异或(排除起始符)。</p>
+<p>校验码计算方式:  </p>
+<pre><code>Set LRC = 0
+For each character c in the package 
+Do
+Set LRC = LRC XOR c
+End Do
+The check begins after the STX.
+</code></pre><p>校验码计算示例:</p>
+<pre><code>The algorithm is XOR calculation for each byte of data
+
+The hexadecimal format is 01 A0 7C FF 02
+01 xor A0 xor 7C xor FF xor 02 = 20
+The LRC is 20
+</code></pre><h3 id="-">通信控制</h3>
+<h4 id="ack">ACK</h4>
+<p>该报文用来确认消息已经被成功接收。当接收到一个完整的数据包,并且数据包格式是正确时,接收方需要回复一个ACK。
+该报文在 TCP/SSL/UART/USB 中被使用。</p>
+<p>格式: \x06 </p>
+<h4 id="nak">NAK</h4>
+<p>该报文用来反馈报文有问题。当接收到一个数据包,但该数据包数据有错。接收方需要回复一个NAK。
+该报文在 UART/USB 中被使用。</p>
+<p>格式:  \x15</p>
+<h4 id="eot">EOT</h4>
+<p>该报文用来标记当前通信已经结束。
+当前支付终端在收到ACK后,会发送EOT给自助服务终端。
+该报文在 TCP/SSL/UART/USB 中被使用。</p>
+<p>格式: \x04</p>
+<p><a id="Communication Header"></a></p>
+<h3 id="-">报文头格式</h3>
+<p>格式:  </p>
+<table>
+<thead>
+<tr>
+<th>报文头标记 <br> (2 Bytes)</th>
+<th>报文头长度 <br> (3 Bytes)</th>
+<th>报文体长度 <br> (6 Bytes)</th>
+<th>包序号 <br> (3 Bytes)</th>
+<th>包状态 <br> (1 Byte)</th>
+<th>协议类型 <br> (2 Bytes)</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>PJ</td>
+<td>017</td>
+<td>000200</td>
+<td>000</td>
+<td>0</td>
+<td>01</td>
+</tr>
+</tbody>
+</table>
+<ul>
+<li>报文头标记: POSLink JSON 协议. 必须为&quot;PJ&quot;。</li>
+<li>报文头长度: 报文头的长度。 在上表中报文头长度为 17 (2+3+6+3+1+2 = 17).</li>
+<li>报文体长度: 报文体的长度。 格式为 n6 (6位数的数字).</li>
+<li>包序号: 预留字段,必须为000。</li>
+<li>包状态: 预留字段,必须为0。</li>
+<li>协议类型: 当前为UPT协议,必须为01。</li>
+<li>报文头里出现的所有数字都是字符串格式。</li>
+</ul>
+<p>示例: 
+PJ017000100000001</p>
+<p><a id="id.communicationScenarios"></a></p>
+<h1 id="-">通信场景</h1>
+<p>该章节介绍了本协议在不同场景下的传输过程以及内容。</p>
+<h2 id="tcp-ssl">TCP/SSL</h2>
+<h3 id="-">普通场景</h3>
+<p>自助服务终端发送命令前先建立连接,执行结束后断开连接。</p>
+<p>一个成功的传输过程: </p>
+<ul>
+<li>Abort: 可选,取消当前正在执行的命令,不需要ACK。</li>
+<li>Report Status: 某些情况下会出现,报告当前状态给自助服务终端,不需要ACK。</li>
+<li>Abort 以及Report Status 并不一定会出现。详细请查看 <a href="#id.commandDefinition">命令定义</a>。</li>
+</ul>
+<center>
+    <img src="./img/TCP.png">
+    <br>
+    <div style="color:gray;">成功传输</div>
+</center>
+
+
+<h3 id="-">超时场景</h3>
+<p>接收消息超时,当接收端没有在指定时间收到完整的报文,那么将断开当前的连接。
+超时时间定义如下: </p>
+<ul>
+<li>请求报文超时: 3 秒</li>
+<li>ACK 超时: 9 秒</li>
+<li>EOT 超时: 1 秒</li>
+<li>响应报文超时: 取决于自助服务终端设置,不同的命令可以采用不同的超时时间。推荐时间120秒。</li>
+</ul>
+<center>
+    <img src="./img/TCP_Timeout_03.png">
+    <br>
+    <div style="color:gray;">请求报文超时/网络错误</div>
+    <br><br>
+    <img src="./img/TCP_Timeout_01.png">
+    <br>
+    <div style="color:gray;">请求报文ACK超时/网络错误</div>
+    <br><br>
+    <img src="./img/TCP_Timeout_02.png">
+    <br>
+    <div style="color:gray;">响应报文超时/网络错误</div>
+    <br><br>
+    <img src="./img/TCP_Timeout_04.png">
+    <br>
+    <div style="color:gray;">响应报文ACK 超时/网络错误</div>
+    <br><br>
+    <img src="./img/TCP_Timeout_05.png">
+    <br>
+    <div style="color:gray;">EOT 超时/网络错误</div>
+
+</center>
+
+<h2 id="uart-usb">UART/USB</h2>
+<h3 id="-">普通场景</h3>
+<p>一个成功的传输过程: </p>
+<ul>
+<li>Abort: 可选,取消当前正在执行的命令,不需要ACK。</li>
+<li>Report Status: 某些情况下会出现,报告当前状态给自助服务终端,不需要ACK。</li>
+<li>Abort 以及Report Status 并不一定会出现。详细请查看 <a href="#id.commandDefinition">命令定义</a>。</li>
+</ul>
+<center>
+    <img src="./img/UART.png">
+    <br>
+    <div style="color:gray;">成功传输</div>
+</center>
+
+
+
+<h3 id="nak-">NAK场景</h3>
+<p>如果校验码(LRC)校验数据失败,那么接收方需要发送NAK来告诉发送方重发数据。
+发送方重试3次,如果3次都失败,那么结束当前的重发。</p>
+<center>
+    <img src="./img/UART_NAK_01.png">
+    <br>
+    <div style="color:gray;">重发请求报文3次, 成功</div>
+    <br><br>
+    <img src="./img/UART_NAK_02.png">
+    <br>
+    <div style="color:gray;">重发响应报文3次, 失败</div>
+    <br><br>
+</center>
+
+
+<h3 id="-">超时场景</h3>
+<p>接收消息ACK超时,如果3秒内发送方没有收到确认成功的ACK,那么发送方需要重新发送,一共重试3次。
+超时时间定义如下:</p>
+<ul>
+<li>ACK 超时: 3 秒</li>
+<li>EOT 超时: 1 秒</li>
+<li>响应报文超时: 取决于自助服务终端设置,不同的命令可以采用不同的超时时间。推荐时间120秒。</li>
+</ul>
+<center>
+    <img src="./img/UART_Timeout_01.png">
+     <br>
+    <div style="color:gray;">等待请求报文ACK3次, 成功</div>
+    <br><br>
+    <img src="./img/UART_Timeout_02.png">
+    <br>
+    <div style="color:gray;">等待响应报文ACK3次, 失败</div>
+</center>
+
+<p><a id="id.normalTransactionFlow"></a></p>
+<h1 id="-">一般交易流程</h1>
+<ul>
+<li>自助服务终端发送TransactionStart给PAX终端。</li>
+<li>持卡人在PAX终端上完成操作。</li>
+<li>PAX终端和后台通信完成交易。</li>
+<li>PAX终端返回TransactionStart执行结果给自助服务终端。</li>
+<li>自助服务终端处理自己的业务逻辑。</li>
+<li>自助服务终端根据自身的执行结果发送TransactionCompletion或者TransactionReversal给PAX终端。</li>
+<li>PAX终端和后台通信后,返回TransactionCompletion或者TransactionReversal执行结果给自助服务终端。此次交易结束。</li>
+</ul>
+<center>
+    <img src="./img/Normal_Transaction_Flow.png">
+    <br>
+    <div style="color:gray;">普通交易流程</div>
+</center>
+
+
+<p><a id="id.commandDataAttribute"></a></p>
+<h1 id="-">命令数据属性</h1>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">修饰符</th>
+<th style="text-align:left">含义</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">n</td>
+<td style="text-align:left">数字,0 到 9</td>
+</tr>
+<tr>
+<td style="text-align:left">a</td>
+<td style="text-align:left">字母 A-Z 以及 a-z</td>
+</tr>
+<tr>
+<td style="text-align:left">s</td>
+<td style="text-align:left">特殊字符, 字母数字外的可打印字符</td>
+</tr>
+<tr>
+<td style="text-align:left">an</td>
+<td style="text-align:left">字母以及数字</td>
+</tr>
+<tr>
+<td style="text-align:left">ans</td>
+<td style="text-align:left">字母,数字以及特殊字符</td>
+</tr>
+<tr>
+<td style="text-align:left">YYYY</td>
+<td style="text-align:left">年,0000 到 9999</td>
+</tr>
+<tr>
+<td style="text-align:left">YY</td>
+<td style="text-align:left">年,00 到 99</td>
+</tr>
+<tr>
+<td style="text-align:left">MM</td>
+<td style="text-align:left">月,01 到 12</td>
+</tr>
+<tr>
+<td style="text-align:left">DD</td>
+<td style="text-align:left">日,01 到 31</td>
+</tr>
+<tr>
+<td style="text-align:left">hh</td>
+<td style="text-align:left">时,00 到 23</td>
+</tr>
+<tr>
+<td style="text-align:left">mm</td>
+<td style="text-align:left">分,00 到 59</td>
+</tr>
+<tr>
+<td style="text-align:left">ss</td>
+<td style="text-align:left">秒,00 到 59</td>
+</tr>
+</tbody>
+</table>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">修饰符</th>
+<th style="text-align:left">含义</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">M</td>
+<td style="text-align:left">Mandatory, 必须字段</td>
+</tr>
+<tr>
+<td style="text-align:left">C</td>
+<td style="text-align:left">Conditional, 在某些条件下,该字段是必须字段</td>
+</tr>
+<tr>
+<td style="text-align:left">O</td>
+<td style="text-align:left">Optional, 可选字段</td>
+</tr>
+</tbody>
+</table>
+<p><a id="id.commandDefinition"></a></p>
+<h1 id="-">命令定义</h1>
+<h2 id="admin">Admin</h2>
+<p><a id="id.commandGetTerminalInfo"></a></p>
+<h3 id="getterminalinfo">GetTerminalInfo</h3>
+<p>获取终端信息。</p>
+<h4 id="-">请求报文</h4>
+<p>本命令没有相关字段。</p>
+<h4 id="-">响应报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">responseCode</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n6</td>
+<td style="text-align:left">响应码。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">responseMessage</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans…64</td>
+<td style="text-align:left">响应消息。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">sn</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">ans...16</td>
+<td style="text-align:left">设备的序列号。</td>
+</tr>
+<tr>
+<td style="text-align:left">modelName</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">ans...10</td>
+<td style="text-align:left">设备的型号。</td>
+</tr>
+<tr>
+<td style="text-align:left">osVersion</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">ans...64</td>
+<td style="text-align:left">操作系统的版本号。</td>
+</tr>
+<tr>
+<td style="text-align:left">appVersion</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">ans...32</td>
+<td style="text-align:left">应用版本。</td>
+</tr>
+<tr>
+<td style="text-align:left">appUpdateTimeStamp</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">n14</td>
+<td style="text-align:left">应用更新结束的时间戳。如果应用从来没有更新过,那么该字段不会出现。该时间戳格式YYYYMMDDhhmmss。该值和终端更新结束时的显示时间相同。</td>
+</tr>
+<tr>
+<td style="text-align:left">ipAddress</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">ans...15</td>
+<td style="text-align:left">当前在局域网中的IP地址。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">示例</h4>
+<p>请求报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;request&quot;:[
+        {
+            &quot;command&quot;:&quot;GetTerminalInfo&quot;
+        }
+    ]
+}
+</code></pre><p>响应报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;response&quot;:[
+        {
+            &quot;command&quot;:&quot;GetTerminalInfo&quot;,
+            &quot;properties&quot;:{
+                &quot;responseCode&quot;:&quot;*&quot;,
+                &quot;responseMessage&quot;:&quot;*&quot;,
+                &quot;sn&quot;:&quot;*&quot;,
+                &quot;modelName&quot;:&quot;*&quot;,
+                &quot;osVersion&quot;:&quot;*&quot;,
+                &quot;appVersion&quot;:&quot;*&quot;,
+                &quot;appUpdateTimeStamp&quot;:&quot;*&quot;,
+                &quot;ipAddress&quot;:&quot;*&quot;
+            }
+        }
+    ]
+}
+</code></pre><p><a id="id.commandAbort"></a></p>
+<h3 id="abort">Abort</h3>
+<p>当已经发送了命令A,并且终端正在等待用户操作,自助服务设备可以发送Abort命令来中断命令的执行,并收到命令A的执行结果。</p>
+<h4 id="-">请求报文</h4>
+<p>本命令没有相关字段。</p>
+<h4 id="-">示例</h4>
+<p>请求报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;request&quot;:[
+        {
+            &quot;command&quot;:&quot;Abort&quot;
+        }
+    ]
+}
+</code></pre><p><a id="id.commandReboot"></a></p>
+<h3 id="reboot">Reboot</h3>
+<p>重启设备。</p>
+<h4 id="-">请求报文</h4>
+<p>本命令没有相关字段。</p>
+<h4 id="-">响应报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">responseCode</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n6</td>
+<td style="text-align:left">响应码。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">responseMessage</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans…64</td>
+<td style="text-align:left">响应消息。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">示例</h4>
+<p>请求报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;request&quot;:[
+        {
+            &quot;command&quot;:&quot;Reboot&quot;
+        }
+    ]
+}
+</code></pre><p>响应报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;response&quot;:[
+        {
+            &quot;command&quot;:&quot;Reboot&quot;,
+            &quot;properties&quot;:{
+                &quot;responseCode&quot;:&quot;*&quot;,
+                &quot;responseMessage&quot;:&quot;*&quot;
+            }
+        }
+    ]
+}
+</code></pre><p><a id="id.commandReset"></a></p>
+<h3 id="reset">Reset</h3>
+<p>重置终端屏幕到空闲状态。</p>
+<h4 id="-">请求报文</h4>
+<p>本命令没有相关字段。</p>
+<h4 id="-">响应报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">responseCode</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n6</td>
+<td style="text-align:left">响应码。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">responseMessage</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans…64</td>
+<td style="text-align:left">响应消息。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">示例</h4>
+<p>请求报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;request&quot;:[
+        {
+            &quot;command&quot;:&quot;Reset&quot;
+        }
+    ]
+}
+</code></pre><p>响应报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;response&quot;:[
+        {
+            &quot;command&quot;:&quot;Reset&quot;,
+            &quot;properties&quot;:{
+                &quot;responseCode&quot;:&quot;*&quot;,
+                &quot;responseMessage&quot;:&quot;*&quot;
+            }
+        }
+    ]
+}
+</code></pre><p><a id="id.commandGetConfiguration"></a></p>
+<h3 id="getconfiguration">GetConfiguration</h3>
+<p>获取终端参数配置。</p>
+<h4 id="-">请求报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">names</td>
+<td style="text-align:center">string[]</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center"></td>
+<td style="text-align:left">需要获取的配置参数名列表。请查看 <a href="#id.Util.GConfigurationNames">GConfigurationNames</a>。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">响应报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">responseCode</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n6</td>
+<td style="text-align:left">响应码。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">responseMessage</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans…64</td>
+<td style="text-align:left">响应消息。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">configurations</td>
+<td style="text-align:center"><a href="#id.Util.GConfigurationInfo">GConfigurationInfo[]</a></td>
+<td style="text-align:center">C</td>
+<td style="text-align:center"></td>
+<td style="text-align:left">从终端返回的配置信息。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">示例</h4>
+<p>请求报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;request&quot;:[
+        {
+            &quot;command&quot;:&quot;GetConfiguration&quot;,
+            &quot;properties&quot;:{
+                &quot;names&quot;:[&quot;*&quot;]
+            }
+        }
+    ]
+}
+</code></pre><p>响应报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;response&quot;:[
+        {
+            &quot;command&quot;:&quot;GetConfiguration&quot;,
+            &quot;properties&quot;:{
+                &quot;responseCode&quot;:&quot;*&quot;,
+                &quot;responseMessage&quot;:&quot;*&quot;,
+                &quot;configurations&quot;:[{
+                    &quot;name&quot;:&quot;*&quot;,
+                    &quot;value&quot;:&quot;*&quot;
+                }]
+            }
+        }
+    ]
+}
+</code></pre><p><a id="id.commandSetConfiguration"></a></p>
+<h3 id="setconfiguration">SetConfiguration</h3>
+<p>设置终端参数配置。</p>
+<h4 id="-">请求报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">configurations</td>
+<td style="text-align:center"><a href="#id.Util.SConfigurationInfo">SConfigurationInfo[]</a></td>
+<td style="text-align:center">O</td>
+<td style="text-align:center"></td>
+<td style="text-align:left">配置参数列表</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">响应报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">responseCode</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n6</td>
+<td style="text-align:left">响应码。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">responseMessage</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans…64</td>
+<td style="text-align:left">响应消息。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">示例</h4>
+<p>请求报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;request&quot;:[
+        {
+            &quot;command&quot;:&quot;SetConfiguration&quot;,
+            &quot;properties&quot;:{
+                &quot;configurations&quot;:[{
+                    &quot;name&quot;:&quot;*&quot;,
+                    &quot;value&quot;:&quot;*&quot;
+                }]
+            }
+        }
+    ]
+}
+</code></pre><p>响应报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;response&quot;:[
+        {
+            &quot;command&quot;:&quot;SetConfiguration&quot;,
+            &quot;properties&quot;:{
+                &quot;responseCode&quot;:&quot;*&quot;,
+                &quot;responseMessage&quot;:&quot;*&quot;
+            }
+        }
+    ]
+}
+</code></pre><p><a id="id.commandReportStatus"></a></p>
+<h3 id="reportstatus">ReportStatus</h3>
+<p>报告当前的终端状态给自助服务设备. 本命令不需要请求报文。</p>
+<h4 id="-">响应报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">statusCode</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n7</td>
+<td style="text-align:left">状态码</td>
+</tr>
+<tr>
+<td style="text-align:left">statusMessage</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans...64</td>
+<td style="text-align:left">状态消息。请查看 <a href="#id.reportStatusCode">消息上报状态码</a>。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">示例</h4>
+<p>响应报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;response&quot;:[
+        {
+            &quot;command&quot;:&quot;ReportStatus&quot;,
+            &quot;properties&quot;:{
+                &quot;statusCode&quot;:&quot;*&quot;,
+                &quot;statusMessage&quot;:&quot;*&quot;
+            }
+        }
+    ]
+}
+</code></pre><p><a id="id.commandPing"></a></p>
+<h3 id="ping">Ping</h3>
+<p>Ping一个指定的服务器,测试网络是否工作正常。</p>
+<h4 id="-">请求报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">targetName</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans...256</td>
+<td style="text-align:left">目标名字,可以为IPv4的地址或者域名。</td>
+</tr>
+<tr>
+<td style="text-align:left">timeout</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">n...3</td>
+<td style="text-align:left">等待超时的时间,单位为100毫秒,(超时时间 = 字段值 * 100ms)<br>有效的取值区间为[30, 300]. 默认值为50。<br></td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">响应报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">responseCode</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n6</td>
+<td style="text-align:left">响应码。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">responseMessage</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans…64</td>
+<td style="text-align:left">响应消息。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">rtt</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">n...7</td>
+<td style="text-align:left">来回传输时间。单位为100ms(传输时间 = 字段值 * 100ms)<br>该值的取值方法为截断小数点后的位数,比如真实时间为199ms,那么在这里该值为1。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">示例</h4>
+<p>请求报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;request&quot;:[
+        {
+            &quot;command&quot;:&quot;Ping&quot;,
+            &quot;properties&quot;:{
+                &quot;targetName&quot;:&quot;*&quot;,
+                &quot;timeout&quot;:&quot;*&quot;
+            }
+        }
+    ]
+}
+</code></pre><p>响应报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;response&quot;:[
+        {
+            &quot;command&quot;:&quot;Ping&quot;,
+            &quot;properties&quot;:{
+                &quot;responseCode&quot;:&quot;*&quot;,
+                &quot;responseMessage&quot;:&quot;*&quot;,
+                &quot;rtt&quot;:&quot;*&quot;
+            }
+        }
+    ]
+}
+</code></pre><h2 id="transaction">Transaction</h2>
+<p><a id="id.commandTransactionStart"></a></p>
+<h3 id="transactionstart">TransactionStart</h3>
+<p>开始交易,命令成功后,必须要发送TransactionCompletion或者TransactionReversal来结束或者取消交易。 </p>
+<h4 id="-">请求报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">transactionAmount</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n...9</td>
+<td style="text-align:left">交易金额。<br>小数点位数取决于地域。<br>示例,在中国,该值包含两位小数,“1000”代表“10.00”元。<br>当支付终端处在demo模式下,使用特殊的金额去执行交易可以触发特殊的结果。<br>如果使用GetTraceInfoByCard来预处理交易,该值必须和GetTraceInfoByCard中的amount字段值一样。<br>如果使用GetCardStatus来预处理交易,该值必须和配置preprocessingAmount值一样,可以通过SetConfiguration命令配置。请查看 <a href="#id.specialAmountInDemoMode">Demo模式特殊金额</a>。</td>
+</tr>
+<tr>
+<td style="text-align:left">registerReferenceNumber</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans...32</td>
+<td style="text-align:left">交易流水号,自助服务终端可以用来标记一笔交易的唯一标识符。目前应用支持字母,数字和特殊字符“_”和“-”。</td>
+</tr>
+<tr>
+<td style="text-align:left">account</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">ans...19</td>
+<td style="text-align:left">从GetTraceInfoByCard/GetCardStatus命令返回的account字段值。如果需要使用GetTraceInfoByCard/GetCardStatus来预处理交易,那么你必须输入该字段。<br>当你设置了该字段:<br>1. 如果它和存储在支付终端的卡号相同,那么用户没有必要再次插卡/拍卡/刷卡。<br>2. 如果它和存储在支付终端的卡号不同,那么用户需要再次插卡/拍卡/刷卡。</td>
+</tr>
+<tr>
+<td style="text-align:left">reportStatus</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">n1</td>
+<td style="text-align:left">上报状态功能的开关。                <br>0 = 关 (默认值)<br>1 = 开</td>
+</tr>
+<tr>
+<td style="text-align:left">hostGateway</td>
+<td style="text-align:center"><a href="#id.Util.HostGateway">HostGateway</a></td>
+<td style="text-align:center">O</td>
+<td style="text-align:center"></td>
+<td style="text-align:left">RFU</td>
+</tr>
+<tr>
+<td style="text-align:left">accountInformation</td>
+<td style="text-align:center"><a href="#id.Util.AccountReq">AccountReq</a></td>
+<td style="text-align:center">O</td>
+<td style="text-align:center"></td>
+<td style="text-align:left">RFU</td>
+</tr>
+<tr>
+<td style="text-align:left">enableCardUniqueIdentifier</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center"></td>
+<td style="text-align:left">开启是否获取卡片唯一标识。默认值是“Off”。<br>请查看<a href="#id.Const.EnableCardUniqueIdentifier">EnableCardUniqueIdentifier</a>。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">响应报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">responseCode</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n6</td>
+<td style="text-align:left">响应码。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">responseMessage</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans…64</td>
+<td style="text-align:left">响应消息。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">hostReferenceNumber</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">ans...64</td>
+<td style="text-align:left">后台返回的交易流水号<br>TransactionCompletion和TransactionReversal命令中的originalHostReferenceNumber应使用该值。<br>如果交易失败该字段可能为空。<br></td>
+</tr>
+<tr>
+<td style="text-align:left">hostData</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">ans...256</td>
+<td style="text-align:left">后台返回的交易数据。<br>TransactionCompletion和TransactionReversal命令中的originalHostData应使用该值。<br>如果交易失败该字段可能为空。</td>
+</tr>
+<tr>
+<td style="text-align:left">account</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">ans...19</td>
+<td style="text-align:left">卡号,返回前6位以及后4位,其它用“*”代替。<br>示例: 545454*********5454。</td>
+</tr>
+<tr>
+<td style="text-align:left">timestamp</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n14</td>
+<td style="text-align:left">交易时间戳,格式YYYYMMDDhhmmss.</td>
+</tr>
+<tr>
+<td style="text-align:left">accountInformation</td>
+<td style="text-align:center"><a href="#id.Util.AccountRsp">AccountRsp</a></td>
+<td style="text-align:center">C</td>
+<td style="text-align:center"></td>
+<td style="text-align:left">卡片信息。</td>
+</tr>
+<tr>
+<td style="text-align:left">hostInformation</td>
+<td style="text-align:center"><a href="#id.Util.HostRsp">HostRsp</a></td>
+<td style="text-align:center">C</td>
+<td style="text-align:center"></td>
+<td style="text-align:left">RFU</td>
+</tr>
+<tr>
+<td style="text-align:left">amountInformation</td>
+<td style="text-align:center"><a href="#id.Util.AmountRsp">AmountRsp</a></td>
+<td style="text-align:center">C</td>
+<td style="text-align:center"></td>
+<td style="text-align:left">交易金额相关信息。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">示例</h4>
+<p>请求报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;request&quot;:[
+        {
+            &quot;command&quot;:&quot;TransactionStart&quot;,
+            &quot;properties&quot;:{
+                &quot;transactionAmount&quot;:&quot;*&quot;,
+                &quot;registerReferenceNumber&quot;:&quot;*&quot;,
+                &quot;account&quot;:&quot;*&quot;,
+                &quot;reportStatus&quot;:&quot;*&quot;,
+                &quot;hostGateway&quot;:{
+                    &quot;tokenRequestFlag&quot;:&quot;*&quot;,
+                    &quot;token&quot;:&quot;*&quot;
+                },
+                &quot;accountInformation&quot;:{
+                    &quot;cardExpireDate&quot;:&quot;*&quot;
+                },
+                &quot;enableCardUniqueIdentifier&quot;:&quot;*&quot;
+            }
+        }
+    ]
+}
+</code></pre><p>响应报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;response&quot;:[
+        {
+            &quot;command&quot;:&quot;TransactionStart&quot;,
+            &quot;properties&quot;:{
+                &quot;responseCode&quot;:&quot;*&quot;,
+                &quot;responseMessage&quot;:&quot;*&quot;,
+                &quot;hostReferenceNumber&quot;:&quot;*&quot;,
+                &quot;hostData&quot;:&quot;*&quot;,
+                &quot;account&quot;:&quot;*&quot;,
+                &quot;timestamp&quot;:&quot;*&quot;,
+                &quot;accountInformation&quot;:{
+                    &quot;expireDate&quot;:&quot;*&quot;,
+                    &quot;cardType&quot;:&quot;*&quot;,
+                    &quot;cardTypeName&quot;:&quot;*&quot;,
+                    &quot;cardUniqueIdentifier&quot;:&quot;*&quot;
+                },
+                &quot;hostInformation&quot;:{
+                    &quot;token&quot;:&quot;*&quot;
+                },
+                &quot;amountInformation&quot;:{
+                    &quot;approvedAmount&quot;:&quot;*&quot;
+                }
+            }
+        }
+    ]
+}
+</code></pre><p><a id="id.commandTransactionCompletion"></a></p>
+<h3 id="transactioncompletion">TransactionCompletion</h3>
+<p>正常完成一笔交易。</p>
+<h4 id="-">请求报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">transactionAmount</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n...9</td>
+<td style="text-align:left">交易金额。<br>小数点位数取决于地域。<br>示例,在中国,该值包含两位小数,&quot;1000&quot;代表&quot;10.00&quot;元。<br>当支付终端处在demo模式下,使用特殊金额去执行交易可以触发特殊的结果。请查看 <a href="#id.specialAmountInDemoMode">Demo模式特殊金额</a>。</td>
+</tr>
+<tr>
+<td style="text-align:left">originalHostReferenceNumber</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans...64</td>
+<td style="text-align:left">原始的后台流水号,从TransactionStart命令执行结果的hostReferenceNumber获取。</td>
+</tr>
+<tr>
+<td style="text-align:left">originalHostData</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans...256</td>
+<td style="text-align:left">原始的后台数据。从TransactionStart命令执行结果的hostData获取。</td>
+</tr>
+<tr>
+<td style="text-align:left">verifyCard</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">n1</td>
+<td style="text-align:left">[ 已废弃 ] 校验卡标记位。<br>0: 不校验(默认)<br>1: 校验。如果该卡与执行TransactionStart命令时使用的卡是同一张卡,交易会正常执行。如果不是,交易将停止。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">响应报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">responseCode</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n6</td>
+<td style="text-align:left">响应码。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">responseMessage</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans…64</td>
+<td style="text-align:left">响应消息。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">hostReferenceNumber</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">ans...64</td>
+<td style="text-align:left">后台返回的交易流水号。</td>
+</tr>
+<tr>
+<td style="text-align:left">hostData</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">ans...256</td>
+<td style="text-align:left">后台返回的交易数据。</td>
+</tr>
+<tr>
+<td style="text-align:left">timestamp</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">n14</td>
+<td style="text-align:left">交易时间,格式为YYYYMMDDhhmmss.</td>
+</tr>
+<tr>
+<td style="text-align:left">amountInformation</td>
+<td style="text-align:center"><a href="#id.Util.AmountRsp">AmountRsp</a></td>
+<td style="text-align:center">C</td>
+<td style="text-align:center"></td>
+<td style="text-align:left">交易金额相关信息。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">示例</h4>
+<p>请求报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;request&quot;:[
+        {
+            &quot;command&quot;:&quot;TransactionCompletion&quot;,
+            &quot;properties&quot;:{
+                &quot;transactionAmount&quot;:&quot;*&quot;,
+                &quot;originalHostReferenceNumber&quot;:&quot;*&quot;,
+                &quot;originalHostData&quot;:&quot;*&quot;,
+                &quot;verifyCard&quot;:&quot;*&quot;
+            }
+        }
+    ]
+}
+</code></pre><p>响应报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;response&quot;:[
+        {
+            &quot;command&quot;:&quot;TransactionCompletion&quot;,
+            &quot;properties&quot;:{
+                &quot;responseCode&quot;:&quot;*&quot;,
+                &quot;responseMessage&quot;:&quot;*&quot;,
+                &quot;hostReferenceNumber&quot;:&quot;*&quot;,
+                &quot;hostData&quot;:&quot;*&quot;,
+                &quot;timestamp&quot;:&quot;*&quot;,
+                &quot;amountInformation&quot;:{
+                    &quot;approvedAmount&quot;:&quot;*&quot;
+                }
+            }
+        }
+    ]
+}
+</code></pre><p><a id="id.commandTransactionReversal"></a></p>
+<h3 id="transactionreversal">TransactionReversal</h3>
+<p>取消一笔交易,可以在TransactionStart命令成功之后,TransactionCompletion命令未执行前使用。</p>
+<h4 id="-">请求报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">originalHostReferenceNumber</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans...64</td>
+<td style="text-align:left">原始的后台流水号,从TransactionStart命令执行结果的hostReferenceNumber获取。</td>
+</tr>
+<tr>
+<td style="text-align:left">originalHostData</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans...256</td>
+<td style="text-align:left">原始的后台数据。从TransactionStart命令执行结果的hostData获取。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">响应报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">responseCode</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n6</td>
+<td style="text-align:left">响应码。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">responseMessage</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans…64</td>
+<td style="text-align:left">响应消息。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">示例</h4>
+<p>请求报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;request&quot;:[
+        {
+            &quot;command&quot;:&quot;TransactionReversal&quot;,
+            &quot;properties&quot;:{
+                &quot;originalHostReferenceNumber&quot;:&quot;*&quot;,
+                &quot;originalHostData&quot;:&quot;*&quot;
+            }
+        }
+    ]
+}
+</code></pre><p>响应报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;response&quot;:[
+        {
+            &quot;command&quot;:&quot;TransactionReversal&quot;,
+            &quot;properties&quot;:{
+                &quot;responseCode&quot;:&quot;*&quot;,
+                &quot;responseMessage&quot;:&quot;*&quot;
+            }
+        }
+    ]
+}
+</code></pre><p><a id="id.commandTransactionIncremental"></a></p>
+<h3 id="transactionincremental">TransactionIncremental</h3>
+<p>当顾客实际消费金额超过预设金额时使用,使用该命令增加金额到实际消费的金额。</p>
+<h4 id="-">请求报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">transactionAmount</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n...9</td>
+<td style="text-align:left">待增加的金额,预设的金额+该字段值=实际消费的金额。<br>格式与TransactionStart里transactionAmount保持一致。</td>
+</tr>
+<tr>
+<td style="text-align:left">originalHostReferenceNumber</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans...64</td>
+<td style="text-align:left">原始的后台流水号,从TransactionStart命令执行结果的hostReferenceNumber获取。</td>
+</tr>
+<tr>
+<td style="text-align:left">originalHostData</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans...256</td>
+<td style="text-align:left">原始的后台数据。从TransactionStart命令执行结果的hostData获取。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">响应报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">responseCode</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n6</td>
+<td style="text-align:left">响应码。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">responseMessage</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans…64</td>
+<td style="text-align:left">响应消息。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">hostReferenceNumber</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">ans...64</td>
+<td style="text-align:left">后台返回的交易流水号。</td>
+</tr>
+<tr>
+<td style="text-align:left">hostData</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">ans...256</td>
+<td style="text-align:left">后台返回的交易数据。</td>
+</tr>
+<tr>
+<td style="text-align:left">timestamp</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">n14</td>
+<td style="text-align:left">交易时间,格式为YYYYMMDDhhmmss.</td>
+</tr>
+<tr>
+<td style="text-align:left">amountInformation</td>
+<td style="text-align:center"><a href="#id.Util.AmountRsp">AmountRsp</a></td>
+<td style="text-align:center">C</td>
+<td style="text-align:center"></td>
+<td style="text-align:left">交易金额相关信息。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">示例</h4>
+<p>请求报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;request&quot;:[
+        {
+            &quot;command&quot;:&quot;TransactionIncremental&quot;,
+            &quot;properties&quot;:{
+                &quot;transactionAmount&quot;:&quot;*&quot;,
+                &quot;originalHostReferenceNumber&quot;:&quot;*&quot;,
+                &quot;originalHostData&quot;:&quot;*&quot;
+            }
+        }
+    ]
+}
+</code></pre><p>响应报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;response&quot;:[
+        {
+            &quot;command&quot;:&quot;TransactionIncremental&quot;,
+            &quot;properties&quot;:{
+                &quot;responseCode&quot;:&quot;*&quot;,
+                &quot;responseMessage&quot;:&quot;*&quot;,
+                &quot;hostReferenceNumber&quot;:&quot;*&quot;,
+                &quot;hostData&quot;:&quot;*&quot;,
+                &quot;timestamp&quot;:&quot;*&quot;,
+                &quot;amountInformation&quot;:{
+                    &quot;approvedAmount&quot;:&quot;*&quot;
+                }
+            }
+        }
+    ]
+}
+</code></pre><h2 id="batch">Batch</h2>
+<p><a id="id.commandBatchClose"></a></p>
+<h3 id="batchclose">BatchClose</h3>
+<p>关闭当前的清结算处理。</p>
+<h4 id="-">请求报文</h4>
+<p>本命令没有相关字段。</p>
+<h4 id="-">响应报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">responseCode</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n6</td>
+<td style="text-align:left">响应码。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">responseMessage</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans…64</td>
+<td style="text-align:left">响应消息。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">hostData</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">ans...256</td>
+<td style="text-align:left">后台返回的交易数据。</td>
+</tr>
+<tr>
+<td style="text-align:left">totalCount</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">n...4</td>
+<td style="text-align:left">净存款计数。<br>不包含未完成和撤回的交易计数。</td>
+</tr>
+<tr>
+<td style="text-align:left">totalAmount</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">n...9</td>
+<td style="text-align:left">净存款金额。<br>不包含未结清和撤回的交易金额。</td>
+</tr>
+<tr>
+<td style="text-align:left">timeStamp</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">n14</td>
+<td style="text-align:left">时间戳,格式为YYYYMMDDhhmmss.</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">示例</h4>
+<p>请求报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;request&quot;:[
+        {
+            &quot;command&quot;:&quot;BatchClose&quot;
+        }
+    ]
+}
+</code></pre><p>响应报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;response&quot;:[
+        {
+            &quot;command&quot;:&quot;BatchClose&quot;,
+            &quot;properties&quot;:{
+                &quot;responseCode&quot;:&quot;*&quot;,
+                &quot;responseMessage&quot;:&quot;*&quot;,
+                &quot;hostData&quot;:&quot;*&quot;,
+                &quot;totalCount&quot;:&quot;*&quot;,
+                &quot;totalAmount&quot;:&quot;*&quot;,
+                &quot;timeStamp&quot;:&quot;*&quot;
+            }
+        }
+    ]
+}
+</code></pre><p><a id="id.commandBatchClear"></a></p>
+<h3 id="batchclear">BatchClear</h3>
+<p>清空本地数据库。</p>
+<h4 id="-">请求报文</h4>
+<p>本命令没有相关字段。</p>
+<h4 id="-">响应报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">responseCode</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n6</td>
+<td style="text-align:left">响应码。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">responseMessage</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans…64</td>
+<td style="text-align:left">响应消息。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">示例</h4>
+<p>请求报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;request&quot;:[
+        {
+            &quot;command&quot;:&quot;BatchClear&quot;
+        }
+    ]
+}
+</code></pre><p>响应报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;response&quot;:[
+        {
+            &quot;command&quot;:&quot;BatchClear&quot;,
+            &quot;properties&quot;:{
+                &quot;responseCode&quot;:&quot;*&quot;,
+                &quot;responseMessage&quot;:&quot;*&quot;
+            }
+        }
+    ]
+}
+</code></pre><h2 id="device">Device</h2>
+<p><a id="id.commandMifareClassicRead"></a></p>
+<h3 id="mifareclassicread">MifareClassicRead</h3>
+<p>读取Mifare Classic卡。</p>
+<h4 id="-">请求报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">password</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans…32</td>
+<td style="text-align:left">授权密码,格式为16进制,最大长度为32。<br>示例:<br>“01234567890123ABCDEF” 即为 “\x01\x23\x45\x67\x89\x01\x23\xAB\xCD\xEF”</td>
+</tr>
+<tr>
+<td style="text-align:left">passwordType</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n1</td>
+<td style="text-align:left">密码类型:<br>0: A类型。<br>1: B类型。</td>
+</tr>
+<tr>
+<td style="text-align:left">blockNumber</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n...3</td>
+<td style="text-align:left">块序号。格式为10进制,最大长度为3. 最大数值为255。</td>
+</tr>
+<tr>
+<td style="text-align:left">timeout</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n...4</td>
+<td style="text-align:left">检测卡的超时时间,单位为100ms。有效值为[0, 9999]。<br>如果值为0,则表示立即返回。(超时时间=字段值* 100ms)</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">响应报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">responseCode</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n6</td>
+<td style="text-align:left">响应码。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">responseMessage</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans…64</td>
+<td style="text-align:left">响应消息。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">blockValue</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">an32</td>
+<td style="text-align:left">从卡上读到的结果。格式为16进制,长度为32。<br>示例:<br>“01234567890123ABCDEF” 即为 “\x01\x23\x45\x67\x89\x01\x23\xAB\xCD\xEF”</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">示例</h4>
+<p>请求报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;request&quot;:[
+        {
+            &quot;command&quot;:&quot;MifareClassicRead&quot;,
+            &quot;properties&quot;:{
+                &quot;password&quot;:&quot;*&quot;,
+                &quot;passwordType&quot;:&quot;*&quot;,
+                &quot;blockNumber&quot;:&quot;*&quot;,
+                &quot;timeout&quot;:&quot;*&quot;
+            }
+        }
+    ]
+}
+</code></pre><p>响应报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;response&quot;:[
+        {
+            &quot;command&quot;:&quot;MifareClassicRead&quot;,
+            &quot;properties&quot;:{
+                &quot;responseCode&quot;:&quot;*&quot;,
+                &quot;responseMessage&quot;:&quot;*&quot;,
+                &quot;blockValue&quot;:&quot;*&quot;
+            }
+        }
+    ]
+}
+</code></pre><p><a id="id.commandMifareClassicWrite"></a></p>
+<h3 id="mifareclassicwrite">MifareClassicWrite</h3>
+<p>写入Mifare Classic卡。</p>
+<h4 id="-">请求报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">password</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans…32</td>
+<td style="text-align:left">授权密码,格式为16进制,最大长度为32。<br>示例:<br>“01234567890123ABCDEF” 即为 “\x01\x23\x45\x67\x89\x01\x23\xAB\xCD\xEF”。</td>
+</tr>
+<tr>
+<td style="text-align:left">passwordType</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n1</td>
+<td style="text-align:left">密码类型:<br>0: A类型。<br>1: B类型。</td>
+</tr>
+<tr>
+<td style="text-align:left">blockNumber</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n...3</td>
+<td style="text-align:left">块序号。格式为10进制,最大长度为3. 最大数值为255。</td>
+</tr>
+<tr>
+<td style="text-align:left">blockValue</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans32</td>
+<td style="text-align:left">待写入的值,格式为16进制,长度为32。<br>示例:<br>“01234567890123ABCDEF” 即为 “\x01\x23\x45\x67\x89\x01\x23\xAB\xCD\xEF”。<br></td>
+</tr>
+<tr>
+<td style="text-align:left">timeout</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n...4</td>
+<td style="text-align:left">检测卡的超时时间,单位为100ms。有效值为[0, 9999]。<br>如果值为0,则表示立即返回。(超时时间=字段值* 100ms)</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">响应报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">responseCode</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n6</td>
+<td style="text-align:left">响应码。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">responseMessage</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans…64</td>
+<td style="text-align:left">响应消息。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">示例</h4>
+<p>请求报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;request&quot;:[
+        {
+            &quot;command&quot;:&quot;MifareClassicWrite&quot;,
+            &quot;properties&quot;:{
+                &quot;password&quot;:&quot;*&quot;,
+                &quot;passwordType&quot;:&quot;*&quot;,
+                &quot;blockNumber&quot;:&quot;*&quot;,
+                &quot;blockValue&quot;:&quot;*&quot;,
+                &quot;timeout&quot;:&quot;*&quot;
+            }
+        }
+    ]
+}
+</code></pre><p>响应报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;response&quot;:[
+        {
+            &quot;command&quot;:&quot;MifareClassicWrite&quot;,
+            &quot;properties&quot;:{
+                &quot;responseCode&quot;:&quot;*&quot;,
+                &quot;responseMessage&quot;:&quot;*&quot;
+            }
+        }
+    ]
+}
+</code></pre><p><a id="id.commandMifareClassicGetUID"></a></p>
+<h3 id="mifareclassicgetuid">MifareClassicGetUID</h3>
+<p>获取Mifare Classic卡的UID。</p>
+<h4 id="-">请求报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">timeout</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n...4</td>
+<td style="text-align:left">检测卡的超时时间,单位为100ms。有效值为[0, 9999]。<br>如果值为0,则表示立即返回。(超时时间=字段值* 100ms)</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">响应报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">responseCode</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n6</td>
+<td style="text-align:left">响应码。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">responseMessage</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans…64</td>
+<td style="text-align:left">响应消息。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">uid</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">an...20</td>
+<td style="text-align:left">从Mifare Classic卡获取到的UID。格式为16进制。<br>示例:<br>“01234567” 即为 “\x01\x23\x45\x67”<br></td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">示例</h4>
+<p>请求报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;request&quot;:[
+        {
+            &quot;command&quot;:&quot;MifareClassicGetUID&quot;,
+            &quot;properties&quot;:{
+                &quot;timeout&quot;:&quot;*&quot;
+            }
+        }
+    ]
+}
+</code></pre><p>响应报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;response&quot;:[
+        {
+            &quot;command&quot;:&quot;MifareClassicGetUID&quot;,
+            &quot;properties&quot;:{
+                &quot;responseCode&quot;:&quot;*&quot;,
+                &quot;responseMessage&quot;:&quot;*&quot;,
+                &quot;uid&quot;:&quot;*&quot;
+            }
+        }
+    ]
+}
+</code></pre><h2 id="report">Report</h2>
+<p><a id="id.commandGetTransactionInfo"></a></p>
+<h3 id="gettransactioninfo">GetTransactionInfo</h3>
+<p>获取交易信息。用于查询交易状态,确定交易是否已完成。 它还可用于获取交易数据以帮助跟踪交易。<br>只有当终端包含对应记录时,才会返回结果。 清结算操作后记录将被清除,交易失败时不记录。</p>
+<h4 id="-">请求报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">registerReferenceNumber</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">an...32</td>
+<td style="text-align:left">交易流水号,自助服务终端可以用来标记一笔交易的唯一标识符,与TransactionStart中的registerReferenceNumber字段相同。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">响应报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">responseCode</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n6</td>
+<td style="text-align:left">响应码。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">responseMessage</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans…64</td>
+<td style="text-align:left">响应消息。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">status</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">n1</td>
+<td style="text-align:left">交易状态<br>0: 已开始。<br>1: 已完成。<br>2: 已撤销。</td>
+</tr>
+<tr>
+<td style="text-align:left">hostData</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">ans...256</td>
+<td style="text-align:left">从后台返回的交易数据。<br>取决于status字段, 如果status字段为0 (已开始), 该值来自TransactionStart的执行结果。如果status字段为1 (已完成),该值来自TransactionCompletion的执行结果。如果status字段为2(已撤销),该值为空。</td>
+</tr>
+<tr>
+<td style="text-align:left">hostReferenceNumber</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">ans...64</td>
+<td style="text-align:left">从后台返回的交易流水号。<br>取决于status字段, 如果status字段为0 (已开始), 该值来自TransactionStart的执行结果。如果status字段为1 (已完成),该值来自TransactionCompletion的执行结果。如果status字段为2(已撤销),该值为空。</td>
+</tr>
+<tr>
+<td style="text-align:left">timeStamp</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">n14</td>
+<td style="text-align:left">交易时间,格式为YYYYMMDDhhmmss。<br>取决于status字段, 如果status字段为0 (已开始), 该值来自TransactionStart的执行结果。如果status字段为1 (已完成),该值来自TransactionCompletion的执行结果。如果status字段为2(已撤销),该值为空。</td>
+</tr>
+<tr>
+<td style="text-align:left">amountInformation</td>
+<td style="text-align:center"><a href="#id.Util.AmountRsp">AmountRsp</a></td>
+<td style="text-align:center">C</td>
+<td style="text-align:center"></td>
+<td style="text-align:left">交易金额相关信息。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">示例</h4>
+<p>请求报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;request&quot;:[
+        {
+            &quot;command&quot;:&quot;GetTransactionInfo&quot;,
+            &quot;properties&quot;:{
+                &quot;registerReferenceNumber&quot;:&quot;*&quot;
+            }
+        }
+    ]
+}
+</code></pre><p>响应报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;response&quot;:[
+        {
+            &quot;command&quot;:&quot;GetTransactionInfo&quot;,
+            &quot;properties&quot;:{
+                &quot;responseCode&quot;:&quot;*&quot;,
+                &quot;responseMessage&quot;:&quot;*&quot;,
+                &quot;status&quot;:&quot;*&quot;,
+                &quot;hostData&quot;:&quot;*&quot;,
+                &quot;hostReferenceNumber&quot;:&quot;*&quot;,
+                &quot;timeStamp&quot;:&quot;*&quot;,
+                &quot;amountInformation&quot;:{
+                    &quot;approvedAmount&quot;:&quot;*&quot;
+                }
+            }
+        }
+    ]
+}
+</code></pre><p><a id="id.commandGetTraceInfoByCard"></a></p>
+<h3 id="gettraceinfobycard">GetTraceInfoByCard</h3>
+<p>[ 已废弃 ] 自助服务终端发送请求让用户去拍卡/插卡/刷卡。支付终端等待用户完成相关操作,并返回相关的交易痕迹信息以及交易流水号和账号信息。与此同时,支付终端会将卡片信息保留一定时间(30s),当发送下一条命令(TransactionStart)时,用户不需要重新拍卡/插卡/刷卡。</p>
+<h4 id="-">请求报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">timeout</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans...5</td>
+<td style="text-align:left">默认超时时间为30s。<br>有效值的取值范围为[-1, 9999]。如果值为0,那么意味着命令将立刻返回。如果值为-1,那么意味着终端将一直保持在等待状态。(超时时间 = 字段值 * 100ms)</td>
+</tr>
+<tr>
+<td style="text-align:left">transactionAmount</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n...9</td>
+<td style="text-align:left">用来预处理交易,一些操作必须在有卡时完成。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">响应报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">responseCode</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n6</td>
+<td style="text-align:left">响应码。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">responseMessage</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans…64</td>
+<td style="text-align:left">响应消息。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">traceInfo</td>
+<td style="text-align:center"><a href="#id.Util.TraceInfo">TraceInfo[]</a></td>
+<td style="text-align:center">C</td>
+<td style="text-align:center"></td>
+<td style="text-align:left">帮助跟踪交易的信息。如果一张卡开启了多笔交易并且都未完成,那么终端将返回和此卡相关的所有交易信息。</td>
+</tr>
+<tr>
+<td style="text-align:left">account</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">ans...19</td>
+<td style="text-align:left">卡号,返回前6位以及后4位,其它用&#39;*&#39;代替。示例: 545454*********5454。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">示例</h4>
+<p>请求报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;request&quot;:[
+        {
+            &quot;command&quot;:&quot;GetTraceInfoByCard&quot;,
+            &quot;properties&quot;:{
+                &quot;timeout&quot;:&quot;*&quot;,
+                &quot;transactionAmount&quot;:&quot;*&quot;
+            }
+        }
+    ]
+}
+</code></pre><p>响应报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;response&quot;:[
+        {
+            &quot;command&quot;:&quot;GetTraceInfoByCard&quot;,
+            &quot;properties&quot;:{
+                &quot;responseCode&quot;:&quot;*&quot;,
+                &quot;responseMessage&quot;:&quot;*&quot;,
+                &quot;traceInfo&quot;:[{
+                    &quot;registerReferenceNumber&quot;:&quot;*&quot;,
+                    &quot;hostReferenceNumber&quot;:&quot;*&quot;
+                }],
+                &quot;account&quot;:&quot;*&quot;
+            }
+        }
+    ]
+}
+</code></pre><p><a id="id.commandGetCardStatus"></a></p>
+<h3 id="getcardstatus">GetCardStatus</h3>
+<p>自助服务终端发送请求给支付终端,一旦确认用户拍卡/插卡/刷卡, 自助服务终端就可以发送TransactionStart命令。 </p>
+<h4 id="-">请求报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">enableCardUniqueIdentifier</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center"></td>
+<td style="text-align:left">开启是否获取卡片唯一标识。默认值是“Off”。<br>请查看<a href="#id.Const.EnableCardUniqueIdentifier">EnableCardUniqueIdentifier</a>。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">响应报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">responseCode</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n6</td>
+<td style="text-align:left">响应码。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">responseMessage</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans…64</td>
+<td style="text-align:left">响应消息。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">cardType</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">n1</td>
+<td style="text-align:left">卡片类型.<br>1:Credit/Debit卡<br>2:Mifare Classic(M1)卡,是遵守ISO14443A标准的非接触式IC卡,比如Mifare S50和Mifare S70系列。<br>如果没人拍卡/插卡/刷卡,该字段为空。</td>
+</tr>
+<tr>
+<td style="text-align:left">account</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">an...20</td>
+<td style="text-align:left">卡片的卡号或者UID。<br>当卡片类型为信用/借记卡时,返回前6位以及后4位,其它用“*”代替。<br>示例:545454*********5454<br>当卡片类型为M1卡时,返回卡片的UID。格式为16进制。<br>示例:“01234567” 即为 “\x01\x23\x45\x67”<br>如果没人拍卡/插卡/刷卡,该字段为空。</td>
+</tr>
+<tr>
+<td style="text-align:left">accountInformation</td>
+<td style="text-align:center"><a href="#id.Util.AccountRsp">AccountRsp</a></td>
+<td style="text-align:center">C</td>
+<td style="text-align:center"></td>
+<td style="text-align:left">卡片信息。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">示例</h4>
+<p>请求报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;request&quot;:[
+        {
+            &quot;command&quot;:&quot;GetCardStatus&quot;,
+            &quot;properties&quot;:{
+                &quot;enableCardUniqueIdentifier&quot;:&quot;*&quot;
+            }
+        }
+    ]
+}
+</code></pre><p>响应报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;response&quot;:[
+        {
+            &quot;command&quot;:&quot;GetCardStatus&quot;,
+            &quot;properties&quot;:{
+                &quot;responseCode&quot;:&quot;*&quot;,
+                &quot;responseMessage&quot;:&quot;*&quot;,
+                &quot;cardType&quot;:&quot;*&quot;,
+                &quot;account&quot;:&quot;*&quot;,
+                &quot;accountInformation&quot;:{
+                    &quot;expireDate&quot;:&quot;*&quot;,
+                    &quot;cardType&quot;:&quot;*&quot;,
+                    &quot;cardTypeName&quot;:&quot;*&quot;,
+                    &quot;cardUniqueIdentifier&quot;:&quot;*&quot;
+                }
+            }
+        }
+    ]
+}
+</code></pre><p><a id="id.commandGetCardInfo"></a></p>
+<h3 id="getcardinfo">GetCardInfo</h3>
+<p>自助服务终端发送请求让用户去拍卡/插卡/刷卡以获取卡号.获取的卡号被用来校验持卡人是否为同一人.</p>
+<h4 id="-">请求报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">timeout</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">n...4</td>
+<td style="text-align:left">检测卡的超时时间,单位为100ms。有效值的取值范围为[-1, 9999]。<br>如果值为0,那么意味着命令将立刻返回。如果值为-1,那么意味着终端将一直保持在等待状态。(超时时间 = 字段值 * 100ms)</td>
+</tr>
+<tr>
+<td style="text-align:left">transactionAmount</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">n...9</td>
+<td style="text-align:left">用来预处理交易,一些操作必须在有卡时完成。</td>
+</tr>
+<tr>
+<td style="text-align:left">enableCardUniqueIdentifier</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center"></td>
+<td style="text-align:left">开启是否获取卡片唯一标识。默认值是“Off”。<br>请查看<a href="#id.Const.EnableCardUniqueIdentifier">EnableCardUniqueIdentifier</a>。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">响应报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">responseCode</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n6</td>
+<td style="text-align:left">响应码。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">responseMessage</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans…64</td>
+<td style="text-align:left">响应消息。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">account</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">an...19</td>
+<td style="text-align:left">卡号,返回前6位以及后4位,其它用&#39;*&#39;代替。<br>示例: 545454*********5454<br>如果没人拍卡/插卡/刷卡,该字段为空。</td>
+</tr>
+<tr>
+<td style="text-align:left">accountInformation</td>
+<td style="text-align:center"><a href="#id.Util.AccountRsp">AccountRsp</a></td>
+<td style="text-align:center">C</td>
+<td style="text-align:center"></td>
+<td style="text-align:left">卡片信息。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">示例</h4>
+<p>请求报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;request&quot;:[
+        {
+            &quot;command&quot;:&quot;GetCardInfo&quot;,
+            &quot;properties&quot;:{
+                &quot;timeout&quot;:&quot;*&quot;,
+                &quot;transactionAmount&quot;:&quot;*&quot;,
+                &quot;enableCardUniqueIdentifier&quot;:&quot;*&quot;
+            }
+        }
+    ]
+}
+</code></pre><p>响应报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;response&quot;:[
+        {
+            &quot;command&quot;:&quot;GetCardInfo&quot;,
+            &quot;properties&quot;:{
+                &quot;responseCode&quot;:&quot;*&quot;,
+                &quot;responseMessage&quot;:&quot;*&quot;,
+                &quot;account&quot;:&quot;*&quot;,
+                &quot;accountInformation&quot;:{
+                    &quot;expireDate&quot;:&quot;*&quot;,
+                    &quot;cardType&quot;:&quot;*&quot;,
+                    &quot;cardTypeName&quot;:&quot;*&quot;,
+                    &quot;cardUniqueIdentifier&quot;:&quot;*&quot;
+                }
+            }
+        }
+    ]
+}
+</code></pre><h2 id="form">Form</h2>
+<p><a id="id.commandInputText"></a></p>
+<h3 id="inputtext">InputText</h3>
+<p>通过该指令可以让终端显示输入界面允许用户输入相关文本,例如邮箱和手机号。</p>
+<h4 id="-">请求报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">title</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans...36</td>
+<td style="text-align:left">显示在输入界面的标题。</td>
+</tr>
+<tr>
+<td style="text-align:left">prompt</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">ans...256</td>
+<td style="text-align:left">显示在输入界面的提示信息。</td>
+</tr>
+<tr>
+<td style="text-align:left">inputType</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans...24</td>
+<td style="text-align:left">输入文本的类型:<br>email: 邮箱<br>phoneNumber: 手机号</td>
+</tr>
+<tr>
+<td style="text-align:left">timeout</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n...4</td>
+<td style="text-align:left">用户输入的超时时间,单位为100ms。有效值为[0, 9999]。<br>超时时间=字段值* 100ms</td>
+</tr>
+<tr>
+<td style="text-align:left">minLength</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">n...2</td>
+<td style="text-align:left">输入的最小长度,默认0,有效值[0,64]。</td>
+</tr>
+<tr>
+<td style="text-align:left">maxLength</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">n...2</td>
+<td style="text-align:left">输入的最大长度,默认64,有效值[1,64]。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">响应报文</h4>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">responseCode</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">n6</td>
+<td style="text-align:left">响应码。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">responseMessage</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">M</td>
+<td style="text-align:center">ans…64</td>
+<td style="text-align:left">响应消息。请查看 <a href="#id.ResponseCodeAndMessage">响应码和响应消息</a> 。</td>
+</tr>
+<tr>
+<td style="text-align:left">inputText</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">ans...64</td>
+<td style="text-align:left">用户输入的文本。</td>
+</tr>
+</tbody>
+</table>
+<h4 id="-">示例</h4>
+<p>请求报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;request&quot;:[
+        {
+            &quot;command&quot;:&quot;InputText&quot;,
+            &quot;properties&quot;:{
+                &quot;title&quot;:&quot;*&quot;,
+                &quot;prompt&quot;:&quot;*&quot;,
+                &quot;inputType&quot;:&quot;*&quot;,
+                &quot;timeout&quot;:&quot;*&quot;,
+                &quot;minLength&quot;:&quot;*&quot;,
+                &quot;maxLength&quot;:&quot;*&quot;
+            }
+        }
+    ]
+}
+</code></pre><p>响应报文</p>
+<pre><code>{
+    &quot;version&quot;:&quot;2.00&quot;,
+    &quot;response&quot;:[
+        {
+            &quot;command&quot;:&quot;InputText&quot;,
+            &quot;properties&quot;:{
+                &quot;responseCode&quot;:&quot;*&quot;,
+                &quot;responseMessage&quot;:&quot;*&quot;,
+                &quot;inputText&quot;:&quot;*&quot;
+            }
+        }
+    ]
+}
+</code></pre><p><a id="id.commandObjectDefinition"></a></p>
+<h1 id="-">命令对象定义</h1>
+<p><a id="id.Util.AccountReq"></a></p>
+<h2 id="accountreq">AccountReq</h2>
+<p>请求卡号信息。</p>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">cardExpireDate</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">n...65</td>
+<td style="text-align:left">RFU</td>
+</tr>
+</tbody>
+</table>
+<p><a id="id.Util.AccountRsp"></a></p>
+<h2 id="accountrsp">AccountRsp</h2>
+<p>命令返回的卡片信息。</p>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">expireDate</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">n4</td>
+<td style="text-align:left">卡片的过期日期。格式为MMYY。</td>
+</tr>
+<tr>
+<td style="text-align:left">cardType</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center"></td>
+<td style="text-align:left">卡片类型。<br>请查看<a href="#id.Const.CardType">CardType</a>。</td>
+</tr>
+<tr>
+<td style="text-align:left">cardTypeName</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">a...32</td>
+<td style="text-align:left">卡片品牌名称。例如Cup指代China Union Pay。</td>
+</tr>
+<tr>
+<td style="text-align:left">cardUniqueIdentifier</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">ans...64</td>
+<td style="text-align:left">卡片唯一标识。</td>
+</tr>
+</tbody>
+</table>
+<p><a id="id.Util.AmountRsp"></a></p>
+<h2 id="amountrsp">AmountRsp</h2>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">approvedAmount</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">n...9</td>
+<td style="text-align:left">通过的金额, 格式为$$$$$$$CC。 会返回该字段是因为不是所有请求的金额都会被完全通过。</td>
+</tr>
+</tbody>
+</table>
+<p><a id="id.Util.GConfigurationInfo"></a></p>
+<h2 id="gconfigurationinfo">GConfigurationInfo</h2>
+<p>终端返回的配置信息。</p>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">name</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center"></td>
+<td style="text-align:left">配置参数名字。您可以在GConfigurationNames中找到所有参数名称。</td>
+</tr>
+<tr>
+<td style="text-align:left">value</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center"></td>
+<td style="text-align:left">此参数的当前值。</td>
+</tr>
+</tbody>
+</table>
+<p><a id="id.Util.GConfigurationNames"></a></p>
+<h2 id="gconfigurationnames">GConfigurationNames</h2>
+<p>可以获取配置名称。</p>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">preprocessingAmount</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">n...9</td>
+<td style="text-align:left">预处理交易,如果希望终端默认预处理卡片,那么需要设置该值以启用该功能。然后才可以使用GetCardStatus命令。</td>
+</tr>
+<tr>
+<td style="text-align:left">currencyCode</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">n3</td>
+<td style="text-align:left">终端的货币代码,根据ISO 4217指示交易的货币代码。</td>
+</tr>
+<tr>
+<td style="text-align:left">tapImageName</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">ans...16</td>
+<td style="text-align:left">显示在支付终端的图片的名称,图片由客户提供。用户需按照以下规则定义:<br>最长为16位,需包含前缀CST_,后缀必须是.r<br>图片名举例:CST_XXXXX.r<br>图片类型支持PNG,BMP<br>当此项为空,表明关闭用户自定义显示界面,用户可以重新设置“tapPromptMsgLine1/tapPromptMsgLine2”显示默认界面。</td>
+</tr>
+<tr>
+<td style="text-align:left">tapPromptMsgLine1</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">ans...30</td>
+<td style="text-align:left">当tapImageName未指定使用的自定义图片时,在Tap Any  Time时显示在支付终端上的提示信息1。<br>当此项为空,显示默认信息。</td>
+</tr>
+<tr>
+<td style="text-align:left">tapPromptMsgLine2</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">ans...40</td>
+<td style="text-align:left">当tapImageName未指定使用的自定义图片时,在Tap Any  Time时显示在支付终端上的提示信息2。<br>当此项为空,显示默认信息。</td>
+</tr>
+<tr>
+<td style="text-align:left">cardReadSuccessMsg</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">ans...40</td>
+<td style="text-align:left">当tapImageName未指定使用的自定义图片时,读卡成功时显示在支付终端的附加提示信息。<br>当此项为空,显示默认信息。</td>
+</tr>
+<tr>
+<td style="text-align:left">displayMode</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">n1</td>
+<td style="text-align:left">该参数用于设置屏幕的显示方向:<br>0:代表横屏模式。<br>1:代表竖屏模式。<br>请注意,更改此参数后需要重启设备才能生效。<br>(仅支持IM15)</td>
+</tr>
+<tr>
+<td style="text-align:left">detectCardTimeout</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">n...4</td>
+<td style="text-align:left">等待检卡的超时的时间,单位为100毫秒,(超时时间 = 字段值 * 100ms)<br>有效的取值区间为[300,9999]. 默认值为300。<br>仅对TransactionStart命令有效。</td>
+</tr>
+</tbody>
+</table>
+<p><a id="id.Util.HostGateway"></a></p>
+<h2 id="hostgateway">HostGateway</h2>
+<p>Host网关信息。</p>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">tokenRequestFlag</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">n1</td>
+<td style="text-align:left">RFU</td>
+</tr>
+<tr>
+<td style="text-align:left">token</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">ans...128</td>
+<td style="text-align:left">RFU</td>
+</tr>
+</tbody>
+</table>
+<p><a id="id.Util.HostRsp"></a></p>
+<h2 id="hostrsp">HostRsp</h2>
+<p>命令返回的Host信息。</p>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">token</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">ans...128</td>
+<td style="text-align:left">RFU</td>
+</tr>
+</tbody>
+</table>
+<p><a id="id.Util.SConfigurationInfo"></a></p>
+<h2 id="sconfigurationinfo">SConfigurationInfo</h2>
+<p>用于设置终端的配置信息。</p>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">name</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center"></td>
+<td style="text-align:left">要设置的配置参数名称。您可以在SConfigurationNames中找到所有参数名称。</td>
+</tr>
+<tr>
+<td style="text-align:left">value</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center"></td>
+<td style="text-align:left">要设置到参数的值。</td>
+</tr>
+</tbody>
+</table>
+<p><a id="id.Util.SConfigurationNames"></a></p>
+<h2 id="sconfigurationnames">SConfigurationNames</h2>
+<p>可以设置的可配置参数名</p>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">preprocessingAmount</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">n...9</td>
+<td style="text-align:left">预处理交易,如果希望终端默认预处理卡片,那么需要设置该值以启用该功能。 然后才可以使用 GetCardStatus 命令。</td>
+</tr>
+<tr>
+<td style="text-align:left">tapImageName</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">ans...16</td>
+<td style="text-align:left">显示在支付终端的图片的名称,图片由客户提供。用户需按照以下规则定义:<br>最长为16位,需包含前缀CST_,后缀必须是.r<br>图片名举例:CST_XXXXX.r<br>图片类型支持PNG,BMP<br>当此项为空,表明关闭用户自定义显示界面,用户可以重新设置“tapPromptMsgLine1/tapPromptMsgLine2”显示默认界面。</td>
+</tr>
+<tr>
+<td style="text-align:left">tapPromptMsgLine1</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">ans...30</td>
+<td style="text-align:left">当tapImageName未指定使用的自定义图片时,在Tap Any  Time时显示在支付终端上的提示信息1。<br>当此项为空,显示默认信息。</td>
+</tr>
+<tr>
+<td style="text-align:left">tapPromptMsgLine2</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">ans...40</td>
+<td style="text-align:left">当tapImageName未指定使用的自定义图片时,在Tap Any  Time时显示在支付终端上的提示信息2。<br>当此项为空,显示默认信息。</td>
+</tr>
+<tr>
+<td style="text-align:left">cardReadSuccessMsg</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">ans...40</td>
+<td style="text-align:left">当tapImageName未指定使用的自定义图片时,读卡成功时显示在支付终端的附加提示信息。<br>当此项为空,显示默认信息。</td>
+</tr>
+<tr>
+<td style="text-align:left">displayMode</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">n1</td>
+<td style="text-align:left">该参数用于设置屏幕的显示方向:<br>0:代表横屏模式。<br>1:代表竖屏模式。<br>请注意,更改此参数后需要重启设备才能生效。<br>(仅支持IM15)</td>
+</tr>
+<tr>
+<td style="text-align:left">ipAddress</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">ans...15</td>
+<td style="text-align:left">IP地址。</td>
+</tr>
+<tr>
+<td style="text-align:left">subnetMask</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">ans...15</td>
+<td style="text-align:left">子网掩码。</td>
+</tr>
+<tr>
+<td style="text-align:left">defaultGateway</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">ans...15</td>
+<td style="text-align:left">默认网关。</td>
+</tr>
+<tr>
+<td style="text-align:left">dnsServer</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">ans...15</td>
+<td style="text-align:left">DNS服务器地址。</td>
+</tr>
+<tr>
+<td style="text-align:left">backgroundMode</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">a1</td>
+<td style="text-align:left">标记应用是否要在后台运行。Y:后台运行。N:必要情况下会在前台展示页面。</td>
+</tr>
+<tr>
+<td style="text-align:left">detectCardTimeout</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">O</td>
+<td style="text-align:center">n...4</td>
+<td style="text-align:left">等待检卡的超时的时间,单位为100毫秒,(超时时间 = 字段值 * 100ms)<br>有效的取值区间为[300,9999]. 默认值为300。<br>仅对TransactionStart命令有效。</td>
+</tr>
+</tbody>
+</table>
+<p><a id="id.Util.TraceInfo"></a></p>
+<h2 id="traceinfo">TraceInfo</h2>
+<p>可以帮助追踪一笔交易的信息。</p>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">参数名</th>
+<th style="text-align:center">类型</th>
+<th style="text-align:center">是否必需</th>
+<th style="text-align:center">属性</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">registerReferenceNumber</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">an...32</td>
+<td style="text-align:left">交易流水号,自助服务终端可以用来标记一笔交易的唯一标识符。</td>
+</tr>
+<tr>
+<td style="text-align:left">hostReferenceNumber</td>
+<td style="text-align:center">string</td>
+<td style="text-align:center">C</td>
+<td style="text-align:center">ans...64</td>
+<td style="text-align:left">后台返回的交易流水号。<br>TransactionCompletion和TransactionReversal命令的originalHostReferenceNumber应使用该值。</td>
+</tr>
+</tbody>
+</table>
+<p><a id="id.constValueReference"></a></p>
+<h1 id="-">常量值定义</h1>
+<p><a id="id.Const.CardType"></a></p>
+<h2 id="cardtype">CardType</h2>
+<table>
+<thead>
+<tr>
+<th style="text-align:center">值</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:center">01</td>
+<td style="text-align:left">VISA</td>
+</tr>
+<tr>
+<td style="text-align:center">02</td>
+<td style="text-align:left">Mastercard</td>
+</tr>
+<tr>
+<td style="text-align:center">03</td>
+<td style="text-align:left">AMEX</td>
+</tr>
+<tr>
+<td style="text-align:center">04</td>
+<td style="text-align:left">Discover</td>
+</tr>
+<tr>
+<td style="text-align:center">05</td>
+<td style="text-align:left">Diners Club</td>
+</tr>
+<tr>
+<td style="text-align:center">18</td>
+<td style="text-align:left">China Union Pay</td>
+</tr>
+<tr>
+<td style="text-align:center">19</td>
+<td style="text-align:left">Maestro</td>
+</tr>
+<tr>
+<td style="text-align:center">99</td>
+<td style="text-align:left">如果卡片类型未出现在列表中,使用其作为类型。</td>
+</tr>
+</tbody>
+</table>
+<p><a id="id.Const.EnableCardUniqueIdentifier"></a></p>
+<h2 id="enablecarduniqueidentifier">EnableCardUniqueIdentifier</h2>
+<table>
+<thead>
+<tr>
+<th style="text-align:center">值</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:center">Off</td>
+<td style="text-align:left">不获取卡片唯一标识。</td>
+</tr>
+<tr>
+<td style="text-align:center">On</td>
+<td style="text-align:left">获取卡片唯一标识。</td>
+</tr>
+</tbody>
+</table>
+<p><a id="id.valueReference"></a></p>
+<h1 id="-">常量值定义</h1>
+<p><a id="id.ResponseCodeAndMessage"></a></p>
+<h2 id="-">响应码和响应消息</h2>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">响应码</th>
+<th style="text-align:left">响应消息</th>
+<th style="text-align:left">备注</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">000000</td>
+<td style="text-align:left">OK</td>
+<td style="text-align:left">对于交易命令,返回&quot;OK&quot;代表交易成功。 <br> 对于其它命令,返回&quot;OK&quot;代表命令执行成功。</td>
+</tr>
+<tr>
+<td style="text-align:left">110000</td>
+<td style="text-align:left">HOST ERROR MESSAGE</td>
+<td style="text-align:left">后台拒绝,返回后台的错误消息。</td>
+</tr>
+<tr>
+<td style="text-align:left">110000</td>
+<td style="text-align:left">HOST ERROR CODE-HOST ERROR MESSAGE</td>
+<td style="text-align:left">后台拒绝,返回后台的错误码以及错误消息,以&quot;-&quot;隔开。</td>
+</tr>
+<tr>
+<td style="text-align:left">110001</td>
+<td style="text-align:left">EMV ERROR CODE-EMV ERROR MESSAGE</td>
+<td style="text-align:left">EMV错误,返回EMV错误码和错误消息。以&quot;-&quot;隔开。</td>
+</tr>
+<tr>
+<td style="text-align:left">110002</td>
+<td style="text-align:left">FORMAT ERROR</td>
+<td style="text-align:left">自助服务终端发送的消息格式错误,返回具体的错误信息,下面同一个错误代码的是可能的错误消息。</td>
+</tr>
+<tr>
+<td style="text-align:left">110002</td>
+<td style="text-align:left">TRANSACTION AMOUNT INVALID</td>
+<td style="text-align:left">transactionAmount 字段无效。<br>1. 长度超过限制。<br>2. 无效的字符: 包含 &quot;.&quot;,&quot;-&quot;.<br>3. 金额为 &quot;0&quot;.</td>
+</tr>
+<tr>
+<td style="text-align:left">110002</td>
+<td style="text-align:left">TRANSACTION AMOUNT NOT ALLOWED</td>
+<td style="text-align:left">在零售模式下金额不允许出现在TransactionCompletion命令中。</td>
+</tr>
+<tr>
+<td style="text-align:left">110002</td>
+<td style="text-align:left">REGISTER REFERENCE NUMBER INVALID</td>
+<td style="text-align:left">请检查 &quot;registerReferenceNumber&quot; 参数。</td>
+</tr>
+<tr>
+<td style="text-align:left">110002</td>
+<td style="text-align:left">ORIGINAL HOST REFERENCE NUMBER INVALID</td>
+<td style="text-align:left">请检查 &quot;originalHostReferenceNumber&quot; 参数。</td>
+</tr>
+<tr>
+<td style="text-align:left">110002</td>
+<td style="text-align:left">ORIGINAL HOST DATA INVALID</td>
+<td style="text-align:left">请检查 &quot;originalHostData&quot; 参数。</td>
+</tr>
+<tr>
+<td style="text-align:left">110002</td>
+<td style="text-align:left">REPORT STATUS INVALID</td>
+<td style="text-align:left">请检查 &quot;reportStatus&quot; 参数。</td>
+</tr>
+<tr>
+<td style="text-align:left">110002</td>
+<td style="text-align:left">PASSWORD INVALID</td>
+<td style="text-align:left">请检查 &quot;password&quot; 参数。</td>
+</tr>
+<tr>
+<td style="text-align:left">110002</td>
+<td style="text-align:left">PASSWORD TYPE INVALID</td>
+<td style="text-align:left">请检查 &quot;passwordType&quot; 参数。</td>
+</tr>
+<tr>
+<td style="text-align:left">110002</td>
+<td style="text-align:left">BLOCK NUMBER INVALID</td>
+<td style="text-align:left">请检查 &quot;blockNumber&quot; 参数。</td>
+</tr>
+<tr>
+<td style="text-align:left">110002</td>
+<td style="text-align:left">TIMEOUT INVALID</td>
+<td style="text-align:left">请检查 &quot;timeout&quot; 参数。</td>
+</tr>
+<tr>
+<td style="text-align:left">110002</td>
+<td style="text-align:left">BLOCK VALUE INVALID</td>
+<td style="text-align:left">请检查 &quot;blockValue&quot; 参数。</td>
+</tr>
+<tr>
+<td style="text-align:left">110002</td>
+<td style="text-align:left">VERIFY CARD INVALID</td>
+<td style="text-align:left">verifyCard 参数应该是0或者1。</td>
+</tr>
+<tr>
+<td style="text-align:left">110002</td>
+<td style="text-align:left">TARGET NAME INVALID</td>
+<td style="text-align:left">targetName 参数应该是IPv4地址或者域名。</td>
+</tr>
+<tr>
+<td style="text-align:left">110002</td>
+<td style="text-align:left">MINLENGTH INVALID</td>
+<td style="text-align:left">请查看&quot;minLength&quot;参数。</td>
+</tr>
+<tr>
+<td style="text-align:left">110002</td>
+<td style="text-align:left">MAXLENGTH INVALID</td>
+<td style="text-align:left">请查看&quot;maxLength&quot;参数。</td>
+</tr>
+<tr>
+<td style="text-align:left">110002</td>
+<td style="text-align:left">TITLE INVALID</td>
+<td style="text-align:left">请查看&quot;title&quot;参数。</td>
+</tr>
+<tr>
+<td style="text-align:left">110002</td>
+<td style="text-align:left">PROMPT INVALID</td>
+<td style="text-align:left">请查看&quot;prompt&quot;参数。</td>
+</tr>
+<tr>
+<td style="text-align:left">110002</td>
+<td style="text-align:left">INPUTTYPE INVALID</td>
+<td style="text-align:left">请查看&quot;inputType&quot;参数。</td>
+</tr>
+<tr>
+<td style="text-align:left">110002</td>
+<td style="text-align:left">MIN EXCEED MAX</td>
+<td style="text-align:left">请查看&quot;minLength&quot;和&quot;maxLength&quot;参数。</td>
+</tr>
+<tr>
+<td style="text-align:left">110002</td>
+<td style="text-align:left">TRACK INVALID</td>
+<td style="text-align:left">磁道数据错误。</td>
+</tr>
+<tr>
+<td style="text-align:left">110002</td>
+<td style="text-align:left">EXP DATE INVALID</td>
+<td style="text-align:left">1. 长度不对。<br> 2. 无效的日期格式,月大于12或者日期大于31。<br> 3. 非数字。</td>
+</tr>
+<tr>
+<td style="text-align:left">110002</td>
+<td style="text-align:left">TOKEN REQUEST FLAG INVALID</td>
+<td style="text-align:left">请检查“tokenRequestFlag”字段。</td>
+</tr>
+<tr>
+<td style="text-align:left">110002</td>
+<td style="text-align:left">ENABLE CARD UNIQUE IDENTIFIER INVALID</td>
+<td style="text-align:left">请检查 &quot;enableCardUniqueIdentifier&quot; 参数。</td>
+</tr>
+<tr>
+<td style="text-align:left">110100</td>
+<td style="text-align:left">UNSUPPORTED COMMAND</td>
+<td style="text-align:left">该命令不支持。</td>
+</tr>
+<tr>
+<td style="text-align:left">110101</td>
+<td style="text-align:left">TIMEOUT</td>
+<td style="text-align:left">等待用户操作超时。</td>
+</tr>
+<tr>
+<td style="text-align:left">110102</td>
+<td style="text-align:left">ABORTED</td>
+<td style="text-align:left">用户取消了当前命令。</td>
+</tr>
+<tr>
+<td style="text-align:left">110103</td>
+<td style="text-align:left">CARD EXPIRED</td>
+<td style="text-align:left">卡过期。</td>
+</tr>
+<tr>
+<td style="text-align:left">110104</td>
+<td style="text-align:left">FALLBACK TO SWIPE NOT ALLOWED</td>
+<td style="text-align:left">不允许回滚到刷卡。</td>
+</tr>
+<tr>
+<td style="text-align:left">110105</td>
+<td style="text-align:left">UNSUPPORTED CARD TYPE</td>
+<td style="text-align:left">不支持的卡类型。</td>
+</tr>
+<tr>
+<td style="text-align:left">110106</td>
+<td style="text-align:left">CARD TYPE DISABLED</td>
+<td style="text-align:left">该类型卡已经被禁用。</td>
+</tr>
+<tr>
+<td style="text-align:left">110107</td>
+<td style="text-align:left">NEED REMOVE CARD FIRST</td>
+<td style="text-align:left">需要先移除卡片。</td>
+</tr>
+<tr>
+<td style="text-align:left">110108</td>
+<td style="text-align:left">SEE PHONE</td>
+<td style="text-align:left">请看下手机,该交易需要重新开始。</td>
+</tr>
+<tr>
+<td style="text-align:left">110109</td>
+<td style="text-align:left">HOST SEND ERROR</td>
+<td style="text-align:left">终端发送消息给后台失败。</td>
+</tr>
+<tr>
+<td style="text-align:left">110110</td>
+<td style="text-align:left">HOST RECEIVE ERROR</td>
+<td style="text-align:left">终端从后台接收消息失败。</td>
+</tr>
+<tr>
+<td style="text-align:left">110111</td>
+<td style="text-align:left">HOST CONNECT ERROR</td>
+<td style="text-align:left">终端连接后台错误。</td>
+</tr>
+<tr>
+<td style="text-align:left">110112</td>
+<td style="text-align:left">NETWORK UNAVAILABLE</td>
+<td style="text-align:left">网络不可用。</td>
+</tr>
+<tr>
+<td style="text-align:left">110113</td>
+<td style="text-align:left">PINPAD ERROR</td>
+<td style="text-align:left">PINPAD 错误。</td>
+</tr>
+<tr>
+<td style="text-align:left">110114</td>
+<td style="text-align:left">DUPLICATE TRANSACTION</td>
+<td style="text-align:left">重复的交易,在一次清结算处理中用了相同的register reference number。</td>
+</tr>
+<tr>
+<td style="text-align:left">110115</td>
+<td style="text-align:left">ALREADY REVERSED</td>
+<td style="text-align:left">该交易已经被撤销。</td>
+</tr>
+<tr>
+<td style="text-align:left">110116</td>
+<td style="text-align:left">ALREADY COMPLETED</td>
+<td style="text-align:left">该交易已经完成。</td>
+</tr>
+<tr>
+<td style="text-align:left">110117</td>
+<td style="text-align:left">PLEASE BATCH</td>
+<td style="text-align:left">请做清结算处理。</td>
+</tr>
+<tr>
+<td style="text-align:left">110118</td>
+<td style="text-align:left">DATA STORAGE KEY MISSING</td>
+<td style="text-align:left">数据存储密钥丢失。</td>
+</tr>
+<tr>
+<td style="text-align:left">110119</td>
+<td style="text-align:left">P2PE KEY MISSING</td>
+<td style="text-align:left">P2PE密钥丢失。</td>
+</tr>
+<tr>
+<td style="text-align:left">110120</td>
+<td style="text-align:left">TRANSACTION NOT FOUND</td>
+<td style="text-align:left">根据originalHostReferenceNumber或者registerReferenceNumber没有找到对应的交易。</td>
+</tr>
+<tr>
+<td style="text-align:left">110121</td>
+<td style="text-align:left">NOT SAME CARD</td>
+<td style="text-align:left">当verifyCard开关打开时,发现执行TransactionCompletion命令时使用的卡和执行TransactionStart命令时不是同一张卡。</td>
+</tr>
+<tr>
+<td style="text-align:left">110122</td>
+<td style="text-align:left">CARD INFO EXPIRED</td>
+<td style="text-align:left">卡信息过期,在一些场景中,在完成GetCardStatus命令后,你需要及时发送TransactionStart命令。</td>
+</tr>
+<tr>
+<td style="text-align:left">110123</td>
+<td style="text-align:left">ACCOUNT MISMATCH</td>
+<td style="text-align:left">TransactionStart请求中的account字段不匹配用户输入的账号。当自助终端指定账号,但该账号与终端缓存不匹配时,终端会要求重新刷卡/拍卡/插卡。当输入账户与TransactionStart请求中的账户不同时会出现此错误。</td>
+</tr>
+<tr>
+<td style="text-align:left">110124</td>
+<td style="text-align:left">AMOUNT MISMATCH</td>
+<td style="text-align:left">TransactionStart请求中的amount字段不匹配GetTraceInfoByCard中的amount字段。由于卡片的处理流程,如果使用GetTraceInfoByCard对卡片进行预处理,GetTraceInfoByCard中的金额必须与GetTraceInfoByCard中的金额相同。</td>
+</tr>
+<tr>
+<td style="text-align:left">110125</td>
+<td style="text-align:left">PREPROCESSING AMOUNT MISSING</td>
+<td style="text-align:left">请先使用SetConfiguration命令设置preprocessingAmount参数。相关功能基于此配置。</td>
+</tr>
+<tr>
+<td style="text-align:left">110126</td>
+<td style="text-align:left">SET CONFIGURATION ERROR: XXX,XXX</td>
+<td style="text-align:left">SetConfiguration命令参数错误,没有配置会被设置。该消息包含了有哪些配置参数名导致了命令失败(XXX 就是配置参数名)。该错误发生在以下情况:1.配置参数名错误,使用了没在SConfigurationNames出现过的名字。 2. 设置值错误,请检查相关配置的设置要求。</td>
+</tr>
+<tr>
+<td style="text-align:left">110127</td>
+<td style="text-align:left">GET CONFIGURATION ERROR: XXX,XXX</td>
+<td style="text-align:left">GetConfiguration命令参数错误,没有配置会被返回。该消息包含了有哪些配置参数名导致了命令失败(XXX 就是配置参数名)。该错误为配置参数名错误,使用了没在GConfigurationNames出现过的名字。</td>
+</tr>
+<tr>
+<td style="text-align:left">110128</td>
+<td style="text-align:left">PING DOMAIN NAME RESOLVE ERROR</td>
+<td style="text-align:left">Ping服务器时解析域名失败。</td>
+</tr>
+<tr>
+<td style="text-align:left">110129</td>
+<td style="text-align:left">PING TIMEOUT</td>
+<td style="text-align:left">Ping服务器超时。</td>
+</tr>
+<tr>
+<td style="text-align:left">110130</td>
+<td style="text-align:left">AMOUNT OVER CONTACTLESS LIMIT</td>
+<td style="text-align:left">交易金额超过了非接交易的限制。仅适用于仅支持非接触卡的终端。</td>
+</tr>
+<tr>
+<td style="text-align:left">110131</td>
+<td style="text-align:left">IP CONFIGURATION DISABLED IN DHCP</td>
+<td style="text-align:left">在DHCP模式下不能配置IP。</td>
+</tr>
+<tr>
+<td style="text-align:left">110132</td>
+<td style="text-align:left">IP CONFIGURATION PARAMETER ERROR</td>
+<td style="text-align:left">必须一次性设置所有与IP相关的参数。IP相关参数包括ipAddress、subnetMask、defaulgateway、dnsServer。</td>
+</tr>
+<tr>
+<td style="text-align:left">110133</td>
+<td style="text-align:left">PIN KEY MISSING</td>
+<td style="text-align:left">PIN密钥丢失。</td>
+</tr>
+<tr>
+<td style="text-align:left">110134</td>
+<td style="text-align:left">PIN KEY AND P2PE KEY MISSING</td>
+<td style="text-align:left">PIN 和P2PE 密钥丢失。</td>
+</tr>
+<tr>
+<td style="text-align:left">110200</td>
+<td style="text-align:left">INTERFACE CHIP DOES NOT EXIST OR ABNORMAL</td>
+<td style="text-align:left">接口芯片不存在或异常。</td>
+</tr>
+<tr>
+<td style="text-align:left">110201</td>
+<td style="text-align:left">PARAMETER ERROR</td>
+<td style="text-align:left">参数错误。</td>
+</tr>
+<tr>
+<td style="text-align:left">110202</td>
+<td style="text-align:left">RF MODULE IS CLOSED</td>
+<td style="text-align:left">RF(射频)模块关闭。</td>
+</tr>
+<tr>
+<td style="text-align:left">110203</td>
+<td style="text-align:left">NOT DETECT CARD</td>
+<td style="text-align:left">感应区域内没有卡,或该卡未激活。</td>
+</tr>
+<tr>
+<td style="text-align:left">110204</td>
+<td style="text-align:left">COMMUNICATION CONFLICT</td>
+<td style="text-align:left">感应区卡太多,通讯冲突。</td>
+</tr>
+<tr>
+<td style="text-align:left">110205</td>
+<td style="text-align:left">PROTOCOL ERROR</td>
+<td style="text-align:left">协议错误,卡的数据响应违反协议。</td>
+</tr>
+<tr>
+<td style="text-align:left">110206</td>
+<td style="text-align:left">CARD NOT ACTIVATED</td>
+<td style="text-align:left">卡未激活。</td>
+</tr>
+<tr>
+<td style="text-align:left">110207</td>
+<td style="text-align:left">MULTI-CARD CONFLICT</td>
+<td style="text-align:left">多卡冲突。</td>
+</tr>
+<tr>
+<td style="text-align:left">110208</td>
+<td style="text-align:left">NO RESPONSE TIMEOUT</td>
+<td style="text-align:left">没有响应超时。</td>
+</tr>
+<tr>
+<td style="text-align:left">110209</td>
+<td style="text-align:left">PROTOCOL ERROR</td>
+<td style="text-align:left">协议错误。</td>
+</tr>
+<tr>
+<td style="text-align:left">110210</td>
+<td style="text-align:left">COMMUNICATION TRANSMISSION ERROR</td>
+<td style="text-align:left">通讯传输错误。</td>
+</tr>
+<tr>
+<td style="text-align:left">110211</td>
+<td style="text-align:left">MIFARE CLASSIC CARD AUTHENTICATION FAILURE</td>
+<td style="text-align:left">Mifare Classic卡认证失败。</td>
+</tr>
+<tr>
+<td style="text-align:left">110212</td>
+<td style="text-align:left">SECTOR IS NOT CERTIFIED</td>
+<td style="text-align:left">未指定扇区。</td>
+</tr>
+<tr>
+<td style="text-align:left">110213</td>
+<td style="text-align:left">VALUE BLOCK FORMAT ERROR</td>
+<td style="text-align:left">数据块值的数据格式不正确。</td>
+</tr>
+<tr>
+<td style="text-align:left">110214</td>
+<td style="text-align:left">CARD IS STILL IN SENSING AREA</td>
+<td style="text-align:left">卡仍在感应区。</td>
+</tr>
+<tr>
+<td style="text-align:left">110215</td>
+<td style="text-align:left">CARD STATUS ERROR</td>
+<td style="text-align:left">卡状态错误。</td>
+</tr>
+<tr>
+<td style="text-align:left">110216</td>
+<td style="text-align:left">PARAMETER INVALID</td>
+<td style="text-align:left">参数错误。</td>
+</tr>
+<tr>
+<td style="text-align:left">110217</td>
+<td style="text-align:left">RPC I/O ERROR</td>
+<td style="text-align:left">RPC I/O 错误。</td>
+</tr>
+<tr>
+<td style="text-align:left">110218</td>
+<td style="text-align:left">NOT SUPPORT FOR THIS DEVICE</td>
+<td style="text-align:left">不支持此设备。</td>
+</tr>
+<tr>
+<td style="text-align:left">110219</td>
+<td style="text-align:left">NOT PERMISSION FOR PICC</td>
+<td style="text-align:left">不允许 PICC。</td>
+</tr>
+<tr>
+<td style="text-align:left">110220</td>
+<td style="text-align:left">RPC BUSY</td>
+<td style="text-align:left">RPC繁忙。</td>
+</tr>
+<tr>
+<td style="text-align:left">110221</td>
+<td style="text-align:left">AUTOMATIC REBOOT COUNTDOWN</td>
+<td style="text-align:left">应用已经锁定,设备正在准备重启。</td>
+</tr>
+<tr>
+<td style="text-align:left">110222</td>
+<td style="text-align:left">CARD EXPIRE DATE MISSING</td>
+<td style="text-align:left">卡片过期时间对于tokenize交易是必要字段。请设置该值。</td>
+</tr>
+<tr>
+<td style="text-align:left">110223</td>
+<td style="text-align:left">SERVICE BUSY</td>
+<td style="text-align:left">服务繁忙。</td>
+</tr>
+<tr>
+<td style="text-align:left">110224</td>
+<td style="text-align:left">PARAMETERS FILE CORRUPTION</td>
+<td style="text-align:left">参数导入失败或参数文件损坏。</td>
+</tr>
+<tr>
+<td style="text-align:left">110225</td>
+<td style="text-align:left">NEED READ CARD FIRST</td>
+<td style="text-align:left">支付终端在执行此操作前需要先读卡。</td>
+</tr>
+<tr>
+<td style="text-align:left">110300</td>
+<td style="text-align:left">PARTIALLY APPROVED</td>
+<td style="text-align:left">部分金额通过。</td>
+</tr>
+</tbody>
+</table>
+<p><a id="id.reportStatusCode"></a></p>
+<h2 id="-">消息上报状态码</h2>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">状态码</th>
+<th style="text-align:left">状态消息</th>
+<th style="text-align:left">描述</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">9000000</td>
+<td style="text-align:left">Waiting For Card Operation</td>
+<td style="text-align:left">等待刷卡/拍卡/插卡。(对于IM700,自助服务终端应该显示&quot;Please Tap Card&quot;,当收到一个新的状态码后清空显示。)</td>
+</tr>
+<tr>
+<td style="text-align:left">9000001</td>
+<td style="text-align:left">Waiting For PIN Entry</td>
+<td style="text-align:left">等待输入PIN。</td>
+</tr>
+<tr>
+<td style="text-align:left">9000003</td>
+<td style="text-align:left">Online Processing</td>
+<td style="text-align:left">在线处理中,正在和后台通信。</td>
+</tr>
+<tr>
+<td style="text-align:left">9000006</td>
+<td style="text-align:left">Waiting For PIN Re-entry</td>
+<td style="text-align:left">输入错误,等待重新输PIN。</td>
+</tr>
+<tr>
+<td style="text-align:left">9000007</td>
+<td style="text-align:left">Please See Phone</td>
+<td style="text-align:left">持卡人需要去检查他/她的手机。 (对于IM700,自助服务终端应该显示该消息,当收到一个新的状态码后清空显示。)</td>
+</tr>
+<tr>
+<td style="text-align:left">9000008</td>
+<td style="text-align:left">Waiting For Try Another Card</td>
+<td style="text-align:left">持卡人需要去尝试使用另一张卡。</td>
+</tr>
+<tr>
+<td style="text-align:left">9000009</td>
+<td style="text-align:left">Please Present One Card Only</td>
+<td style="text-align:left">持卡人需要只使用一张卡。 (对于IM700,自助服务终端应该显示该消息,当收到一个新的状态码后清空显示。)</td>
+</tr>
+<tr>
+<td style="text-align:left">9000010</td>
+<td style="text-align:left">Fallback, Waiting For Swipe</td>
+<td style="text-align:left">读取芯片卡失败,需要回滚到刷卡。</td>
+</tr>
+<tr>
+<td style="text-align:left">9000011</td>
+<td style="text-align:left">Waiting For Remove Card</td>
+<td style="text-align:left">需要移除卡片。</td>
+</tr>
+<tr>
+<td style="text-align:left">9000012</td>
+<td style="text-align:left">Waiting For Re-Insert Card</td>
+<td style="text-align:left">持卡人需要重新插卡。</td>
+</tr>
+</tbody>
+</table>
+<p><a id="id.appendix"></a></p>
+<h1 id="-">附录</h1>
+<h2 id="demo-">Demo模式特殊金额</h2>
+<p><a id="id.specialAmountInDemoMode"></a></p>
+<table>
+<thead>
+<tr>
+<th style="text-align:left">序号</th>
+<th style="text-align:left">交易金额</th>
+<th style="text-align:left">交易结果</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:left">1</td>
+<td style="text-align:left">2001</td>
+<td style="text-align:left">授权拒绝</td>
+</tr>
+<tr>
+<td style="text-align:left">2</td>
+<td style="text-align:left">2002</td>
+<td style="text-align:left">无效卡片</td>
+</tr>
+</tbody>
+</table>
+
+          	</article>
+        </div>
+		</div>
+  </body>
+</html>
+<script type="text/javascript" src="toc/js/jquery-1.4.4.min.js"></script>
+<script type="text/javascript" src="toc/js/jquery.ztree.all-3.5.min.js"></script>
+<script type="text/javascript" src="toc/js/ztree_toc.js"></script>
+<script type="text/javascript" src="toc_conf.js"></script>
+
+<SCRIPT type="text/javascript" >
+<!--
+$(document).ready(function(){
+    var css_conf = eval(markdown_panel_style);
+    $('#readme').css(css_conf)
+    
+    var conf = eval(jquery_ztree_toc_opts);
+		$('#tree').ztree_toc(conf);
+});
+//-->
+</SCRIPT>

+ 11 - 2
cfg/tcu_config.json

@@ -4,6 +4,15 @@
         "pos": false,
         "qr": false
     },
+    "user_list":[
+        "Root",
+        "Operator",
+        "Administrator"
+    ],
+    "Root_config": {
+        "password": "123456",
+        "username": "Root"
+    },
     "ccu_config_path": "/home/root/app_run/etc/ccu_config.json",
     "charge_layout_strect": {
         "column_strect": [
@@ -69,7 +78,7 @@
         "slave_log_path": "/home/root/log/slave/",
         "total_log_size": 100
     },
-    "login": {
+    "Administrator_config": {
         "password": "123456",
         "username": "Administrator"
     },
@@ -77,7 +86,7 @@
     "ocpp16_charging_profile_path": "/home/root/app_run/etc/ocpp16_ChargingProfiles.json",
     "ocpp16_config_key_path": "/home/root/app_run/etc/ocpp16_configkey.json",
     "ocpp16_offline_charging_records_path": "/home/root/app_run/etc/ocpp16_OfflineChargingRecords.json",
-    "operator": {
+    "Operator_config": {
         "password": "123456",
         "username": "Operator"
     },

BIN=BIN
docs/充电桩终端UI软件需求详解.docx


BIN=BIN
docs/充电系统页面需求详解.pdf


+ 3 - 0
rec/Resource.qrc

@@ -91,5 +91,8 @@
         <file>images/price/dialog_edit_background.png</file>
         <file>images/charging/icon_voltage_consumption.png</file>
         <file>images/charging/icon_current_consumption.png</file>
+        <file>icons/warning.png</file>
+        <file>icons/question.png</file>
+        <file>icons/information.png</file>
     </qresource>
 </RCC>

BIN=BIN
rec/icons/information.png


BIN=BIN
rec/icons/question.png


BIN=BIN
rec/icons/warning.png


+ 7 - 0
rec/styles/Dark.qss

@@ -211,6 +211,13 @@ QLabel#titles {
     font-weight: bold;    /* 加粗 */
 }
 
+FormChargeSettings QLineEdit#value,
+FormChargeSettings QLabel#unit {
+    color: #00C1C3;
+    font-size: 40px;
+    font-weight: bold;    /* 加粗 */
+}
+
 FormError QLabel#error_tips {
     color: #E45F45;
 }

+ 6 - 18
src/MainWindow.cpp

@@ -6,6 +6,7 @@
 #include <QDebug>
 #include <QGridLayout>
 #include <QScreen>
+#include <QThread>
 #include <QGuiApplication>
 
 #include "LanguageManager.h"
@@ -55,20 +56,9 @@ void MainWindow::initWidget()
     ui->stackedWidget->addWidget(m_startup);
 
     m_home = new FormHome();
-    m_home->init();
     ui->stackedWidget->addWidget(m_home);
 
-    // 强制布局系统更新
-    ui->stackedWidget->updateGeometry();
-
     ui->stackedWidget->setCurrentWidget(m_startup);
-
-    if (QGuiApplication::platformName().contains("wayland")) {
-        setWindowFlags(windowFlags() |
-                       Qt::FramelessWindowHint |
-                       Qt::WindowStaysOnTopHint |
-                       Qt::BypassWindowManagerHint);
-    }
 }
 
 void MainWindow::initConnect()
@@ -80,17 +70,15 @@ void MainWindow::initConnect()
         ui->stackedWidget->setCurrentWidget(m_startup);
     });
 
+    // connect(m_home,     &FormHome::refreshProgressBar,  this, [this](const int& value) {
+    //     m_startup->refreshProgressBar(value);
+    // });
+
     connect(LanguageManager::instance(), &LanguageManager::languageChanged, this, [this]() { ui->retranslateUi(this); });
 }
 
 void MainWindow::showEvent(QShowEvent *event)
 {
-    QMainWindow::showEvent(event);
 
-    // Wayland 环境下需要延迟激活
-    if (QGuiApplication::platformName().contains("wayland")) {
-        QTimer::singleShot(100, this, &MainWindow::activate);
-    } else {
-        this->activate();
-    }
+    QMainWindow::showEvent(event);
 }

+ 6 - 5
src/main.cpp

@@ -16,6 +16,7 @@
 #include "Globals.h"
 #include "LanguageManager.h"
 #include "GeneralInterface.h"
+#include "FunctionTimer.h"
 
 static void initGlobals() {
     // 初始化充电枪基本信息
@@ -176,7 +177,7 @@ int main(int argc, char *argv[])
 
     // 加载虚拟键盘模块
     qputenv("QT_IM_MODULE", QByteArray("qtvirtualkeyboard"));
-    qputenv("QT_LOGGING_RULES", "qt.scenegraph.*=true");
+    // qputenv("QT_LOGGING_RULES", "qt.scenegraph.*=true");
 
     // ARM平台专用渲染参数
     if (QStringList({ "arm", "aarch64" }).contains(QSysInfo::currentCpuArchitecture()))
@@ -196,14 +197,14 @@ int main(int argc, char *argv[])
         // 设置 OpenGL 版本和特性
         QSurfaceFormat format;
         format.setRenderableType(QSurfaceFormat::OpenGL);
-        format.setVersion(4, 3);  // 根据设备支持选择版本
-        // format.setProfile(QSurfaceFormat::CoreProfile);
+        format.setVersion(2, 2);  // 根据设备支持选择版本
+        format.setProfile(QSurfaceFormat::CoreProfile);
         QSurfaceFormat::setDefaultFormat(format);
 
         // 设置 Qt 使用 OpenGL 渲染引擎
-        // QApplication::setAttribute(Qt::AA_UseOpenGLES);  // 嵌入式设备用 OpenGL ES
+        QApplication::setAttribute(Qt::AA_UseOpenGLES);  // 嵌入式设备用 OpenGL ES
         // QApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);  // 桌面 OpenGL
-        QApplication::setAttribute(Qt::AA_UseDesktopOpenGL);  // 桌面 OpenGL
+        // QApplication::setAttribute(Qt::AA_UseDesktopOpenGL);  // 桌面 OpenGL
     }
 
     QApplication a(argc, argv);

+ 98 - 0
src/utils/AsyncInitManager.cpp

@@ -0,0 +1,98 @@
+#include "AsyncInitManager.h"
+#include <QDebug>
+#include <QCoreApplication>
+
+AsyncInitManager* AsyncInitManager::m_instance = nullptr;
+
+AsyncInitManager* AsyncInitManager::instance()
+{
+    if (!m_instance) {
+        m_instance = new AsyncInitManager();
+    }
+    return m_instance;
+}
+
+AsyncInitManager::AsyncInitManager(QObject *parent)
+    : QObject(parent)
+    , m_workerThread(nullptr)
+    , m_processTimer(nullptr)
+    , m_totalTasks(0)
+    , m_completedTasks(0)
+    , m_isRunning(false)
+{
+    // 创建工作线程
+    m_workerThread = new QThread(this);
+    this->moveToThread(m_workerThread);
+    
+    // 创建处理定时器
+    m_processTimer = new QTimer(this);
+    m_processTimer->setInterval(10); // 10ms间隔处理任务
+    connect(m_processTimer, &QTimer::timeout, this, &AsyncInitManager::processNextTask);
+    
+    m_workerThread->start();
+}
+
+AsyncInitManager::~AsyncInitManager()
+{
+    if (m_workerThread) {
+        m_workerThread->quit();
+        m_workerThread->wait();
+    }
+}
+
+void AsyncInitManager::addInitTask(std::function<void()> task, const QString& taskName)
+{
+    QMutexLocker locker(&m_mutex);
+    m_taskQueue.enqueue(InitTask(task, taskName));
+    m_totalTasks++;
+}
+
+void AsyncInitManager::startAsyncInit()
+{
+    if (m_isRunning) {
+        return;
+    }
+    
+    m_isRunning = true;
+    m_completedTasks = 0;
+    
+    // 启动处理定时器
+    m_processTimer->start();
+}
+
+bool AsyncInitManager::isAllTasksCompleted() const
+{
+    return m_completedTasks >= m_totalTasks;
+}
+
+void AsyncInitManager::processNextTask()
+{
+    QMutexLocker locker(&m_mutex);
+    
+    if (m_taskQueue.isEmpty()) {
+        if (m_completedTasks >= m_totalTasks) {
+            m_processTimer->stop();
+            m_isRunning = false;
+            emit allTasksCompleted();
+        }
+        return;
+    }
+    
+    InitTask task = m_taskQueue.dequeue();
+    locker.unlock();
+    
+    // 执行任务
+    try {
+        task.task();
+        task.completed = true;
+    } catch (...) {
+        qWarning() << "Task failed:" << task.name;
+    }
+    
+    m_completedTasks++;
+    emit taskCompleted(task.name);
+    emit progressUpdated(m_completedTasks, m_totalTasks);
+    
+    // 短暂延迟,避免阻塞主线程
+    QThread::msleep(1);
+} 

+ 61 - 0
src/utils/AsyncInitManager.h

@@ -0,0 +1,61 @@
+#ifndef ASYNCINITMANAGER_H
+#define ASYNCINITMANAGER_H
+
+#include <QObject>
+#include <QThread>
+#include <QTimer>
+#include <QQueue>
+#include <QMutex>
+#include <functional>
+
+class AsyncInitManager : public QObject
+{
+    Q_OBJECT
+
+public:
+    static AsyncInitManager* instance();
+    
+    // 添加初始化任务
+    void addInitTask(std::function<void()> task, const QString& taskName = "");
+    
+    // 开始异步初始化
+    void startAsyncInit();
+    
+    // 检查是否所有任务都完成
+    bool isAllTasksCompleted() const;
+
+signals:
+    void taskCompleted(const QString& taskName);
+    void allTasksCompleted();
+    void progressUpdated(int progress, int total);
+
+private:
+    explicit AsyncInitManager(QObject *parent = nullptr);
+    ~AsyncInitManager();
+    
+    void processNextTask();
+    void onTaskCompleted();
+
+private:
+    static AsyncInitManager* m_instance;
+    
+    struct InitTask {
+        std::function<void()> task;
+        QString name;
+        bool completed;
+        
+        InitTask(std::function<void()> t, const QString& n) 
+            : task(t), name(n), completed(false) {}
+    };
+    
+    QQueue<InitTask> m_taskQueue;
+    QMutex m_mutex;
+    QThread* m_workerThread;
+    QTimer* m_processTimer;
+    
+    int m_totalTasks;
+    int m_completedTasks;
+    bool m_isRunning;
+};
+
+#endif // ASYNCINITMANAGER_H 

+ 62 - 17
src/utils/ConfigManager.cpp

@@ -278,7 +278,7 @@ void ConfigManager::setLanguage(int language)
  * @brief ConfigManager::getAdminConfig 获取管理员配置
  * @return   返回管理员配置信息
  */
-admin_cfg_info_t ConfigManager::getAdminConfig()
+user_cfg_info_t ConfigManager::getAdminConfig()
 {
     // 返回管理员配置
     return m_tcu_cfg.admin_cfg;
@@ -288,12 +288,50 @@ admin_cfg_info_t ConfigManager::getAdminConfig()
  * @brief ConfigManager::setAdminConfig 设置管理员配置
  * @param admin_cfg 管理员配置
  */
-void ConfigManager::setAdminConfig(const admin_cfg_info_t &admin_cfg)
+void ConfigManager::setAdminConfig(const user_cfg_info_t &admin_cfg)
 {
     // 将传入的管理员配置赋值给m_tcu_cfg中的admin_cfg
     m_tcu_cfg.admin_cfg = admin_cfg;
 }
 
+void ConfigManager::setAdminConfig(const QString &username, const QString &password)
+{
+    m_tcu_cfg.admin_cfg.username = username;
+    m_tcu_cfg.admin_cfg.password = password;
+}
+
+user_cfg_info_t ConfigManager::getOperatorConfig()
+{
+    return m_tcu_cfg.operator_cfg;
+}
+
+void ConfigManager::setOperatorConfig(const user_cfg_info_t &operator_cfg)
+{
+    m_tcu_cfg.operator_cfg = operator_cfg;
+}
+
+void ConfigManager::setOperatorConfig(const QString &username, const QString &password)
+{
+    m_tcu_cfg.operator_cfg.username = username;
+    m_tcu_cfg.operator_cfg.password = password;
+}
+
+user_cfg_info_t ConfigManager::getRootConfig()
+{
+    return m_tcu_cfg.root_cfg;
+}
+
+void ConfigManager::setRootConfig(const user_cfg_info_t &root_cfg)
+{
+    m_tcu_cfg.root_cfg = root_cfg;
+}
+
+void ConfigManager::setRootConfig(const QString &username, const QString &password)
+{
+    m_tcu_cfg.root_cfg.username = username;
+    m_tcu_cfg.root_cfg.password = password;
+}
+
 /**
  * @brief ConfigManager::initWatcher    初始化监视器
  */
@@ -679,13 +717,16 @@ void ConfigManager::tcuCfgFromJson()
         m_tcu_cfg.tcp_server_cfg.port       = tcp_server.value("port").toInt(3001);
     }
 
-    // 获取LOGIN的值
+    // 获取Admin的值
     QJsonObject login_cfg = tcu_cfg.value(Config::Keys::LOGIN).toObject();
     if(!login_cfg.isEmpty()) {
         m_tcu_cfg.admin_cfg.username = login_cfg.value("username").toString("");
         m_tcu_cfg.admin_cfg.password = login_cfg.value("password").toString("");
     }
 
+    // 获取用户列表
+    m_tcu_cfg.user_list = jsonToStringList(tcu_cfg.value(Config::Keys::USER_LIST));
+
     // 获取OPERATOR的值 
     QJsonObject operator_cfg = tcu_cfg.value(Config::Keys::OPERATOR).toObject();
     if(!operator_cfg.isEmpty()) {
@@ -693,6 +734,13 @@ void ConfigManager::tcuCfgFromJson()
         m_tcu_cfg.operator_cfg.password = operator_cfg.value("password").toString("");
     }
 
+    // 获取 ROOT 的值
+    QJsonObject root_cfg = tcu_cfg.value(Config::Keys::ROOT_CONFIG).toObject();
+    if(!root_cfg.isEmpty()) {
+        m_tcu_cfg.root_cfg.username = root_cfg.value("username").toString("");
+        m_tcu_cfg.root_cfg.password = root_cfg.value("password").toString("");
+    }
+
     // 设置语言、时区、TCU消息日志路径和CCU消息日志路径
     m_tcu_cfg.language                              = tcu_cfg.value("language").toInt(0);
     m_tcu_cfg.time_zone                             = tcu_cfg.value("time_zone").toInt(0);
@@ -789,7 +837,7 @@ QJsonObject ConfigManager::tcpServerToJson(const tcp_server_cfg_info_t &data)
  * @param data  登录信息
  * @return  Json对象
  */
-QJsonObject ConfigManager::loginToJson(const admin_cfg_info_t &data)
+QJsonObject ConfigManager::loginToJson(const user_cfg_info_t &data)
 {
     QJsonObject obj;
 
@@ -1009,9 +1057,9 @@ void ConfigManager::ccuCfgFromJson()
     m_ccu_cfg.ISO4217_MinorUnit = ccu_cfg.value("ISO4217_MinorUnit").toInt();
     m_ccu_cfg.ISO4217_LeastSign = ccu_cfg.value("ISO4217_LeastSign").toInt();
 
-    // GUN_Detail
-    if (ccu_cfg.contains("GUN")) {
-        m_ccu_cfg.GUN_Detail = jsonToGUNDetail(ccu_cfg.value("GUN").toArray());
+    // GUN_config
+    if (ccu_cfg.contains("GUN_config")) {
+        m_ccu_cfg.GUN_config = jsonToGUNDetail(ccu_cfg.value("GUN_config").toArray());
     }
 
     // pcuhw config
@@ -1053,7 +1101,7 @@ QList<GUN_DETAIL> ConfigManager::jsonToGUNDetail(const QJsonArray &array)
     for (const auto &item : array) {
         QJsonObject obj = item.toObject();
         GUN_DETAIL config;
-        config.GUN_ID                   = obj.value("GUN_ID").toInt();
+        config.connectorId              = obj.value("connectorId").toInt();
         config.GUN_Type                 = obj.value("GUN_Type").toString("");
         config.GUN_Available            = obj.value("GUN_Available").toBool();
         config.GUN_maxI                 = obj.value("GUN_maxI").toInt();
@@ -1066,10 +1114,6 @@ QList<GUN_DETAIL> ConfigManager::jsonToGUNDetail(const QJsonArray &array)
         config.requestPowerBySOC        = obj.value("requestPowerBySOC").toBool();
         config.GUNOverTemp_Warning      = obj.value("GUNOverTemp_Warning").toInt();
         config.GUNOverTemp_Stopping     = obj.value("GUNOverTemp_Stopping").toInt();
-        config.enable_current_limit     = obj.value("enable_current_limit").toBool();
-        config.permitted_current        = obj.value("permitted_current").toInt();
-        config.enable_powerKW_limit     = obj.value("enable_powerKW_limit").toBool();
-        config.permitted_powerKW        = obj.value("permitted_powerKW").toInt();
         list.append(config);
     }
     return list;
@@ -1181,8 +1225,8 @@ bool ConfigManager::ccuCfgToJson()
     m_cfg_object[CCU_CONFIG]["TCU_ID"]                  = m_ccu_cfg.TCU_ID;
     m_cfg_object[CCU_CONFIG]["GUN_Numb"]                = m_ccu_cfg.GUN_Numb;
     m_cfg_object[CCU_CONFIG]["CCU_SN"]                  = m_ccu_cfg.CCU_SN;
-    m_cfg_object[CCU_CONFIG]["CCU_ProductID"]              = m_ccu_cfg.CCU_ProductID;
-    m_cfg_object[CCU_CONFIG]["CCU_VendorID"]              = m_ccu_cfg.CCU_VendorID;
+    m_cfg_object[CCU_CONFIG]["CCU_ProductID"]           = m_ccu_cfg.CCU_ProductID;
+    m_cfg_object[CCU_CONFIG]["CCU_VendorID"]            = m_ccu_cfg.CCU_VendorID;
     m_cfg_object[CCU_CONFIG]["CCU_Available"]           = m_ccu_cfg.CCU_Available;
     m_cfg_object[CCU_CONFIG]["username"]                = m_ccu_cfg.username;
     m_cfg_object[CCU_CONFIG]["password"]                = m_ccu_cfg.password;
@@ -1194,7 +1238,7 @@ bool ConfigManager::ccuCfgToJson()
     m_cfg_object[CCU_CONFIG]["ISO4217_LeastSign"]       = m_ccu_cfg.ISO4217_LeastSign;
 
     // 将GUN_Detail配置信息写入m_cfg_object
-    m_cfg_object[CCU_CONFIG]["GUN"]                     = gunDetailToJson(m_ccu_cfg.GUN_Detail);
+    m_cfg_object[CCU_CONFIG]["GUN_config"]              = gunDetailToJson(m_ccu_cfg.GUN_config);
 
     // 将pcuhw配置信息写入m_cfg_object
     m_cfg_object[CONFIG_KEY]["pcuhw"]                   = pcuhwToJson(m_ccu_cfg.pcuhw);
@@ -1223,7 +1267,7 @@ QJsonArray ConfigManager::gunDetailToJson(const QList<GUN_DETAIL> &config)
     QJsonArray arr;
     for (const auto &item : config) {
         QJsonObject obj;
-        obj.insert("GUN_ID",                item.GUN_ID);
+        obj.insert("connectorId",           item.connectorId);
         obj.insert("GUN_Type",              item.GUN_Type);
         obj.insert("GUN_Available",         item.GUN_Available);
         obj.insert("GUN_maxI",              item.GUN_maxI);
@@ -1512,6 +1556,7 @@ void ConfigManager::authorizationFromJson()
  */
 void ConfigManager::fromValue(QList<AUTH_CARD_INFO> &auth_card_list, const QJsonArray &jsonArray)
 {
+    auth_card_list.clear();
     // 遍历QJsonArray中的每个元素
     foreach (const QJsonValue &auth_info, jsonArray){
         // 如果元素是对象
@@ -1634,7 +1679,7 @@ CORE_PROFILE ConfigManager::jsonToCoreProfile(const QJsonObject &obj)
     config.LightIntensity                       = obj["LightIntensity"].toInt();
     config.LocalAuthorizeOffline                = obj["LocalAuthorizeOffline"].toBool();
     config.LocalPreAuthorize                    = obj["LocalPreAuthorize"].toBool();
-    config.MaxEnergyOnInvalidId                 = obj["MaxEnergyOnInvalidId"].toInt();
+    config.MaxEnergyOnInvalidId                 = obj["MaxEnergyOnInvalidId"].toInt(INT_MAX);
     config.MeterValuesAlignedData               = obj["MeterValuesAlignedData"].toString();
     config.MeterValuesAlignedDataMaxLength      = obj["MeterValuesAlignedDataMaxLength"].toInt();
     config.MeterValuesSampledData               = obj["MeterValuesSampledData"].toString();

+ 12 - 3
src/utils/ConfigManager.h

@@ -64,8 +64,17 @@ public:
     int getLanguage();
     void setLanguage(int language);
 
-    admin_cfg_info_t getAdminConfig();
-    void setAdminConfig(const admin_cfg_info_t& admin_cfg);
+    user_cfg_info_t getAdminConfig();
+    void setAdminConfig(const user_cfg_info_t& admin_cfg);
+    void setAdminConfig(const QString& username, const QString& password);
+
+    user_cfg_info_t getOperatorConfig();
+    void setOperatorConfig(const user_cfg_info_t& operator_cfg);
+    void setOperatorConfig(const QString& username, const QString& password);
+
+    user_cfg_info_t getRootConfig();
+    void setRootConfig(const user_cfg_info_t& root_cfg);
+    void setRootConfig(const QString& username, const QString& password);
 
     tcu_config_info_t tcu_cfg() const;
 
@@ -103,7 +112,7 @@ private:
     WIZAR_INFO      jsonToWizarInfo(const QJsonObject& obj);
     void tcuCfgFromJson();
     QJsonObject tcpServerToJson(const tcp_server_cfg_info_t& data);
-    QJsonObject loginToJson(const admin_cfg_info_t& data);
+    QJsonObject loginToJson(const user_cfg_info_t& data);
     QJsonObject strectToJson(const layout_strect_info_t& data);
     QJsonObject logCfgToJson(const LOG_INFO& data);
     QJsonObject authTypeEnableToJson(const AUTH_TYPE_ENABLE& data);

+ 19 - 8
src/utils/DataTypeDef.h

@@ -11,8 +11,10 @@
 namespace Config {
     namespace Keys {
         constexpr const char* TCP_SERVER                            = "tcp_server";
-        constexpr const char* LOGIN                                 = "login";
-        constexpr const char* OPERATOR                              = "operator";
+        constexpr const char* LOGIN                                 = "Administrator_config";
+        constexpr const char* OPERATOR                              = "Operator_config";
+        constexpr const char* ROOT_CONFIG                           = "Root_config";
+        constexpr const char* USER_LIST                             = "user_list";
         constexpr const char* LANGUAGE                              = "language";
         constexpr const char* TIME_ZONE                             = "time_zone";
         constexpr const char* RS485_PORT_NAME                       = "rs485_port_name";
@@ -60,6 +62,12 @@ namespace General {
         constexpr const int LONG_TEXT   = 0x2;
         constexpr const int DATE_TIME   = 0x3;
     }
+
+    namespace UserType {
+        constexpr const int OPERATOR    = 0x0;
+        constexpr const int ADMIN       = 0x1;
+        constexpr const int ROOT        = 0x2;
+    }
 }
 
 // OCPP16 配置文件
@@ -120,6 +128,7 @@ namespace Global {
         constexpr const char* CHARGING_PROFILES_MAP     = "m_charging_profiles_map";
         constexpr const char* CFG_KEY                   = "m_cfg_key";
         constexpr const char* OFFLINE_CHARGING_RECORDS  = "m_chargings_records";
+        constexpr const char* CURRENCY_SYMBOL_MAP       = "m_currency_symbol";
     }
 }
 
@@ -699,9 +708,9 @@ typedef struct tcp_server_cfg_info_t {
 Q_DECLARE_METATYPE(TCP_CFG)
 
 /**
- * @brief The admin_cfg_info_t class                管理员账号密码
+ * @brief The user_cfg_info_t class                管理员账号密码
  */
-typedef struct admin_cfg_info_t {
+typedef struct user_cfg_info_t {
     QString     username;               // 用户名
     QString     password;               // 密码
 }ADMIN_CFG;
@@ -795,8 +804,10 @@ Q_DECLARE_METATYPE(PAYMENT_INFO)
  */
 typedef struct tcu_config_info_t {
     tcp_server_cfg_info_t   tcp_server_cfg;                         // tcp 服务端配置
-    admin_cfg_info_t        operator_cfg;                           // 操作员用户信息配置
-    admin_cfg_info_t        admin_cfg;                              // 管理员用户信息配置
+    user_cfg_info_t         operator_cfg;                           // 操作员用户信息配置
+    user_cfg_info_t         root_cfg;                               // 管理员用户信息配置
+    user_cfg_info_t         admin_cfg;                              // 管理员用户信息配置
+    QStringList             user_list;                              // 用户列表
     int                     language;                               // 界面语言
     int                     time_zone;                              // 界面时区
     LOG_INFO                log_config;                             // 日志配置
@@ -861,7 +872,7 @@ typedef struct ocpp2_1_info_t {
 Q_DECLARE_METATYPE(OCPP2_1)
 
 typedef struct gun_detail_info_t {
-    int         GUN_ID;                     // 枪ID
+    int         connectorId;                // 枪ID
     QString     GUN_Type;                   // 枪类型
     bool        GUN_Available;              // 枪可用
     int         GUN_maxI;                   // 枪最大电流
@@ -904,7 +915,7 @@ typedef struct ccu_config_info_t {
     QString                 ISO4217_CurrencySymbol;     // 货币符号
     int                     ISO4217_MinorUnit;          // 货币最小单位
     int                     ISO4217_LeastSign;          // 货币小数位
-    QList<GUN_DETAIL>       GUN_Detail;                 // 充电枪详细信息
+    QList<GUN_DETAIL>       GUN_config;                 // 充电枪详细信息
     PCUHW_CFG               pcuhw;                      // PCU 硬件信息
     PCUTC_CFG               pcutc;                      // 
     QTTCU_CFG               qttcu;                      // TCU 通用配置

+ 31 - 0
src/utils/FunctionTimer.h

@@ -0,0 +1,31 @@
+#ifndef FUNCTIONTIMER_H
+#define FUNCTIONTIMER_H
+
+#include <QElapsedTimer>
+#include <QString>
+#include <QDebug>
+
+// 函数耗时测量工具类(自动在析构时输出耗时)
+class FunctionTimer {
+public:
+    // 构造函数:传入函数名称,开始计时
+    explicit FunctionTimer(const QString& functionName)
+        : m_functionName(functionName) {
+        m_timer.start();
+    }
+
+    // 析构函数:自动计算并输出耗时
+    ~FunctionTimer() {
+        qint64 elapsed = m_timer.elapsed();
+        qDebug() << QString("[性能统计] %1 耗时:%2 ms").arg(m_functionName).arg(elapsed);
+    }
+
+private:
+    QElapsedTimer m_timer;  // 计时器
+    QString m_functionName; // 函数名称
+};
+
+// 宏定义:简化使用(自动以当前函数名作为标识)
+#define MEASURE_TIME() FunctionTimer timer(__FUNCTION__)
+
+#endif // FUNCTIONTIMER_H

+ 261 - 1
src/utils/GeneralInterface.cpp

@@ -303,6 +303,187 @@ void GeneralInterface::setTouchScroller(QScrollArea *area)
 }
 
 /**
+ * @brief GeneralInterface::setTouchScroller    设置QListWidget的滚动方式为触摸滚动
+ * @param listWidget  
+ */
+void GeneralInterface::setTouchScroller(QListWidget *listWidget)
+{
+    QScroller::grabGesture(listWidget,              QScroller::TouchGesture);
+    QScroller::grabGesture(listWidget->viewport(),  QScroller::LeftMouseButtonGesture);
+}
+
+/**
+ * @brief GeneralInterface::setTouchScroller    设置QTableWidget的滚动方式为触摸滚动
+ * @param tableWidget  
+ */
+void GeneralInterface::setTouchScroller(QTableWidget *tableWidget)
+{
+    QScroller::grabGesture(tableWidget,              QScroller::TouchGesture);
+    QScroller::grabGesture(tableWidget->viewport(),  QScroller::LeftMouseButtonGesture);
+}
+
+/**
+ * @brief GeneralInterface::setTouchScroller    设置QTreeWidget的滚动方式为触摸滚动
+ * @param treeWidget  
+ */
+void GeneralInterface::setTouchScroller(QTreeWidget *treeWidget)
+{
+    QScroller::grabGesture(treeWidget,              QScroller::TouchGesture);
+    QScroller::grabGesture(treeWidget->viewport(),  QScroller::LeftMouseButtonGesture);
+}
+
+/**
+ * @brief GeneralInterface::setTouchScroller    设置QTextEdit的滚动方式为触摸滚动
+ * @param textEdit  
+ */
+void GeneralInterface::setTouchScroller(QTextEdit *textEdit)
+{
+    QScroller::grabGesture(textEdit,              QScroller::TouchGesture);
+    QScroller::grabGesture(textEdit->viewport(),  QScroller::LeftMouseButtonGesture);
+}
+
+/**
+ * @brief GeneralInterface::setTouchScroller    设置QAbstractScrollArea的滚动方式为触摸滚动
+ * @param scrollArea  
+ */
+void GeneralInterface::setTouchScroller(QAbstractScrollArea *scrollArea)
+{
+    QScroller::grabGesture(scrollArea,              QScroller::TouchGesture);
+    QScroller::grabGesture(scrollArea->viewport(),  QScroller::LeftMouseButtonGesture);
+}
+
+void GeneralInterface::setControlEnabled(QWidget *control, QWidget *label, const int &userType)
+{
+    // 管理员和根用户都有控制权
+    const bool hasControl = (userType == General::UserType::ADMIN || userType == General::UserType::ROOT);
+    if (control) {
+        control->setEnabled(hasControl);
+    }
+    if (label) {
+        label->setEnabled(hasControl);
+    }
+}
+
+void GeneralInterface::setControlVisiabled(QWidget *control, QWidget *label, const int &userType)
+{
+    // 管理员和根用户都有控制权
+    const bool hasControl = (userType == General::UserType::ROOT);
+    if (control) {
+        control->setVisible(hasControl);
+    }
+    if (label) {
+        label->setVisible(hasControl);
+    }
+}
+
+/**
+ * @brief GeneralInterface::setAdvancedTouchScroller    设置高级触摸滚动配置
+ * @param scrollArea  滚动区域
+ * @param properties  滚动属性
+ */
+void GeneralInterface::setAdvancedTouchScroller(QAbstractScrollArea *scrollArea, 
+                                               const QScrollerProperties &properties)
+{
+    // 设置基本手势
+    QScroller::grabGesture(scrollArea,              QScroller::TouchGesture);
+    QScroller::grabGesture(scrollArea->viewport(),  QScroller::LeftMouseButtonGesture);
+    
+    // 应用自定义属性
+    QScroller *scroller = QScroller::scroller(scrollArea);
+    if (scroller) {
+        scroller->setScrollerProperties(properties);
+    }
+}
+
+/**
+ * @brief GeneralInterface::setTouchScrollerWithProperties    设置带属性的触摸滚动
+ * @param scrollArea  滚动区域
+ * @param enableOvershoot  是否启用过度滚动
+ * @param enableFlick  是否启用轻弹
+ * @param decelerationFactor  减速度因子
+ */
+void GeneralInterface::setTouchScrollerWithProperties(QAbstractScrollArea *scrollArea,
+                                                     bool enableOvershoot,
+                                                     bool enableFlick,
+                                                     qreal decelerationFactor)
+{
+    // 设置基本手势
+    QScroller::grabGesture(scrollArea,              QScroller::TouchGesture);
+    QScroller::grabGesture(scrollArea->viewport(),  QScroller::LeftMouseButtonGesture);
+    
+    // 配置滚动属性
+    QScroller *scroller = QScroller::scroller(scrollArea);
+    if (scroller) {
+        QScrollerProperties properties = scroller->scrollerProperties();
+        
+        // 设置过度滚动
+        properties.setScrollMetric(QScrollerProperties::OvershootDragResistanceFactor, enableOvershoot ? 0.5 : 0.0);
+        properties.setScrollMetric(QScrollerProperties::OvershootScrollDistanceFactor, enableOvershoot ? 0.5 : 0.0);
+        
+        // 设置轻弹
+        properties.setScrollMetric(QScrollerProperties::DecelerationFactor, enableFlick ? decelerationFactor : 0.0);
+        
+        // 设置其他优化参数
+        properties.setScrollMetric(QScrollerProperties::DragVelocitySmoothingFactor, 0.5);
+        properties.setScrollMetric(QScrollerProperties::AxisLockThreshold, 0.5);
+        properties.setScrollMetric(QScrollerProperties::ScrollingCurve, QEasingCurve::OutCubic);
+        
+        scroller->setScrollerProperties(properties);
+    }
+}
+
+/**
+ * @brief GeneralInterface::setTouchScrollerForChildren    为父控件的所有子控件设置触摸滚动
+ * @param parent  父控件
+ * @param className  指定类名(可选)
+ */
+void GeneralInterface::setTouchScrollerForChildren(QWidget *parent, const QString &className)
+{
+    if (!parent) return;
+    
+    // 查找所有可滚动的子控件
+    QList<QAbstractScrollArea*> scrollAreas = parent->findChildren<QAbstractScrollArea*>();
+    
+    foreach (QAbstractScrollArea* area, scrollAreas) {
+        if (className.isEmpty() || area->metaObject()->className() == className) {
+            setTouchScroller(area);
+        }
+    }
+    
+    // 查找所有ListWidget
+    QList<QListWidget*> listWidgets = parent->findChildren<QListWidget*>();
+    foreach (QListWidget* listWidget, listWidgets) {
+        if (className.isEmpty() || listWidget->metaObject()->className() == className) {
+            setTouchScroller(listWidget);
+        }
+    }
+    
+    // 查找所有TableWidget
+    QList<QTableWidget*> tableWidgets = parent->findChildren<QTableWidget*>();
+    foreach (QTableWidget* tableWidget, tableWidgets) {
+        if (className.isEmpty() || tableWidget->metaObject()->className() == className) {
+            setTouchScroller(tableWidget);
+        }
+    }
+    
+    // 查找所有TreeWidget
+    QList<QTreeWidget*> treeWidgets = parent->findChildren<QTreeWidget*>();
+    foreach (QTreeWidget* treeWidget, treeWidgets) {
+        if (className.isEmpty() || treeWidget->metaObject()->className() == className) {
+            setTouchScroller(treeWidget);
+        }
+    }
+    
+    // 查找所有TextEdit
+    QList<QTextEdit*> textEdits = parent->findChildren<QTextEdit*>();
+    foreach (QTextEdit* textEdit, textEdits) {
+        if (className.isEmpty() || textEdit->metaObject()->className() == className) {
+            setTouchScroller(textEdit);
+        }
+    }
+}
+
+/**
  * @brief   GeneralInterface::getWindowTitle  获取窗口标题
  * @param   type  窗口类型
  * @return  窗口标题
@@ -367,7 +548,16 @@ gui_state_enum GeneralInterface::getGuiState(const charge_prepare_enum &form, co
 {
     switch (form) {
     case PLUG_IN:           return CHARGE_GUN_AVAILABLE;
-    case AUTHENTICATION:    return getGuiStateAuthForm(state);
+    case AUTHENTICATION: {
+        if (state == 0) {
+            int authState = getAuthShowType(ConfigManager::instance()->tcu_cfg().auth_type_enable.qr,
+                                            ConfigManager::instance()->tcu_cfg().auth_type_enable.nfc,
+                                            ConfigManager::instance()->tcu_cfg().auth_type_enable.pos);
+            return getGuiStateAuthForm(authState);
+        } else {
+            return getGuiStateAuthForm(state);
+        }
+    }
     case CHARGE_PREPARE:    return getGuiStatePrepareForm(state);
     case CHARGING_FORM:     return getGuiStateChargingForm(state);
     case FINISH_FORM:       return RETURN_GUN;
@@ -393,6 +583,21 @@ gui_state_enum GeneralInterface::getGuiStateAuthForm(const int &state)
     }
 }
 
+int GeneralInterface::getAuthShowType(const bool &qrEnable, const bool &cardEnable, const bool &posEnable)
+{
+    if (qrEnable && !cardEnable && !posEnable) {
+        return AuthType::QR;
+    } else if (qrEnable && cardEnable && !posEnable) {
+        return AuthType::QR_OR_CARD;
+    } else if (!qrEnable && cardEnable && !posEnable) {
+        return AuthType::CARD;
+    } else if (!qrEnable && !cardEnable && posEnable) {
+        return AuthType::POS;
+    }
+
+    return -1;
+}
+
 /**
  * @brief   GeneralInterface::getGuiStatePrepareForm  根据状态码获取准备表单的GUI状态
  * @param   state 状态码
@@ -555,6 +760,61 @@ void GeneralInterface::initLanguageComboBox(CustomComboBox *combox)
     combox->addItems(timezone_list);
 }
 
+void GeneralInterface::initCurrencySymbolMap()
+{
+    QMap<QString, QString> currencySymbol;
+    currencySymbol.insert("USD", "$");
+    currencySymbol.insert("EUR", "€");
+    currencySymbol.insert("GBP", "£");
+    currencySymbol.insert("JPY", "¥");
+    currencySymbol.insert("CNY", "¥");
+    currencySymbol.insert("AUD", "A$");
+    currencySymbol.insert("CAD", "C$");
+    currencySymbol.insert("CHF", "Fr");
+    currencySymbol.insert("HKD", "HK$");
+    currencySymbol.insert("SGD", "S$");
+    currencySymbol.insert("INR", "₹");
+    currencySymbol.insert("BRL", "R$");
+    currencySymbol.insert("RUB", "₽");
+    currencySymbol.insert("KRW", "₩");
+    currencySymbol.insert("MXN", "Mex$");
+    currencySymbol.insert("NZD", "NZ$");
+    currencySymbol.insert("SEK", "kr");
+    currencySymbol.insert("DKK", "kr");
+    currencySymbol.insert("NOK", "kr");
+    currencySymbol.insert("SAR", "﷼");
+    currencySymbol.insert("AED", "د.إ");
+    currencySymbol.insert("ZAR", "R");
+    currencySymbol.insert("TRY", "₺");
+    currencySymbol.insert("CHF", "Fr");
+
+    GLOBALS->setValue(Global::Keys::CURRENCY_SYMBOL_MAP, QVariant::fromValue(currencySymbol));
+}
+
+QString GeneralInterface::getCurrencySymbol(const QString &str)
+{
+    auto map = GLOBALS->getValue(Global::Keys::CURRENCY_SYMBOL_MAP).value<QMap<QString, QString>>();
+    return QString("%1(%2)").arg(str, map.value(str));
+}
+
+QString GeneralInterface::getCurrencySymbol(CustomComboBox *combox)
+{
+    auto str = combox->currentText();
+    auto list = str.split('(');
+    return list[0];
+}
+
+void GeneralInterface::initCurrencySymbolComboBox(CustomComboBox *combox)
+{
+    QStringList currencySymbol;
+    auto map = GLOBALS->getValue(Global::Keys::CURRENCY_SYMBOL_MAP).value<QMap<QString, QString>>();
+    foreach (const auto& key, map.keys()) {
+        currencySymbol.append(QString("%1(%2)").arg(key, map.value(key)));
+    }
+
+    combox->addItems(currencySymbol);
+}
+
 /**
  * @brief GeneralInterface::clearGridLayoutChiledren    清空QGridLayout的子控件
  * @param layout    

+ 34 - 1
src/utils/GeneralInterface.h

@@ -9,7 +9,12 @@
 #include <QPushButton>
 #include <QPalette>
 #include <QLineEdit>
+#include <QListWidget>
+#include <QTableWidget>
+#include <QTreeWidget>
+#include <QTextEdit>
 #include <QScrollArea>
+#include <QScrollerProperties>
 
 #include "DataTypeDef.h"
 #include "CustomComboBox.h"
@@ -98,7 +103,31 @@ public:
 
     static void setCheckBoxChecked(const QWidget* widget, const bool& checked);
 
+    // 触摸滚动相关方法
     static void setTouchScroller(QScrollArea* area);
+    static void setTouchScroller(QListWidget* listWidget);
+    static void setTouchScroller(QTableWidget* tableWidget);
+    static void setTouchScroller(QTreeWidget* treeWidget);
+    static void setTouchScroller(QTextEdit* textEdit);
+    static void setTouchScroller(QAbstractScrollArea* scrollArea);
+    /**
+     * @brief 设置控件及其标签的可见性
+     * @param control 控件指针
+     * @param label 标签指针(可选)
+     */
+    static void setControlEnabled(QWidget* control, QWidget* label, const int& userType);
+    static void setControlVisiabled(QWidget* control, QWidget* label, const int& userType);
+    
+    // 高级触摸滚动配置
+    static void setAdvancedTouchScroller(QAbstractScrollArea* scrollArea, 
+                                       const QScrollerProperties& properties = QScrollerProperties());
+    static void setTouchScrollerWithProperties(QAbstractScrollArea* scrollArea,
+                                             bool enableOvershoot = true,
+                                             bool enableFlick = true,
+                                             qreal decelerationFactor = 0.125);
+    
+    // 批量设置触摸滚动
+    static void setTouchScrollerForChildren(QWidget* parent, const QString& className = QString());
 
     static QString getWindowTitle(const int& type);
     static QString getLogFilePath(const int& type);
@@ -107,6 +136,7 @@ public:
 
     static gui_state_enum getGuiState(const charge_prepare_enum& form, const int& state = 0);
     static gui_state_enum getGuiStateAuthForm(const int& state = 0);
+    static int getAuthShowType(const bool& qrEnable, const bool& cardEnable, const bool& posEnable);
     static gui_state_enum getGuiStatePrepareForm(const int& state = 0);
     static gui_state_enum getGuiStateChargingForm(const int& state = 0);
     static gui_state_enum getGuiStateFinishForm(const int& state = 0);
@@ -120,6 +150,10 @@ public:
     static int getMaxHeight(QWidget* widget);
     static void initTimezoneComboBox(CustomComboBox* combox);
     static void initLanguageComboBox(CustomComboBox* combox);
+    static void initCurrencySymbolMap();
+    static void initCurrencySymbolComboBox(CustomComboBox* combox);
+    static QString getCurrencySymbol(const QString& str);
+    static QString getCurrencySymbol(CustomComboBox* combox);
 
     static void clearGridLayoutChiledren(QGridLayout* layout);
     static void gridLayoutAddWidget(QGridLayout* layout, QWidget* widget, int row = -1, int col = 0);
@@ -193,7 +227,6 @@ public:
     static void sortByStackLevel(QList<charging_profiles_detail_info_t>& list);
     static int getMaxChargingProfileId(QList<charging_profiles_detail_info_t>& list);
     static QString getVersion(const QString& appName);
-
 };
 
 

+ 14 - 4
src/utils/Globals.cpp

@@ -22,10 +22,20 @@ Globals *Globals::instance()
 
 void Globals::setValue(const QString &key, const QVariant &value)
 {
-    QMutexLocker locker(&m_mutex);
-    if (m_values.value(key) != value) {
-        m_values.insert(key, value);
-        // emit valueChanged(key, value);
+    bool shouldEmit = false;
+    QVariant oldValue;
+    
+    {
+        QMutexLocker locker(&m_mutex);
+        oldValue = m_values.value(key);
+        if (oldValue != value) {
+            m_values.insert(key, value);
+            shouldEmit = true;
+        }
+    }
+    
+    // 在锁外发出信号,避免死锁
+    if (shouldEmit) {
         signalGeneration(key, value);
     }
 }

+ 17 - 16
src/utils/NFCReaderWorker.cpp

@@ -73,13 +73,14 @@ void NFCReaderWorker::doWork(const QString& portName, int gunId, int timeout)
     emit resultReady(AuthError::SUCCESS, cardId_str);
 }
 
-void NFCReaderWorker::doReadCard(charging_control_info_t& data)
+void NFCReaderWorker::doReadCard(const charging_control_info_t& data)
 {
+    charging_control_info_t result = data;
     m_activeReader = std::make_unique<M4255NFCHelper>();
     if (m_activeReader->isPortOpen()) {
         LOG_INFO(QString("Gun %1: NFCReaderWorker is busy, another operation is in progress.").arg(data.gunID));
-        data.nfcExecResult = AuthError::WAITING_FOR_OTHER_INSTANCE;
-        emit execResultReady(data);
+        result.nfcExecResult = AuthError::WAITING_FOR_OTHER_INSTANCE;
+        emit execResultReady(result);
         return;
     }
 
@@ -87,30 +88,30 @@ void NFCReaderWorker::doReadCard(charging_control_info_t& data)
     int initResult = m_activeReader->init(m_tcu_cfg.rs485_port_name);
     if (initResult != 0) {
         LOG_ERROR(QString("Gun %1: NFCReaderWorker init failed, error code: %2").arg(QString::number(data.gunID)).arg(initResult));
-        data.nfcExecResult = AuthError::INIT_FAILED;
-        emit execResultReady(data);
+        result.nfcExecResult = AuthError::INIT_FAILED;
+        emit execResultReady(result);
         return;
     }
     LOG_INFO(QString("Gun %1: NFC device initialization completed.").arg(QString::number(data.gunID)));
 
     if (m_activeReader->setBeep(1) != 0) {
         m_activeReader->closePort();
-        data.nfcExecResult = AuthError::INIT_FAILED;
-        emit execResultReady(data);
+        result.nfcExecResult = AuthError::INIT_FAILED;
+        emit execResultReady(result);
         return;
     }
 
     if (m_activeReader->setReadOnce(M4255_READ_ONLYONCE) != 0) {
         m_activeReader->closePort();
-        data.nfcExecResult = AuthError::INIT_FAILED;
-        emit execResultReady(data);
+        result.nfcExecResult = AuthError::INIT_FAILED;
+        emit execResultReady(result);
         return;
     }
 
     if (m_activeReader->setWorkMode(M4255_AUTO_READ_CARDID) != 0) {
         m_activeReader->closePort();
-        data.nfcExecResult = AuthError::INIT_FAILED;
-        emit execResultReady(data);
+        result.nfcExecResult = AuthError::INIT_FAILED;
+        emit execResultReady(result);
         return;
     }
 
@@ -120,8 +121,8 @@ void NFCReaderWorker::doReadCard(charging_control_info_t& data)
     if (ret != 0 || cardId.isEmpty()) {
         m_activeReader->closePort();
         LOG_INFO(QString("Gun %1: NFC device: Read card id timeout or failed.").arg(QString::number(data.gunID)));
-        data.nfcExecResult = AuthError::READ_CARD_FAILED;
-        emit execResultReady(data);
+        result.nfcExecResult = AuthError::READ_CARD_FAILED;
+        emit execResultReady(result);
         return;
     }
 
@@ -129,10 +130,10 @@ void NFCReaderWorker::doReadCard(charging_control_info_t& data)
     m_activeReader->forceBeep(0);
     m_activeReader->closePort();
 
-    data.cardID = QString("NFCA") + cardId.toHex().toUpper();
+    result.cardID = QString("NFCA") + cardId.toHex().toUpper();
     LOG_INFO(QString("Gun %1: NFC device: Card ID: %2").arg(QString::number(data.gunID), data.cardID));
-    data.nfcExecResult = AuthError::SUCCESS;
-    emit execResultReady(data);
+    result.nfcExecResult = AuthError::SUCCESS;
+    emit execResultReady(result);
 }
 
 void NFCReaderWorker::closePort()

+ 2 - 2
src/utils/NFCReaderWorker.h

@@ -72,7 +72,7 @@ public slots:
      * 
      * @param data 用于存储读取结果的charging_control_info_t类型的引用
      */
-    void doReadCard(charging_control_info_t& data);
+    void doReadCard(const charging_control_info_t& data);
 
     /**
      * @brief 关闭读卡器端口。
@@ -95,7 +95,7 @@ signals:
      * 
      * @param data 用于存储执行结果的charging_control_info_t类型的引用
      */
-    void execResultReady(charging_control_info_t& data);
+    void execResultReady(const charging_control_info_t& data);
 
     void readCardInfo(QString cardId);
 

+ 1 - 1
src/utils/TcpServerThread.cpp

@@ -313,7 +313,7 @@ bool TcpServerThread::chargeGunQr(const uint32_t &gun_id, const QString &qr)
  * @brief TcpServerThread::slotChargingCtl  充电控制
  * @param data   充电控制数据
  */
-void TcpServerThread::slotChargingCtl(charging_control_info_t &data)
+void TcpServerThread::slotChargingCtl(const charging_control_info_t &data)
 {
     switch (data.cmd) {
     case CHARGE_GUN_START_CMD: {

+ 1 - 1
src/utils/TcpServerThread.h

@@ -75,7 +75,7 @@ public:
     bool chargeGunQr(const uint32_t& gun_id, const QString& qr);
 
 public slots:
-    void slotChargingCtl(charging_control_info_t& data);    
+    void slotChargingCtl(const charging_control_info_t& data);
 
 private:
     // 工作线程相关

+ 269 - 0
src/utils/TouchScrollerHelper.cpp

@@ -0,0 +1,269 @@
+#include "TouchScrollerHelper.h"
+#include <QDebug>
+#include <QApplication>
+
+TouchScrollerHelper::TouchScrollerHelper(QObject *parent)
+    : QObject(parent)
+{
+}
+
+TouchScrollerHelper::~TouchScrollerHelper()
+{
+}
+
+void TouchScrollerHelper::enableTouchScrolling(QAbstractScrollArea *scrollArea)
+{
+    if (!scrollArea) return;
+    
+    setupBasicGestures(scrollArea);
+}
+
+void TouchScrollerHelper::enableTouchScrolling(QListWidget *listWidget)
+{
+    if (!listWidget) return;
+    
+    setupBasicGestures(listWidget);
+}
+
+void TouchScrollerHelper::enableTouchScrolling(QTableWidget *tableWidget)
+{
+    if (!tableWidget) return;
+    
+    setupBasicGestures(tableWidget);
+}
+
+void TouchScrollerHelper::enableTouchScrolling(QTreeWidget *treeWidget)
+{
+    if (!treeWidget) return;
+    
+    setupBasicGestures(treeWidget);
+}
+
+void TouchScrollerHelper::enableTouchScrolling(QTextEdit *textEdit)
+{
+    if (!textEdit) return;
+    
+    setupBasicGestures(textEdit);
+}
+
+void TouchScrollerHelper::enableTouchScrolling(QScrollArea *scrollArea)
+{
+    if (!scrollArea) return;
+    
+    setupBasicGestures(scrollArea);
+}
+
+void TouchScrollerHelper::setPresetScrolling(QAbstractScrollArea *scrollArea, ScrollerPreset preset)
+{
+    if (!scrollArea) return;
+    
+    setupBasicGestures(scrollArea);
+    QScroller *scroller = QScroller::scroller(scrollArea);
+    if (scroller) {
+        applyPresetToScroller(scroller, preset);
+    }
+}
+
+void TouchScrollerHelper::setPresetScrolling(QListWidget *listWidget, ScrollerPreset preset)
+{
+    if (!listWidget) return;
+    
+    setupBasicGestures(listWidget);
+    QScroller *scroller = QScroller::scroller(listWidget);
+    if (scroller) {
+        applyPresetToScroller(scroller, preset);
+    }
+}
+
+void TouchScrollerHelper::setPresetScrolling(QTableWidget *tableWidget, ScrollerPreset preset)
+{
+    if (!tableWidget) return;
+    
+    setupBasicGestures(tableWidget);
+    QScroller *scroller = QScroller::scroller(tableWidget);
+    if (scroller) {
+        applyPresetToScroller(scroller, preset);
+    }
+}
+
+void TouchScrollerHelper::setPresetScrolling(QTreeWidget *treeWidget, ScrollerPreset preset)
+{
+    if (!treeWidget) return;
+    
+    setupBasicGestures(treeWidget);
+    QScroller *scroller = QScroller::scroller(treeWidget);
+    if (scroller) {
+        applyPresetToScroller(scroller, preset);
+    }
+}
+
+void TouchScrollerHelper::setCustomScrolling(QAbstractScrollArea *scrollArea, 
+                                            const QScrollerProperties &properties)
+{
+    if (!scrollArea) return;
+    
+    setupBasicGestures(scrollArea);
+    QScroller *scroller = QScroller::scroller(scrollArea);
+    if (scroller) {
+        scroller->setScrollerProperties(properties);
+    }
+}
+
+void TouchScrollerHelper::setCustomScrolling(QListWidget *listWidget,
+                                            const QScrollerProperties &properties)
+{
+    if (!listWidget) return;
+    
+    setupBasicGestures(listWidget);
+    QScroller *scroller = QScroller::scroller(listWidget);
+    if (scroller) {
+        scroller->setScrollerProperties(properties);
+    }
+}
+
+void TouchScrollerHelper::enableTouchScrollingForWidget(QWidget *widget)
+{
+    if (!widget) return;
+    
+    // 查找所有可滚动的子控件
+    QList<QAbstractScrollArea*> scrollAreas = widget->findChildren<QAbstractScrollArea*>();
+    foreach (QAbstractScrollArea* area, scrollAreas) {
+        enableTouchScrolling(area);
+    }
+    
+    // 查找所有ListWidget
+    QList<QListWidget*> listWidgets = widget->findChildren<QListWidget*>();
+    foreach (QListWidget* listWidget, listWidgets) {
+        enableTouchScrolling(listWidget);
+    }
+    
+    // 查找所有TableWidget
+    QList<QTableWidget*> tableWidgets = widget->findChildren<QTableWidget*>();
+    foreach (QTableWidget* tableWidget, tableWidgets) {
+        enableTouchScrolling(tableWidget);
+    }
+    
+    // 查找所有TreeWidget
+    QList<QTreeWidget*> treeWidgets = widget->findChildren<QTreeWidget*>();
+    foreach (QTreeWidget* treeWidget, treeWidgets) {
+        enableTouchScrolling(treeWidget);
+    }
+    
+    // 查找所有TextEdit
+    QList<QTextEdit*> textEdits = widget->findChildren<QTextEdit*>();
+    foreach (QTextEdit* textEdit, textEdits) {
+        enableTouchScrolling(textEdit);
+    }
+}
+
+void TouchScrollerHelper::setPresetScrollingForWidget(QWidget *widget, ScrollerPreset preset)
+{
+    if (!widget) return;
+    
+    // 查找所有可滚动的子控件
+    QList<QAbstractScrollArea*> scrollAreas = widget->findChildren<QAbstractScrollArea*>();
+    foreach (QAbstractScrollArea* area, scrollAreas) {
+        setPresetScrolling(area, preset);
+    }
+    
+    // 查找所有ListWidget
+    QList<QListWidget*> listWidgets = widget->findChildren<QListWidget*>();
+    foreach (QListWidget* listWidget, listWidgets) {
+        setPresetScrolling(listWidget, preset);
+    }
+    
+    // 查找所有TableWidget
+    QList<QTableWidget*> tableWidgets = widget->findChildren<QTableWidget*>();
+    foreach (QTableWidget* tableWidget, tableWidgets) {
+        setPresetScrolling(tableWidget, preset);
+    }
+    
+    // 查找所有TreeWidget
+    QList<QTreeWidget*> treeWidgets = widget->findChildren<QTreeWidget*>();
+    foreach (QTreeWidget* treeWidget, treeWidgets) {
+        setPresetScrolling(treeWidget, preset);
+    }
+}
+
+QScrollerProperties TouchScrollerHelper::getPresetProperties(ScrollerPreset preset)
+{
+    QScrollerProperties properties;
+    
+    switch (preset) {
+    case Default:
+        // 使用默认配置
+        break;
+        
+    case Smooth:
+        // 平滑滚动配置
+        properties.setScrollMetric(QScrollerProperties::DecelerationFactor, 0.125);
+        properties.setScrollMetric(QScrollerProperties::DragVelocitySmoothingFactor, 0.5);
+        properties.setScrollMetric(QScrollerProperties::AxisLockThreshold, 0.5);
+        properties.setScrollMetric(QScrollerProperties::ScrollingCurve, QEasingCurve::OutCubic);
+        properties.setScrollMetric(QScrollerProperties::OvershootDragResistanceFactor, 0.5);
+        properties.setScrollMetric(QScrollerProperties::OvershootScrollDistanceFactor, 0.5);
+        break;
+        
+    case Fast:
+        // 快速滚动配置
+        properties.setScrollMetric(QScrollerProperties::DecelerationFactor, 0.08);
+        properties.setScrollMetric(QScrollerProperties::DragVelocitySmoothingFactor, 0.3);
+        properties.setScrollMetric(QScrollerProperties::AxisLockThreshold, 0.3);
+        properties.setScrollMetric(QScrollerProperties::ScrollingCurve, QEasingCurve::OutQuart);
+        properties.setScrollMetric(QScrollerProperties::OvershootDragResistanceFactor, 0.3);
+        properties.setScrollMetric(QScrollerProperties::OvershootScrollDistanceFactor, 0.3);
+        break;
+        
+    case Responsive:
+        // 响应式滚动配置
+        properties.setScrollMetric(QScrollerProperties::DecelerationFactor, 0.15);
+        properties.setScrollMetric(QScrollerProperties::DragVelocitySmoothingFactor, 0.7);
+        properties.setScrollMetric(QScrollerProperties::AxisLockThreshold, 0.7);
+        properties.setScrollMetric(QScrollerProperties::ScrollingCurve, QEasingCurve::OutBack);
+        properties.setScrollMetric(QScrollerProperties::OvershootDragResistanceFactor, 0.7);
+        properties.setScrollMetric(QScrollerProperties::OvershootScrollDistanceFactor, 0.7);
+        break;
+        
+    case Custom:
+        // 自定义配置 - 使用默认值
+        break;
+    }
+    
+    return properties;
+}
+
+void TouchScrollerHelper::disableTouchScrolling(QAbstractScrollArea *scrollArea)
+{
+    if (!scrollArea) return;
+    
+    QScroller::ungrabGesture(scrollArea);
+    QScroller::ungrabGesture(scrollArea->viewport());
+}
+
+void TouchScrollerHelper::disableTouchScrolling(QWidget *widget)
+{
+    if (!widget) return;
+    
+    // 查找所有可滚动的子控件并禁用触摸滚动
+    QList<QAbstractScrollArea*> scrollAreas = widget->findChildren<QAbstractScrollArea*>();
+    foreach (QAbstractScrollArea* area, scrollAreas) {
+        disableTouchScrolling(area);
+    }
+}
+
+void TouchScrollerHelper::applyPresetToScroller(QScroller *scroller, ScrollerPreset preset)
+{
+    if (!scroller) return;
+    
+    QScrollerProperties properties = getPresetProperties(preset);
+    scroller->setScrollerProperties(properties);
+}
+
+void TouchScrollerHelper::setupBasicGestures(QAbstractScrollArea *scrollArea)
+{
+    if (!scrollArea) return;
+    
+    // 设置触摸手势
+    QScroller::grabGesture(scrollArea, QScroller::TouchGesture);
+    QScroller::grabGesture(scrollArea->viewport(), QScroller::LeftMouseButtonGesture);
+} 

+ 77 - 0
src/utils/TouchScrollerHelper.h

@@ -0,0 +1,77 @@
+#ifndef TOUCHSCROLLERHELPER_H
+#define TOUCHSCROLLERHELPER_H
+
+#include <QObject>
+#include <QWidget>
+#include <QAbstractScrollArea>
+#include <QListWidget>
+#include <QTableWidget>
+#include <QTreeWidget>
+#include <QTextEdit>
+#include <QScrollArea>
+#include <QScroller>
+#include <QScrollerProperties>
+#include <QEasingCurve>
+
+/**
+ * @brief TouchScrollerHelper 触摸滚动助手类
+ * 
+ * 提供完善的触摸屏滚动功能,支持多种控件类型和自定义配置
+ */
+class TouchScrollerHelper : public QObject
+{
+    Q_OBJECT
+
+public:
+    // 预设配置枚举
+    enum ScrollerPreset {
+        Default,        // 默认配置
+        Smooth,         // 平滑滚动
+        Fast,           // 快速滚动
+        Responsive,     // 响应式滚动
+        Custom          // 自定义配置
+    };
+
+    explicit TouchScrollerHelper(QObject *parent = nullptr);
+    ~TouchScrollerHelper();
+
+    // 基本触摸滚动设置
+    static void enableTouchScrolling(QAbstractScrollArea *scrollArea);
+    static void enableTouchScrolling(QListWidget *listWidget);
+    static void enableTouchScrolling(QTableWidget *tableWidget);
+    static void enableTouchScrolling(QTreeWidget *treeWidget);
+    static void enableTouchScrolling(QTextEdit *textEdit);
+    static void enableTouchScrolling(QScrollArea *scrollArea);
+
+    // 预设配置设置
+    static void setPresetScrolling(QAbstractScrollArea *scrollArea, ScrollerPreset preset);
+    static void setPresetScrolling(QListWidget *listWidget, ScrollerPreset preset);
+    static void setPresetScrolling(QTableWidget *tableWidget, ScrollerPreset preset);
+    static void setPresetScrolling(QTreeWidget *treeWidget, ScrollerPreset preset);
+
+    // 高级配置设置
+    static void setCustomScrolling(QAbstractScrollArea *scrollArea, 
+                                  const QScrollerProperties &properties);
+    static void setCustomScrolling(QListWidget *listWidget,
+                                  const QScrollerProperties &properties);
+
+    // 批量设置
+    static void enableTouchScrollingForWidget(QWidget *widget);
+    static void setPresetScrollingForWidget(QWidget *widget, ScrollerPreset preset);
+
+    // 获取预设配置
+    static QScrollerProperties getPresetProperties(ScrollerPreset preset);
+
+    // 禁用触摸滚动
+    static void disableTouchScrolling(QAbstractScrollArea *scrollArea);
+    static void disableTouchScrolling(QWidget *widget);
+
+private:
+    // 应用预设配置
+    static void applyPresetToScroller(QScroller *scroller, ScrollerPreset preset);
+    
+    // 设置基本手势
+    static void setupBasicGestures(QAbstractScrollArea *scrollArea);
+};
+
+#endif // TOUCHSCROLLERHELPER_H 

+ 27 - 1
src/widgets/custom/BaseWidget.cpp

@@ -1,8 +1,16 @@
 #include "BaseWidget.h"
 
+#include "DataTypeDef.h"
+
 BaseWidget::BaseWidget(QWidget *parent)
     : QWidget{parent}
-{}
+    , m_userType(General::UserType::OPERATOR)
+{
+    messageBox = new DialogMessageBox();
+    messageBox->setParent(parent);
+    messageBox->setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
+    messageBox->setWindowModality(Qt::WindowModal);
+}
 
 int BaseWidget::currentForm() const
 {
@@ -33,3 +41,21 @@ void BaseWidget::setIsModify(bool newIsModify)
 {
     m_isModify = newIsModify;
 }
+
+int BaseWidget::userType() const
+{
+    return m_userType;
+}
+
+void BaseWidget::setUserType(int newUserType)
+{
+    if (m_userType != newUserType) {
+        m_userType = newUserType;
+        emit userTypeChanged(newUserType);
+    }
+}
+
+DialogMessageBox *BaseWidget::getMessageBox() const
+{
+    return messageBox;
+}

+ 18 - 0
src/widgets/custom/BaseWidget.h

@@ -3,6 +3,7 @@
 
 #include <QObject>
 #include <QWidget>
+#include "OtherSettings/dialog/DialogMessageBox.h"
 
 /**
  * @class BaseWidget
@@ -75,6 +76,11 @@ public:
      */
     void setIsModify(bool newIsModify);
 
+    int userType() const;
+    void setUserType(int newUserType);
+
+    DialogMessageBox *getMessageBox() const;
+
 signals:
     /**
      * @brief 当标题刷新时发出此信号。
@@ -83,6 +89,15 @@ signals:
      */
     void refreshTitles(const QString& title);
 
+    void refreshProgressBar(const int& value);
+    
+    /**
+     * @brief 当用户类型改变时发出此信号。
+     * 
+     * @param userType 新的用户类型。
+     */
+    void userTypeChanged(int userType);
+
 private:
     /**
      * @brief 当前表单的索引。
@@ -98,6 +113,9 @@ private:
      * @brief 修改标记。
      */
     bool m_isModify = false;
+
+    int m_userType;
+    DialogMessageBox* messageBox;
 };
 
 #endif // BASEWIDGET_H

+ 441 - 58
src/widgets/custom/CustomComboBox.cpp

@@ -7,14 +7,38 @@
 #include <QApplication>
 #include <QDesktopWidget>
 #include <QScroller>
+#include <QScrollBar>
+#include <QKeyEvent>
+#include <QFocusEvent>
+#include <QResizeEvent>
+#include <QShowEvent>
+#include <QScreen>
+#include <QTimer>
 
 #include "GeneralInterface.h"
 
+CustomComboBoxPopup::CustomComboBoxPopup(QWidget *parent)
+    : QWidget(parent)
+{
+    setWindowFlags(Qt::Popup | Qt::FramelessWindowHint);
+    setAttribute(Qt::WA_TranslucentBackground);
+}
+
+void CustomComboBoxPopup::resizeEvent(QResizeEvent *event)
+{
+    QWidget::resizeEvent(event);
+    emit sizeChanged(event->size().width(), event->size().height());
+}
+
 CustomComboBox::CustomComboBox(QWidget *parent)
     : QWidget(parent)
 {
     // setFixedHeight(40);
 
+    // 设置焦点策略
+    setFocusPolicy(Qt::StrongFocus);
+    setTabOrder(this, this);
+
     displayLabel = new QLabel(this);
     displayLabel->setText("Please Select...");
     displayLabel->setAlignment(Qt::AlignCenter);
@@ -28,30 +52,139 @@ CustomComboBox::CustomComboBox(QWidget *parent)
     QHBoxLayout *mainLayout = new QHBoxLayout(this);
     mainLayout->addWidget(displayLabel, 1);
     mainLayout->addWidget(arrowBtn);
-    // mainLayout->setContentsMargins(10, 10, 10, 10);
+    mainLayout->setSpacing(4);
+    mainLayout->setContentsMargins(0, 0, 0, 0);
     setLayout(mainLayout);
 
-    // 下拉列表
-    listWidget = new QListWidget();
-    listWidget->setWindowFlags(Qt::Popup);
-    listWidget->setFrameShape(QFrame::Box);
-    listWidget->setFrameShadow(QFrame::Plain);
-    // listWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+    // 创建弹出窗口
+    createPopupWidget();
 
-    QScroller::grabGesture(listWidget,              QScroller::TouchGesture);
-    QScroller::grabGesture(listWidget->viewport(),  QScroller::LeftMouseButtonGesture);
+    qApp->installEventFilter(this);
+}
 
-    connect(listWidget, &QListWidget::itemClicked, this, &CustomComboBox::onItemClicked);
+void CustomComboBox::createPopupWidget()
+{
+    // 创建弹出窗口容器
+    popupWidget = new CustomComboBoxPopup();
+    
+    // 连接大小变化信号
+    connect(popupWidget, &CustomComboBoxPopup::sizeChanged, this, &CustomComboBox::onPopupSizeChanged);
+    
+    // 创建主框架
+    QFrame *mainFrame = new QFrame(popupWidget);
+    mainFrame->setFrameShape(QFrame::Box);
+    mainFrame->setFrameShadow(QFrame::Plain);
+    mainFrame->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+    mainFrame->setStyleSheet(
+        "QFrame { "
+        "    background-color: #2A2A2F; "
+        "    border: 1px solid #3A3A3F; "
+        "    border-radius: 10px; "
+        "}"
+    );
+    
+    // 创建滚动区域
+    scrollArea = new QScrollArea(mainFrame);
+    scrollArea->setWidgetResizable(true);
+    scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+    scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+    scrollArea->setFrameShape(QFrame::NoFrame);
+    scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+    scrollArea->setStyleSheet(
+        "QScrollArea { "
+        "    background-color: #2A2A2F; "
+        "    border: none; "
+        "    border-radius: 10px; "
+        "}"
+    );
+    
+    // 创建滚动内容容器
+    scrollContent = new QWidget();
+    scrollLayout = new QVBoxLayout(scrollContent);
+    scrollLayout->setSpacing(0);
+    scrollLayout->setContentsMargins(0, 0, 0, 0);
+    scrollContent->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+    scrollContent->setStyleSheet(
+        "QWidget { "
+        "    background-color: #2A2A2F; "
+        "    border: none; "
+        "}"
+    );
+    
+    scrollArea->setWidget(scrollContent);
+    
+    // 设置弹出窗口布局
+    QVBoxLayout *popupLayout = new QVBoxLayout();
+    popupLayout->addWidget(mainFrame);
+    popupLayout->setContentsMargins(0, 0, 0, 0);
 
-    qApp->installEventFilter(this);
+    popupWidget->setLayout(popupLayout);
+    
+    // 设置触摸滚动
+    GeneralInterface::setTouchScroller(scrollArea);
+}
+
+QToolButton* CustomComboBox::createItemButton(const QString &text, int index)
+{
+    QToolButton *button = new QToolButton();
+    button->setText(text);
+    button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+    button->setFixedHeight(50);
+    button->setCheckable(true); // 确保按钮可以被选中
+    button->setStyleSheet(
+        "QToolButton { "
+        "    border: none; "
+        "    background-color: #2A2A2F; "
+        "    text-align: center; "
+        "    font-size: 22px; "
+        "    color: white; "
+        "    padding: 0px; "
+        "    margin: 0px; "
+        "    border-radius: 0px; "
+        "} "
+        "QToolButton:hover { "
+        "    background-color: #3A3A3F; "
+        "    color: #00C1C3; "
+        "} "
+        "QToolButton:pressed { "
+        "    background-color: #00C1C3; "
+        "    color: #2A2A2F; "
+        "} "
+        "QToolButton:checked { "
+        "    background-color: #00C1C3; "
+        "    color: #2A2A2F; "
+        "    font-weight: bold; "
+        "}"
+    );
+    
+    // 存储按钮索引
+    button->setProperty("itemIndex", index);
+    
+    // 连接点击信号
+    connect(button, &QToolButton::clicked, this, &CustomComboBox::onItemClicked);
+    
+    return button;
 }
 
 void CustomComboBox::addItem(const QString &text)
 {
-    QListWidgetItem* item = new QListWidgetItem(text);
-    item->setTextAlignment(Qt::AlignCenter);
-    listWidget->addItem(item);
-    setCurrentIndex();
+    int index = itemButtons.size();
+    QToolButton *button = createItemButton(text, index);
+    itemButtons.append(button);
+    
+    // 将按钮添加到布局中,确保铺满
+    scrollLayout->addWidget(button);
+    
+    // 如果是第一个项目,设置为当前选中
+    if (index == 0) {
+        setCurrentIndex(0);
+        // qDebug() << "First item added and set as current:" << text;
+    }
+    // 如果当前没有选中项目,设置为第一个
+    else if (m_currentIndex == -1) {
+        setCurrentIndex(0);
+        // qDebug() << "No current selection, setting first item as current:" << itemButtons[0]->text();
+    }
 }
 
 void CustomComboBox::addItems(const QStringList &list)
@@ -63,9 +196,24 @@ void CustomComboBox::addItems(const QStringList &list)
 
 void CustomComboBox::clear()
 {
-    listWidget->clear();
-    displayLabel->setText(tr("Please Select..."));
+    // 清除所有按钮
+    foreach (QToolButton *button, itemButtons) {
+        scrollLayout->removeWidget(button);
+        delete button;
+        update();
+    }
+    itemButtons.clear();
+    
+    // 重置状态
     m_currentIndex = -1;
+    displayLabel->setText(tr("Please Select..."));
+    
+    // 发送信号通知状态改变
+    emit currentIndexChanged(-1);
+    emit currentTextChanged(tr("Please Select..."));
+    
+    // 验证状态
+    validateState();
 }
 
 QString CustomComboBox::currentText() const
@@ -75,25 +223,44 @@ QString CustomComboBox::currentText() const
 
 void CustomComboBox::setCurrentIndex(int index)
 {
+    // 如果索引无效,重置状态
+    if (index < 0 || index >= itemButtons.size()) {
+        if (m_currentIndex != -1) {
+            m_currentIndex = -1;
+            displayLabel->setText(tr("Please Select..."));
+            emit currentIndexChanged(-1);
+            emit currentTextChanged(tr("Please Select..."));
+        }
+        validateState();
+        return;
+    }
+    
+    // 如果索引相同,不重复设置
     if (m_currentIndex == index) return;
+    
+    // 设置按钮选中状态
+    setButtonChecked(index);
+    
     m_currentIndex = index;
-    listWidget->setCurrentRow(index);
-    displayLabel->setText(listWidget->currentItem()->text());
-    emit currentIndexChanged(index);
-    emit currentTextChanged(listWidget->currentItem()->text());
+    
+    // 更新显示文本
+    if (index >= 0 && index < itemButtons.size()) {
+        displayLabel->setText(itemButtons[index]->text());
+        emit currentIndexChanged(index);
+        emit currentTextChanged(itemButtons[index]->text());
+    }
+    
+    // 验证状态
+    validateState();
 }
 
 void CustomComboBox::setCurrentText(const QString &text)
 {
-    auto row = listWidget->count();
     if (text == displayLabel->text()) return;
-    for (int index = 0; index < row; index ++) {
-        if (text == listWidget->item(index)->text()) {
-            m_currentIndex = index;
-            listWidget->setCurrentRow(index);
-            displayLabel->setText(listWidget->currentItem()->text());
-            emit currentIndexChanged(index);
-            emit currentTextChanged(text);
+    
+    for (int index = 0; index < itemButtons.size(); index++) {
+        if (text == itemButtons[index]->text()) {
+            setCurrentIndex(index);
             return;
         }
     }
@@ -106,64 +273,280 @@ int CustomComboBox::currentIndex() const
 
 int CustomComboBox::findText(const QString &text)
 {
-    for (int row = 0; row < listWidget->count(); row ++) {
-        if (text == listWidget->item(row)->text()) {
-            return row;
+    for (int index = 0; index < itemButtons.size(); index++) {
+        if (text == itemButtons[index]->text()) {
+            return index;
         }
     }
-
     return -1;
 }
 
 int CustomComboBox::count()
 {
-    return listWidget->count();
+    return itemButtons.size();
+}
+
+void CustomComboBox::updatePopupSize()
+{
+    if (!popupWidget) return;
+    
+    // 计算弹出窗口的大小
+    int itemHeight = 50;
+    int maxHeight = GeneralInterface::getMaxHeight(this);
+    int contentHeight = itemButtons.size() * itemHeight;
+    int popupHeight = qMin(contentHeight, maxHeight);
+    
+    // qDebug() << "Popup height calculation:";
+    // qDebug() << "  Item count:" << itemButtons.size();
+    // qDebug() << "  Item height:" << itemHeight;
+    // qDebug() << "  Content height:" << contentHeight;
+    // qDebug() << "  Max height:" << maxHeight;
+    // qDebug() << "  Calculated height:" << popupHeight;
+    
+    // 确保最小高度
+    popupHeight = qMax(popupHeight, 100);
+    
+    // 设置弹出窗口大小,确保宽度与主控件一致
+    popupWidget->resize(width(), popupHeight);
+    
+    // 强制设置所有按钮的宽度
+    foreach (QToolButton *button, itemButtons) {
+        button->setFixedWidth(width());
+    }
+    
+    // 强制更新布局和滚动区域
+    popupWidget->updateGeometry();
+    if (scrollContent) {
+        scrollContent->updateGeometry();
+        scrollContent->adjustSize();
+    }
+    if (scrollArea) {
+        scrollArea->updateGeometry();
+        scrollArea->adjustSize();
+        // 设置滚动区域的大小策略
+        scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+    }
+    
+    // 确保滚动区域能够正确显示
+    if (scrollArea) {
+        int scrollAreaHeight = popupHeight - POPUPSRCOLLAREA_OFFSET; // 留出边框空间
+        scrollArea->setMinimumHeight(scrollAreaHeight);
+        scrollArea->setMaximumHeight(scrollAreaHeight);
+        scrollArea->updateGeometry();
+    }
+}
+
+void CustomComboBox::showPopup()
+{
+    if (!popupWidget || isDisplay) return;
+    
+    updatePopupSize();
+    
+    // 计算弹出位置,确保不超出屏幕边界
+    QPoint globalPos = mapToGlobal(QPoint(0, height()));
+    QRect screenGeometry = QApplication::primaryScreen()->geometry();
+    
+    // 检查是否会超出屏幕底部
+    if (globalPos.y() + popupWidget->height() > screenGeometry.bottom()) {
+        // 如果会超出底部,则向上弹出
+        globalPos = mapToGlobal(QPoint(0, -popupWidget->height()));
+    }
+    
+    // 检查是否会超出屏幕右边界
+    if (globalPos.x() + popupWidget->width() > screenGeometry.right()) {
+        globalPos.setX(screenGeometry.right() - popupWidget->width());
+    }
+    
+    popupWidget->move(globalPos);
+    popupWidget->show();
+    popupWidget->raise(); // 确保弹出窗口在最前面
+    
+    // 再次确保按钮宽度正确并更新滚动区域
+    QTimer::singleShot(0, this, [this]() {
+        foreach (QToolButton *button, itemButtons) {
+            button->setFixedWidth(popupWidget->width());
+        }
+        // 强制更新滚动区域
+        if (scrollArea) {
+            scrollArea->updateGeometry();
+            scrollArea->adjustSize();
+            // 确保滚动区域大小正确
+            int scrollAreaHeight = popupWidget->height() - POPUPSRCOLLAREA_OFFSET;
+            scrollArea->setMinimumHeight(scrollAreaHeight);
+            scrollArea->setMaximumHeight(scrollAreaHeight);
+        }
+    });
+    
+    isDisplay = true;
+    arrowBtn->setIcon(QIcon(":/icons/packup.png"));
+}
+
+void CustomComboBox::hidePopup()
+{
+    if (!popupWidget || !isDisplay) return;
+    
+    popupWidget->hide();
+    isDisplay = false;
+    arrowBtn->setIcon(QIcon(":/icons/spread.png"));
 }
 
 void CustomComboBox::mousePressEvent(QMouseEvent *event)
 {
     QWidget::mousePressEvent(event);
+    if (!isEnabled()) return;
 
     if (isDisplay) {
-        listWidget->hide();
-        isDisplay = false;
-        arrowBtn->setIcon(QIcon(":/icons/spread.png"));
+        hidePopup();
     } else {
-        QPoint pos = mapToGlobal(QPoint(0, height()));
-        listWidget->move(pos);
-        auto height = (listWidget->count() * 60) > GeneralInterface::getMaxHeight(this) ? GeneralInterface::getMaxHeight(this) : (listWidget->count() * 60);
-        listWidget->resize(width(), height);
-        listWidget->show();
-        isDisplay = true;
-        arrowBtn->setIcon(QIcon(":/icons/packup.png"));
+        showPopup();
     }
 }
 
-void CustomComboBox::onItemClicked(QListWidgetItem *item)
+void CustomComboBox::onItemClicked()
 {
-    if (item->text() != displayLabel->text()) {
-        displayLabel->setText(item->text());
-        m_currentIndex = listWidget->row(item);
-        listWidget->hide();
-        isDisplay = false;
-        arrowBtn->setIcon(QIcon(":/icons/spread.png"));
-        emit currentIndexChanged(m_currentIndex);
-        emit currentTextChanged(item->text());
+    QToolButton *senderButton = qobject_cast<QToolButton*>(sender());
+    if (!senderButton) return;
+    
+    int index = senderButton->property("itemIndex").toInt();
+    if (index >= 0 && index < itemButtons.size()) {
+        // 设置按钮选中状态(这会自动实现互斥)
+        setButtonChecked(index);
+        
+        // 更新当前索引和显示文本
+        m_currentIndex = index;
+        displayLabel->setText(senderButton->text());
+        
+        // 发送信号
+        emit currentIndexChanged(index);
+        emit currentTextChanged(senderButton->text());
+        
+        // 隐藏弹出窗口
+        hidePopup();
+        
+        // 设置焦点回到主控件
+        // setFocus();
     }
 }
 
 bool CustomComboBox::eventFilter(QObject *obj, QEvent *event)
 {
     if (isDisplay && event->type() == QEvent::MouseButtonPress) {
+        if (!isEnabled()) return true;
         QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
         QWidget *widget = QApplication::widgetAt(mouseEvent->globalPos());
-        // 如果点击的不是listWidget和不是CustomComboBox本身
-        if (widget != listWidget && widget != this && !listWidget->isAncestorOf(widget) && !this->isAncestorOf(widget)) {
-            listWidget->hide();
-            isDisplay = false;
-            arrowBtn->setIcon(QIcon(":/icons/spread.png"));
+        // 如果点击的不是popupWidget和不是CustomComboBox本身
+        if (widget != popupWidget && widget != this && !popupWidget->isAncestorOf(widget) && !this->isAncestorOf(widget)) {
+            hidePopup();
             return true; // 拦截事件
         }
     }
+    
     return QWidget::eventFilter(obj, event);
 }
+
+void CustomComboBox::resizeEvent(QResizeEvent *event)
+{
+    QWidget::resizeEvent(event);
+    // 当控件大小改变时,更新弹出窗口的大小
+    if (isDisplay) {
+        updatePopupSize();
+    }
+}
+
+void CustomComboBox::showEvent(QShowEvent *event)
+{
+    QWidget::showEvent(event);
+    // 确保控件可见时能够接收焦点
+    if (focusPolicy() != Qt::NoFocus) {
+        // setFocus();
+    }
+}
+
+void CustomComboBox::clearAllButtonStates()
+{
+    if (itemButtons.isEmpty()) {
+        // qDebug() << "Button list is empty, nothing to clear";
+        return;
+    }
+    
+    foreach (QToolButton *button, itemButtons) {
+        button->setChecked(false);
+    }
+    
+    // qDebug() << "Cleared all button states, button count:" << itemButtons.size();
+}
+
+void CustomComboBox::setButtonChecked(int index)
+{
+    // 如果按钮列表为空,直接返回
+    if (itemButtons.isEmpty()) {
+        // qDebug() << "Button list is empty, cannot set checked state";
+        return;
+    }
+    
+    if (index >= 0 && index < itemButtons.size()) {
+        // 先清除所有按钮的选中状态
+        clearAllButtonStates();
+        
+        // 设置指定按钮为选中状态
+        itemButtons[index]->setChecked(true);
+        
+        // 验证互斥功能
+        int checkedCount = 0;
+        foreach (QToolButton *button, itemButtons) {
+            if (button->isChecked()) {
+                checkedCount++;
+            }
+        }
+        Q_ASSERT(checkedCount == 1); // 确保只有一个按钮被选中
+        
+        // 调试输出
+        // qDebug() << "Button" << index << "checked, total checked:" << checkedCount;
+    } else {
+        // qDebug() << "Invalid index:" << index << "button count:" << itemButtons.size();
+    }
+}
+
+void CustomComboBox::validateState()
+{
+    int checkedCount = 0;
+    int checkedIndex = -1;
+    
+    for (int i = 0; i < itemButtons.size(); ++i) {
+        if (itemButtons[i]->isChecked()) {
+            checkedCount++;
+            checkedIndex = i;
+        }
+    }
+    
+    // qDebug() << "State validation:";
+    // qDebug() << "  Button count:" << itemButtons.size();
+    // qDebug() << "  Checked count:" << checkedCount;
+    // qDebug() << "  Current index:" << m_currentIndex;
+    // qDebug() << "  Checked index:" << checkedIndex;
+    // qDebug() << "  Display text:" << displayLabel->text();
+    
+    // 验证状态一致性
+    if (itemButtons.isEmpty()) {
+        Q_ASSERT(m_currentIndex == -1);
+        Q_ASSERT(displayLabel->text() == tr("Please Select..."));
+    } else {
+        Q_ASSERT(checkedCount <= 1); // 最多只有一个按钮被选中
+        if (checkedCount == 1) {
+            Q_ASSERT(checkedIndex == m_currentIndex); // 选中索引应该匹配
+            Q_ASSERT(displayLabel->text() == itemButtons[checkedIndex]->text()); // 显示文本应该匹配
+        }
+    }
+}
+
+void CustomComboBox::onPopupSizeChanged(int width, int height)
+{
+    if (scrollArea) {
+        int scrollAreaHeight = height - POPUPSRCOLLAREA_OFFSET; // 留出边框空间
+        scrollArea->setMaximumWidth(width);
+        scrollArea->setMinimumHeight(scrollAreaHeight);
+        scrollArea->setMaximumHeight(scrollAreaHeight);
+        scrollArea->updateGeometry();
+        scrollArea->adjustSize();
+    }
+}

+ 37 - 5
src/widgets/custom/CustomComboBox.h

@@ -4,9 +4,13 @@
 #include <QWidget>
 #include <QLabel>
 #include <QToolButton>
-#include <QListWidget>
+#include <QScrollArea>
 #include <QVBoxLayout>
 #include <QMouseEvent>
+#include <QFrame>
+#include <QList>
+
+#define POPUPSRCOLLAREA_OFFSET 3
 
 /**
  * @class CustomComboBox
@@ -28,6 +32,19 @@
  *     qDebug() << "Current index changed to:" << index;
  * });
  */
+class CustomComboBoxPopup : public QWidget
+{
+    Q_OBJECT
+public:
+    explicit CustomComboBoxPopup(QWidget *parent = nullptr);
+    
+protected:
+    void resizeEvent(QResizeEvent *event) override;
+    
+signals:
+    void sizeChanged(int width, int height);
+};
+
 class CustomComboBox : public QWidget
 {
     Q_OBJECT
@@ -50,17 +67,32 @@ signals:
 
 protected:
     void mousePressEvent(QMouseEvent *event) override;
-    void extracted(QWidget *&widget);
+    void resizeEvent(QResizeEvent *event) override;
+    void showEvent(QShowEvent *event) override;
     bool eventFilter(QObject *obj, QEvent *event) override;
     
 private slots:
-    void onItemClicked(QListWidgetItem *item);
+    void onItemClicked();
+    void onPopupSizeChanged(int width, int height);
+
+private:
+    void createPopupWidget();
+    void updatePopupSize();
+    void hidePopup();
+    void showPopup();
+    QToolButton* createItemButton(const QString &text, int index);
+    void clearAllButtonStates();
+    void setButtonChecked(int index);
+    void validateState();
 
 private:
     QLabel *displayLabel;
     QToolButton *arrowBtn;
-    QListWidget *listWidget;
-    QWidget *popupWidget;
+    CustomComboBoxPopup *popupWidget;
+    QScrollArea *scrollArea;
+    QWidget *scrollContent;
+    QVBoxLayout *scrollLayout;
+    QList<QToolButton*> itemButtons;
     bool isDisplay = false;
     int m_currentIndex = -1;
 };

+ 3 - 0
src/widgets/custom/CustomCommandLinkButton.cpp

@@ -47,12 +47,14 @@ void CustomCommandLinkButton::setBackground()
 
 void CustomCommandLinkButton::mouseMoveEvent(QMouseEvent *event)
 {
+    if (!isEnabled()) return;
     m_background->setPixmap(QPixmap(":/images/background/custom_btn_press_background.png"));
     QWidget::mouseMoveEvent(event);
 }
 
 void CustomCommandLinkButton::mousePressEvent(QMouseEvent *event)
 {
+    if (!isEnabled()) return;
     m_background->setPixmap(QPixmap(":/images/background/custom_btn_press_background.png"));
     emit clicked();
     QWidget::mousePressEvent(event);
@@ -60,6 +62,7 @@ void CustomCommandLinkButton::mousePressEvent(QMouseEvent *event)
 
 void CustomCommandLinkButton::mouseReleaseEvent(QMouseEvent *event)
 {
+    if (!isEnabled()) return;
     m_background->setPixmap(QPixmap(":/images/background/custom_btn_background.png"));
     QWidget::mouseReleaseEvent(event);
 }

+ 2 - 1
src/widgets/custom/CustomDoubleSpinBox.cpp

@@ -25,12 +25,13 @@ CustomDoubleSpinBox::~CustomDoubleSpinBox()
 bool CustomDoubleSpinBox::eventFilter(QObject *obj, QEvent *event)
 {
     if (event->type() == QEvent::MouseButtonPress) {
+        if (!isEnabled()) return true;
         // 弹出你的输入对话框
         m_input_dialog->setValue(text());
         m_input_dialog->setEditType(EditType::DOUBLE);
         auto ret = m_input_dialog->exec();
         if (ret == QDialog::Accepted) {
-            setValue(m_input_dialog->getValue().toInt());
+            setValue(m_input_dialog->getValue().toDouble());
         }
         return true; // 拦截
     }

+ 1 - 0
src/widgets/custom/CustomLineEdit.cpp

@@ -22,6 +22,7 @@ CustomLineEdit::~CustomLineEdit()
 bool CustomLineEdit::event(QEvent *event)
 {
     if (event->type() == QEvent::MouseButtonPress) {
+        if (!isEnabled()) return true;
         m_input_dialog->setValue(text(), formType);
         m_input_dialog->setEditType(editType);
         auto ret = m_input_dialog->exec();  // 阻塞,直到窗口关闭

+ 3 - 2
src/widgets/custom/CustomNavigationBar.cpp

@@ -4,6 +4,8 @@
 #include <QDebug>
 #include <QScroller>
 
+#include "GeneralInterface.h"
+
 CustomNavigationBar::CustomNavigationBar(QWidget *parent)
     : QWidget(parent)
     , ui(new Ui::CustomNavigationBar)
@@ -137,8 +139,7 @@ void CustomNavigationBar::initTreeWidget()
 
     connect(ui->navigationBar, &QTreeWidget::itemClicked,       this, &CustomNavigationBar::slotTreeWidgetItemClicked);
 
-    QScroller::grabGesture(ui->navigationBar,              QScroller::TouchGesture);
-    QScroller::grabGesture(ui->navigationBar->viewport(),  QScroller::LeftMouseButtonGesture);
+    GeneralInterface::setTouchScroller(ui->navigationBar);
 }
 
 bool  CustomNavigationBar::findAndSelectItem(QTreeWidgetItem *parentItem, const QString &targetText)

+ 1 - 0
src/widgets/custom/CustomQDateTimeEdit.cpp

@@ -29,6 +29,7 @@ CustomQDateTimeEdit::~CustomQDateTimeEdit()
 bool CustomQDateTimeEdit::eventFilter(QObject *obj, QEvent *event)
 {
     if (event->type() == QEvent::MouseButtonPress) {
+        if (!isEnabled()) return true;
         // 弹出你的输入对话框
         m_input_dialog->setValue(text(), General::Type::DATE_TIME);
         m_input_dialog->setEditType(EditType::DATETIME);

+ 3 - 0
src/widgets/custom/CustomSpinBox.cpp

@@ -3,6 +3,8 @@
 #include <QInputDialog>
 #include <QApplication>
 #include <QDebug>
+#include <QLineEdit>
+#include <QValidator>
 
 CustomSpinBox::CustomSpinBox(QWidget *parent)
     : QSpinBox(parent)
@@ -27,6 +29,7 @@ CustomSpinBox::~CustomSpinBox()
 bool CustomSpinBox::eventFilter(QObject *obj, QEvent *event)
 {
     if (event->type() == QEvent::MouseButtonPress) {
+        if (!isEnabled()) return true;
         // 弹出你的输入对话框
         m_input_dialog->setValue(text());
         m_input_dialog->setEditType(EditType::INT);

+ 12 - 1
src/widgets/custom/CustomSpinBox.h

@@ -4,12 +4,21 @@
 #include <QObject>
 #include <QSpinBox>
 #include <QWidget>
-
 #include <QScopedPointer>
 #include <QObject>
+#include <cstdint>
 
 #include "settings/OtherSettings/dialog/DialogEditValue.h"
 
+// 数据类型枚举
+enum class SpinBoxDataType {
+    INT32,      // 有符号32位整数
+    UINT8,      // 无符号8位整数
+    UINT16,     // 无符号16位整数
+    UINT32,     // 无符号32位整数
+    UINT64      // 无符号64位整数
+};
+
 /**
  * @class CustomSpinBox
  * @brief CustomSpinBox 是一个继承自 QSpinBox 的自定义类,用于创建一个带有自定义编辑对话框的数字选择框。
@@ -19,11 +28,13 @@
  * 核心功能包括:
  * - 提供一个自定义的编辑对话框,用于输入和编辑数值。
  * - 重写 eventFilter 方法,用于处理自定义的编辑事件。
+ * - 支持多种数据类型:int32_t, uint8_t, uint16_t, uint32_t, uint64_t
  * 
  * 使用示例:
  * @code
  * CustomSpinBox *spinBox = new CustomSpinBox(this);
  * spinBox->setValue(10);
+ * spinBox->setDataType(SpinBoxDataType::UINT16);
  * @endcode
  * 
  * 构造函数参数:

+ 35 - 36
src/widgets/home/FormHome.cpp

@@ -5,13 +5,6 @@
 #include <QShowEvent>
 
 #include "DataTypeDef.h"
-
-// Standby Form
-#include "FormStandby.h"
-
-// Settings Form
-#include "FormSettings.h"
-
 #include "LanguageManager.h"
 
 FormHome::FormHome(QWidget *parent)
@@ -20,7 +13,7 @@ FormHome::FormHome(QWidget *parent)
     , m_currentForm(Workspace::Home::STANDBY)
 {
     ui->setupUi(this);
-
+    init();
     // 安装事件过滤器到应用程序对象
     qApp->installEventFilter(this);
 }
@@ -33,7 +26,7 @@ FormHome::~FormHome()
 void FormHome::init()
 {
     initWidget();
-
+    // emit initFinished();
     setupConnections();
 }
 
@@ -47,20 +40,7 @@ void FormHome::initWidget()
     // 设置为应用程序的模态窗口,阻止本应用所有窗口的输入
     m_login->setWindowModality(Qt::WindowModal);
 
-    m_formMap[Workspace::Home::STANDBY]                         = new FormStandby();
-    m_formMap[Workspace::Home::SETTINGS]                        = new FormSettings();
-
-    // 添加页面到堆叠窗口并隐藏
-    auto widgets = m_formMap.values();
-    foreach (const auto& widget, std::as_const(widgets)) {
-        ui->workspace->addWidget(widget);
-
-        // 强制布局系统更新
-        ui->workspace->updateGeometry();
-    }
-
-    // 显示初始页面
-    showForm(Workspace::Home::STANDBY);
+    initForms();
 }
 
 void FormHome::setupConnections()
@@ -84,10 +64,9 @@ void FormHome::setupConnections()
         }
     });
 
-    auto settings = qobject_cast<FormSettings*>(m_formMap[Workspace::Home::SETTINGS]);
-    connect(settings,   &FormSettings::refreshTitles,   this,       [this](const QString& title) { ui->titleBar->setTitle(title); });
-    connect(this,       &FormHome::returnPrevForm,      settings,   &FormSettings::slotReturnPrevForm);
-    connect(settings,   &FormSettings::returnPrevForm,  this,       [this]() {
+    connect(m_settings, &FormSettings::refreshTitles,   this,       [this](const QString& title) { ui->titleBar->setTitle(title); });
+    connect(this,       &FormHome::returnPrevForm,      m_settings,   &FormSettings::slotReturnPrevForm);
+    connect(m_settings, &FormSettings::returnPrevForm,  this,       [this]() {
         BaseWidget *widget = qobject_cast<BaseWidget *>(ui->workspace->currentWidget());
         if (!widget) return;
         if (widget->returnParent()) {
@@ -95,28 +74,45 @@ void FormHome::setupConnections()
             showForm(m_prevForm);                       // 需要维护历史记录
         }
     });
+    connect(m_settings, &FormSettings::refreshProgressBar, this, &FormHome::refreshProgressBar);
 
     // 显示 settings 界面事件
-    connect(m_login, &FormLogin::showSetings, this, [=]() { showForm(Workspace::Home::SETTINGS); });
+    connect(m_login, &FormLogin::showSetings, this, [this](const int& userType) {
+        m_settings->setUserType(userType);
+        showForm(Workspace::Home::SETTINGS);
+    });
 
     connect(LanguageManager::instance(), &LanguageManager::languageChanged, this, [this]() { ui->retranslateUi(this); });
 }
 
+void FormHome::initForms()
+{
+    m_standBy = new FormStandby();
+    ui->workspace->addWidget(m_standBy);
+    m_settings = new FormSettings();
+    ui->workspace->addWidget( m_settings);
+}
+
 void FormHome::showForm(int form)
 {
-    if (!m_formMap.contains(form)) {
-        return;
+    switch (form) {
+    case Workspace::Home::STANDBY:
+        ui->workspace->setCurrentWidget(m_standBy);
+        // 更新标题栏标题
+        ui->titleBar->setTitle(m_standBy->windowTitle());
+        break;
+    case Workspace::Home::SETTINGS:
+        ui->workspace->setCurrentWidget(m_settings);
+        // 更新标题栏标题
+        ui->titleBar->setTitle(m_settings->windowTitle());
+        break;
+    default:
+        break;
     }
 
-    m_currentForm = form;
-    ui->workspace->setCurrentWidget(m_formMap[form]);
-
     // 更新标题栏状态
     ui->titleBar->setSettingsEnable(form < Workspace::Home::SETTINGS);
     ui->titleBar->setReturnVisible(form != Workspace::Home::STANDBY);
-
-    // 更新标题栏标题
-    ui->titleBar->setTitle(m_formMap[form]->windowTitle());
 }
 
 void FormHome::setPrevForm(int form)
@@ -133,6 +129,9 @@ void FormHome::setPrevForm(int form)
 
 void FormHome::showEvent(QShowEvent *event)
 {
+
+    // 显示初始页面
+    showForm(Workspace::Home::STANDBY);
     QWidget::showEvent(event);
 }
 

+ 14 - 1
src/widgets/home/FormHome.h

@@ -7,6 +7,12 @@
 
 #include "login/FormLogin.h"
 
+// Standby Form
+#include "FormStandby.h"
+
+// Settings Form
+#include "FormSettings.h"
+
 namespace Ui {
 /**
  * @brief FormHome 类用于表示和操作主窗体界面。
@@ -43,6 +49,9 @@ private:
     void initWidget();
     // 设置连接函数,设置FormHome对象中的信号和槽的连接
     void setupConnections();
+
+    void initForms();
+
     // 显示表单函数,显示指定类型的表单
     void showForm(int form);
 
@@ -62,6 +71,8 @@ signals:
     void userInactive();
 
     void returnPrevForm();
+    void refreshProgressBar(const int& value);
+    void initFinished();
 
 private:
     // UI对象指针
@@ -75,7 +86,9 @@ private:
     QMap<int, QWidget*> m_formMap;
 
     // 登录页面
-    FormLogin*                          m_login;
+    FormLogin*      m_login;
+    FormStandby*    m_standBy;
+    FormSettings*   m_settings;
 };
 
 #endif // FORMHOME_H

+ 12 - 3
src/widgets/home/FormStartUp.cpp

@@ -20,8 +20,8 @@ FormStartUp::FormStartUp(QWidget *parent)
 
     m_timer = new QTimer();
     connect(m_timer, &QTimer::timeout, this, &FormStartUp::timeProc);
-    m_timer->setInterval(20);
-    ui->progressBar->setMaximum(Constants::START_TIME_VAL * Constants::START_TIME_VAL * 1000);
+    m_timer->setInterval(100);
+    ui->progressBar->setMaximum(Constants::START_TIME_VAL * Constants::START_TIME_VAL * 300);
     m_timer->start();
 
     ui->progressBar->setValue(0);
@@ -52,6 +52,15 @@ void FormStartUp::setBackgrounImage(const QString &imageUrl)
     backgroundImage->setPixmap(QPixmap(imageUrl));
 }
 
+void FormStartUp::refreshProgressBar(const int &value)
+{
+    // qDebug() << value;
+    ui->progressBar->setValue(ui->progressBar->value() + (value * 5));
+    if (ui->progressBar->value() == ui->progressBar->maximum()) {
+        emit screenSaverHide();
+    }
+}
+
 void FormStartUp::refreshVersion()
 {
     setVersion(m_version_info.ccu_version, m_version_info.tcu_version, m_version_info.pcu_version);
@@ -93,8 +102,8 @@ void FormStartUp::mousePressEvent(QMouseEvent *event)
 
 void FormStartUp::showEvent(QShowEvent *event)
 {
+    QWidget::showEvent(event);
     m_version_info = GLOBALS->getValue(Global::Keys::VERSION).value<VERSION>();
     refreshVersion();
     setChargePileInfo(m_version_info.hw_version);
-    QWidget::showEvent(event);
 }

+ 3 - 0
src/widgets/home/FormStartUp.h

@@ -24,6 +24,9 @@ public:
 
     void setBackgrounImage(const QString& imageUrl);  // 设置背景图片
 
+public slots:
+    void refreshProgressBar(const int& value);
+
 private:
     void refreshVersion();
     void setVersion(const QString& ccu_version,

+ 25 - 9
src/widgets/label/CircleProgressLabel.cpp

@@ -12,7 +12,9 @@ CircleProgressLabel::CircleProgressLabel(QWidget *parent)
 
 void CircleProgressLabel::setProgress(qreal value)
 {
-    m_progress = qBound(0.0, value, 1.0);
+    qreal newVal = qBound(0.0, value, 1.0);
+    if (newVal == m_progress) return;
+    m_progress = newVal;
     if (value != 0) {
         m_centerValue = QString("%1%").arg(QString::number(value*100));
     }
@@ -26,13 +28,8 @@ void CircleProgressLabel::paintEvent(QPaintEvent *event)
     QPainter painter(this);
     painter.setRenderHint(QPainter::Antialiasing);
 
-    int w = width();
-    int h = height();
-    int side = qMin(w, h);
-    // int margin = 20; // 边距,保证所有内容都在控件内
-    QPointF center(w/2.0, h/2.0);
-
-    qreal maxR = side/3.0;
+    QPointF center = m_cache.center;
+    qreal maxR = m_cache.maxR;
 
     // 背景
     painter.setBrush(QColor(0x0B, 0x10, 0x17));
@@ -50,7 +47,7 @@ void CircleProgressLabel::paintEvent(QPaintEvent *event)
     painter.save();
     painter.setPen(QPen(m_subColor, 2));
     int tickCount = 12;
-    qreal tickRadius = maxR*0.6;
+    qreal tickRadius = m_cache.tickRadius;
     for (int i = 0; i < tickCount; ++i) {
         qreal angle = 2 * M_PI * i / tickCount;
         QPointF p1 = center + QPointF(qCos(angle), qSin(angle)) * (tickRadius - 6);
@@ -134,6 +131,24 @@ void CircleProgressLabel::paintEvent(QPaintEvent *event)
     }
 }
 
+void CircleProgressLabel::resizeEvent(QResizeEvent *event)
+{
+    QLabel::resizeEvent(event);
+    int w = width();
+    int h = height();
+    int side = qMin(w, h);
+    m_cache.center = QPointF(w/2.0, h/2.0);
+    m_cache.maxR = side / 3.0;
+    m_cache.tickRadius = m_cache.maxR * 0.6;
+    // 缓存各环的半径
+    m_cache.ringRadii = {
+        m_cache.maxR * 0.90,
+        m_cache.maxR * 0.85,
+        m_cache.maxR * 0.80,
+        m_cache.maxR * 0.75
+    };
+}
+
 void CircleProgressLabel::setPrepareState(int newPrepareState)
 {
     m_prepareState = newPrepareState;
@@ -162,6 +177,7 @@ void CircleProgressLabel::setPrepareState(int newPrepareState)
 
 void CircleProgressLabel::setCenterTips(const QString &newCenterTips)
 {
+    if (newCenterTips == m_centerTips) return;
     m_centerTips = newCenterTips;
     update();
 }

+ 9 - 0
src/widgets/label/CircleProgressLabel.h

@@ -4,6 +4,13 @@
 #include <QLabel>
 #include <QObject>
 
+struct Cache {
+    qreal maxR;
+    QPointF center;
+    qreal tickRadius;
+    QVector<qreal> ringRadii;
+};
+
 /**
  * @brief CircleProgressLabel 是一个继承自 QLabel 的自定义控件,用于显示圆形进度条。
  *
@@ -46,6 +53,7 @@ private:
 
 protected:
     void paintEvent(QPaintEvent *event) override;
+    void resizeEvent(QResizeEvent* event) override;
 
 private:
     qreal m_progress = 0.75; // 进度,0~1
@@ -53,6 +61,7 @@ private:
     QString m_centerTips = "Charging";
 
     int m_prepareState;
+    Cache m_cache;
 
     QColor m_mainColor = QColor(0xFF, 0x7A, 0x2F); // 主色(橙/蓝)
     QColor m_subColor = QColor(0xFF, 0xB3, 0x6B);  // 副色(浅橙/浅蓝)

+ 36 - 28
src/widgets/login/FormLogin.cpp

@@ -12,6 +12,7 @@
 #include <QPropertyAnimation>
 #include <QGraphicsDropShadowEffect>
 
+#include "Globals.h"
 #include "ConfigManager.h"
 #include "LanguageManager.h"
 #include "LoggerHelper.h"
@@ -70,21 +71,12 @@ void FormLogin::initWidget()
     setLineeditBackground();
     setButtonBackground();
 
-    // 在构造函数中
-    if (QGuiApplication::platformName().contains("wayland")) {
-        setWindowFlags(windowFlags() |
-                       Qt::FramelessWindowHint |
-                       Qt::WindowStaysOnTopHint |
-                       Qt::BypassWindowManagerHint);
-    }
-
     initComboBox();
 }
 
 void FormLogin::initComboBox()
 {
-    ui->username->addItem(tr("Operator"));
-    ui->username->addItem(tr("Administrator"));
+    ui->username->addItems(ConfigManager::instance()->tcu_cfg().user_list);
 }
 
 void FormLogin::setLineeditBackground()
@@ -136,6 +128,11 @@ void FormLogin::initConnect()
         this->hide();
     });
 
+    connect(GLOBALS, &Globals::tcuConfigValueChanged, this, [this](const TCU_CFG& value) {
+        ui->username->clear();
+        ui->username->addItems(value.user_list);
+    });
+
     // 登录按钮点击事件
     connect(ui->login, &QPushButton::clicked, this, &FormLogin::slotLoginClicked);
 
@@ -181,24 +178,26 @@ void FormLogin::centerWindow()
     int x = (screenGeometry.width() - this->width()) / 2 + screenGeometry.x();
     int y = (screenGeometry.height() - this->height()) / 2 + screenGeometry.y();
 
-    if (QGuiApplication::platformName().contains("wayland")) {
-        // Wayland专用处理
-        if (QWindow *window = this->windowHandle()) {
-            // 重要:延迟设置位置,确保Wayland合成器已准备好
-            QTimer::singleShot(100, this, [window, x, y]() {
-                window->setPosition(QPoint(x, y));
-
-                // 替代requestActivate的方案
-                window->setFlags(window->flags() | Qt::WindowStaysOnTopHint);
-                QTimer::singleShot(50, [window]() {
-                    window->setFlags(window->flags() & ~Qt::WindowStaysOnTopHint);
-                });
-            });
-        }
-    } else {
-        // 传统X11处理
+    // qDebug() << QGuiApplication::platformName();
+
+    // if (QGuiApplication::platformName().contains("wayland")) {
+    //     // Wayland专用处理
+    //     if (QWindow *window = this->windowHandle()) {
+    //         // 重要:延迟设置位置,确保Wayland合成器已准备好
+    //         QTimer::singleShot(100, this, [window, x, y]() {
+    //             window->setPosition(QPoint(x, y));
+
+    //             // 替代requestActivate的方案
+    //             window->setFlags(window->flags() | Qt::WindowStaysOnTopHint);
+    //             QTimer::singleShot(50, [window]() {
+    //                 window->setFlags(window->flags() & ~Qt::WindowStaysOnTopHint);
+    //             });
+    //         });
+    //     }
+    // } else {
+    //     // 传统X11处理
         this->move(x, y);
-    }
+    // }
 }
 
 void FormLogin::onKeyboardVisibilityChanged()
@@ -234,10 +233,18 @@ void FormLogin::slotLoginClicked()
 
     // 后续添加读取配置文件中的管理员账号和密码
     auto admin_cfg = ConfigManager::instance()->getAdminConfig();
+    auto operator_cfg = ConfigManager::instance()->getOperatorConfig();
+    auto root_cfg = ConfigManager::instance()->getRootConfig();
 
     if (username == admin_cfg.username && pwd == admin_cfg.password) {
         this->hide();
-        emit showSetings(1);
+        emit showSetings(General::UserType::ADMIN);
+    } else if (username == operator_cfg.username && pwd == operator_cfg.password) {
+        this->hide();
+        emit showSetings(General::UserType::OPERATOR);
+    } else if (username == root_cfg.username && pwd == root_cfg.password) {
+        this->hide();
+        emit showSetings(General::UserType::ROOT);
     } else {
         setTips(false, false);
     }
@@ -245,6 +252,7 @@ void FormLogin::slotLoginClicked()
 
 void FormLogin::showEvent(QShowEvent *event)
 {
+    
     QWidget::showEvent(event);
 
     centerWindow();

+ 20 - 11
src/widgets/workspace/home/FormAuthentication.cpp

@@ -102,11 +102,11 @@ void FormAuthentication::initConnect()
         connect(this,                           &FormAuthentication::signalChargingCtl,   TcpServerThread::instance(),    &TcpServerThread::slotChargingCtl, Qt::QueuedConnection);
     });
     connect(GLOBALS, &Globals::tcuConfigValueChanged, this, [this](const TCU_CFG& value){
+        m_tcu_cfg = value;
+        m_gun.cur_time = m_tcu_cfg.time_out.auth_form_wait_time;
         setCardIconVisible(value.auth_type_enable.nfc);
         setPosIconVisible(value.auth_type_enable.pos);
         setQrIconVisible(value.auth_type_enable.qr);
-        m_gun.cur_time = m_tcu_cfg.time_out.auth_form_wait_time;
-        m_tcu_cfg = value;
     });
 }
 
@@ -199,7 +199,9 @@ void FormAuthentication::startAuth()
 
     if (!m_gun.is_reading_card) {
         m_gun.is_reading_card = true;
-        emit signalStartNFCReading(m_gun.charging_info);
+        if (m_tcu_cfg.auth_type_enable.nfc) {
+            emit signalStartNFCReading(m_gun.charging_info);
+        }
     }
 }
 
@@ -228,29 +230,36 @@ void FormAuthentication::authTimeout()
     }
 }
 
-void FormAuthentication::onNFCReadCard(charging_control_info_t& data)
+void FormAuthentication::onNFCReadCard(const charging_control_info_t& data)
 {
+    charging_control_info_t result = data;
     m_gun.is_reading_card = false;
     m_timer->stop();
 
     if (data.nfcExecResult == AuthError::SUCCESS) {
         if (m_gun.is_stop_charging) {
-            data.cmd = CHARGE_GUN_STOP_CMD;
+            result.cmd = CHARGE_GUN_STOP_CMD;
         } else {
-            data.cmd = CHARGE_GUN_START_CMD;
+            result.cmd = CHARGE_GUN_START_CMD;
         }
-        emit signalChargingCtl(data);
+        emit signalChargingCtl(result);
     }
 
-    emit signalAuthResult(data.nfcExecResult);
+    emit signalAuthResult(result.nfcExecResult);
 }
 
 void FormAuthentication::showEvent(QShowEvent *event)
 {
     QWidget::showEvent(event);
-    setCardIconVisible(true);
-    setPosIconVisible(false);
-    setQrIconVisible(false);
+
+    m_tcu_cfg = ConfigManager::instance()->tcu_cfg();
+    m_gun.is_stop_charging = false;
+    m_gun.cur_time = m_tcu_cfg.time_out.auth_form_wait_time;
+    m_gun.is_reading_card = false;
+
+    setCardIconVisible(m_tcu_cfg.auth_type_enable.nfc);
+    setPosIconVisible(m_tcu_cfg.auth_type_enable.pos);
+    setQrIconVisible(m_tcu_cfg.auth_type_enable.qr);
     
     startAuth();
 }

+ 4 - 4
src/widgets/workspace/home/FormAuthentication.h

@@ -50,13 +50,13 @@ public slots:
 signals:
     void signalCancelAuth();
     void signalAuthResult(int result);
-    void signalChargingCtl(charging_control_info_t& data);
-    void signalStartNFCReading(charging_control_info_t& data);
-    void signalStartNFCReadCard(charging_control_info_t& data);
+    void signalChargingCtl(const charging_control_info_t& data);
+    void signalStartNFCReading(const charging_control_info_t& data);
+    void signalStartNFCReadCard(const charging_control_info_t& data);
 
 private slots:
     void authTimeout();
-    void onNFCReadCard(charging_control_info_t &data);
+    void onNFCReadCard(const charging_control_info_t &data);
 
 protected:
     void showEvent(QShowEvent* event) override;

+ 3 - 1
src/widgets/workspace/home/FormChargeSettings.cpp

@@ -1,4 +1,5 @@
 #include "FormChargeSettings.h"
+#include "FunctionTimer.h"
 #include "ui_FormChargeSettings.h"
 
 #include <QDebug>
@@ -159,9 +160,10 @@ void FormChargeSettings::initEnergyButtonGroup()
 
 void FormChargeSettings::showEvent(QShowEvent *event)
 {
+    
+    QWidget::showEvent(event);
     updateShow(editType);
     ui->value->setFocus();
-    QWidget::showEvent(event);
 }
 
 int FormChargeSettings::getValue()

+ 171 - 197
src/widgets/workspace/home/FormChargeSettings.ui

@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>610</width>
-    <height>471</height>
+    <width>561</width>
+    <height>531</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -87,7 +87,7 @@
      <item>
       <widget class="QStackedWidget" name="stackedWidget">
        <property name="currentIndex">
-        <number>0</number>
+        <number>2</number>
        </property>
        <widget class="QWidget" name="time_widget">
         <layout class="QGridLayout" name="gridLayout_3">
@@ -101,7 +101,7 @@
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
@@ -117,7 +117,7 @@
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
@@ -133,7 +133,7 @@
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
@@ -149,7 +149,7 @@
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
@@ -168,7 +168,7 @@
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
@@ -184,7 +184,7 @@
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
@@ -200,7 +200,7 @@
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
@@ -216,7 +216,7 @@
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
@@ -232,7 +232,7 @@
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
@@ -248,7 +248,7 @@
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
@@ -264,7 +264,7 @@
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
@@ -280,7 +280,7 @@
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
@@ -296,7 +296,7 @@
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
@@ -312,7 +312,7 @@
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
@@ -328,7 +328,7 @@
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
@@ -344,7 +344,7 @@
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
@@ -360,7 +360,7 @@
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
@@ -376,7 +376,7 @@
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
@@ -392,7 +392,7 @@
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
@@ -411,324 +411,311 @@
         <layout class="QGridLayout" name="gridLayout_5">
          <item row="0" column="0">
           <layout class="QGridLayout" name="gridLayout_4">
-           <item row="2" column="2">
-            <widget class="QPushButton" name="btn_60_energy">
+           <item row="3" column="0">
+            <widget class="QPushButton" name="btn_70_energy">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>60Kwh</string>
+              <string>70Kwh</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="3" column="2">
-            <widget class="QPushButton" name="btn_80_energy">
+           <item row="1" column="1">
+            <widget class="QPushButton" name="btn_35_energy">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>80Kwh</string>
+              <string>35Kwh</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="3" column="0">
-            <widget class="QPushButton" name="btn_70_energy">
+           <item row="2" column="0">
+            <widget class="QPushButton" name="btn_50_energy">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>70Kwh</string>
+              <string>50Kwh</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="2" column="1">
-            <widget class="QPushButton" name="btn_55_energy">
+           <item row="4" column="0">
+            <widget class="QPushButton" name="btn_90_energy">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>55Kwh</string>
+              <string>90Kwh</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="1" column="2">
-            <widget class="QPushButton" name="btn_40_energy">
+           <item row="4" column="2">
+            <widget class="QPushButton" name="btn_100_energy">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>40Kwh</string>
+              <string>100Kwh</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="3" column="3">
-            <widget class="QPushButton" name="btn_85_energy">
+           <item row="4" column="1">
+            <widget class="QPushButton" name="btn_95_energy">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>85Kwh</string>
+              <string>95Kwh</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
-             <property name="checked">
-              <bool>false</bool>
-             </property>
             </widget>
            </item>
-           <item row="3" column="1">
-            <widget class="QPushButton" name="btn_75_energy">
+           <item row="0" column="2">
+            <widget class="QPushButton" name="btn_20_energy">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>75Kwh</string>
+              <string>20Kwh</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="0" column="0">
-            <widget class="QPushButton" name="btn_10_energy">
+           <item row="3" column="1">
+            <widget class="QPushButton" name="btn_75_energy">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>10Kwh</string>
+              <string>75Kwh</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="5" column="0">
-            <spacer name="verticalSpacer_2">
-             <property name="orientation">
-              <enum>Qt::Vertical</enum>
-             </property>
-             <property name="sizeHint" stdset="0">
-              <size>
-               <width>20</width>
-               <height>40</height>
-              </size>
-             </property>
-            </spacer>
-           </item>
-           <item row="1" column="3">
-            <widget class="QPushButton" name="btn_45_energy">
+           <item row="0" column="1">
+            <widget class="QPushButton" name="btn_15_energy">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>45Kwh</string>
+              <string>15Kwh</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="1" column="0">
-            <widget class="QPushButton" name="btn_30_energy">
+           <item row="0" column="3">
+            <widget class="QPushButton" name="btn_25_energy">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>30Kwh</string>
+              <string>25Kwh</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="2" column="0">
-            <widget class="QPushButton" name="btn_50_energy">
+           <item row="2" column="1">
+            <widget class="QPushButton" name="btn_55_energy">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>50Kwh</string>
+              <string>55Kwh</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="2" column="3">
-            <widget class="QPushButton" name="btn_65_energy">
+           <item row="3" column="2">
+            <widget class="QPushButton" name="btn_80_energy">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>65Kwh</string>
+              <string>80Kwh</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="0" column="2">
-            <widget class="QPushButton" name="btn_20_energy">
+           <item row="2" column="2">
+            <widget class="QPushButton" name="btn_60_energy">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>20Kwh</string>
+              <string>60Kwh</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="0" column="1">
-            <widget class="QPushButton" name="btn_15_energy">
+           <item row="1" column="0">
+            <widget class="QPushButton" name="btn_30_energy">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>15Kwh</string>
+              <string>30Kwh</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="0" column="3">
-            <widget class="QPushButton" name="btn_25_energy">
+           <item row="0" column="0">
+            <widget class="QPushButton" name="btn_10_energy">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>25Kwh</string>
+              <string>10Kwh</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="1" column="1">
-            <widget class="QPushButton" name="btn_35_energy">
+           <item row="1" column="2">
+            <widget class="QPushButton" name="btn_40_energy">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>35Kwh</string>
+              <string>40Kwh</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="4" column="0">
-            <widget class="QPushButton" name="btn_90_energy">
+           <item row="1" column="3">
+            <widget class="QPushButton" name="btn_45_energy">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>90Kwh</string>
+              <string>45Kwh</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="4" column="1">
-            <widget class="QPushButton" name="btn_95_energy">
+           <item row="2" column="3">
+            <widget class="QPushButton" name="btn_65_energy">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>95Kwh</string>
+              <string>65Kwh</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="4" column="2">
-            <widget class="QPushButton" name="btn_100_energy">
+           <item row="3" column="3">
+            <widget class="QPushButton" name="btn_85_energy">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>100Kwh</string>
+              <string>85Kwh</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
+             <property name="checked">
+              <bool>false</bool>
+             </property>
             </widget>
            </item>
           </layout>
@@ -744,7 +731,7 @@
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
@@ -755,64 +742,64 @@
              </property>
             </widget>
            </item>
-           <item row="3" column="2">
-            <widget class="QPushButton" name="btn_80_soc">
+           <item row="0" column="3">
+            <widget class="QPushButton" name="btn_25_soc">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>80%</string>
+              <string>25%</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="3" column="0">
-            <widget class="QPushButton" name="btn_70_soc">
+           <item row="2" column="0">
+            <widget class="QPushButton" name="btn_50_soc">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>70%</string>
+              <string>50%</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="2" column="1">
-            <widget class="QPushButton" name="btn_55_soc">
+           <item row="3" column="2">
+            <widget class="QPushButton" name="btn_80_soc">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>55%</string>
+              <string>80%</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="1" column="2">
-            <widget class="QPushButton" name="btn_40_soc">
+           <item row="0" column="0">
+            <widget class="QPushButton" name="btn_10_soc">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>40%</string>
+              <string>10%</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
@@ -824,7 +811,7 @@
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
@@ -838,221 +825,208 @@
              </property>
             </widget>
            </item>
-           <item row="3" column="1">
-            <widget class="QPushButton" name="btn_75_soc">
+           <item row="4" column="2">
+            <widget class="QPushButton" name="btn_100_soc">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>75%</string>
+              <string>100%</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="0" column="0">
-            <widget class="QPushButton" name="btn_10_soc">
+           <item row="3" column="0">
+            <widget class="QPushButton" name="btn_70_soc">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>10%</string>
+              <string>70%</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="5" column="0">
-            <spacer name="verticalSpacer_4">
-             <property name="orientation">
-              <enum>Qt::Vertical</enum>
-             </property>
-             <property name="sizeHint" stdset="0">
-              <size>
-               <width>20</width>
-               <height>40</height>
-              </size>
-             </property>
-            </spacer>
-           </item>
-           <item row="1" column="3">
-            <widget class="QPushButton" name="btn_45_soc">
+           <item row="0" column="1">
+            <widget class="QPushButton" name="btn_15_soc">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>45%</string>
+              <string>15%</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="1" column="0">
-            <widget class="QPushButton" name="btn_30_soc">
+           <item row="1" column="1">
+            <widget class="QPushButton" name="btn_35_soc">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>30%</string>
+              <string>35%</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="2" column="0">
-            <widget class="QPushButton" name="btn_50_soc">
+           <item row="2" column="3">
+            <widget class="QPushButton" name="btn_65_soc">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>50%</string>
+              <string>65%</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="2" column="3">
-            <widget class="QPushButton" name="btn_65_soc">
+           <item row="0" column="2">
+            <widget class="QPushButton" name="btn_20_soc">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>65%</string>
+              <string>20%</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="0" column="2">
-            <widget class="QPushButton" name="btn_20_soc">
+           <item row="4" column="0">
+            <widget class="QPushButton" name="btn_90_soc">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>20%</string>
+              <string>90%</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="0" column="1">
-            <widget class="QPushButton" name="btn_15_soc">
+           <item row="1" column="2">
+            <widget class="QPushButton" name="btn_40_soc">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>15%</string>
+              <string>40%</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="0" column="3">
-            <widget class="QPushButton" name="btn_25_soc">
+           <item row="3" column="1">
+            <widget class="QPushButton" name="btn_75_soc">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>25%</string>
+              <string>75%</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="1" column="1">
-            <widget class="QPushButton" name="btn_35_soc">
+           <item row="4" column="1">
+            <widget class="QPushButton" name="btn_95_soc">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>35%</string>
+              <string>95%</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="4" column="0">
-            <widget class="QPushButton" name="btn_90_soc">
+           <item row="2" column="1">
+            <widget class="QPushButton" name="btn_55_soc">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>90%</string>
+              <string>55%</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="4" column="1">
-            <widget class="QPushButton" name="btn_95_soc">
+           <item row="1" column="3">
+            <widget class="QPushButton" name="btn_45_soc">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>95%</string>
+              <string>45%</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
              </property>
             </widget>
            </item>
-           <item row="4" column="2">
-            <widget class="QPushButton" name="btn_100_soc">
+           <item row="1" column="0">
+            <widget class="QPushButton" name="btn_30_soc">
              <property name="minimumSize">
               <size>
                <width>0</width>
-               <height>40</height>
+               <height>60</height>
               </size>
              </property>
              <property name="text">
-              <string>100%</string>
+              <string>30%</string>
              </property>
              <property name="checkable">
               <bool>true</bool>

+ 4 - 0
src/widgets/workspace/home/FormCharging.cpp

@@ -17,6 +17,7 @@ FormCharging::FormCharging(int gun_id, QWidget *parent)
 
     m_tcu_cfg = ConfigManager::instance()->tcu_cfg();
     m_ccu_cfg = ConfigManager::instance()->ccu_cfg();
+    m_currentGunNum = m_ccu_cfg.GUN_Numb;
 
     initWidget();
     initConnect();
@@ -45,6 +46,8 @@ void FormCharging::initConnect()
     connect(GLOBALS,                        &Globals::chargeInfoValueChanged,   this, &FormCharging::chargeInfoValueChanged);
     connect(GLOBALS,                        &Globals::ccuConfigValueChanged,    this, [this](const CCU_CFG& ccu_cfg) {
         m_ccu_cfg = ccu_cfg;
+        if (m_currentGunNum == m_ccu_cfg.GUN_Numb) return;
+        refreshChargingBackground();
     });
     connect(GLOBALS,                        &Globals::tcuConfigValueChanged,    this, [this](const TCU_CFG& tcu_cfg) {
         m_tcu_cfg = tcu_cfg;
@@ -84,6 +87,7 @@ void FormCharging::setChargingBackground()
 
 void FormCharging::refreshChargingBackground()
 {
+    if (m_ccu_cfg.GUN_Numb == m_currentGunNum) return;
     bool isOnce;
     if (m_ccu_cfg.GUN_Numb == 1) {
         setBackgroundImage(charging_bg_image, ":/images/charging/charging_background_once.png");

+ 1 - 0
src/widgets/workspace/home/FormCharging.h

@@ -61,6 +61,7 @@ private:
     QLabel* voltage_bg_image;
     QLabel* current_bg_image;
     QLabel* stop_btn_bg_image;
+    int m_currentGunNum;
 
     tcu_config_info_t m_tcu_cfg;
     ccu_config_info_t m_ccu_cfg;

+ 73 - 45
src/widgets/workspace/home/FormGunDetail.cpp

@@ -74,19 +74,14 @@ void FormGunDetail::initWidget()
 
 void FormGunDetail::initForms()
 {
-    m_formMap[PLUG_IN]              = new FormPlugIn(m_gun.gun_id);
-    m_formMap[CHARGING_FORM]        = new FormCharging(m_gun.gun_id);
-    m_formMap[CHARGING_SETTINGS]    = new FormChargeSettings(m_gun.gun_id);
-    m_formMap[AUTHENTICATION]       = new FormAuthentication(m_gun.gun_id);
-    m_formMap[CHARGE_PREPARE]       = new FormChargePrepare(m_gun.gun_id);
-    m_formMap[FINISH_FORM]          = new FormFinished(m_gun.gun_id);
+    // m_formMap[PLUG_IN]              = new FormPlugIn(m_gun.gun_id);
+    // m_formMap[CHARGING_FORM]        = new FormCharging(m_gun.gun_id);
+    // m_formMap[CHARGING_SETTINGS]    = new FormChargeSettings(m_gun.gun_id);
+    // m_formMap[AUTHENTICATION]       = new FormAuthentication(m_gun.gun_id);
+    // m_formMap[CHARGE_PREPARE]       = new FormChargePrepare(m_gun.gun_id);
+    // m_formMap[FINISH_FORM]          = new FormFinished(m_gun.gun_id);
     m_formMap[ERROR_FORM]           = new FormError(m_gun.gun_id);
-    // m_formMap_1[PRICE_FORM]  = new FormPrice();
-
-    for (const auto& widget : std::as_const(m_formMap)) {
-        ui->gun_widget->addWidget(widget);
-        ui->gun_widget->updateGeometry();
-    }
+    ui->gun_widget->addWidget(m_formMap[ERROR_FORM]);
 
     showForm(ERROR_FORM);
 }
@@ -99,17 +94,14 @@ void FormGunDetail::initConnect()
 
     setupTcpServerConnections();
     setupGlobalsConnections();
-    setupChargingFormConnections();
-    setupAuthenticationFormConnections();
-    setupChargingSettingsConnections();
+    // setupChargingFormConnections();
+    // setupAuthenticationFormConnections();
+    // setupChargingSettingsConnections();
 
     connect(ui->restart, &QPushButton::clicked, this, [this]() {
         m_gun.auth_result = true;
         showForm(AUTHENTICATION);
     });
-
-    auto auth_form = qobject_cast<FormAuthentication*>(m_formMap[AUTHENTICATION]);
-    connect(this, &FormGunDetail::signalChanged, auth_form, &FormAuthentication::slotStartAuth);
 }
 
 void FormGunDetail::setupTcpServerConnections()
@@ -180,13 +172,13 @@ void FormGunDetail::setupGlobalsConnections()
     }
 
     connect(GLOBALS,    &Globals::tcuConfigValueChanged,        this,   [this](const TCU_CFG& tcu_cfg) {
-        charge_prepare_enum form = static_cast<charge_prepare_enum>(tcu_cfg.current_prepare_form);
+        m_tcu_cfg = tcu_cfg;
+        charge_prepare_enum form = static_cast<charge_prepare_enum>(m_tcu_cfg.current_prepare_form);
         if (TcpServerThread::instance()->isClientConnected()) {
             showForm(form);
         }
         // showForm(form);
-
-        ui->gun_line_temp->setVisible(tcu_cfg.gun_line_temperature_visible && m_formMap[CHARGING_FORM]->isVisible());
+        refreshGunLinTempVisible();
     });
 
     connect(GLOBALS,    &Globals::chargeInfoValueChanged,       this,   [this](const CHARGING_INFO& info) {
@@ -197,8 +189,8 @@ void FormGunDetail::setupGlobalsConnections()
     });
 
     connect(GLOBALS,    &Globals::ccuConfigValueChanged,        this,   [this](const CCU_CFG& ccu_cfg) {
-        foreach (const auto& gun_detail, ccu_cfg.GUN_Detail) {
-            if (gun_detail.GUN_ID == m_gun.gun_id) {
+        foreach (const auto& gun_detail, ccu_cfg.GUN_config) {
+            if (gun_detail.connectorId == m_gun.gun_id) {
                 m_gun.requestPowerByMinutes = gun_detail.requestPowerByMinutes;
                 m_gun.requestPowerByPowerKW = gun_detail.requestPowerByPowerKW;
                 m_gun.requestPowerBySoc     = gun_detail.requestPowerBySOC;
@@ -222,6 +214,7 @@ void FormGunDetail::setupChargingFormConnections()
 void FormGunDetail::setupAuthenticationFormConnections()
 {
     auto auth_form = qobject_cast<FormAuthentication*>(m_formMap[AUTHENTICATION]);
+    connect(this, &FormGunDetail::signalChanged, auth_form, &FormAuthentication::slotStartAuth);
     connect(auth_form, &FormAuthentication::signalAuthResult, this, [this](const int& state) {
         if (state == AuthError::WAITING_FOR_OTHER_INSTANCE)  {
             ui->title->setText("Waiting");
@@ -323,8 +316,7 @@ void FormGunDetail::refreshChargeGunBackground(const bool &state)
 void FormGunDetail::showForm(charge_prepare_enum form)
 {
     if (!m_formMap.contains(form)) {
-        LOG_WARNING("Invalid form for gun 1: " + QString::number(form));
-        return;
+        initStackWidgetItem(form);
     }
 
     refreshChargeGunTips(GeneralInterface::getTips(GeneralInterface::getGuiState(form)));
@@ -339,13 +331,42 @@ void FormGunDetail::showForm(charge_prepare_enum form)
     m_gun.currentForm = form;
     setCurrentChargeProgress(GeneralInterface::getChargeProgress(form));
     ui->gun_widget->setCurrentWidget(m_formMap[form]);
-    ui->gun_line_temp->setVisible((m_tcu_cfg.gun_line_temperature_visible && m_formMap[CHARGING_FORM]->isVisible()));
 
-    // 确保按钮位置不变且可以接收事件
-    ui->price->raise();
-    ui->price->setAttribute(Qt::WA_TransparentForMouseEvents, false);
-    ui->price->setAttribute(Qt::WA_AcceptTouchEvents, true);
-    update();
+    refreshGunLinTempVisible();
+}
+
+void FormGunDetail::initStackWidgetItem(charge_prepare_enum form)
+{
+    switch (form) {
+    case PLUG_IN:
+        m_formMap[form] = new FormPlugIn(m_gun.gun_id);
+        break;
+    case AUTHENTICATION:
+        m_formMap[form] = new FormAuthentication(m_gun.gun_id);
+        setupAuthenticationFormConnections();
+        break;
+    case CHARGE_PREPARE:
+        m_formMap[form] = new FormChargePrepare(m_gun.gun_id);
+        break;
+    case CHARGING_FORM:
+        m_formMap[form] = new FormCharging(m_gun.gun_id);
+        setupChargingFormConnections();
+        break;
+    case CHARGING_SETTINGS:
+        m_formMap[form] = new FormChargeSettings(m_gun.gun_id);
+        setupChargingSettingsConnections();
+        break;
+    case FINISH_FORM:
+        m_formMap[form] = new FormFinished(m_gun.gun_id);
+        break;
+    case ERROR_FORM:
+        m_formMap[form] = new FormError(m_gun.gun_id);
+        break;
+    default:
+        break;
+    }
+
+    ui->gun_widget->addWidget(m_formMap[form]);
 }
 
 void FormGunDetail::refreshChargeGunTips(const QString &tips)
@@ -366,6 +387,16 @@ void FormGunDetail::refreshLabelStyleSheet(const charge_prepare_enum &form)
     refreshChargeGunBackground(form != ERROR_FORM);
 }
 
+void FormGunDetail::refreshGunLinTempVisible()
+{
+    bool isVisible = false;
+    auto charging_form = m_formMap.value(CHARGING_FORM, nullptr);
+    if (charging_form) {
+        isVisible = m_tcu_cfg.gun_line_temperature_visible && charging_form->isVisible();
+    }
+    ui->gun_line_temp->setVisible(isVisible);
+}
+
 QString FormGunDetail::getTitles(const charge_prepare_enum &form)
 {
     switch (form) {
@@ -521,20 +552,14 @@ void FormGunDetail::refreshPlugIn(const uint32_t &state)
 
 void FormGunDetail::refreshAuthorization()
 {
-    auto auth_form = qobject_cast<FormAuthentication*>(m_formMap[AUTHENTICATION]);
-    auth_form->setRequestPowerByMinutes(m_gun.requestPowerByMinutes);
-    auth_form->setRequestPowerByPowerKw(m_gun.requestPowerByPowerKW);
-    auth_form->setRequestPowerBySOC(m_gun.requestPowerBySoc);
+    showForm(CHARGING_SETTINGS);
     auto charging_settings = qobject_cast<FormChargeSettings*>(m_formMap[CHARGING_SETTINGS]);
-    if (!charging_settings->isVisible()) {
-        if (m_gun.requestPowerByMinutes) {
-            charging_settings->setEditType(EditType::TIME);
-        } else if (m_gun.requestPowerByPowerKW) {
-            charging_settings->setEditType(EditType::ENERGY);
-        } else if (m_gun.requestPowerBySoc) {
-            charging_settings->setEditType(EditType::SOC);
-        }
-        showForm(CHARGING_SETTINGS);
+    if (m_gun.requestPowerByMinutes) {
+        charging_settings->setEditType(EditType::TIME);
+    } else if (m_gun.requestPowerByPowerKW) {
+        charging_settings->setEditType(EditType::ENERGY);
+    } else if (m_gun.requestPowerBySoc) {
+        charging_settings->setEditType(EditType::SOC);
     }
 }
 
@@ -585,7 +610,11 @@ void FormGunDetail::setFinishedTextColor(const QString &color)
 
 void FormGunDetail::slotExecNextStep(int editType, int value)
 {
+    showForm(AUTHENTICATION);
     auto auth_form = qobject_cast<FormAuthentication*>(m_formMap[AUTHENTICATION]);
+    auth_form->setRequestPowerByMinutes(m_gun.requestPowerByMinutes);
+    auth_form->setRequestPowerByPowerKw(m_gun.requestPowerByPowerKW);
+    auth_form->setRequestPowerBySOC(m_gun.requestPowerBySoc);
     if (!auth_form) return;
     switch (editType) {
     case EditType::ENERGY:
@@ -600,5 +629,4 @@ void FormGunDetail::slotExecNextStep(int editType, int value)
     default:
         break;
     }
-    showForm(AUTHENTICATION);
 }

+ 2 - 0
src/widgets/workspace/home/FormGunDetail.h

@@ -51,9 +51,11 @@ private:
     void refreshChargeGunBackground(const bool &state = true);
 
     void showForm(charge_prepare_enum form);
+    void initStackWidgetItem(charge_prepare_enum form);
 
     void refreshChargeGunTips(const QString& tips);
     void refreshLabelStyleSheet(const charge_prepare_enum& form);
+    void refreshGunLinTempVisible();
 
     QString getTitles(const charge_prepare_enum& form);
 

+ 7 - 3
src/widgets/workspace/home/FormPlugIn.cpp

@@ -98,12 +98,16 @@ void FormPlugIn::setAuthenticationResult(const bool &result)
 
 void FormPlugIn::refreshChargingBackground()
 {
+    QString newPath;
     if (m_ccu_cfg.GUN_Numb == 1) {
-        ui->background->setPixmap(QPixmap(":/images/charging/charge_gun_background_once.png"));
+        newPath = ":/images/charging/charge_gun_background_once.png";
     } else if (m_ccu_cfg.GUN_Numb == 2) {
-        ui->background->setPixmap(QPixmap());
-        ui->background->setPixmap(QPixmap(":/images/charging/charge_gun_background.png"));
+        newPath = ":/images/charging/charge_gun_background.png";
     }
+
+    if (newPath == m_currentBgPath) return; // 路径相同不处理
+    m_currentBgPath = newPath;
+    ui->background->setPixmap(QPixmap(newPath));
 }
 
 void FormPlugIn::initWidget()

+ 1 - 0
src/widgets/workspace/home/FormPlugIn.h

@@ -50,6 +50,7 @@ private:
     uint8_t m_gun_type;
     bool m_auth_result;
     QTimer* m_timer;
+    QString m_currentBgPath;
 
     QStringList m_gun_variable_names;
     QStringList m_charge_variable_names;

+ 4 - 22
src/widgets/workspace/home/FormPrice.cpp

@@ -9,6 +9,7 @@
 #include <QGraphicsDropShadowEffect>
 
 #include "LanguageManager.h"
+#include "GeneralInterface.h"
 
 FormPrice::FormPrice(QWidget *parent)
     : QWidget(parent)
@@ -52,8 +53,8 @@ void FormPrice::initTableWidget()
     ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
     ui->tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
     ui->tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
-    QScroller::grabGesture(ui->tableWidget,              QScroller::TouchGesture);
-    QScroller::grabGesture(ui->tableWidget->viewport(),  QScroller::LeftMouseButtonGesture);
+
+    GeneralInterface::setTouchScroller(ui->tableWidget);
 
     ui->tableWidget->setColumnCount(4);
 
@@ -128,28 +129,9 @@ void FormPrice::centerWindow()
     }
     QRect screenGeometry = screen->availableGeometry();
 
-    // 计算居中位置(考虑Wayland特性)
     int x = (screenGeometry.width() - this->width()) / 2 + screenGeometry.x();
     int y = (screenGeometry.height() - this->height()) / 2 + screenGeometry.y();
-
-    if (QGuiApplication::platformName().contains("wayland")) {
-        // Wayland专用处理
-        if (QWindow *window = this->windowHandle()) {
-            // 重要:延迟设置位置,确保Wayland合成器已准备好
-            QTimer::singleShot(100, this, [window, x, y]() {
-                window->setPosition(QPoint(x, y));
-
-                // 替代requestActivate的方案
-                window->setFlags(window->flags() | Qt::WindowStaysOnTopHint);
-                QTimer::singleShot(50, [window]() {
-                    window->setFlags(window->flags() & ~Qt::WindowStaysOnTopHint);
-                });
-            });
-        }
-    } else {
-        // 传统X11处理
-        this->move(x, y);
-    }
+    this->move(x, y);
 }
 
 void FormPrice::showEvent(QShowEvent *event)

+ 6 - 0
src/widgets/workspace/home/FormStandby.cpp

@@ -6,6 +6,7 @@
 
 #include "Globals.h"
 #include "LanguageManager.h"
+#include "FunctionTimer.h"
 
 FormStandby::FormStandby(QWidget *parent)
     : QWidget(parent)
@@ -14,6 +15,8 @@ FormStandby::FormStandby(QWidget *parent)
     ui->setupUi(this);
 
     initWidget();
+
+    initConnect();
 }
 
 FormStandby::~FormStandby()
@@ -30,7 +33,10 @@ void FormStandby::initWidget()
     m_price->setParent(this);
     m_price->setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
     m_price->setWindowModality(Qt::WindowModal);
+}
 
+void FormStandby::initConnect()
+{
     connect(ui->gun_widget_1, &FormGunDetail::signalControlAuth, ui->gun_widget_2, &FormGunDetail::slotParseControlAuth);
     connect(ui->gun_widget_2, &FormGunDetail::signalControlAuth, ui->gun_widget_1, &FormGunDetail::slotParseControlAuth);
 

+ 1 - 0
src/widgets/workspace/home/FormStandby.h

@@ -27,6 +27,7 @@ public:
 
 private:
     void initWidget();
+    void initConnect();
 
 private:
     Ui::FormStandby *ui;

+ 4 - 22
src/widgets/workspace/settings/CcuSettings/DialogPriceDetail.cpp

@@ -9,6 +9,7 @@
 #include <QPropertyAnimation>
 
 #include "LanguageManager.h"
+#include "FunctionTimer.h"
 
 DialogPriceDetail::DialogPriceDetail(QWidget *parent)
     : QDialog(parent)
@@ -44,7 +45,6 @@ void DialogPriceDetail::setPrice(const OFFLINE_PRICE &newPrice)
 void DialogPriceDetail::initWidget()
 {
     setBackgroundImage();
-
 }
 
 void DialogPriceDetail::initConnect()
@@ -104,33 +104,15 @@ void DialogPriceDetail::centerWindow()
     }
     QRect screenGeometry = screen->availableGeometry();
 
-    // 计算居中位置(考虑Wayland特性)
     int x = (screenGeometry.width() - this->width()) / 2 + screenGeometry.x();
     int y = (screenGeometry.height() - this->height()) / 2 + screenGeometry.y();
-
-    if (QGuiApplication::platformName().contains("wayland")) {
-        // Wayland专用处理
-        if (QWindow *window = this->windowHandle()) {
-            // 重要:延迟设置位置,确保Wayland合成器已准备好
-            QTimer::singleShot(100, this, [window, x, y]() {
-                window->setPosition(QPoint(x, y));
-
-                // 替代requestActivate的方案
-                window->setFlags(window->flags() | Qt::WindowStaysOnTopHint);
-                QTimer::singleShot(50, [window]() {
-                    window->setFlags(window->flags() & ~Qt::WindowStaysOnTopHint);
-                });
-            });
-        }
-    } else {
-        // 传统X11处理
-        this->move(x, y);
-    }
+    this->move(x, y);
 }
 
 void DialogPriceDetail::showEvent(QShowEvent *event)
 {
+    
+    QDialog::showEvent(event);
     refreshData();
     centerWindow();
-    QDialog::showEvent(event);
 }

+ 34 - 12
src/widgets/workspace/settings/CcuSettings/FormCcuSetting.cpp

@@ -8,12 +8,14 @@
 
 #include <QMessageBox>
 
-FormCcuSetting::FormCcuSetting(BaseWidget *parent)
+FormCcuSetting::FormCcuSetting(const int &userType, BaseWidget *parent)
     : BaseWidget(parent)
     , ui(new Ui::FormCcuSetting)
 {
     ui->setupUi(this);
 
+    setUserType(userType);
+
     initWidget();
     initConnect();
 }
@@ -35,6 +37,13 @@ bool FormCcuSetting::returnParent()
 void FormCcuSetting::initWidget()
 {
     GeneralInterface::setTouchScroller(ui->scrollArea);
+    initComboBox();
+}
+
+void FormCcuSetting::initComboBox()
+{
+    GeneralInterface::initCurrencySymbolMap();
+    GeneralInterface::initCurrencySymbolComboBox(ui->iso4217_currencySymbol);
 }
 
 void FormCcuSetting::initConnect()
@@ -59,6 +68,11 @@ void FormCcuSetting::initConnect()
         }
     });
 
+    // 监听用户类型变化,更新控件权限
+    // connect(this, &BaseWidget::userTypeChanged, this, [this](int userType) {
+    //     refreshVisible();
+    // });
+
     connectAllValueChanged(this);
 }
 
@@ -92,9 +106,6 @@ void FormCcuSetting::refreshData(const CCU_CFG &data)
 {
     ui->tcu_id->setValue(data.TCU_ID);
     ui->gun_number->setValue(data.GUN_Numb);
-    ui->ccu_sn->setText(data.CCU_SN);
-    ui->CCU_ProductID->setText(data.CCU_ProductID);
-    ui->CCU_VendorID->setText(data.CCU_VendorID);
     ui->ccu_available->setChecked(data.CCU_Available);
 
     ui->username->setText(data.username);
@@ -103,42 +114,53 @@ void FormCcuSetting::refreshData(const CCU_CFG &data)
     ui->BoxOverTemp_Stopping->setValue(data.BoxOverTemp_Stopping);
 
     ui->enable_offline_price->setChecked(data.enalbe_offline_price);
-    ui->iso4217_currencySymbol->setText(data.ISO4217_CurrencySymbol);
+    ui->iso4217_currencySymbol->setCurrentText(GeneralInterface::getCurrencySymbol(data.ISO4217_CurrencySymbol));
     ui->iso4217_minor_unit->setValue(data.ISO4217_MinorUnit);
     ui->iso4217_least_sign->setValue(data.ISO4217_LeastSign);
 }
 
+void FormCcuSetting::refreshVisible()
+{
+    // 将控件可见性与管理员权限绑定
+    GeneralInterface::setControlEnabled(ui->tcu_id,                 ui->label_tcuId,                userType());
+    GeneralInterface::setControlEnabled(ui->gun_number,             ui->label_gunNumber,            userType());
+    GeneralInterface::setControlVisiabled(ui->username,             ui->label_username,             userType());
+    GeneralInterface::setControlVisiabled(ui->password,             ui->label_passwprd,             userType());
+    GeneralInterface::setControlEnabled(ui->BoxOverTemp_Stopping,   ui->label_BoxOverTemp_Stopping, userType());
+}
+
 bool FormCcuSetting::getCCUConfig(CCU_CFG &data)
 {
     data.TCU_ID                 = ui->tcu_id->value();
     data.GUN_Numb               = ui->gun_number->value();
-    data.CCU_SN                 = ui->ccu_sn->text();
-    data.CCU_ProductID             = ui->CCU_ProductID->text();
-    data.CCU_VendorID             = ui->CCU_VendorID->text();
     data.CCU_Available          = ui->ccu_available->isChecked();
     data.username               = ui->username->text();
     data.password               = ui->password->text();
     data.BoxOverTemp_Warning    = ui->BoxOverTemp_Warning->value();
     data.BoxOverTemp_Stopping   = ui->BoxOverTemp_Stopping->value();
     data.enalbe_offline_price   = ui->enable_offline_price->isChecked();
-    data.ISO4217_CurrencySymbol = ui->iso4217_currencySymbol->text();
+    data.ISO4217_CurrencySymbol = GeneralInterface::getCurrencySymbol(ui->iso4217_currencySymbol);
     data.ISO4217_MinorUnit      = ui->iso4217_minor_unit->value();
     data.ISO4217_LeastSign      = ui->iso4217_least_sign->value();
     return true;
 }
 
 void FormCcuSetting::showEvent(QShowEvent *event)
-{
+{    
+    BaseWidget::showEvent(event);
     setIsModify(false);
     m_ccu_cfg = ConfigManager::instance()->ccu_cfg();
     refreshData(m_ccu_cfg);
-    BaseWidget::showEvent(event);
+    refreshVisible();
 }
 
 void FormCcuSetting::hideEvent(QHideEvent *event)
 {
-    setIsModify(false);
     BaseWidget::hideEvent(event);
+    if (getCCUConfig(m_ccu_cfg)) {
+        ConfigManager::instance()->saveConfig(CCU_CONFIG, QVariant::fromValue<CCU_CFG>(m_ccu_cfg));
+        return;
+    }
 }
 
 void FormCcuSetting::onValueChanged()

+ 4 - 1
src/widgets/workspace/settings/CcuSettings/FormCcuSetting.h

@@ -44,7 +44,7 @@ public:
      * @brief 构造函数,创建一个 FormCcuSetting 对象。
      * @param parent 指向父窗口的指针,默认为 nullptr。
      */
-    explicit FormCcuSetting(BaseWidget *parent = nullptr);
+    explicit FormCcuSetting(const int& userType = General::UserType::ROOT, BaseWidget *parent = nullptr);
     
     /**
      * @brief 析构函数,销毁 FormCcuSetting 对象。
@@ -59,6 +59,7 @@ public:
 
 private:
     void initWidget();
+    void initComboBox();
     void initConnect();
     void connectAllValueChanged(QWidget *widget);
     /**
@@ -67,6 +68,8 @@ private:
      */
     void refreshData(const CCU_CFG& data);
     
+    void refreshVisible();
+    
     /**
      * @brief 获取 CCU 配置。
      * @param data 用于存储 CCU 配置的引用。

+ 146 - 272
src/widgets/workspace/settings/CcuSettings/FormCcuSetting.ui

@@ -23,33 +23,33 @@
       <property name="geometry">
        <rect>
         <x>0</x>
-        <y>0</y>
+        <y>-75</y>
         <width>984</width>
-        <height>944</height>
+        <height>746</height>
        </rect>
       </property>
       <layout class="QGridLayout" name="gridLayout_3">
        <item row="0" column="0">
-        <layout class="QGridLayout" name="gridLayout">
-         <item row="4" column="1">
-          <layout class="QHBoxLayout" name="horizontalLayout_14" stretch="1,4">
+        <layout class="QGridLayout" name="gridLayout" rowstretch="0,0,0,0,0,0,0,0,0,0,0,1">
+         <item row="6" column="1">
+          <layout class="QHBoxLayout" name="horizontalLayout_9">
            <item>
-            <spacer name="horizontalSpacer_14">
+            <spacer name="horizontalSpacer_9">
              <property name="orientation">
               <enum>Qt::Horizontal</enum>
              </property>
              <property name="sizeHint" stdset="0">
               <size>
                <width>40</width>
-               <height>20</height>
+               <height>0</height>
               </size>
              </property>
             </spacer>
            </item>
            <item>
-            <widget class="CustomLineEdit" name="CCU_VendorID">
+            <widget class="CustomSpinBox" name="BoxOverTemp_Stopping">
              <property name="sizePolicy">
-              <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+              <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
                <horstretch>0</horstretch>
                <verstretch>0</verstretch>
               </sizepolicy>
@@ -57,41 +57,14 @@
              <property name="alignment">
               <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
              </property>
-            </widget>
-           </item>
-          </layout>
-         </item>
-         <item row="7" column="1">
-          <layout class="QHBoxLayout" name="horizontalLayout_7">
-           <item>
-            <spacer name="horizontalSpacer_7">
-             <property name="orientation">
-              <enum>Qt::Horizontal</enum>
-             </property>
-             <property name="sizeHint" stdset="0">
-              <size>
-               <width>40</width>
-               <height>20</height>
-              </size>
-             </property>
-            </spacer>
-           </item>
-           <item>
-            <widget class="CustomLineEdit" name="password">
-             <property name="sizePolicy">
-              <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
-               <horstretch>0</horstretch>
-               <verstretch>0</verstretch>
-              </sizepolicy>
-             </property>
-             <property name="alignment">
-              <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+             <property name="maximum">
+              <number>999</number>
              </property>
             </widget>
            </item>
           </layout>
          </item>
-         <item row="6" column="1">
+         <item row="3" column="1">
           <layout class="QHBoxLayout" name="horizontalLayout_6">
            <item>
             <spacer name="horizontalSpacer_6">
@@ -101,7 +74,7 @@
              <property name="sizeHint" stdset="0">
               <size>
                <width>40</width>
-               <height>20</height>
+               <height>0</height>
               </size>
              </property>
             </spacer>
@@ -121,8 +94,8 @@
            </item>
           </layout>
          </item>
-         <item row="13" column="0">
-          <widget class="QLabel" name="label_14">
+         <item row="6" column="0">
+          <widget class="QLabel" name="label_BoxOverTemp_Stopping">
            <property name="minimumSize">
             <size>
              <width>0</width>
@@ -130,27 +103,53 @@
             </size>
            </property>
            <property name="text">
-            <string>Least Sign(ISO4217):</string>
+            <string>Box Over Temperature Stopping:</string>
            </property>
           </widget>
          </item>
-         <item row="1" column="1">
-          <layout class="QHBoxLayout" name="horizontalLayout_2">
+         <item row="7" column="0">
+          <widget class="QLabel" name="label_offlinePriceEnable">
+           <property name="minimumSize">
+            <size>
+             <width>0</width>
+             <height>60</height>
+            </size>
+           </property>
+           <property name="text">
+            <string>Offline Prices Enable:</string>
+           </property>
+          </widget>
+         </item>
+         <item row="2" column="0">
+          <widget class="QLabel" name="label_ccuAvailable">
+           <property name="minimumSize">
+            <size>
+             <width>0</width>
+             <height>60</height>
+            </size>
+           </property>
+           <property name="text">
+            <string>CCU Available:</string>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="1">
+          <layout class="QHBoxLayout" name="horizontalLayout">
            <item>
-            <spacer name="horizontalSpacer_2">
+            <spacer name="horizontalSpacer">
              <property name="orientation">
               <enum>Qt::Horizontal</enum>
              </property>
              <property name="sizeHint" stdset="0">
               <size>
                <width>40</width>
-               <height>20</height>
+               <height>0</height>
               </size>
              </property>
             </spacer>
            </item>
            <item>
-            <widget class="CustomSpinBox" name="gun_number">
+            <widget class="CustomSpinBox" name="tcu_id">
              <property name="sizePolicy">
               <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
                <horstretch>0</horstretch>
@@ -167,38 +166,25 @@
            </item>
           </layout>
          </item>
-         <item row="11" column="0">
-          <widget class="QLabel" name="label_12">
-           <property name="minimumSize">
-            <size>
-             <width>0</width>
-             <height>60</height>
-            </size>
-           </property>
-           <property name="text">
-            <string>Currency Symbol(ISO4217):</string>
-           </property>
-          </widget>
-         </item>
-         <item row="3" column="1">
-          <layout class="QHBoxLayout" name="horizontalLayout_4" stretch="1,4">
+         <item row="1" column="1">
+          <layout class="QHBoxLayout" name="horizontalLayout_2">
            <item>
-            <spacer name="horizontalSpacer_4">
+            <spacer name="horizontalSpacer_2">
              <property name="orientation">
               <enum>Qt::Horizontal</enum>
              </property>
              <property name="sizeHint" stdset="0">
               <size>
                <width>40</width>
-               <height>20</height>
+               <height>0</height>
               </size>
              </property>
             </spacer>
            </item>
            <item>
-            <widget class="CustomLineEdit" name="CCU_ProductID">
+            <widget class="CustomSpinBox" name="gun_number">
              <property name="sizePolicy">
-              <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+              <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
                <horstretch>0</horstretch>
                <verstretch>0</verstretch>
               </sizepolicy>
@@ -206,37 +192,14 @@
              <property name="alignment">
               <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
              </property>
+             <property name="maximum">
+              <number>10</number>
+             </property>
             </widget>
            </item>
           </layout>
          </item>
-         <item row="10" column="0">
-          <widget class="QLabel" name="label_11">
-           <property name="minimumSize">
-            <size>
-             <width>0</width>
-             <height>60</height>
-            </size>
-           </property>
-           <property name="text">
-            <string>Offline Prices Enable:</string>
-           </property>
-          </widget>
-         </item>
-         <item row="4" column="0">
-          <widget class="QLabel" name="label_5">
-           <property name="minimumSize">
-            <size>
-             <width>0</width>
-             <height>60</height>
-            </size>
-           </property>
-           <property name="text">
-            <string>CCU Vendor ID:</string>
-           </property>
-          </widget>
-         </item>
-         <item row="13" column="1">
+         <item row="10" column="1">
           <layout class="QHBoxLayout" name="horizontalLayout_13">
            <item>
             <spacer name="horizontalSpacer_13">
@@ -246,7 +209,7 @@
              <property name="sizeHint" stdset="0">
               <size>
                <width>40</width>
-               <height>20</height>
+               <height>0</height>
               </size>
              </property>
             </spacer>
@@ -269,54 +232,38 @@
            </item>
           </layout>
          </item>
-         <item row="9" column="0">
-          <widget class="QLabel" name="label_10">
-           <property name="minimumSize">
-            <size>
-             <width>0</width>
-             <height>60</height>
-            </size>
-           </property>
-           <property name="text">
-            <string>Box Over Temperature Stopping:</string>
-           </property>
-          </widget>
-         </item>
-         <item row="8" column="1">
-          <layout class="QHBoxLayout" name="horizontalLayout_8">
+         <item row="7" column="1">
+          <layout class="QHBoxLayout" name="horizontalLayout_10">
            <item>
-            <spacer name="horizontalSpacer_8">
+            <spacer name="horizontalSpacer_10">
              <property name="orientation">
               <enum>Qt::Horizontal</enum>
              </property>
              <property name="sizeHint" stdset="0">
               <size>
                <width>40</width>
-               <height>20</height>
+               <height>0</height>
               </size>
              </property>
             </spacer>
            </item>
            <item>
-            <widget class="CustomSpinBox" name="BoxOverTemp_Warning">
+            <widget class="QCheckBox" name="enable_offline_price">
              <property name="sizePolicy">
               <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
                <horstretch>0</horstretch>
                <verstretch>0</verstretch>
               </sizepolicy>
              </property>
-             <property name="alignment">
-              <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
-             </property>
-             <property name="maximum">
-              <number>999</number>
+             <property name="text">
+              <string/>
              </property>
             </widget>
            </item>
           </layout>
          </item>
-         <item row="2" column="0">
-          <widget class="QLabel" name="label_3">
+         <item row="0" column="0">
+          <widget class="QLabel" name="label_tcuId">
            <property name="minimumSize">
             <size>
              <width>0</width>
@@ -324,12 +271,12 @@
             </size>
            </property>
            <property name="text">
-            <string>CCU SN:</string>
+            <string>TCU ID:</string>
            </property>
           </widget>
          </item>
-         <item row="1" column="0">
-          <widget class="QLabel" name="label_2">
+         <item row="9" column="0">
+          <widget class="QLabel" name="label_minorUnit">
            <property name="minimumSize">
             <size>
              <width>0</width>
@@ -337,12 +284,25 @@
             </size>
            </property>
            <property name="text">
-            <string>Charge Gun Number:</string>
+            <string>Minor Unit(ISO4217):</string>
            </property>
           </widget>
          </item>
-         <item row="7" column="0">
-          <widget class="QLabel" name="label_8">
+         <item row="8" column="0">
+          <widget class="QLabel" name="label_currencySymbol">
+           <property name="minimumSize">
+            <size>
+             <width>0</width>
+             <height>60</height>
+            </size>
+           </property>
+           <property name="text">
+            <string>Currency Symbol(ISO4217):</string>
+           </property>
+          </widget>
+         </item>
+         <item row="4" column="0">
+          <widget class="QLabel" name="label_passwprd">
            <property name="minimumSize">
             <size>
              <width>0</width>
@@ -354,8 +314,8 @@
            </property>
           </widget>
          </item>
-         <item row="11" column="1">
-          <layout class="QHBoxLayout" name="horizontalLayout_11" stretch="0,0">
+         <item row="8" column="1">
+          <layout class="QHBoxLayout" name="horizontalLayout_11" stretch="1,0">
            <item>
             <spacer name="horizontalSpacer_11">
              <property name="orientation">
@@ -364,41 +324,25 @@
              <property name="sizeHint" stdset="0">
               <size>
                <width>40</width>
-               <height>20</height>
+               <height>0</height>
               </size>
              </property>
             </spacer>
            </item>
            <item>
-            <widget class="CustomLineEdit" name="iso4217_currencySymbol">
-             <property name="sizePolicy">
-              <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
-               <horstretch>0</horstretch>
-               <verstretch>0</verstretch>
-              </sizepolicy>
-             </property>
-             <property name="alignment">
-              <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+            <widget class="CustomComboBox" name="iso4217_currencySymbol" native="true">
+             <property name="minimumSize">
+              <size>
+               <width>160</width>
+               <height>0</height>
+              </size>
              </property>
             </widget>
            </item>
           </layout>
          </item>
-         <item row="3" column="0">
-          <widget class="QLabel" name="label_4">
-           <property name="minimumSize">
-            <size>
-             <width>0</width>
-             <height>60</height>
-            </size>
-           </property>
-           <property name="text">
-            <string>CCU Product ID:</string>
-           </property>
-          </widget>
-         </item>
-         <item row="6" column="0">
-          <widget class="QLabel" name="label_7">
+         <item row="10" column="0">
+          <widget class="QLabel" name="label_leastSign">
            <property name="minimumSize">
             <size>
              <width>0</width>
@@ -406,70 +350,60 @@
             </size>
            </property>
            <property name="text">
-            <string>username:</string>
+            <string>Least Sign(ISO4217):</string>
            </property>
           </widget>
          </item>
-         <item row="10" column="1">
-          <layout class="QHBoxLayout" name="horizontalLayout_10">
+         <item row="9" column="1">
+          <layout class="QHBoxLayout" name="horizontalLayout_12">
            <item>
-            <spacer name="horizontalSpacer_10">
+            <spacer name="horizontalSpacer_12">
              <property name="orientation">
               <enum>Qt::Horizontal</enum>
              </property>
              <property name="sizeHint" stdset="0">
               <size>
                <width>40</width>
-               <height>20</height>
+               <height>0</height>
               </size>
              </property>
             </spacer>
            </item>
            <item>
-            <widget class="QCheckBox" name="enable_offline_price">
+            <widget class="CustomSpinBox" name="iso4217_minor_unit">
              <property name="sizePolicy">
               <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
                <horstretch>0</horstretch>
                <verstretch>0</verstretch>
               </sizepolicy>
              </property>
-             <property name="text">
-              <string/>
+             <property name="alignment">
+              <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+             </property>
+             <property name="maximum">
+              <number>9999</number>
              </property>
             </widget>
            </item>
           </layout>
          </item>
-         <item row="8" column="0">
-          <widget class="QLabel" name="label_9">
-           <property name="minimumSize">
-            <size>
-             <width>0</width>
-             <height>60</height>
-            </size>
-           </property>
-           <property name="text">
-            <string>Box Over Temperature Warning:</string>
-           </property>
-          </widget>
-         </item>
-         <item row="12" column="1">
-          <layout class="QHBoxLayout" name="horizontalLayout_12">
+         <item row="5" column="1">
+          <layout class="QHBoxLayout" name="horizontalLayout_8">
            <item>
-            <spacer name="horizontalSpacer_12">
+            <spacer name="horizontalSpacer_8">
              <property name="orientation">
               <enum>Qt::Horizontal</enum>
              </property>
              <property name="sizeHint" stdset="0">
               <size>
                <width>40</width>
-               <height>20</height>
+               <height>0</height>
               </size>
              </property>
             </spacer>
            </item>
            <item>
-            <widget class="CustomSpinBox" name="iso4217_minor_unit">
+            <widget class="CustomSpinBox" name="BoxOverTemp_Warning">
              <property name="sizePolicy">
               <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
                <horstretch>0</horstretch>
@@ -480,27 +414,14 @@
               <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
              </property>
              <property name="maximum">
-              <number>9999</number>
+              <number>999</number>
              </property>
             </widget>
            </item>
           </layout>
          </item>
-         <item row="0" column="0">
-          <widget class="QLabel" name="label">
-           <property name="minimumSize">
-            <size>
-             <width>0</width>
-             <height>60</height>
-            </size>
-           </property>
-           <property name="text">
-            <string>TCU ID:</string>
-           </property>
-          </widget>
-         </item>
          <item row="5" column="0">
-          <widget class="QLabel" name="label_6">
+          <widget class="QLabel" name="label_BoxOverTemp_Warning">
            <property name="minimumSize">
             <size>
              <width>0</width>
@@ -508,11 +429,11 @@
             </size>
            </property>
            <property name="text">
-            <string>CCU Available:</string>
+            <string>Box Over Temperature Warning:</string>
            </property>
           </widget>
          </item>
-         <item row="5" column="1">
+         <item row="2" column="1">
           <layout class="QHBoxLayout" name="horizontalLayout_5">
            <item>
             <spacer name="horizontalSpacer_5">
@@ -522,7 +443,7 @@
              <property name="sizeHint" stdset="0">
               <size>
                <width>40</width>
-               <height>20</height>
+               <height>0</height>
               </size>
              </property>
             </spacer>
@@ -542,88 +463,38 @@
            </item>
           </layout>
          </item>
-         <item row="2" column="1">
-          <layout class="QHBoxLayout" name="horizontalLayout_3" stretch="1,4">
-           <item>
-            <spacer name="horizontalSpacer_3">
-             <property name="orientation">
-              <enum>Qt::Horizontal</enum>
-             </property>
-             <property name="sizeHint" stdset="0">
-              <size>
-               <width>40</width>
-               <height>20</height>
-              </size>
-             </property>
-            </spacer>
-           </item>
-           <item>
-            <widget class="CustomLineEdit" name="ccu_sn">
-             <property name="sizePolicy">
-              <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
-               <horstretch>0</horstretch>
-               <verstretch>0</verstretch>
-              </sizepolicy>
-             </property>
-             <property name="alignment">
-              <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
-             </property>
-            </widget>
-           </item>
-          </layout>
-         </item>
-         <item row="9" column="1">
-          <layout class="QHBoxLayout" name="horizontalLayout_9">
-           <item>
-            <spacer name="horizontalSpacer_9">
-             <property name="orientation">
-              <enum>Qt::Horizontal</enum>
-             </property>
-             <property name="sizeHint" stdset="0">
-              <size>
-               <width>40</width>
-               <height>20</height>
-              </size>
-             </property>
-            </spacer>
-           </item>
-           <item>
-            <widget class="CustomSpinBox" name="BoxOverTemp_Stopping">
-             <property name="sizePolicy">
-              <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
-               <horstretch>0</horstretch>
-               <verstretch>0</verstretch>
-              </sizepolicy>
-             </property>
-             <property name="alignment">
-              <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
-             </property>
-             <property name="maximum">
-              <number>999</number>
-             </property>
-            </widget>
-           </item>
-          </layout>
+         <item row="3" column="0">
+          <widget class="QLabel" name="label_username">
+           <property name="minimumSize">
+            <size>
+             <width>0</width>
+             <height>60</height>
+            </size>
+           </property>
+           <property name="text">
+            <string>username:</string>
+           </property>
+          </widget>
          </item>
-         <item row="0" column="1">
-          <layout class="QHBoxLayout" name="horizontalLayout">
+         <item row="4" column="1">
+          <layout class="QHBoxLayout" name="horizontalLayout_7">
            <item>
-            <spacer name="horizontalSpacer">
+            <spacer name="horizontalSpacer_7">
              <property name="orientation">
               <enum>Qt::Horizontal</enum>
              </property>
              <property name="sizeHint" stdset="0">
               <size>
                <width>40</width>
-               <height>20</height>
+               <height>0</height>
               </size>
              </property>
             </spacer>
            </item>
            <item>
-            <widget class="CustomSpinBox" name="tcu_id">
+            <widget class="CustomLineEdit" name="password">
              <property name="sizePolicy">
-              <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+              <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
                <horstretch>0</horstretch>
                <verstretch>0</verstretch>
               </sizepolicy>
@@ -631,15 +502,12 @@
              <property name="alignment">
               <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
              </property>
-             <property name="maximum">
-              <number>10</number>
-             </property>
             </widget>
            </item>
           </layout>
          </item>
-         <item row="12" column="0">
-          <widget class="QLabel" name="label_13">
+         <item row="1" column="0">
+          <widget class="QLabel" name="label_gunNumber">
            <property name="minimumSize">
             <size>
              <width>0</width>
@@ -647,11 +515,11 @@
             </size>
            </property>
            <property name="text">
-            <string>Minor Unit(ISO4217):</string>
+            <string>Charge Gun Number:</string>
            </property>
           </widget>
          </item>
-         <item row="14" column="0">
+         <item row="11" column="0">
           <spacer name="verticalSpacer">
            <property name="orientation">
             <enum>Qt::Vertical</enum>
@@ -683,6 +551,12 @@
    <extends>QSpinBox</extends>
    <header location="global">CustomSpinBox.h</header>
   </customwidget>
+  <customwidget>
+   <class>CustomComboBox</class>
+   <extends>QWidget</extends>
+   <header location="global">CustomComboBox.h</header>
+   <container>1</container>
+  </customwidget>
  </customwidgets>
  <resources/>
  <connections/>

+ 67 - 46
src/widgets/workspace/settings/CcuSettings/FormChargeGunDetail.cpp

@@ -1,6 +1,7 @@
 #include "FormChargeGunDetail.h"
 #include "ui_FormChargeGunDetail.h"
 
+#include "Globals.h"
 #include "ConfigManager.h"
 #include "LanguageManager.h"
 #include "GeneralInterface.h"
@@ -35,26 +36,12 @@ void FormChargeGunDetail::initConnect()
 {
     connectAllValueChanged(this);
     connect(LanguageManager::instance(), &LanguageManager::languageChanged, this, [this]() { ui->retranslateUi(this); });
+    connect(GLOBALS, &Globals::ccuConfigValueChanged, this, [this](const CCU_CFG& value) { m_ccu_cfg = value; });
 
     // test
-    connect(ui->requestPowerByMinutes, &QCheckBox::clicked,     this, [this](bool status) {
-        if (status) {
-            DialogChargingPopup* dialog = new DialogChargingPopup(this, EditType::TIME);
-            dialog->exec();
-        }
-    });
-    connect(ui->requestPowerByPowerKW, &QCheckBox::clicked,     this, [this](bool status) {
-        if (status) {
-            DialogChargingPopup* dialog = new DialogChargingPopup(this, EditType::ENERGY);
-            dialog->exec();
-        }
-    });
-    connect(ui->requestPowerBySOC, &QCheckBox::clicked,         this, [this](bool status) {
-        if (status) {
-            DialogChargingPopup* dialog = new DialogChargingPopup(this, EditType::SOC);
-            dialog->exec();
-        }
-    });
+    connect(ui->requestPowerByMinutes,  &QCheckBox::clicked,    this, &FormChargeGunDetail::onRequestPowerByMinutesChanged);
+    connect(ui->requestPowerByPowerKW,  &QCheckBox::clicked,    this, &FormChargeGunDetail::onRequestPowerByPowerKWChanged);
+    connect(ui->requestPowerBySOC,      &QCheckBox::clicked,    this, &FormChargeGunDetail::onRequestPowerBySOCChanged);
 }
 
 void FormChargeGunDetail::initComboBox()
@@ -91,9 +78,9 @@ void FormChargeGunDetail::initCanIfnameComboBox()
 
 void FormChargeGunDetail::refreshData()
 {
-    foreach (const auto& data, m_ccu_cfg.GUN_Detail) {
-        if (data.GUN_ID != m_gun_id) continue;
-        ui->GUN_ID->setText(QString::number(data.GUN_ID));
+    foreach (const auto& data, m_ccu_cfg.GUN_config) {
+        if (data.connectorId != m_gun_id) continue;
+        ui->connectorId->setText(QString::number(data.connectorId));
         ui->GUN_Type->setCurrentText(data.GUN_Type);
         ui->GUN_Available->setChecked(data.GUN_Available);
         ui->GUN_maxI->setValue(data.GUN_maxI);
@@ -106,37 +93,39 @@ void FormChargeGunDetail::refreshData()
         ui->requestPowerBySOC->setChecked(data.requestPowerBySOC);
         ui->GUNOverTemp_Warning->setValue(data.GUNOverTemp_Warning);
         ui->GUNOverTemp_Stopping->setValue(data.GUNOverTemp_Stopping);
-        ui->enable_current_limit->setChecked(data.enable_current_limit);
-        ui->permitted_current->setValue(data.permitted_current);
-        ui->enable_powerKW_limit->setChecked(data.enable_powerKW_limit);
-        ui->permitted_powerKW->setValue(data.permitted_powerKW);
     }
 }
 
 void FormChargeGunDetail::updateData()
 {
-    for(int index = 0; index < m_ccu_cfg.GUN_Detail.size(); index ++) {
-        if (m_ccu_cfg.GUN_Detail[index].GUN_ID != m_gun_id) continue;
-        m_ccu_cfg.GUN_Detail[index].GUN_ID                 = ui->GUN_ID->text().toInt();
-        m_ccu_cfg.GUN_Detail[index].GUN_Type               = ui->GUN_Type->currentText();
-        m_ccu_cfg.GUN_Detail[index].GUN_Available          = ui->GUN_Available->isChecked();
-        m_ccu_cfg.GUN_Detail[index].GUN_maxI               = ui->GUN_maxI->value();
-        m_ccu_cfg.GUN_Detail[index].slac_ifname            = ui->slac_ifname->currentText();
-        m_ccu_cfg.GUN_Detail[index].can_ifname             = ui->can_ifname->currentText();
-        m_ccu_cfg.GUN_Detail[index].QRCode_enable          = ui->QRCode_enable->isChecked();
-        m_ccu_cfg.GUN_Detail[index].QRCode_URL             = ui->QRCode_URL->text();
-        m_ccu_cfg.GUN_Detail[index].requestPowerByMinutes  = ui->requestPowerByMinutes->isChecked();
-        m_ccu_cfg.GUN_Detail[index].requestPowerByPowerKW  = ui->requestPowerByPowerKW->isChecked();
-        m_ccu_cfg.GUN_Detail[index].requestPowerBySOC      = ui->requestPowerBySOC->isChecked();
-        m_ccu_cfg.GUN_Detail[index].GUNOverTemp_Warning    = ui->GUNOverTemp_Warning->value();
-        m_ccu_cfg.GUN_Detail[index].GUNOverTemp_Stopping   = ui->GUNOverTemp_Stopping->value();
-        m_ccu_cfg.GUN_Detail[index].enable_current_limit   = ui->enable_current_limit->isChecked();
-        m_ccu_cfg.GUN_Detail[index].permitted_current      = ui->permitted_current->value();
-        m_ccu_cfg.GUN_Detail[index].enable_powerKW_limit   = ui->enable_powerKW_limit->isChecked();
-        m_ccu_cfg.GUN_Detail[index].permitted_powerKW      = ui->permitted_powerKW->value();
+    for(int index = 0; index < m_ccu_cfg.GUN_config.size(); index ++) {
+        if (m_ccu_cfg.GUN_config[index].connectorId != m_gun_id) continue;
+        m_ccu_cfg.GUN_config[index].connectorId             = ui->connectorId->text().toInt();
+        m_ccu_cfg.GUN_config[index].GUN_Type                = ui->GUN_Type->currentText();
+        m_ccu_cfg.GUN_config[index].GUN_Available           = ui->GUN_Available->isChecked();
+        m_ccu_cfg.GUN_config[index].GUN_maxI                = ui->GUN_maxI->value();
+        m_ccu_cfg.GUN_config[index].slac_ifname             = ui->slac_ifname->currentText();
+        m_ccu_cfg.GUN_config[index].can_ifname              = ui->can_ifname->currentText();
+        m_ccu_cfg.GUN_config[index].QRCode_enable           = ui->QRCode_enable->isChecked();
+        m_ccu_cfg.GUN_config[index].QRCode_URL              = ui->QRCode_URL->text();
+        m_ccu_cfg.GUN_config[index].requestPowerByMinutes   = ui->requestPowerByMinutes->isChecked();
+        m_ccu_cfg.GUN_config[index].requestPowerByPowerKW   = ui->requestPowerByPowerKW->isChecked();
+        m_ccu_cfg.GUN_config[index].requestPowerBySOC       = ui->requestPowerBySOC->isChecked();
+        m_ccu_cfg.GUN_config[index].GUNOverTemp_Warning     = ui->GUNOverTemp_Warning->value();
+        m_ccu_cfg.GUN_config[index].GUNOverTemp_Stopping    = ui->GUNOverTemp_Stopping->value();
     }
 }
 
+void FormChargeGunDetail::refreshVisible()
+{
+    GeneralInterface::setControlEnabled(ui->connectorId,    ui->label_connectID,    userType());
+    GeneralInterface::setControlEnabled(ui->GUN_Type,       ui->label_gunType,      userType());
+    GeneralInterface::setControlEnabled(ui->GUN_maxI,       ui->label_maxI,         userType());
+    GeneralInterface::setControlVisiabled(ui->slac_ifname,  ui->label_slacIfname,   userType());
+    GeneralInterface::setControlVisiabled(ui->can_ifname,   ui->label_canIfname,    userType());
+    GeneralInterface::setControlEnabled(ui->GUNOverTemp_Stopping, ui->label_overTempStopping, userType());
+}
+
 void FormChargeGunDetail::connectAllValueChanged(QWidget *widget)
 {
     // QLineEdit
@@ -179,10 +168,42 @@ void FormChargeGunDetail::onValueChanged()
     setIsModify(true);
 }
 
-void FormChargeGunDetail::showEvent(QShowEvent *event)
+void FormChargeGunDetail::onRequestPowerByMinutesChanged(bool status)
+{
+    if (status) {
+        ui->requestPowerByPowerKW->setChecked(false);
+        ui->requestPowerBySOC->setChecked(false);
+    }
+}
+
+void FormChargeGunDetail::onRequestPowerByPowerKWChanged(bool status)
+{
+    if (status) {
+        ui->requestPowerByMinutes->setChecked(false);
+        ui->requestPowerBySOC->setChecked(false);
+    }
+}
+
+void FormChargeGunDetail::onRequestPowerBySOCChanged(bool status)
 {
+    if (status) {
+        ui->requestPowerByPowerKW->setChecked(false);
+        ui->requestPowerByMinutes->setChecked(false);
+    }
+}
+
+void FormChargeGunDetail::showEvent(QShowEvent *event)
+{    
+    BaseWidget::showEvent(event);
     setIsModify(false);
     m_ccu_cfg = ConfigManager::instance()->ccu_cfg();
     refreshData();
-    BaseWidget::showEvent(event);
+    refreshVisible();
+}
+
+void FormChargeGunDetail::hideEvent(QHideEvent *event)
+{
+    BaseWidget::hideEvent(event);
+    updateData();
+    ConfigManager::instance()->saveConfig(CCU_CONFIG, QVariant::fromValue(m_ccu_cfg));
 }

+ 6 - 0
src/widgets/workspace/settings/CcuSettings/FormChargeGunDetail.h

@@ -30,16 +30,22 @@ private:
     void refreshData();
     void updateData();
 
+    void refreshVisible();
+
     void connectAllValueChanged(QWidget *widget);
 
 private slots:
     void onValueChanged();
+    void onRequestPowerByMinutesChanged(bool status);
+    void onRequestPowerByPowerKWChanged(bool status);
+    void onRequestPowerBySOCChanged(bool status);
 
 signals:
     void valueChanged();
 
 protected:
     void showEvent(QShowEvent* event) override;
+    void hideEvent(QHideEvent* event) override;
 
 private:
     Ui::FormChargeGunDetail *ui;

+ 237 - 313
src/widgets/workspace/settings/CcuSettings/FormChargeGunDetail.ui

@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>670</width>
-    <height>505</height>
+    <width>844</width>
+    <height>515</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -23,9 +23,9 @@
       <property name="geometry">
        <rect>
         <x>0</x>
-        <y>-420</y>
-        <width>636</width>
-        <height>1154</height>
+        <y>-533</y>
+        <width>810</width>
+        <height>1028</height>
        </rect>
       </property>
       <layout class="QGridLayout" name="gridLayout_3">
@@ -33,102 +33,36 @@
         <widget class="QWidget" name="gun_detail" native="true">
          <layout class="QVBoxLayout" name="verticalLayout">
           <item>
-           <layout class="QGridLayout" name="gridLayout_2">
-            <item row="10" column="1">
-             <layout class="QHBoxLayout" name="horizontalLayout_11">
-              <item>
-               <spacer name="horizontalSpacer_11">
-                <property name="orientation">
-                 <enum>Qt::Horizontal</enum>
-                </property>
-                <property name="sizeHint" stdset="0">
-                 <size>
-                  <width>40</width>
-                  <height>20</height>
-                 </size>
-                </property>
-               </spacer>
-              </item>
-              <item>
-               <widget class="QCheckBox" name="requestPowerBySOC">
-                <property name="sizePolicy">
-                 <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
-                  <horstretch>0</horstretch>
-                  <verstretch>0</verstretch>
-                 </sizepolicy>
-                </property>
-                <property name="text">
-                 <string/>
-                </property>
-               </widget>
-              </item>
-             </layout>
-            </item>
-            <item row="3" column="1">
-             <layout class="QHBoxLayout" name="horizontalLayout_4">
+           <layout class="QGridLayout" name="gridLayout_2" rowstretch="0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1">
+            <item row="4" column="1">
+             <layout class="QHBoxLayout" name="horizontalLayout_5" stretch="1,0">
               <item>
-               <spacer name="horizontalSpacer_4">
+               <spacer name="horizontalSpacer_5">
                 <property name="orientation">
                  <enum>Qt::Horizontal</enum>
                 </property>
                 <property name="sizeHint" stdset="0">
                  <size>
                   <width>40</width>
-                  <height>20</height>
+                  <height>0</height>
                  </size>
                 </property>
                </spacer>
               </item>
               <item>
-               <widget class="CustomSpinBox" name="GUN_maxI">
-                <property name="sizePolicy">
-                 <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
-                  <horstretch>0</horstretch>
-                  <verstretch>0</verstretch>
-                 </sizepolicy>
-                </property>
-                <property name="alignment">
-                 <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
-                </property>
-                <property name="maximum">
-                 <number>9999</number>
-                </property>
-               </widget>
-              </item>
-             </layout>
-            </item>
-            <item row="9" column="1">
-             <layout class="QHBoxLayout" name="horizontalLayout_10">
-              <item>
-               <spacer name="horizontalSpacer_10">
-                <property name="orientation">
-                 <enum>Qt::Horizontal</enum>
-                </property>
-                <property name="sizeHint" stdset="0">
+               <widget class="CustomComboBox" name="slac_ifname" native="true">
+                <property name="minimumSize">
                  <size>
-                  <width>40</width>
-                  <height>20</height>
+                  <width>100</width>
+                  <height>0</height>
                  </size>
                 </property>
-               </spacer>
-              </item>
-              <item>
-               <widget class="QCheckBox" name="requestPowerByPowerKW">
-                <property name="sizePolicy">
-                 <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
-                  <horstretch>0</horstretch>
-                  <verstretch>0</verstretch>
-                 </sizepolicy>
-                </property>
-                <property name="text">
-                 <string/>
-                </property>
                </widget>
               </item>
              </layout>
             </item>
-            <item row="3" column="0">
-             <widget class="QLabel" name="label_8">
+            <item row="5" column="0">
+             <widget class="QLabel" name="label_canIfname">
               <property name="minimumSize">
                <size>
                 <width>0</width>
@@ -136,27 +70,27 @@
                </size>
               </property>
               <property name="text">
-               <string>Charge gun maximum current : </string>
+               <string>can ifname : </string>
               </property>
              </widget>
             </item>
-            <item row="8" column="1">
-             <layout class="QHBoxLayout" name="horizontalLayout_9">
+            <item row="2" column="1">
+             <layout class="QHBoxLayout" name="horizontalLayout_3">
               <item>
-               <spacer name="horizontalSpacer_9">
+               <spacer name="horizontalSpacer_3">
                 <property name="orientation">
                  <enum>Qt::Horizontal</enum>
                 </property>
                 <property name="sizeHint" stdset="0">
                  <size>
                   <width>40</width>
-                  <height>20</height>
+                  <height>0</height>
                  </size>
                 </property>
                </spacer>
               </item>
               <item>
-               <widget class="QCheckBox" name="requestPowerByMinutes">
+               <widget class="QCheckBox" name="GUN_Available">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
                   <horstretch>0</horstretch>
@@ -170,8 +104,8 @@
               </item>
              </layout>
             </item>
-            <item row="1" column="0">
-             <widget class="QLabel" name="label_9">
+            <item row="9" column="0">
+             <widget class="QLabel" name="label_requestPowerByPower">
               <property name="minimumSize">
                <size>
                 <width>0</width>
@@ -179,12 +113,12 @@
                </size>
               </property>
               <property name="text">
-               <string>Charge gun type : </string>
+               <string>Request Power By Power KW : </string>
               </property>
              </widget>
             </item>
-            <item row="14" column="0">
-             <widget class="QLabel" name="label_14">
+            <item row="13" column="0">
+             <widget class="QLabel" name="label">
               <property name="minimumSize">
                <size>
                 <width>0</width>
@@ -192,12 +126,12 @@
                </size>
               </property>
               <property name="text">
-               <string>Peritted current : </string>
+               <string>Operator Charging Restrictions</string>
               </property>
              </widget>
             </item>
-            <item row="10" column="0">
-             <widget class="QLabel" name="label_12">
+            <item row="2" column="0">
+             <widget class="QLabel" name="label_gunAvailable">
               <property name="minimumSize">
                <size>
                 <width>0</width>
@@ -205,12 +139,42 @@
                </size>
               </property>
               <property name="text">
-               <string>Request Power By SOC : </string>
+               <string>Charge gun Available : </string>
               </property>
              </widget>
             </item>
-            <item row="5" column="0">
-             <widget class="QLabel" name="label_11">
+            <item row="10" column="1">
+             <layout class="QHBoxLayout" name="horizontalLayout_11">
+              <item>
+               <spacer name="horizontalSpacer_11">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>40</width>
+                  <height>0</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item>
+               <widget class="QCheckBox" name="requestPowerBySOC">
+                <property name="sizePolicy">
+                 <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+                  <horstretch>0</horstretch>
+                  <verstretch>0</verstretch>
+                 </sizepolicy>
+                </property>
+                <property name="text">
+                 <string/>
+                </property>
+               </widget>
+              </item>
+             </layout>
+            </item>
+            <item row="6" column="0">
+             <widget class="QLabel" name="label_qrCodeEnable">
               <property name="minimumSize">
                <size>
                 <width>0</width>
@@ -218,25 +182,25 @@
                </size>
               </property>
               <property name="text">
-               <string>can ifname : </string>
+               <string>QR code enable : </string>
               </property>
              </widget>
             </item>
             <item row="15" column="0">
-             <widget class="QLabel" name="label_17">
-              <property name="minimumSize">
+             <spacer name="verticalSpacer">
+              <property name="orientation">
+               <enum>Qt::Vertical</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
                <size>
-                <width>0</width>
-                <height>60</height>
+                <width>20</width>
+                <height>40</height>
                </size>
               </property>
-              <property name="text">
-               <string>power Kw limit Enable : </string>
-              </property>
-             </widget>
+             </spacer>
             </item>
-            <item row="7" column="0">
-             <widget class="QLabel" name="label_4">
+            <item row="10" column="0">
+             <widget class="QLabel" name="label_requestPowerBySOC">
               <property name="minimumSize">
                <size>
                 <width>0</width>
@@ -244,7 +208,7 @@
                </size>
               </property>
               <property name="text">
-               <string>QR code url : </string>
+               <string>Request Power By SOC : </string>
               </property>
              </widget>
             </item>
@@ -258,7 +222,7 @@
                 <property name="sizeHint" stdset="0">
                  <size>
                   <width>40</width>
-                  <height>20</height>
+                  <height>0</height>
                  </size>
                 </property>
                </spacer>
@@ -275,8 +239,71 @@
               </item>
              </layout>
             </item>
-            <item row="2" column="0">
-             <widget class="QLabel" name="label_2">
+            <item row="6" column="1">
+             <layout class="QHBoxLayout" name="horizontalLayout_7">
+              <item>
+               <spacer name="horizontalSpacer_7">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>40</width>
+                  <height>0</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item>
+               <widget class="QCheckBox" name="QRCode_enable">
+                <property name="sizePolicy">
+                 <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+                  <horstretch>0</horstretch>
+                  <verstretch>0</verstretch>
+                 </sizepolicy>
+                </property>
+                <property name="text">
+                 <string/>
+                </property>
+               </widget>
+              </item>
+             </layout>
+            </item>
+            <item row="11" column="1">
+             <layout class="QHBoxLayout" name="horizontalLayout_12">
+              <item>
+               <spacer name="horizontalSpacer_12">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>40</width>
+                  <height>0</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item>
+               <widget class="CustomSpinBox" name="GUNOverTemp_Warning">
+                <property name="sizePolicy">
+                 <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+                  <horstretch>0</horstretch>
+                  <verstretch>0</verstretch>
+                 </sizepolicy>
+                </property>
+                <property name="alignment">
+                 <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+                </property>
+                <property name="maximum">
+                 <number>999</number>
+                </property>
+               </widget>
+              </item>
+             </layout>
+            </item>
+            <item row="11" column="0">
+             <widget class="QLabel" name="label_overTempWarning">
               <property name="minimumSize">
                <size>
                 <width>0</width>
@@ -284,33 +311,27 @@
                </size>
               </property>
               <property name="text">
-               <string>Charge gun Available : </string>
+               <string>Charge gun Over Temperature Warning : </string>
               </property>
              </widget>
             </item>
-            <item row="2" column="1">
-             <layout class="QHBoxLayout" name="horizontalLayout_3">
+            <item row="0" column="1">
+             <layout class="QHBoxLayout" name="horizontalLayout">
               <item>
-               <spacer name="horizontalSpacer_3">
+               <spacer name="horizontalSpacer">
                 <property name="orientation">
                  <enum>Qt::Horizontal</enum>
                 </property>
                 <property name="sizeHint" stdset="0">
                  <size>
                   <width>40</width>
-                  <height>20</height>
+                  <height>0</height>
                  </size>
                 </property>
                </spacer>
               </item>
               <item>
-               <widget class="QCheckBox" name="GUN_Available">
-                <property name="sizePolicy">
-                 <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
-                  <horstretch>0</horstretch>
-                  <verstretch>0</verstretch>
-                 </sizepolicy>
-                </property>
+               <widget class="QLabel" name="connectorId">
                 <property name="text">
                  <string/>
                 </property>
@@ -318,8 +339,8 @@
               </item>
              </layout>
             </item>
-            <item row="4" column="0">
-             <widget class="QLabel" name="label_3">
+            <item row="3" column="0">
+             <widget class="QLabel" name="label_maxI">
               <property name="minimumSize">
                <size>
                 <width>0</width>
@@ -327,12 +348,12 @@
                </size>
               </property>
               <property name="text">
-               <string>slac ifname : </string>
+               <string>Charge gun maximum current : </string>
               </property>
              </widget>
             </item>
             <item row="8" column="0">
-             <widget class="QLabel" name="label_13">
+             <widget class="QLabel" name="label_requestPowerByMinutes">
               <property name="minimumSize">
                <size>
                 <width>0</width>
@@ -344,92 +365,68 @@
               </property>
              </widget>
             </item>
-            <item row="14" column="1">
-             <layout class="QHBoxLayout" name="horizontalLayout_15">
+            <item row="8" column="1">
+             <layout class="QHBoxLayout" name="horizontalLayout_9">
               <item>
-               <spacer name="horizontalSpacer_15">
+               <spacer name="horizontalSpacer_9">
                 <property name="orientation">
                  <enum>Qt::Horizontal</enum>
                 </property>
                 <property name="sizeHint" stdset="0">
                  <size>
                   <width>40</width>
-                  <height>20</height>
+                  <height>0</height>
                  </size>
                 </property>
                </spacer>
               </item>
               <item>
-               <widget class="CustomSpinBox" name="permitted_current">
+               <widget class="QCheckBox" name="requestPowerByMinutes">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
                   <horstretch>0</horstretch>
                   <verstretch>0</verstretch>
                  </sizepolicy>
                 </property>
-                <property name="alignment">
-                 <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
-                </property>
-                <property name="maximum">
-                 <number>999</number>
+                <property name="text">
+                 <string/>
                 </property>
                </widget>
               </item>
              </layout>
             </item>
-            <item row="4" column="1">
-             <layout class="QHBoxLayout" name="horizontalLayout_5" stretch="1,0">
+            <item row="7" column="1">
+             <layout class="QHBoxLayout" name="horizontalLayout_8" stretch="1,4">
               <item>
-               <spacer name="horizontalSpacer_5">
+               <spacer name="horizontalSpacer_8">
                 <property name="orientation">
                  <enum>Qt::Horizontal</enum>
                 </property>
                 <property name="sizeHint" stdset="0">
                  <size>
                   <width>40</width>
-                  <height>20</height>
-                 </size>
-                </property>
-               </spacer>
-              </item>
-              <item>
-               <widget class="CustomComboBox" name="slac_ifname" native="true">
-                <property name="minimumSize">
-                 <size>
-                  <width>100</width>
                   <height>0</height>
                  </size>
                 </property>
-               </widget>
-              </item>
-             </layout>
-            </item>
-            <item row="0" column="1">
-             <layout class="QHBoxLayout" name="horizontalLayout">
-              <item>
-               <spacer name="horizontalSpacer">
-                <property name="orientation">
-                 <enum>Qt::Horizontal</enum>
-                </property>
-                <property name="sizeHint" stdset="0">
-                 <size>
-                  <width>40</width>
-                  <height>20</height>
-                 </size>
-                </property>
                </spacer>
               </item>
               <item>
-               <widget class="QLabel" name="GUN_ID">
-                <property name="text">
-                 <string/>
+               <widget class="CustomLineEdit" name="QRCode_URL">
+                <property name="sizePolicy">
+                 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+                  <horstretch>0</horstretch>
+                  <verstretch>0</verstretch>
+                 </sizepolicy>
+                </property>
+                <property name="alignment">
+                 <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
                 </property>
                </widget>
               </item>
              </layout>
             </item>
-            <item row="11" column="0">
-             <widget class="QLabel" name="label_6">
+            <item row="0" column="0">
+             <widget class="QLabel" name="label_connectID">
               <property name="minimumSize">
                <size>
                 <width>0</width>
@@ -437,27 +434,27 @@
                </size>
               </property>
               <property name="text">
-               <string>Charge gun Over Temperature Warning : </string>
+               <string>Charge gun ID : </string>
               </property>
              </widget>
             </item>
-            <item row="11" column="1">
-             <layout class="QHBoxLayout" name="horizontalLayout_12">
+            <item row="3" column="1">
+             <layout class="QHBoxLayout" name="horizontalLayout_4">
               <item>
-               <spacer name="horizontalSpacer_12">
+               <spacer name="horizontalSpacer_4">
                 <property name="orientation">
                  <enum>Qt::Horizontal</enum>
                 </property>
                 <property name="sizeHint" stdset="0">
                  <size>
                   <width>40</width>
-                  <height>20</height>
+                  <height>0</height>
                  </size>
                 </property>
                </spacer>
               </item>
               <item>
-               <widget class="CustomSpinBox" name="GUNOverTemp_Warning">
+               <widget class="CustomSpinBox" name="GUN_maxI">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
                   <horstretch>0</horstretch>
@@ -468,25 +465,12 @@
                  <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
                 </property>
                 <property name="maximum">
-                 <number>999</number>
+                 <number>9999</number>
                 </property>
                </widget>
               </item>
              </layout>
             </item>
-            <item row="16" column="0">
-             <widget class="QLabel" name="label_16">
-              <property name="minimumSize">
-               <size>
-                <width>0</width>
-                <height>60</height>
-               </size>
-              </property>
-              <property name="text">
-               <string>Peritted power Kw : </string>
-              </property>
-             </widget>
-            </item>
             <item row="12" column="1">
              <layout class="QHBoxLayout" name="horizontalLayout_13">
               <item>
@@ -497,7 +481,7 @@
                 <property name="sizeHint" stdset="0">
                  <size>
                   <width>40</width>
-                  <height>20</height>
+                  <height>0</height>
                  </size>
                 </property>
                </spacer>
@@ -520,49 +504,23 @@
               </item>
              </layout>
             </item>
-            <item row="0" column="0">
-             <widget class="QLabel" name="label">
-              <property name="minimumSize">
-               <size>
-                <width>0</width>
-                <height>60</height>
-               </size>
-              </property>
-              <property name="text">
-               <string>Charge gun ID : </string>
-              </property>
-             </widget>
-            </item>
-            <item row="6" column="0">
-             <widget class="QLabel" name="label_10">
-              <property name="minimumSize">
-               <size>
-                <width>0</width>
-                <height>60</height>
-               </size>
-              </property>
-              <property name="text">
-               <string>QR code enable : </string>
-              </property>
-             </widget>
-            </item>
-            <item row="13" column="1">
-             <layout class="QHBoxLayout" name="horizontalLayout_14">
+            <item row="9" column="1">
+             <layout class="QHBoxLayout" name="horizontalLayout_10">
               <item>
-               <spacer name="horizontalSpacer_14">
+               <spacer name="horizontalSpacer_10">
                 <property name="orientation">
                  <enum>Qt::Horizontal</enum>
                 </property>
                 <property name="sizeHint" stdset="0">
                  <size>
                   <width>40</width>
-                  <height>20</height>
+                  <height>0</height>
                  </size>
                 </property>
                </spacer>
               </item>
               <item>
-               <widget class="QCheckBox" name="enable_current_limit">
+               <widget class="QCheckBox" name="requestPowerByPowerKW">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
                   <horstretch>0</horstretch>
@@ -576,8 +534,8 @@
               </item>
              </layout>
             </item>
-            <item row="13" column="0">
-             <widget class="QLabel" name="label_7">
+            <item row="12" column="0">
+             <widget class="QLabel" name="label_overTempStopping">
               <property name="minimumSize">
                <size>
                 <width>0</width>
@@ -585,12 +543,12 @@
                </size>
               </property>
               <property name="text">
-               <string>Current limit Enable : </string>
+               <string>Charge gun Over Temperature Stopping : </string>
               </property>
              </widget>
             </item>
-            <item row="9" column="0">
-             <widget class="QLabel" name="label_5">
+            <item row="7" column="0">
+             <widget class="QLabel" name="label_qrCodeUrl">
               <property name="minimumSize">
                <size>
                 <width>0</width>
@@ -598,7 +556,20 @@
                </size>
               </property>
               <property name="text">
-               <string>Request Power By Power KW : </string>
+               <string>QR code url : </string>
+              </property>
+             </widget>
+            </item>
+            <item row="1" column="0">
+             <widget class="QLabel" name="label_gunType">
+              <property name="minimumSize">
+               <size>
+                <width>0</width>
+                <height>60</height>
+               </size>
+              </property>
+              <property name="text">
+               <string>Charge gun type : </string>
               </property>
              </widget>
             </item>
@@ -612,7 +583,7 @@
                 <property name="sizeHint" stdset="0">
                  <size>
                   <width>40</width>
-                  <height>20</height>
+                  <height>0</height>
                  </size>
                 </property>
                </spacer>
@@ -629,68 +600,21 @@
               </item>
              </layout>
             </item>
-            <item row="7" column="1">
-             <layout class="QHBoxLayout" name="horizontalLayout_8" stretch="1,4">
-              <item>
-               <spacer name="horizontalSpacer_8">
-                <property name="orientation">
-                 <enum>Qt::Horizontal</enum>
-                </property>
-                <property name="sizeHint" stdset="0">
-                 <size>
-                  <width>40</width>
-                  <height>20</height>
-                 </size>
-                </property>
-               </spacer>
-              </item>
-              <item>
-               <widget class="CustomLineEdit" name="QRCode_URL">
-                <property name="sizePolicy">
-                 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
-                  <horstretch>0</horstretch>
-                  <verstretch>0</verstretch>
-                 </sizepolicy>
-                </property>
-                <property name="alignment">
-                 <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
-                </property>
-               </widget>
-              </item>
-             </layout>
-            </item>
-            <item row="6" column="1">
-             <layout class="QHBoxLayout" name="horizontalLayout_7">
-              <item>
-               <spacer name="horizontalSpacer_7">
-                <property name="orientation">
-                 <enum>Qt::Horizontal</enum>
-                </property>
-                <property name="sizeHint" stdset="0">
-                 <size>
-                  <width>40</width>
-                  <height>20</height>
-                 </size>
-                </property>
-               </spacer>
-              </item>
-              <item>
-               <widget class="QCheckBox" name="QRCode_enable">
-                <property name="sizePolicy">
-                 <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
-                  <horstretch>0</horstretch>
-                  <verstretch>0</verstretch>
-                 </sizepolicy>
-                </property>
-                <property name="text">
-                 <string/>
-                </property>
-               </widget>
-              </item>
-             </layout>
+            <item row="4" column="0">
+             <widget class="QLabel" name="label_slacIfname">
+              <property name="minimumSize">
+               <size>
+                <width>0</width>
+                <height>60</height>
+               </size>
+              </property>
+              <property name="text">
+               <string>slac ifname : </string>
+              </property>
+             </widget>
             </item>
-            <item row="12" column="0">
-             <widget class="QLabel" name="label_15">
+            <item row="14" column="0">
+             <widget class="QLabel" name="label_2">
               <property name="minimumSize">
                <size>
                 <width>0</width>
@@ -698,27 +622,27 @@
                </size>
               </property>
               <property name="text">
-               <string>Charge gun Over Temperature Stopping : </string>
+               <string>Allowable maximum SOC</string>
               </property>
              </widget>
             </item>
-            <item row="16" column="1">
-             <layout class="QHBoxLayout" name="horizontalLayout_17">
+            <item row="14" column="1">
+             <layout class="QHBoxLayout" name="horizontalLayout_14">
               <item>
-               <spacer name="horizontalSpacer_17">
+               <spacer name="horizontalSpacer_14">
                 <property name="orientation">
                  <enum>Qt::Horizontal</enum>
                 </property>
                 <property name="sizeHint" stdset="0">
                  <size>
                   <width>40</width>
-                  <height>20</height>
+                  <height>0</height>
                  </size>
                 </property>
                </spacer>
               </item>
               <item>
-               <widget class="CustomSpinBox" name="permitted_powerKW">
+               <widget class="CustomSpinBox" name="allow_max_soc">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
                   <horstretch>0</horstretch>
@@ -729,29 +653,29 @@
                  <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
                 </property>
                 <property name="maximum">
-                 <number>999</number>
+                 <number>100</number>
                 </property>
                </widget>
               </item>
              </layout>
             </item>
-            <item row="15" column="1">
-             <layout class="QHBoxLayout" name="horizontalLayout_18">
+            <item row="13" column="1">
+             <layout class="QHBoxLayout" name="horizontalLayout_15">
               <item>
-               <spacer name="horizontalSpacer_18">
+               <spacer name="horizontalSpacer_15">
                 <property name="orientation">
                  <enum>Qt::Horizontal</enum>
                 </property>
                 <property name="sizeHint" stdset="0">
                  <size>
                   <width>40</width>
-                  <height>20</height>
+                  <height>0</height>
                  </size>
                 </property>
                </spacer>
               </item>
               <item>
-               <widget class="QCheckBox" name="enable_powerKW_limit">
+               <widget class="QCheckBox" name="operatorChargeRestriction">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
                   <horstretch>0</horstretch>
@@ -778,12 +702,6 @@
  </widget>
  <customwidgets>
   <customwidget>
-   <class>CustomComboBox</class>
-   <extends>QWidget</extends>
-   <header location="global">CustomComboBox.h</header>
-   <container>1</container>
-  </customwidget>
-  <customwidget>
    <class>CustomLineEdit</class>
    <extends>QLineEdit</extends>
    <header location="global">CustomLineEdit.h</header>
@@ -793,6 +711,12 @@
    <extends>QSpinBox</extends>
    <header location="global">CustomSpinBox.h</header>
   </customwidget>
+  <customwidget>
+   <class>CustomComboBox</class>
+   <extends>QWidget</extends>
+   <header location="global">CustomComboBox.h</header>
+   <container>1</container>
+  </customwidget>
  </customwidgets>
  <resources/>
  <connections/>

+ 2 - 1
src/widgets/workspace/settings/CcuSettings/FormChargeGunType.cpp

@@ -5,11 +5,12 @@
 #include <QSpacerItem>
 #include <QMessageBox>
 
-FormChargeGunType::FormChargeGunType(BaseWidget *parent)
+FormChargeGunType::FormChargeGunType(const int &userType, BaseWidget *parent)
     : BaseWidget(parent)
     , ui(new Ui::FormChargeGunType)
 {
     ui->setupUi(this);
+    setUserType(userType);
 }
 
 FormChargeGunType::~FormChargeGunType()

+ 2 - 1
src/widgets/workspace/settings/CcuSettings/FormChargeGunType.h

@@ -5,6 +5,7 @@
 #include <QScopedPointer>
 
 #include "BaseWidget.h"
+#include "DataTypeDef.h"
 
 namespace Ui {
 class FormChargeGunType;
@@ -15,7 +16,7 @@ class FormChargeGunType : public BaseWidget
     Q_OBJECT
 
 public:
-    explicit FormChargeGunType(BaseWidget *parent = nullptr);
+    explicit FormChargeGunType(const int& userType = General::UserType::ROOT, BaseWidget *parent = nullptr);
     ~FormChargeGunType();
 
     bool returnParent() override;

+ 61 - 8
src/widgets/workspace/settings/CcuSettings/FormOcppGeneralSettings.cpp

@@ -1,11 +1,12 @@
 #include "FormOcppGeneralSettings.h"
 #include "ui_FormOcppGeneralSettings.h"
 
+#include "Globals.h"
 #include "ConfigManager.h"
 #include "LanguageManager.h"
 #include "GeneralInterface.h"
 
-FormOcppGeneralSettings::FormOcppGeneralSettings(const int version, BaseWidget *parent)
+FormOcppGeneralSettings::FormOcppGeneralSettings(const int version, const int& userType, BaseWidget *parent)
     : BaseWidget(parent)
     , ui(new Ui::FormOcppGeneralSettings)
     , m_ocpp_version(version)
@@ -13,7 +14,12 @@ FormOcppGeneralSettings::FormOcppGeneralSettings(const int version, BaseWidget *
     ui->setupUi(this);
 
     initWidget();
+    setUserType(userType);
     connect(LanguageManager::instance(), &LanguageManager::languageChanged, this, [this]() { ui->retranslateUi(this); });
+    connect(GLOBALS, &Globals::ccuConfigValueChanged, this, [this](const CCU_CFG& value) {
+        m_ocpp16 = value.ocpp16_list;
+        m_ocpp21 = value.ocpp21_list;
+    });
 }
 
 FormOcppGeneralSettings::~FormOcppGeneralSettings()
@@ -36,9 +42,13 @@ void FormOcppGeneralSettings::showWidget()
 {
     switch (m_ocpp_version) {
     case OcppVersion::OCPP16:
+        m_ocpp16 = ConfigManager::instance()->ccu_cfg().ocpp16_list;
+        refreshOcpp16();
         ui->stackedWidget->setCurrentWidget(ui->ocpp16);
         break;
     case OcppVersion::OCPP21:
+        m_ocpp21 = ConfigManager::instance()->ccu_cfg().ocpp21_list;
+        refreshOcpp21();
         ui->stackedWidget->setCurrentWidget(ui->ocpp21);
         break;
     default:
@@ -57,7 +67,7 @@ void FormOcppGeneralSettings::refreshOcpp16()
     GeneralInterface::clearGridLayoutChiledren(ui->ocpp16_layout);
     int row = 0;
     for (const ocpp1_6_info_t& data : std::as_const(m_ocpp16)) {
-        m_ocpp16_map[row] = new FormOCPP16GeneralSettings();
+        m_ocpp16_map[row] = new FormOCPP16GeneralSettings(userType());
         m_ocpp16_map[row]->setOcpp_info(data);
         GeneralInterface::gridLayoutAddWidget(ui->ocpp16_layout, m_ocpp16_map[row]);
 
@@ -76,7 +86,7 @@ void FormOcppGeneralSettings::refreshOcpp21()
     GeneralInterface::clearGridLayoutChiledren(ui->ocpp21_layout);
     int row = 0;
     for (const ocpp2_1_info_t& data : std::as_const(m_ocpp21)) {
-        m_ocpp21_map[row] = new FormOCPP21GeneralSettings();
+        m_ocpp21_map[row] = new FormOCPP21GeneralSettings(userType());
         m_ocpp21_map[row]->setOcpp_info(data);
         GeneralInterface::gridLayoutAddWidget(ui->ocpp21_layout, m_ocpp21_map[row]);
 
@@ -92,16 +102,59 @@ void FormOcppGeneralSettings::refreshOcpp21()
 
 void FormOcppGeneralSettings::updateData()
 {
+    switch (m_ocpp_version) {
+    case OcppVersion::OCPP16:
+        updateOcpp16();
+        break;
+    case OcppVersion::OCPP21:
+        updateOcpp21();
+        break;
+    default:
+        break;
+    }
+}
 
+void FormOcppGeneralSettings::updateOcpp16()
+{
+    m_ocpp16.clear();
+    auto widgetList = m_ocpp16_map.values();
+    foreach (const auto& widget, std::as_const(widgetList)) {
+        m_ocpp16.append(widget->ocpp_info());
+    }
 }
 
-void FormOcppGeneralSettings::showEvent(QShowEvent *event)
+void FormOcppGeneralSettings::updateOcpp21()
 {
-    setIsModify(false);
-    m_ocpp16 = ConfigManager::instance()->ccu_cfg().ocpp16_list;
-    m_ocpp21 = ConfigManager::instance()->ccu_cfg().ocpp21_list;
-    refreshData();
+    m_ocpp21.clear();
+    auto widgetList = m_ocpp21_map.values();
+    foreach (const auto& widget, std::as_const(widgetList)) {
+        m_ocpp21.append(widget->ocpp_info());
+    }
+}
+
+void FormOcppGeneralSettings::showEvent(QShowEvent *event)
+{    
     BaseWidget::showEvent(event);
+    setIsModify(false);
+    showWidget();
+}
+
+void FormOcppGeneralSettings::hideEvent(QHideEvent *event)
+{
+    BaseWidget::hideEvent(event);
+    updateData();
+    auto ccu_cfg = ConfigManager::instance()->ccu_cfg();
+    switch (m_ocpp_version) {
+    case OcppVersion::OCPP16:
+        ccu_cfg.ocpp16_list = m_ocpp16;
+        break;
+    case OcppVersion::OCPP21:
+        ccu_cfg.ocpp21_list = m_ocpp21;
+        break;
+    default:
+        break;
+    }
+    ConfigManager::instance()->saveConfig(CCU_CONFIG, QVariant::fromValue(ccu_cfg));
 }
 
 int FormOcppGeneralSettings::ocpp_version() const

+ 4 - 1
src/widgets/workspace/settings/CcuSettings/FormOcppGeneralSettings.h

@@ -22,7 +22,7 @@ class FormOcppGeneralSettings : public BaseWidget
     Q_OBJECT
 
 public:
-    explicit FormOcppGeneralSettings(const int version = OcppVersion::OCPP16, BaseWidget *parent = nullptr);
+    explicit FormOcppGeneralSettings(const int version = OcppVersion::OCPP16, const int& userType = General::UserType::ROOT, BaseWidget *parent = nullptr);
     ~FormOcppGeneralSettings();
 
     bool returnParent() override;
@@ -38,9 +38,12 @@ private:
     void refreshOcpp16();
     void refreshOcpp21();
     void updateData();
+    void updateOcpp16();
+    void updateOcpp21();
 
 protected:
     void showEvent(QShowEvent* event) override;
+    void hideEvent(QHideEvent* event) override;
 
 private:
     Ui::FormOcppGeneralSettings *ui;

+ 13 - 9
src/widgets/workspace/settings/CcuSettings/FormOfflinePrice.cpp

@@ -9,13 +9,13 @@
 #include "LanguageManager.h"
 #include "GeneralInterface.h"
 
-FormOfflinePrice::FormOfflinePrice(BaseWidget *parent)
+FormOfflinePrice::FormOfflinePrice(const int &userType, BaseWidget *parent)
     : BaseWidget(parent)
     , ui(new Ui::FormOfflinePrice)
 {
     ui->setupUi(this);
     initWidget();
-
+    setUserType(userType);
     initConnect();
 }
 
@@ -32,10 +32,8 @@ bool FormOfflinePrice::returnParent()
 
 void FormOfflinePrice::initWidget()
 {
+    
     m_price_detail.reset(new DialogPriceDetail());
-    m_price_detail->setParent(this);
-    m_price_detail->setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
-    m_price_detail->setWindowModality(Qt::WindowModal);
 
     initComboBox();
     initTableWidget();
@@ -71,8 +69,7 @@ void FormOfflinePrice::initTableWidget()
 
     ui->priceTableWidget->setColumnCount(4);
 
-    QScroller::grabGesture(ui->priceTableWidget,              QScroller::TouchGesture);
-    QScroller::grabGesture(ui->priceTableWidget->viewport(),  QScroller::LeftMouseButtonGesture);
+    GeneralInterface::setTouchScroller(ui->priceTableWidget);
 }
 
 void FormOfflinePrice::initConnect()
@@ -186,9 +183,16 @@ void FormOfflinePrice::updateData()
 }
 
 void FormOfflinePrice::showEvent(QShowEvent *event)
-{
+{    
+    BaseWidget::showEvent(event);
     setIsModify(false);
     m_price_info = ConfigManager::instance()->price_info();
     refreshData();
-    BaseWidget::showEvent(event);
+}
+
+void FormOfflinePrice::hideEvent(QHideEvent *event)
+{
+    BaseWidget::hideEvent(event);
+    updateData();
+    ConfigManager::instance()->saveConfig(PRICEINFO, QVariant::fromValue(m_price_info));
 }

+ 2 - 1
src/widgets/workspace/settings/CcuSettings/FormOfflinePrice.h

@@ -17,7 +17,7 @@ class FormOfflinePrice : public BaseWidget
     Q_OBJECT
 
 public:
-    explicit FormOfflinePrice(BaseWidget *parent = nullptr);
+    explicit FormOfflinePrice(const int& userType = General::UserType::ROOT, BaseWidget *parent = nullptr);
     ~FormOfflinePrice();
 
     bool returnParent() override;
@@ -45,6 +45,7 @@ private slots:
 
 protected:
     void showEvent(QShowEvent* event) override;
+    void hideEvent(QHideEvent* event) override;
 
 private:
     Ui::FormOfflinePrice *ui;

+ 6 - 6
src/widgets/workspace/settings/CcuSettings/FormOfflinePrice.ui

@@ -50,7 +50,7 @@
           <widget class="CustomComboBox" name="timezone" native="true">
            <property name="minimumSize">
             <size>
-             <width>200</width>
+             <width>280</width>
              <height>0</height>
             </size>
            </property>
@@ -268,16 +268,16 @@
  </widget>
  <customwidgets>
   <customwidget>
+   <class>CustomDoubleSpinBox</class>
+   <extends>QDoubleSpinBox</extends>
+   <header location="global">CustomDoubleSpinBox.h</header>
+  </customwidget>
+  <customwidget>
    <class>CustomComboBox</class>
    <extends>QWidget</extends>
    <header location="global">CustomComboBox.h</header>
    <container>1</container>
   </customwidget>
-  <customwidget>
-   <class>CustomDoubleSpinBox</class>
-   <extends>QDoubleSpinBox</extends>
-   <header location="global">CustomDoubleSpinBox.h</header>
-  </customwidget>
  </customwidgets>
  <resources/>
  <connections/>

+ 16 - 3
src/widgets/workspace/settings/CcuSettings/FormPcuhwSettings.cpp

@@ -1,11 +1,12 @@
 #include "FormPcuhwSettings.h"
 #include "ui_FormPcuhwSettings.h"
 
+#include "Globals.h"
 #include "LanguageManager.h"
 #include "GeneralInterface.h"
 #include "ConfigManager.h"
 
-FormPcuhwSettings::FormPcuhwSettings(BaseWidget *parent)
+FormPcuhwSettings::FormPcuhwSettings(const int &userType, BaseWidget *parent)
     : BaseWidget(parent)
     , ui(new Ui::FormPcuhwSettings)
 {
@@ -13,6 +14,7 @@ FormPcuhwSettings::FormPcuhwSettings(BaseWidget *parent)
 
     GeneralInterface::setTouchScroller(ui->scrollArea);
     initWidget();
+    setUserType(userType);
 }
 
 FormPcuhwSettings::~FormPcuhwSettings()
@@ -38,6 +40,8 @@ void FormPcuhwSettings::initConnect()
 {
     connectAllValueChanged(this);
     connect(LanguageManager::instance(), &LanguageManager::languageChanged, this, [this]() { ui->retranslateUi(this); });
+
+    connect(GLOBALS, &Globals::ccuConfigValueChanged, this, [this](const CCU_CFG& value) { m_pcuhw_cfg = value.pcuhw; });
 }
 
 void FormPcuhwSettings::connectAllValueChanged(QWidget *widget)
@@ -91,9 +95,18 @@ void FormPcuhwSettings::onValueChanged()
 }
 
 void FormPcuhwSettings::showEvent(QShowEvent *event)
-{
+{    
+    BaseWidget::showEvent(event);
     setIsModify(false);
     m_pcuhw_cfg = ConfigManager::instance()->ccu_cfg().pcuhw;
     refreshData();
-    BaseWidget::showEvent(event);
+}
+
+void FormPcuhwSettings::hideEvent(QHideEvent *event)
+{
+    BaseWidget::hideEvent(event);
+    m_pcuhw_cfg = getNewData();
+    CCU_CFG ccu_cfg = ConfigManager::instance()->ccu_cfg();
+    ccu_cfg.pcuhw = m_pcuhw_cfg;
+    ConfigManager::instance()->saveConfig(CCU_CONFIG, QVariant::fromValue(ccu_cfg));
 }

+ 2 - 1
src/widgets/workspace/settings/CcuSettings/FormPcuhwSettings.h

@@ -15,7 +15,7 @@ class FormPcuhwSettings : public BaseWidget
     Q_OBJECT
 
 public:
-    explicit FormPcuhwSettings(BaseWidget *parent = nullptr);
+    explicit FormPcuhwSettings(const int& userType = General::UserType::ROOT, BaseWidget *parent = nullptr);
     ~FormPcuhwSettings();
 
     bool returnParent() override;
@@ -32,6 +32,7 @@ private:
 
 protected:
     void showEvent(QShowEvent* event) override;
+    void hideEvent(QHideEvent* event) override;
 
 private:
     Ui::FormPcuhwSettings *ui;

+ 15 - 3
src/widgets/workspace/settings/CcuSettings/FormPcutcSettings.cpp

@@ -1,11 +1,12 @@
 #include "FormPcutcSettings.h"
 #include "ui_FormPcutcSettings.h"
 
+#include "Globals.h"
 #include "ConfigManager.h"
 #include "LanguageManager.h"
 #include "GeneralInterface.h"
 
-FormPcutcSettings::FormPcutcSettings(BaseWidget *parent)
+FormPcutcSettings::FormPcutcSettings(const int &userType, BaseWidget *parent)
     : BaseWidget(parent)
     , ui(new Ui::FormPcutcSettings)
 {
@@ -15,6 +16,7 @@ FormPcutcSettings::FormPcutcSettings(BaseWidget *parent)
     connect(LanguageManager::instance(), &LanguageManager::languageChanged, this, [this]() { ui->retranslateUi(this); });
 
     initWidget();
+    setUserType(userType);
 }
 
 FormPcutcSettings::~FormPcutcSettings()
@@ -33,6 +35,7 @@ bool FormPcutcSettings::returnParent()
 void FormPcutcSettings::initWidget()
 {
     ui->connect_ip_string->setFormType(General::Type::IP_ADDR);
+    connect(GLOBALS, &Globals::ccuConfigValueChanged, this, [this](const CCU_CFG& value) { pcutc_info = value.pcutc; });
 
     connect(ui->enable,       &QCheckBox::stateChanged,                                 this, [this]() { setIsModify(true); });
     connect(ui->connect_ip_string,  &CustomLineEdit::textChanged,                       this, [this]() { setIsModify(true); });
@@ -57,9 +60,18 @@ void FormPcutcSettings::updateData()
 }
 
 void FormPcutcSettings::showEvent(QShowEvent *event)
-{
+{    
+    BaseWidget::showEvent(event);
     setIsModify(false);
     pcutc_info = ConfigManager::instance()->ccu_cfg().pcutc;
     refreshData();
-    BaseWidget::showEvent(event);
+}
+
+void FormPcutcSettings::hideEvent(QHideEvent *event)
+{
+    BaseWidget::hideEvent(event);
+    updateData();
+    auto ccu_cfg = ConfigManager::instance()->ccu_cfg();
+    ccu_cfg.pcutc = pcutc_info;
+    ConfigManager::instance()->saveConfig(CCU_CONFIG, QVariant::fromValue(ccu_cfg));
 }

+ 2 - 1
src/widgets/workspace/settings/CcuSettings/FormPcutcSettings.h

@@ -14,7 +14,7 @@ class FormPcutcSettings : public BaseWidget
     Q_OBJECT
 
 public:
-    explicit FormPcutcSettings(BaseWidget *parent = nullptr);
+    explicit FormPcutcSettings(const int& userType = General::UserType::ROOT, BaseWidget *parent = nullptr);
     ~FormPcutcSettings();
 
     bool returnParent() override;
@@ -27,6 +27,7 @@ private:
 
 protected:
     void showEvent(QShowEvent* event) override;
+    void hideEvent(QHideEvent* event) override;
 
 private:
     Ui::FormPcutcSettings *ui;

+ 15 - 5
src/widgets/workspace/settings/CcuSettings/FormQttcuSettings.cpp

@@ -1,11 +1,12 @@
 #include "FormQttcuSettings.h"
 #include "ui_FormQttcuSettings.h"
 
+#include "Globals.h"
 #include "ConfigManager.h"
 #include "LanguageManager.h"
 #include "GeneralInterface.h"
 
-FormQttcuSettings::FormQttcuSettings(BaseWidget *parent)
+FormQttcuSettings::FormQttcuSettings(const int &userType, BaseWidget *parent)
     : BaseWidget(parent)
     , ui(new Ui::FormQttcuSettings)
 {
@@ -13,8 +14,8 @@ FormQttcuSettings::FormQttcuSettings(BaseWidget *parent)
 
     GeneralInterface::setTouchScroller(ui->scrollArea);
     connect(LanguageManager::instance(), &LanguageManager::languageChanged, this, [this]() { ui->retranslateUi(this); });
-
     initWidget();
+    setUserType(userType);
 }
 
 FormQttcuSettings::~FormQttcuSettings()
@@ -33,7 +34,7 @@ bool FormQttcuSettings::returnParent()
 void FormQttcuSettings::initWidget()
 {
     ui->connect_ip_string->setFormType(General::Type::IP_ADDR);
-
+    connect(GLOBALS, &Globals::ccuConfigValueChanged, this, [this](const CCU_CFG& value) { qttcu_info = value.qttcu; });
     connect(ui->enable,             &QCheckBox::stateChanged,                           this, [this]() { setIsModify(true); });
     connect(ui->connect_ip_string,  &CustomLineEdit::textChanged,                       this, [this]() { setIsModify(true); });
     connect(ui->connect_port,       QOverload<int>::of(&CustomSpinBox::valueChanged),   this, [this]() { setIsModify(true); });
@@ -57,9 +58,18 @@ void FormQttcuSettings::updateData()
 }
 
 void FormQttcuSettings::showEvent(QShowEvent *event)
-{
+{    
+    BaseWidget::showEvent(event);
     setIsModify(false);
     qttcu_info = ConfigManager::instance()->ccu_cfg().qttcu;
     refreshData();
-    BaseWidget::showEvent(event);
+}
+
+void FormQttcuSettings::hideEvent(QHideEvent *event)
+{
+    BaseWidget::hideEvent(event);
+    updateData();
+    auto ccu_cfg = ConfigManager::instance()->ccu_cfg();
+    ccu_cfg.qttcu = qttcu_info;
+    ConfigManager::instance()->saveConfig(CCU_CONFIG, QVariant::fromValue(ccu_cfg));
 }

+ 2 - 1
src/widgets/workspace/settings/CcuSettings/FormQttcuSettings.h

@@ -14,7 +14,7 @@ class FormQttcuSettings : public BaseWidget
     Q_OBJECT
 
 public:
-    explicit FormQttcuSettings(BaseWidget *parent = nullptr);
+    explicit FormQttcuSettings(const int& userType = General::UserType::ROOT, BaseWidget *parent = nullptr);
     ~FormQttcuSettings();
 
     bool returnParent() override;
@@ -26,6 +26,7 @@ private:
 
 protected:
     void showEvent(QShowEvent* event) override;
+    void hideEvent(QHideEvent* event) override;
 
 private:
     Ui::FormQttcuSettings *ui;

+ 24 - 2
src/widgets/workspace/settings/CcuSettings/OcppGeneralSetting/FormOCPP16GeneralSettings.cpp

@@ -2,15 +2,17 @@
 #include "ui_FormOCPP16GeneralSettings.h"
 
 #include "LanguageManager.h"
+#include "GeneralInterface.h"
 
-FormOCPP16GeneralSettings::FormOCPP16GeneralSettings(QWidget *parent)
-    : QWidget(parent)
+FormOCPP16GeneralSettings::FormOCPP16GeneralSettings(const int &userType, BaseWidget *parent)
+    : BaseWidget(parent)
     , ui(new Ui::FormOCPP16GeneralSettings)
 {
     ui->setupUi(this);
 
     initWidget();
     initConnect();
+    setUserType(userType);
 }
 
 FormOCPP16GeneralSettings::~FormOCPP16GeneralSettings()
@@ -18,6 +20,11 @@ FormOCPP16GeneralSettings::~FormOCPP16GeneralSettings()
     delete ui;
 }
 
+bool FormOCPP16GeneralSettings::returnParent()
+{
+    return true;
+}
+
 void FormOCPP16GeneralSettings::initWidget()
 {
     ui->connect_ip_string->setFormType(General::Type::IP_ADDR);
@@ -70,6 +77,21 @@ void FormOCPP16GeneralSettings::updateData()
     m_ocpp_info.enable_ssl                  = ui->enable_ssl->isChecked();
 }
 
+void FormOCPP16GeneralSettings::refreshVisiable()
+{
+    GeneralInterface::setControlEnabled(ui->ssl_ca_filepath,            ui->label_ssl_ca_filepath,          userType());
+    GeneralInterface::setControlEnabled(ui->ssl_cert_filepath,          ui->label_ssl_cert_filepath,        userType());
+    GeneralInterface::setControlEnabled(ui->ssl_private_key_filepath,   ui->label_ssl_private_key_filepath, userType());
+}
+
+void FormOCPP16GeneralSettings::showEvent(QShowEvent *event)
+{
+    BaseWidget::showEvent(event);
+    refreshData();
+    setIsModify(false);
+    refreshVisiable();
+}
+
 ocpp1_6_info_t FormOCPP16GeneralSettings::ocpp_info()
 {
     updateData();

+ 11 - 2
src/widgets/workspace/settings/CcuSettings/OcppGeneralSetting/FormOCPP16GeneralSettings.h

@@ -2,20 +2,24 @@
 #define FORMOCPP16GENERALSETTINGS_H
 
 #include <QWidget>
+
+#include "BaseWidget.h"
 #include "DataTypeDef.h"
 
 namespace Ui {
 class FormOCPP16GeneralSettings;
 }
 
-class FormOCPP16GeneralSettings : public QWidget
+class FormOCPP16GeneralSettings : public BaseWidget
 {
     Q_OBJECT
 
 public:
-    explicit FormOCPP16GeneralSettings(QWidget *parent = nullptr);
+    explicit FormOCPP16GeneralSettings(const int& userType = General::UserType::ROOT, BaseWidget *parent = nullptr);
     ~FormOCPP16GeneralSettings();
 
+    bool returnParent() override;
+
     ocpp1_6_info_t ocpp_info();
     void setOcpp_info(const ocpp1_6_info_t &newOcpp_info);
 
@@ -26,9 +30,14 @@ private:
     void refreshData();
     void updateData();
 
+    void refreshVisiable();
+
 signals:
     void valueChanged();
 
+protected:
+    void showEvent(QShowEvent* event) override;
+
 private:
     Ui::FormOCPP16GeneralSettings *ui;
     bool m_is_spread = false;

+ 3 - 3
src/widgets/workspace/settings/CcuSettings/OcppGeneralSetting/FormOCPP16GeneralSettings.ui

@@ -179,7 +179,7 @@
            </widget>
           </item>
           <item row="4" column="0">
-           <widget class="QLabel" name="label_5">
+           <widget class="QLabel" name="label_ssl_cert_filepath">
             <property name="minimumSize">
              <size>
               <width>0</width>
@@ -225,7 +225,7 @@
            </layout>
           </item>
           <item row="5" column="0">
-           <widget class="QLabel" name="label_6">
+           <widget class="QLabel" name="label_ssl_private_key_filepath">
             <property name="minimumSize">
              <size>
               <width>0</width>
@@ -384,7 +384,7 @@
            </layout>
           </item>
           <item row="3" column="0">
-           <widget class="QLabel" name="label_4">
+           <widget class="QLabel" name="label_ssl_ca_filepath">
             <property name="minimumSize">
              <size>
               <width>0</width>

+ 24 - 2
src/widgets/workspace/settings/CcuSettings/OcppGeneralSetting/FormOCPP21GeneralSettings.cpp

@@ -2,15 +2,17 @@
 #include "ui_FormOCPP21GeneralSettings.h"
 
 #include "LanguageManager.h"
+#include "GeneralInterface.h"
 
-FormOCPP21GeneralSettings::FormOCPP21GeneralSettings(QWidget *parent)
-    : QWidget(parent)
+FormOCPP21GeneralSettings::FormOCPP21GeneralSettings(const int &userType, BaseWidget *parent)
+    : BaseWidget(parent)
     , ui(new Ui::FormOCPP21GeneralSettings)
 {
     ui->setupUi(this);
 
     initWidget();
     initConnect();
+    setUserType(userType);
 }
 
 FormOCPP21GeneralSettings::~FormOCPP21GeneralSettings()
@@ -18,6 +20,11 @@ FormOCPP21GeneralSettings::~FormOCPP21GeneralSettings()
     delete ui;
 }
 
+bool FormOCPP21GeneralSettings::returnParent()
+{
+    return true;
+}
+
 ocpp2_1_info_t FormOCPP21GeneralSettings::ocpp_info()
 {
     updateData();
@@ -80,3 +87,18 @@ void FormOCPP21GeneralSettings::updateData()
     m_ocpp_info.ssl_private_key_filepath    = ui->ssl_private_key_filepath->text();
     m_ocpp_info.enable_ssl                  = ui->enable_ssl->isChecked();
 }
+
+void FormOCPP21GeneralSettings::refreshVisiable()
+{
+    GeneralInterface::setControlEnabled(ui->ssl_ca_filepath,            ui->label_ssl_ca_filepath,          userType());
+    GeneralInterface::setControlEnabled(ui->ssl_cert_filepath,          ui->label_ssl_cert_filepath,        userType());
+    GeneralInterface::setControlEnabled(ui->ssl_private_key_filepath,   ui->label_ssl_private_key_filepath, userType());
+}
+
+void FormOCPP21GeneralSettings::showEvent(QShowEvent *event)
+{
+    BaseWidget::showEvent(event);
+    refreshData();
+    setIsModify(false);
+    refreshVisiable();
+}

+ 10 - 2
src/widgets/workspace/settings/CcuSettings/OcppGeneralSetting/FormOCPP21GeneralSettings.h

@@ -2,20 +2,24 @@
 #define FORMOCPP21GENERALSETTINGS_H
 
 #include <QWidget>
+
+#include "BaseWidget.h"
 #include "DataTypeDef.h"
 
 namespace Ui {
 class FormOCPP21GeneralSettings;
 }
 
-class FormOCPP21GeneralSettings : public QWidget
+class FormOCPP21GeneralSettings : public BaseWidget
 {
     Q_OBJECT
 
 public:
-    explicit FormOCPP21GeneralSettings(QWidget *parent = nullptr);
+    explicit FormOCPP21GeneralSettings(const int& userType = General::UserType::ROOT, BaseWidget *parent = nullptr);
     ~FormOCPP21GeneralSettings();
 
+    bool returnParent() override;
+
     ocpp2_1_info_t ocpp_info();
     void setOcpp_info(const ocpp2_1_info_t &newOcpp_info);
 
@@ -25,10 +29,14 @@ private:
 
     void refreshData();
     void updateData();
+    void refreshVisiable();
 
 signals:
     void valueChanged();
 
+protected:
+    void showEvent(QShowEvent* event) override;
+
 private:
     Ui::FormOCPP21GeneralSettings *ui;
     bool m_is_spread = false;

+ 3 - 3
src/widgets/workspace/settings/CcuSettings/OcppGeneralSetting/FormOCPP21GeneralSettings.ui

@@ -179,7 +179,7 @@
            </widget>
           </item>
           <item row="4" column="0">
-           <widget class="QLabel" name="label_5">
+           <widget class="QLabel" name="label_ssl_cert_filepath">
             <property name="minimumSize">
              <size>
               <width>0</width>
@@ -225,7 +225,7 @@
            </layout>
           </item>
           <item row="5" column="0">
-           <widget class="QLabel" name="label_6">
+           <widget class="QLabel" name="label_ssl_private_key_filepath">
             <property name="minimumSize">
              <size>
               <width>0</width>
@@ -384,7 +384,7 @@
            </layout>
           </item>
           <item row="3" column="0">
-           <widget class="QLabel" name="label_4">
+           <widget class="QLabel" name="label_ssl_ca_filepath">
             <property name="minimumSize">
              <size>
               <width>0</width>

+ 181 - 79
src/widgets/workspace/settings/FormSettings.cpp

@@ -47,7 +47,6 @@ FormSettings::FormSettings(BaseWidget *parent)
 
     initWidget();
     initConnect();
-    initNavigationBar();
 }
 
 FormSettings::~FormSettings()
@@ -57,36 +56,23 @@ FormSettings::~FormSettings()
 
 bool FormSettings::returnParent()
 {
-    auto form_list = m_formMap.values();
-    for (QWidget* widget : std::as_const(form_list)) {
-        BaseWidget* temp = qobject_cast<BaseWidget*>(widget);
-        if (!temp) continue;
-        if (temp->isModify()) {
-            setIsModify(true);
-        }
-    }
-
-    bool isSave = true;
-    // if (isModify()) {
-    //     auto ret = QMessageBox::question(this, tr("Save"),
-    //                                      tr("The content has been modified. Do you want to save the changes?"),
-    //                                      QMessageBox::Cancel | QMessageBox::No | QMessageBox::Yes);
-    //     if (ret == QMessageBox::Yes) {      // save
-    //         isSave = true;
-    //     } else if (ret == QMessageBox::No){ // no save
-    //         isSave = false;
-    //     } else {                            // cancel
-    //         return false;
+    // auto form_list = m_formMap.values();
+    // for (QWidget* widget : std::as_const(form_list)) {
+    //     BaseWidget* temp = qobject_cast<BaseWidget*>(widget);
+    //     if (!temp) continue;
+    //     if (temp->isModify()) {
+    //         setIsModify(true);
     //     }
     // }
 
-    for (QWidget* widget : std::as_const(form_list)) {
-        BaseWidget* temp = qobject_cast<BaseWidget*>(widget);
-        if (!temp) continue;
-        if (temp->isModify() && isSave) {
-            temp->returnParent();
-        }
-    }
+    // bool isSave = true;
+    // for (QWidget* widget : std::as_const(form_list)) {
+    //     BaseWidget* temp = qobject_cast<BaseWidget*>(widget);
+    //     if (!temp) continue;
+    //     if (temp->isModify() && isSave) {
+    //         temp->returnParent();
+    //     }
+    // }
 
     return true;
 }
@@ -99,9 +85,6 @@ void FormSettings::initConnect()
         showForm(index);
     });
 
-    auto charging_profiles_form = qobject_cast<FormChargingProfilesSettings*>(m_formMap[Workspace::Settings::Ocpp::CHARGING_PROFILES]);
-    connect(charging_profiles_form, &FormChargingProfilesSettings::currentFormChanged, this, &FormSettings::onUpdateChargingProfileData);
-
     connect(GLOBALS, &Globals::ccuConfigValueChanged, this, [this](const CCU_CFG& ccu_cfg) {
         if (m_ccu_cfg.GUN_Numb != ccu_cfg.GUN_Numb) {
             m_ccu_cfg = ccu_cfg;
@@ -114,6 +97,9 @@ void FormSettings::refreshNavigationBar()
 {
     refreshGunSettingsNavigationBar();
     ui->navigation->setSelectItem(Workspace::Settings::CCU);
+
+    // 显示初始页面
+    showForm(Workspace::Settings::CCU);
 }
 
 void FormSettings::refreshGunSettingsNavigationBar()
@@ -150,17 +136,35 @@ int FormSettings::getNodeDataByGunId(const int &gun_id)
 
 void FormSettings::initNavigationBar()
 {
-    auto ccu = ui->navigation->addNavigationItem(tr("CCU Settings"),        Workspace::Settings::CCU);
+    switch (userType()) {
+    case General::UserType::ADMIN:
+        initAdminNavigationBar();
+        break;
+    case General::UserType::OPERATOR:
+        initOperatorNavigationBar();
+        break;
+    case General::UserType::ROOT:
+        initRoowNavigationBar();
+        break;
+    default:
+        break;
+    }
+}
+
+void FormSettings::initRoowNavigationBar()
+{
+    ui->navigation->clearNavigationItems();
+    auto ccu = ui->navigation->addNavigationItem(tr("Charge Point Settings"),        Workspace::Settings::CCU);
     ui->navigation->addNavigationItem(tr("Charge Gun Settings"),            Workspace::Settings::Ccu::CHARGE_GUN,       ccu);
     ui->navigation->addNavigationItem(tr("Offline Price Settings"),         Workspace::Settings::Ccu::OFFLINE_PRICES,   ccu);
-    ui->navigation->addNavigationItem(tr("pcuhw Settings"),                 Workspace::Settings::Ccu::PCUHW,            ccu);
-    ui->navigation->addNavigationItem(tr("pcutc Settings"),                 Workspace::Settings::Ccu::PCUTC,            ccu);
-    ui->navigation->addNavigationItem(tr("qttcu Settings"),                 Workspace::Settings::Ccu::QTTCU,            ccu);
-    ui->navigation->addNavigationItem(tr("ocpp1.6 Settings"),               Workspace::Settings::Ccu::OCPP16,           ccu);
-    ui->navigation->addNavigationItem(tr("ocpp2.1 Settings"),               Workspace::Settings::Ccu::OCPP21,           ccu);
+    ui->navigation->addNavigationItem(tr("HUAWEI Power Module Settings"),   Workspace::Settings::Ccu::PCUHW,            ccu);
+    ui->navigation->addNavigationItem(tr("TCharge Power Module Settings"),  Workspace::Settings::Ccu::PCUTC,            ccu);
+    ui->navigation->addNavigationItem(tr("Terminal Control Page Settings"), Workspace::Settings::Ccu::QTTCU,            ccu);
+    ui->navigation->addNavigationItem(tr("OCPP1.6 Settings"),               Workspace::Settings::Ccu::OCPP16,           ccu);
+    ui->navigation->addNavigationItem(tr("OCPP2.1 Settings"),               Workspace::Settings::Ccu::OCPP21,           ccu);
 
-    ui->navigation->addNavigationItem(tr("TCU Settings"),                   Workspace::Settings::TCU);
-    ui->navigation->addNavigationItem(tr("PCU Settings"),                   Workspace::Settings::PCU);
+    ui->navigation->addNavigationItem(tr("General Settings"),               Workspace::Settings::TCU);
+    ui->navigation->addNavigationItem(tr("Power Module Settings"),          Workspace::Settings::PCU);
 
     auto ocpp = ui->navigation->addNavigationItem(tr("OCPP Settings"),      Workspace::Settings::OCPP);
     ui->navigation->addNavigationItem(tr("Configure key"),                  Workspace::Settings::Ocpp::CONFIG_KEY,          ocpp);
@@ -169,18 +173,71 @@ void FormSettings::initNavigationBar()
     ui->navigation->addNavigationItem(tr("Charging Profiles"),              Workspace::Settings::Ocpp::CHARGING_PROFILES,   ocpp);
 
     auto other = ui->navigation->addNavigationItem(tr("Other Settings"),    Workspace::Settings::OTHER);
-    ui->navigation->addNavigationItem(tr("device infomation"),              Workspace::Settings::Other::DEVICE_INFO,        other);
-    ui->navigation->addNavigationItem(tr("Firmware infomation"),            Workspace::Settings::Other::FIRMWARE_INFO,      other);
+    ui->navigation->addNavigationItem(tr("Device information"),             Workspace::Settings::Other::DEVICE_INFO,        other);
+    // ui->navigation->addNavigationItem(tr("Firmware information"),           Workspace::Settings::Other::FIRMWARE_INFO,      other);
     ui->navigation->addNavigationItem(tr("Charging Records"),               Workspace::Settings::Other::CHARGING_RECORDS,   other);
     ui->navigation->addNavigationItem(tr("Error Codes"),                    Workspace::Settings::Other::ERROR_CODE_NOTE,    other);
 
     ui->navigation->expandAll();
 }
 
+void FormSettings::initAdminNavigationBar()
+{
+    ui->navigation->clearNavigationItems();
+    auto ccu = ui->navigation->addNavigationItem(tr("Charge Point Settings"),        Workspace::Settings::CCU);
+    ui->navigation->addNavigationItem(tr("Charge Gun Settings"),            Workspace::Settings::Ccu::CHARGE_GUN,       ccu);
+    ui->navigation->addNavigationItem(tr("Offline Price Settings"),         Workspace::Settings::Ccu::OFFLINE_PRICES,   ccu);
+    // ui->navigation->addNavigationItem(tr("HUAWEI Power Module Settings"),   Workspace::Settings::Ccu::PCUHW,            ccu);
+    // ui->navigation->addNavigationItem(tr("TCharge Power Module Settings"),  Workspace::Settings::Ccu::PCUTC,            ccu);
+    // ui->navigation->addNavigationItem(tr("Terminal Control Page Settings"), Workspace::Settings::Ccu::QTTCU,            ccu);
+    ui->navigation->addNavigationItem(tr("OCPP1.6 Settings"),               Workspace::Settings::Ccu::OCPP16,           ccu);
+    ui->navigation->addNavigationItem(tr("OCPP2.1 Settings"),               Workspace::Settings::Ccu::OCPP21,           ccu);
+
+    ui->navigation->addNavigationItem(tr("General Settings"),               Workspace::Settings::TCU);
+    // ui->navigation->addNavigationItem(tr("Power Module Settings"),          Workspace::Settings::PCU);
+
+    auto ocpp = ui->navigation->addNavigationItem(tr("OCPP Settings"),      Workspace::Settings::OCPP);
+    ui->navigation->addNavigationItem(tr("Configure key"),                  Workspace::Settings::Ocpp::CONFIG_KEY,          ocpp);
+    ui->navigation->addNavigationItem(tr("Local AUTH List"),                Workspace::Settings::Ocpp::LOCAL_AUTH_LIST,     ocpp);
+    ui->navigation->addNavigationItem(tr("AUTH Cache"),                     Workspace::Settings::Ocpp::AUTH_CACHE,          ocpp);
+    ui->navigation->addNavigationItem(tr("Charging Profiles"),              Workspace::Settings::Ocpp::CHARGING_PROFILES,   ocpp);
+
+    auto other = ui->navigation->addNavigationItem(tr("Other Settings"),    Workspace::Settings::OTHER);
+    ui->navigation->addNavigationItem(tr("Device information"),             Workspace::Settings::Other::DEVICE_INFO,        other);
+    ui->navigation->addNavigationItem(tr("Charging Records"),               Workspace::Settings::Other::CHARGING_RECORDS,   other);
+    // ui->navigation->addNavigationItem(tr("Error Codes"),                    Workspace::Settings::Other::ERROR_CODE_NOTE,    other);
+
+    ui->navigation->expandAll();
+}
+
+void FormSettings::initOperatorNavigationBar()
+{
+    ui->navigation->clearNavigationItems();
+    auto ccu = ui->navigation->addNavigationItem(tr("Charge Point Settings"),        Workspace::Settings::CCU);
+    ui->navigation->addNavigationItem(tr("Charge Gun Settings"),            Workspace::Settings::Ccu::CHARGE_GUN,       ccu);
+    ui->navigation->addNavigationItem(tr("Offline Price Settings"),         Workspace::Settings::Ccu::OFFLINE_PRICES,   ccu);
+    ui->navigation->addNavigationItem(tr("OCPP1.6 Settings"),               Workspace::Settings::Ccu::OCPP16,           ccu);
+    ui->navigation->addNavigationItem(tr("OCPP2.1 Settings"),               Workspace::Settings::Ccu::OCPP21,           ccu);
+
+    ui->navigation->addNavigationItem(tr("General Settings"),               Workspace::Settings::TCU);
+
+    auto ocpp = ui->navigation->addNavigationItem(tr("OCPP Settings"),      Workspace::Settings::OCPP);
+    ui->navigation->addNavigationItem(tr("Configure key"),                  Workspace::Settings::Ocpp::CONFIG_KEY,          ocpp);
+    ui->navigation->addNavigationItem(tr("Local AUTH List"),                Workspace::Settings::Ocpp::LOCAL_AUTH_LIST,     ocpp);
+    ui->navigation->addNavigationItem(tr("AUTH Cache"),                     Workspace::Settings::Ocpp::AUTH_CACHE,          ocpp);
+    ui->navigation->addNavigationItem(tr("Charging Profiles"),              Workspace::Settings::Ocpp::CHARGING_PROFILES,   ocpp);
+
+    auto other = ui->navigation->addNavigationItem(tr("Other Settings"),    Workspace::Settings::OTHER);
+    ui->navigation->addNavigationItem(tr("Device information"),             Workspace::Settings::Other::DEVICE_INFO,        other);
+    ui->navigation->addNavigationItem(tr("Charging Records"),               Workspace::Settings::Other::CHARGING_RECORDS,   other);
+
+    ui->navigation->expandAll();
+}
+
 void FormSettings::showForm(int form)
 {
     if (!m_formMap.contains(form) || !m_formMap[form]) {
-        return;
+        initStackWidgetItem(form);
     }
 
     setCurrentForm(form);
@@ -190,6 +247,54 @@ void FormSettings::showForm(int form)
     emit refreshTitles(m_formMap[form]->windowTitle());
 }
 
+void FormSettings::initStackWidgetItem(int form)
+{
+    switch (form) {
+    case Workspace::Settings::CCU:                                                  m_formMap[form] = new FormCcuSetting(userType()); break;
+    case Workspace::Settings::Ccu::OFFLINE_PRICES:                                  m_formMap[form] = new FormOfflinePrice(userType()); break;
+    case Workspace::Settings::Ccu::CHARGE_GUN:                                      m_formMap[form] = new FormChargeGunType(userType()); break;
+    case Workspace::Settings::Ccu::PCUHW:                                           m_formMap[form] = new FormPcuhwSettings(userType()); break;
+    case Workspace::Settings::Ccu::PCUTC:                                           m_formMap[form] = new FormPcutcSettings(userType()); break;
+    case Workspace::Settings::Ccu::QTTCU:                                           m_formMap[form] = new FormQttcuSettings(userType()); break;
+    case Workspace::Settings::Ccu::OCPP16:                                          m_formMap[form] = new FormOcppGeneralSettings(OcppVersion::OCPP16, userType()); break;
+    case Workspace::Settings::Ccu::OCPP21:                                          m_formMap[form] = new FormOcppGeneralSettings(OcppVersion::OCPP21, userType()); break;
+    case Workspace::Settings::TCU:                                                  m_formMap[form] = new FormTcuSettings(userType()); break;
+    case Workspace::Settings::PCU:                                                  m_formMap[form] = new FormPcuSettings(userType()); break;
+    case Workspace::Settings::OCPP:                                                 m_formMap[form] = new FormOcppSettings(userType()); break;
+    case Workspace::Settings::Ocpp::CONFIG_KEY:                                     m_formMap[form] = new FormConfigurationKey(userType()); break;
+    case Workspace::Settings::Ocpp::LOCAL_AUTH_LIST:                                m_formMap[form] = new FormLocalAuthList(userType()); break;
+    case Workspace::Settings::Ocpp::AUTH_CACHE:                                     m_formMap[form] = new FormAuthorizationCache(userType()); break;
+    case Workspace::Settings::Ocpp::CHARGING_PROFILES: {
+        m_formMap[form] = new FormChargingProfilesSettings(userType());
+        m_formMap[Workspace::Settings::Ocpp::ChargingProfiles::CHARGE_POINT_MAX_PROFILE]    = new FormChargingPointMaxProfile(userType());
+        ui->stackedWidget->addWidget(m_formMap[Workspace::Settings::Ocpp::ChargingProfiles::CHARGE_POINT_MAX_PROFILE]);
+        m_formMap[Workspace::Settings::Ocpp::ChargingProfiles::TX_DEFAULT_PROFILE]          = new FormTxDufaultProfile(userType());
+        ui->stackedWidget->addWidget(m_formMap[Workspace::Settings::Ocpp::ChargingProfiles::TX_DEFAULT_PROFILE]);
+        m_formMap[Workspace::Settings::Ocpp::ChargingProfiles::TX_PROFILE]                  = new FormTxProfile(userType());
+        ui->stackedWidget->addWidget(m_formMap[Workspace::Settings::Ocpp::ChargingProfiles::TX_PROFILE]);
+        auto charging_profiles_form = qobject_cast<FormChargingProfilesSettings*>(m_formMap[Workspace::Settings::Ocpp::CHARGING_PROFILES]);
+        connect(charging_profiles_form, &FormChargingProfilesSettings::currentFormChanged, this, &FormSettings::onUpdateChargingProfileData);
+        break;
+    }
+    case Workspace::Settings::OTHER:                                                m_formMap[form] = new FormOtherSettings(userType()); break;
+    case Workspace::Settings::Other::DEVICE_INFO:                                   m_formMap[form] = new FormDeviceInfo(userType()); break;
+    case Workspace::Settings::Other::FIRMWARE_INFO:                                 m_formMap[form] = new FormFirmwareInfo(userType()); break;
+    case Workspace::Settings::Other::CHARGING_RECORDS:                              m_formMap[form] = new FormChargeRecords(userType()); break;
+    case Workspace::Settings::Other::ERROR_CODE_NOTE:                               m_formMap[form] = new FormErrorCodeNote(userType()); break;
+    default:
+        break;
+    }
+
+    ui->stackedWidget->addWidget(m_formMap[form]);
+}
+
+void FormSettings::refreshUserType()
+{
+    foreach (auto& widget, m_formMap.values()) {
+        widget->setUserType(userType());
+    }
+}
+
 void FormSettings::onUpdateChargingProfileData(const charging_profiles_detail_info_t &info)
 {
     auto index = GeneralInterface::getChargingProfilePurposeIndex(info.chargingProfilePurpose);
@@ -213,7 +318,7 @@ void FormSettings::onUpdateChargingProfileData(const charging_profiles_detail_in
         break;
     }
     default:
-        break;
+        return;
     }
 
     setPrevForm(index);
@@ -235,9 +340,11 @@ void FormSettings::hideEvent(QHideEvent *event)
 
 void FormSettings::showEvent(QShowEvent *event)
 {
+    BaseWidget::showEvent(event);
+    initNavigationBar();
     m_ccu_cfg = ConfigManager::instance()->ccu_cfg();
     refreshNavigationBar();
-    BaseWidget::showEvent(event);
+    refreshUserType();
 }
 
 void FormSettings::slotReturnPrevForm()
@@ -298,35 +405,36 @@ void FormSettings::initWidget()
     ui->old_settings->setWindowTitle(tr("Settings"));
     ui->new_settings->setWindowTitle(tr("Settings"));
 
-    m_formMap[Workspace::Settings::CCU]                                                 = new FormCcuSetting();
-    m_formMap[Workspace::Settings::Ccu::OFFLINE_PRICES]                                 = new FormOfflinePrice();
-    m_formMap[Workspace::Settings::Ccu::CHARGE_GUN]                                     = new FormChargeGunType();
-    m_formMap[Workspace::Settings::Ccu::PCUHW]                                          = new FormPcuhwSettings();
-    m_formMap[Workspace::Settings::Ccu::PCUTC]                                          = new FormPcutcSettings();
-    m_formMap[Workspace::Settings::Ccu::QTTCU]                                          = new FormQttcuSettings();
-    m_formMap[Workspace::Settings::Ccu::OCPP16]                                         = new FormOcppGeneralSettings(OcppVersion::OCPP16);
-    m_formMap[Workspace::Settings::Ccu::OCPP21]                                         = new FormOcppGeneralSettings(OcppVersion::OCPP21);
-
-    m_formMap[Workspace::Settings::TCU]                                                 = new FormTcuSettings();
-    m_formMap[Workspace::Settings::PCU]                                                 = new FormPcuSettings();
-
-    m_formMap[Workspace::Settings::OCPP]                                                = new FormOcppSettings();
-    m_formMap[Workspace::Settings::Ocpp::CONFIG_KEY]                                    = new FormConfigurationKey();
-    m_formMap[Workspace::Settings::Ocpp::LOCAL_AUTH_LIST]                               = new FormLocalAuthList();
-    m_formMap[Workspace::Settings::Ocpp::AUTH_CACHE]                                    = new FormAuthorizationCache();
-    m_formMap[Workspace::Settings::Ocpp::CHARGING_PROFILES]                             = new FormChargingProfilesSettings();
-
-    m_formMap[Workspace::Settings::Ocpp::ChargingProfiles::CHARGE_POINT_MAX_PROFILE]    = new FormChargingPointMaxProfile();
-    m_formMap[Workspace::Settings::Ocpp::ChargingProfiles::TX_DEFAULT_PROFILE]          = new FormTxDufaultProfile();
-    m_formMap[Workspace::Settings::Ocpp::ChargingProfiles::TX_PROFILE]                  = new FormTxProfile();
-
-    m_formMap[Workspace::Settings::OTHER]                                               = new FormOtherSettings();
-    m_formMap[Workspace::Settings::Other::DEVICE_INFO]                                  = new FormDeviceInfo();
-    m_formMap[Workspace::Settings::Other::FIRMWARE_INFO]                                = new FormFirmwareInfo();
-    m_formMap[Workspace::Settings::Other::CHARGING_RECORDS]                             = new FormChargeRecords();
-    m_formMap[Workspace::Settings::Other::ERROR_CODE_NOTE]                              = new FormErrorCodeNote();
-
-    refreshStackWidget();
+    m_formMap[Workspace::Settings::CCU]                                                 = new FormCcuSetting(userType());
+    ui->stackedWidget->addWidget(m_formMap[Workspace::Settings::CCU]);
+    // m_formMap[Workspace::Settings::Ccu::OFFLINE_PRICES]                                 = new FormOfflinePrice();
+    // m_formMap[Workspace::Settings::Ccu::CHARGE_GUN]                                     = new FormChargeGunType();
+    // m_formMap[Workspace::Settings::Ccu::PCUHW]                                          = new FormPcuhwSettings();
+    // m_formMap[Workspace::Settings::Ccu::PCUTC]                                          = new FormPcutcSettings();
+    // m_formMap[Workspace::Settings::Ccu::QTTCU]                                          = new FormQttcuSettings();
+    // m_formMap[Workspace::Settings::Ccu::OCPP16]                                         = new FormOcppGeneralSettings(OcppVersion::OCPP16);
+    // m_formMap[Workspace::Settings::Ccu::OCPP21]                                         = new FormOcppGeneralSettings(OcppVersion::OCPP21);
+
+    // m_formMap[Workspace::Settings::TCU]                                                 = new FormTcuSettings();
+    // m_formMap[Workspace::Settings::PCU]                                                 = new FormPcuSettings();
+
+    // m_formMap[Workspace::Settings::OCPP]                                                = new FormOcppSettings();
+    // m_formMap[Workspace::Settings::Ocpp::CONFIG_KEY]                                    = new FormConfigurationKey();
+    // m_formMap[Workspace::Settings::Ocpp::LOCAL_AUTH_LIST]                               = new FormLocalAuthList();
+    // m_formMap[Workspace::Settings::Ocpp::AUTH_CACHE]                                    = new FormAuthorizationCache();
+    // m_formMap[Workspace::Settings::Ocpp::CHARGING_PROFILES]                             = new FormChargingProfilesSettings();
+
+    // m_formMap[Workspace::Settings::Ocpp::ChargingProfiles::CHARGE_POINT_MAX_PROFILE]    = new FormChargingPointMaxProfile();
+    // m_formMap[Workspace::Settings::Ocpp::ChargingProfiles::TX_DEFAULT_PROFILE]          = new FormTxDufaultProfile();
+    // m_formMap[Workspace::Settings::Ocpp::ChargingProfiles::TX_PROFILE]                  = new FormTxProfile();
+
+    // m_formMap[Workspace::Settings::OTHER]                                               = new FormOtherSettings();
+    // m_formMap[Workspace::Settings::Other::DEVICE_INFO]                                  = new FormDeviceInfo();
+    // m_formMap[Workspace::Settings::Other::FIRMWARE_INFO]                                = new FormFirmwareInfo();
+    // m_formMap[Workspace::Settings::Other::CHARGING_RECORDS]                             = new FormChargeRecords();
+    // m_formMap[Workspace::Settings::Other::ERROR_CODE_NOTE]                              = new FormErrorCodeNote();
+
+    ui->stackedWidget->setCurrentWidget(m_formMap[Workspace::Settings::CCU]);
 }
 
 void FormSettings::refreshStackWidget()
@@ -335,11 +443,5 @@ void FormSettings::refreshStackWidget()
     auto widgets = m_formMap.values();
     foreach (const auto& widget, std::as_const(widgets)) {
         ui->stackedWidget->addWidget(widget);
-
-        // 强制布局系统更新
-        ui->stackedWidget->updateGeometry();
     }
-
-    // 显示初始页面
-    showForm(Workspace::Home::SETTINGS);
 }

+ 9 - 1
src/widgets/workspace/settings/FormSettings.h

@@ -31,12 +31,20 @@ private:
 
     void refreshNavigationBar();
     void refreshGunSettingsNavigationBar();
+    void refreshNavigationBar(const int& userType);
     int getNodeDataByGunId(const int& gun_id);
 
     void initNavigationBar();
+    void initRoowNavigationBar();
+    void initAdminNavigationBar();
+    void initOperatorNavigationBar();
 
     void showForm(int form);
 
+    void initStackWidgetItem(int form);
+
+    void refreshUserType();
+
 private slots:
     void onUpdateChargingProfileData(const charging_profiles_detail_info_t& info);
 
@@ -52,7 +60,7 @@ private:
     CCU_CFG m_ccu_cfg;
 
     // 表单映射,存储不同类型的表单
-    QMap<int, QWidget*> m_formMap;
+    QMap<int, BaseWidget*> m_formMap;
 };
 
 #endif // FORMSETTINGS_H

+ 4 - 21
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogChargingProfileEdit.cpp

@@ -1,4 +1,5 @@
 #include "DialogChargingProfileEdit.h"
+#include "FunctionTimer.h"
 #include "ui_DialogChargingProfileEdit.h"
 
 #include <QScreen>
@@ -189,33 +190,15 @@ void DialogChargingProfileEdit::centerWindow()
     }
     QRect screenGeometry = screen->availableGeometry();
 
-    // 计算居中位置(考虑Wayland特性)
     int x = (screenGeometry.width() - this->width()) / 2 + screenGeometry.x();
     int y = (screenGeometry.height() - this->height()) / 2 + screenGeometry.y();
-
-    if (QGuiApplication::platformName().contains("wayland")) {
-        // Wayland专用处理
-        if (QWindow *window = this->windowHandle()) {
-            // 重要:延迟设置位置,确保Wayland合成器已准备好
-            QTimer::singleShot(100, this, [window, x, y]() {
-                window->setPosition(QPoint(x, y));
-
-                // 替代requestActivate的方案
-                window->setFlags(window->flags() | Qt::WindowStaysOnTopHint);
-                QTimer::singleShot(50, [window]() {
-                    window->setFlags(window->flags() & ~Qt::WindowStaysOnTopHint);
-                });
-            });
-        }
-    } else {
-        // 传统X11处理
-        this->move(x, y);
-    }
+    this->move(x, y);
 }
 
 void DialogChargingProfileEdit::showEvent(QShowEvent *event)
 {
+    
+    QDialog::showEvent(event);
     centerWindow();
     refreshData();
-    QDialog::showEvent(event);
 }

+ 4 - 21
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogLimitEdit.cpp

@@ -1,4 +1,5 @@
 #include "DialogLimitEdit.h"
+#include "FunctionTimer.h"
 #include "ui_DialogLimitEdit.h"
 
 #include <QScreen>
@@ -112,28 +113,9 @@ void DialogLimitEdit::centerWindow()
     }
     QRect screenGeometry = screen->availableGeometry();
 
-    // 计算居中位置(考虑Wayland特性)
     int x = (screenGeometry.width() - this->width()) / 2 + screenGeometry.x();
     int y = (screenGeometry.height() - this->height()) / 2 + screenGeometry.y();
-
-    if (QGuiApplication::platformName().contains("wayland")) {
-        // Wayland专用处理
-        if (QWindow *window = this->windowHandle()) {
-            // 重要:延迟设置位置,确保Wayland合成器已准备好
-            QTimer::singleShot(100, this, [window, x, y]() {
-                window->setPosition(QPoint(x, y));
-
-                // 替代requestActivate的方案
-                window->setFlags(window->flags() | Qt::WindowStaysOnTopHint);
-                QTimer::singleShot(50, [window]() {
-                    window->setFlags(window->flags() & ~Qt::WindowStaysOnTopHint);
-                });
-            });
-        }
-    } else {
-        // 传统X11处理
-        this->move(x, y);
-    }
+    this->move(x, y);
 }
 
 void DialogLimitEdit::refreshData()
@@ -179,7 +161,8 @@ int DialogLimitEdit::getDuration()
 
 void DialogLimitEdit::showEvent(QShowEvent *event)
 {
+    
+    QDialog::showEvent(event);
     centerWindow();
     refreshData();
-    QDialog::showEvent(event);
 }

+ 4 - 21
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogSelectChargingProfiles.cpp

@@ -1,4 +1,5 @@
 #include "DialogSelectChargingProfiles.h"
+#include "FunctionTimer.h"
 #include "ui_DialogSelectChargingProfiles.h"
 
 #include <QScreen>
@@ -85,32 +86,14 @@ void DialogSelectChargingProfiles::centerWindow()
     }
     QRect screenGeometry = screen->availableGeometry();
 
-    // 计算居中位置(考虑Wayland特性)
     int x = (screenGeometry.width() - this->width()) / 2 + screenGeometry.x();
     int y = (screenGeometry.height() - this->height()) / 2 + screenGeometry.y();
-
-    if (QGuiApplication::platformName().contains("wayland")) {
-        // Wayland专用处理
-        if (QWindow *window = this->windowHandle()) {
-            // 重要:延迟设置位置,确保Wayland合成器已准备好
-            QTimer::singleShot(100, this, [window, x, y]() {
-                window->setPosition(QPoint(x, y));
-
-                // 替代requestActivate的方案
-                window->setFlags(window->flags() | Qt::WindowStaysOnTopHint);
-                QTimer::singleShot(50, [window]() {
-                    window->setFlags(window->flags() & ~Qt::WindowStaysOnTopHint);
-                });
-            });
-        }
-    } else {
-        // 传统X11处理
-        this->move(x, y);
-    }
+    this->move(x, y);
 }
 
 void DialogSelectChargingProfiles::showEvent(QShowEvent *event)
 {
-    centerWindow();
+    
     QDialog::showEvent(event);
+    centerWindow();
 }

+ 5 - 23
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogWeekDayDetail.cpp

@@ -1,4 +1,5 @@
 #include "DialogWeekDayDetail.h"
+#include "FunctionTimer.h"
 #include "ui_DialogWeekDayDetail.h"
 
 #include <QDebug>
@@ -135,28 +136,10 @@ void DialogWeekDayDetail::centerWindow()
     }
     QRect screenGeometry = screen->availableGeometry();
 
-    // 计算居中位置(考虑Wayland特性)
     int x = (screenGeometry.width() - this->width()) / 2 + screenGeometry.x();
     int y = (screenGeometry.height() - this->height()) / 2 + screenGeometry.y();
 
-    if (QGuiApplication::platformName().contains("wayland")) {
-        // Wayland专用处理
-        if (QWindow *window = this->windowHandle()) {
-            // 重要:延迟设置位置,确保Wayland合成器已准备好
-            QTimer::singleShot(100, this, [window, x, y]() {
-                window->setPosition(QPoint(x, y));
-
-                // 替代requestActivate的方案
-                window->setFlags(window->flags() | Qt::WindowStaysOnTopHint);
-                QTimer::singleShot(50, [window]() {
-                    window->setFlags(window->flags() & ~Qt::WindowStaysOnTopHint);
-                });
-            });
-        }
-    } else {
-        // 传统X11处理
-        this->move(x, y);
-    }
+    this->move(x, y);
 }
 
 void DialogWeekDayDetail::onItemDoubleClicked(QTableWidgetItem *item)
@@ -216,9 +199,10 @@ void DialogWeekDayDetail::deleteBtnClicked()
 
 void DialogWeekDayDetail::showEvent(QShowEvent *event)
 {
+    
+    QDialog::showEvent(event);
     refreshData();
     centerWindow();
-    QDialog::showEvent(event);
 }
 
 QList<charging_schedule_period_info_t> DialogWeekDayDetail::info_list() const
@@ -275,9 +259,7 @@ void DialogWeekDayDetail::initTableWidget()
     ui->tablewidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
     ui->tablewidget->setSelectionBehavior(QAbstractItemView::SelectRows);
     ui->tablewidget->setSelectionMode(QAbstractItemView::SingleSelection);
-
-    QScroller::grabGesture(ui->tablewidget,              QScroller::TouchGesture);
-    QScroller::grabGesture(ui->tablewidget->viewport(),  QScroller::LeftMouseButtonGesture);
+    GeneralInterface::setTouchScroller(ui->tablewidget);
 }
 
 void DialogWeekDayDetail::initConnect()

+ 10 - 3
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormChargingPointMaxProfile.cpp

@@ -5,12 +5,13 @@
 #include "ConfigManager.h"
 #include "LanguageManager.h"
 
-FormChargingPointMaxProfile::FormChargingPointMaxProfile(BaseWidget *parent)
+FormChargingPointMaxProfile::FormChargingPointMaxProfile(const int &userType, BaseWidget *parent)
     : BaseWidget(parent)
     , ui(new Ui::FormChargingPointMaxProfile)
 {
     ui->setupUi(this);
 
+    setUserType(userType);
     initWidget();
     initConnect();
 }
@@ -131,8 +132,14 @@ bool FormChargingPointMaxProfile::updateData()
 }
 
 void FormChargingPointMaxProfile::showEvent(QShowEvent *event)
-{
+{    
+    BaseWidget::showEvent(event);
     setIsModify(false);
     refreshData();
-    BaseWidget::showEvent(event);
+}
+
+void FormChargingPointMaxProfile::hideEvent(QHideEvent *event)
+{
+    BaseWidget::hideEvent(event);
+    updateData();
 }

+ 2 - 1
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormChargingPointMaxProfile.h

@@ -15,7 +15,7 @@ class FormChargingPointMaxProfile : public BaseWidget
     Q_OBJECT
 
 public:
-    explicit FormChargingPointMaxProfile(BaseWidget *parent = nullptr);
+    explicit FormChargingPointMaxProfile(const int& userType = General::UserType::ROOT, BaseWidget *parent = nullptr);
     ~FormChargingPointMaxProfile();
 
     bool returnParent() override;
@@ -35,6 +35,7 @@ private:
 
 protected:
     void showEvent(QShowEvent *event) override;
+    void hideEvent(QHideEvent* event) override;
 
 private:
     Ui::FormChargingPointMaxProfile *ui;

+ 6 - 5
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormChargingProfilesSettings.cpp

@@ -6,13 +6,15 @@
 #include "Globals.h"
 #include "ConfigManager.h"
 #include "LanguageManager.h"
+#include "GeneralInterface.h"
 
-FormChargingProfilesSettings::FormChargingProfilesSettings(BaseWidget *parent)
+FormChargingProfilesSettings::FormChargingProfilesSettings(const int &userType, BaseWidget *parent)
     : BaseWidget(parent)
     , ui(new Ui::FormChargingProfilesSettings)
 {
     ui->setupUi(this);
 
+    setUserType(userType);
     initWidget();
     initConnect();
 }
@@ -55,8 +57,7 @@ void FormChargingProfilesSettings::initTableWidget()
     ui->chargingProfileTableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
     ui->chargingProfileTableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
 
-    QScroller::grabGesture(ui->chargingProfileTableWidget,              QScroller::TouchGesture);
-    QScroller::grabGesture(ui->chargingProfileTableWidget->viewport(),  QScroller::LeftMouseButtonGesture);
+    GeneralInterface::setTouchScroller(ui->chargingProfileTableWidget);
 }
 
 void FormChargingProfilesSettings::initConnect()
@@ -151,9 +152,9 @@ void FormChargingProfilesSettings::tableWidgetAppendRow(const int &connectorId,
 }
 
 void FormChargingProfilesSettings::showEvent(QShowEvent *event)
-{
+{    
+    BaseWidget::showEvent(event);
     setIsModify(false);
     m_charging_profiles = ConfigManager::instance()->charging_profiles();
     refreshData();
-    BaseWidget::showEvent(event);
 }

+ 1 - 1
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormChargingProfilesSettings.h

@@ -17,7 +17,7 @@ class FormChargingProfilesSettings : public BaseWidget
     Q_OBJECT
 
 public:
-    explicit FormChargingProfilesSettings(BaseWidget *parent = nullptr);
+    explicit FormChargingProfilesSettings(const int& userType = General::UserType::ROOT, BaseWidget *parent = nullptr);
     ~FormChargingProfilesSettings();
 
     bool returnParent() override;

+ 10 - 4
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxDefaultProfileDetail.cpp

@@ -1,4 +1,5 @@
 #include "FormTxDefaultProfileDetail.h"
+#include "FunctionTimer.h"
 #include "ui_FormTxDefaultProfileDetail.h"
 
 #include <QScroller>
@@ -135,8 +136,7 @@ void FormTxDefaultProfileDetail::initTableWidget()
     ui->dailyTablewidget->setSelectionBehavior(QAbstractItemView::SelectRows);
     ui->dailyTablewidget->setSelectionMode(QAbstractItemView::SingleSelection);
 
-    QScroller::grabGesture(ui->dailyTablewidget,              QScroller::TouchGesture);
-    QScroller::grabGesture(ui->dailyTablewidget->viewport(),  QScroller::LeftMouseButtonGesture);
+    GeneralInterface::setTouchScroller(ui->dailyTablewidget);
 }
 
 void FormTxDefaultProfileDetail::initListWidget()
@@ -489,10 +489,16 @@ void FormTxDefaultProfileDetail::deleteBtnClicked()
 }
 
 void FormTxDefaultProfileDetail::showEvent(QShowEvent *event)
-{
+{    
+    BaseWidget::showEvent(event);
     setIsModify(false);
     refreshData();
-    BaseWidget::showEvent(event);
+}
+
+void FormTxDefaultProfileDetail::hideEvent(QHideEvent *event)
+{
+    BaseWidget::hideEvent(event);
+    updateData();
 }
 
 charging_profiles_detail_info_t FormTxDefaultProfileDetail::profile_info() const

+ 1 - 0
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxDefaultProfileDetail.h

@@ -179,6 +179,7 @@ private slots:
 
 protected:
     void showEvent(QShowEvent* event) override;
+    void hideEvent(QHideEvent* event) override;
 
 private:
     Ui::FormTxDefaultProfileDetail *ui;

+ 11 - 5
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxDufaultProfile.cpp

@@ -8,12 +8,13 @@
 #include "LanguageManager.h"
 #include "GeneralInterface.h"
 
-FormTxDufaultProfile::FormTxDufaultProfile(BaseWidget *parent)
+FormTxDufaultProfile::FormTxDufaultProfile(const int &userType, BaseWidget *parent)
     : BaseWidget(parent)
     , ui(new Ui::FormTxDufaultProfile)
 {
     ui->setupUi(this);
 
+    setUserType(userType);
     initWidget();
     initConnect();
 }
@@ -157,8 +158,7 @@ void FormTxDufaultProfile::initTableWidget()
     ui->dailyTablewidget->setSelectionBehavior(QAbstractItemView::SelectRows);
     ui->dailyTablewidget->setSelectionMode(QAbstractItemView::SingleSelection);
 
-    QScroller::grabGesture(ui->dailyTablewidget,              QScroller::TouchGesture);
-    QScroller::grabGesture(ui->dailyTablewidget->viewport(),  QScroller::LeftMouseButtonGesture);
+    GeneralInterface::setTouchScroller(ui->dailyTablewidget);
 }
 
 void FormTxDufaultProfile::initListWidget()
@@ -362,10 +362,16 @@ void FormTxDufaultProfile::deleteBtnClicked()
 }
 
 void FormTxDufaultProfile::showEvent(QShowEvent *event)
-{
+{    
+    BaseWidget::showEvent(event);
     setIsModify(false);
     refreshData();
-    BaseWidget::showEvent(event);
+}
+
+void FormTxDufaultProfile::hideEvent(QHideEvent *event)
+{
+    BaseWidget::hideEvent(event);
+    updateData();
 }
 
 charging_profiles_detail_info_t FormTxDufaultProfile::profile_info() const

+ 2 - 1
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxDufaultProfile.h

@@ -21,7 +21,7 @@ class FormTxDufaultProfile : public BaseWidget
     Q_OBJECT
 
 public:
-    explicit FormTxDufaultProfile(BaseWidget *parent = nullptr);
+    explicit FormTxDufaultProfile(const int& userType = General::UserType::ROOT, BaseWidget *parent = nullptr);
     ~FormTxDufaultProfile();
 
     bool returnParent() override;
@@ -68,6 +68,7 @@ private slots:
 
 protected:
     void showEvent(QShowEvent* event) override;
+    void hideEvent(QHideEvent* event) override;
 
 private:
     Ui::FormTxDufaultProfile *ui;

+ 10 - 4
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxProfile.cpp

@@ -4,14 +4,14 @@
 #include "Globals.h"
 #include "ConfigManager.h"
 #include "LanguageManager.h"
-#include "GeneralInterface.h"
 
-FormTxProfile::FormTxProfile(BaseWidget *parent)
+FormTxProfile::FormTxProfile(const int &userType, BaseWidget *parent)
     : BaseWidget(parent)
     , ui(new Ui::FormTxProfile)
 {
     ui->setupUi(this);
 
+    setUserType(userType);
     initWidget();
     initConnect();
 }
@@ -122,10 +122,16 @@ bool FormTxProfile::updateData()
 }
 
 void FormTxProfile::showEvent(QShowEvent *event)
-{
+{    
+    BaseWidget::showEvent(event);
     setIsModify(false);
     refreshData();
-    BaseWidget::showEvent(event);
+}
+
+void FormTxProfile::hideEvent(QHideEvent *event)
+{
+    BaseWidget::hideEvent(event);
+    updateData();
 }
 
 charging_profiles_detail_info_t FormTxProfile::profile_info() const

+ 2 - 1
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxProfile.h

@@ -15,7 +15,7 @@ class FormTxProfile : public BaseWidget
     Q_OBJECT
 
 public:
-    explicit FormTxProfile(BaseWidget *parent = nullptr);
+    explicit FormTxProfile(const int& userType = General::UserType::ROOT, BaseWidget *parent = nullptr);
     ~FormTxProfile();
 
     bool returnParent() override;
@@ -35,6 +35,7 @@ private:
 
 protected:
     void showEvent(QShowEvent *event) override;
+    void hideEvent(QHideEvent* event) override;
 
 private:
     Ui::FormTxProfile *ui;

+ 4 - 21
src/widgets/workspace/settings/OcppSettings/DialogAddCard.cpp

@@ -1,4 +1,5 @@
 #include "DialogAddCard.h"
+#include "FunctionTimer.h"
 #include "ui_DialogAddCard.h"
 
 #include <QScreen>
@@ -112,28 +113,9 @@ void DialogAddCard::centerWindow()
     }
     QRect screenGeometry = screen->availableGeometry();
 
-    // 计算居中位置(考虑Wayland特性)
     int x = (screenGeometry.width() - this->width()) / 2 + screenGeometry.x();
     int y = (screenGeometry.height() - this->height()) / 2 + screenGeometry.y();
-
-    if (QGuiApplication::platformName().contains("wayland")) {
-        // Wayland专用处理
-        if (QWindow *window = this->windowHandle()) {
-            // 重要:延迟设置位置,确保Wayland合成器已准备好
-            QTimer::singleShot(100, this, [window, x, y]() {
-                window->setPosition(QPoint(x, y));
-
-                // 替代requestActivate的方案
-                window->setFlags(window->flags() | Qt::WindowStaysOnTopHint);
-                QTimer::singleShot(50, [window]() {
-                    window->setFlags(window->flags() & ~Qt::WindowStaysOnTopHint);
-                });
-            });
-        }
-    } else {
-        // 传统X11处理
-        this->move(x, y);
-    }
+    this->move(x, y);
 }
 
 void DialogAddCard::restartTimer()
@@ -202,6 +184,8 @@ void DialogAddCard::onNFCReadCard(const QString &cardId)
 
 void DialogAddCard::showEvent(QShowEvent *event)
 {
+    
+    QDialog::showEvent(event);
     centerWindow();
     switch (type) {
     case Type::ADD:
@@ -217,7 +201,6 @@ void DialogAddCard::showEvent(QShowEvent *event)
     default:
         break;
     }
-    QDialog::showEvent(event);
 }
 
 authorization_card_info_t DialogAddCard::card_info() const

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio