GeneralInterface.cpp 77 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148
  1. #include "GeneralInterface.h"
  2. #include <QTime>
  3. #include <QRect>
  4. #include <QPoint>
  5. #include <QScreen>
  6. #include <QDateTime>
  7. #include <QCheckBox>
  8. #include <QApplication>
  9. #include <QCoreApplication>
  10. #include <QGraphicsScene>
  11. #include <QGraphicsProxyWidget>
  12. #include <QParallelAnimationGroup>
  13. #include <QPropertyAnimation>
  14. #include <QDataStream>
  15. #include <QScroller>
  16. #include <QPainter>
  17. #include <unistd.h>
  18. // libqrencode 相关头文件
  19. #include <qrencode.h>
  20. #include <QImage>
  21. #include <QBuffer>
  22. #include "Globals.h"
  23. #include "ConfigManager.h"
  24. #include "LoggerHelper.h"
  25. #include "OtherSettings/log/FormLogView.h"
  26. #include "VersionManager.h"
  27. template<typename T>
  28. T GeneralInterface::toInt(const QByteArray &data, int offset, bool networkOrder)
  29. {
  30. if ((offset + sizeof(T)) > static_cast<size_t>(data.size())) {
  31. return 0;
  32. }
  33. T value;
  34. memcpy(&value, data.constData() + offset, sizeof(T));
  35. if (networkOrder) {
  36. if constexpr (sizeof(T) == 2) {
  37. return qFromBigEndian(value);
  38. } else if constexpr (sizeof(T) == 4) {
  39. return qFromBigEndian(value);
  40. } else if constexpr (sizeof(T) == 8) {
  41. return qFromBigEndian<qint64>(value);
  42. }
  43. }
  44. return value;
  45. }
  46. /**
  47. * @brief 将QByteArray中的数据转换为uint8_t类型
  48. *
  49. * @param data QByteArray对象,包含要转换的数据
  50. * @param offset 数据在QByteArray中的偏移量
  51. * @return uint8_t 转换后的uint8_t类型数据
  52. */
  53. uint8_t GeneralInterface::toUInt8(const QByteArray &data, int offset)
  54. {
  55. return toInt<uint8_t>(data, offset);
  56. }
  57. /**
  58. * @brief 将QByteArray中的数据转换为uint16_t类型
  59. *
  60. * @param data QByteArray对象,包含要转换的数据
  61. * @param offset 数据在QByteArray中的偏移量
  62. * @param networkOrder 是否使用网络字节序
  63. * @return uint16_t 转换后的uint16_t值
  64. */
  65. uint16_t GeneralInterface::toUInt16(const QByteArray &data, int offset, bool networkOrder)
  66. {
  67. return toInt<uint16_t>(data, offset, networkOrder);
  68. }
  69. /**
  70. * @brief 将QByteArray中的数据转换为uint32_t类型
  71. *
  72. * @param data QByteArray对象,包含要转换的数据
  73. * @param offset 数据在QByteArray中的偏移量
  74. * @param networkOrder 是否使用网络字节序
  75. * @return uint32_t 转换后的uint32_t值
  76. */
  77. uint32_t GeneralInterface::toUInt32(const QByteArray &data, int offset, bool networkOrder) {
  78. return toInt<uint32_t>(data, offset, networkOrder);
  79. }
  80. /**
  81. * @brief 将QByteArray转换为uint64_t类型
  82. *
  83. * @param data QByteArray对象,包含要转换的数据
  84. * @param offset 数据在QByteArray中的偏移量
  85. * @param networkOrder 是否使用网络字节序
  86. *
  87. * @return uint64_t 转换后的uint64_t类型数据
  88. */
  89. uint64_t GeneralInterface::toUInt64(const QByteArray &data, int offset, bool networkOrder)
  90. {
  91. return toInt<uint64_t>(data, offset, networkOrder);
  92. }
  93. /**
  94. * @brief GeneralInterface::networkStructToByteArray 将MSG_HEAD结构体转换为网络字节序的字节数组
  95. * @param data MSG_HEAD结构体
  96. * @return QByteArray
  97. */
  98. QByteArray GeneralInterface::networkStructToByteArray(const MSG_HEAD &data)
  99. {
  100. // 将MSG_HEAD结构体转换为网络字节序的字节数组
  101. MSG_HEAD networkData;
  102. networkData.trans_id = qToBigEndian(data.trans_id);
  103. networkData.proto_id = qToBigEndian(data.proto_id);
  104. networkData.length = qToBigEndian(data.length);
  105. networkData.unit_id = qToBigEndian(data.unit_id);
  106. networkData.cmd = qToBigEndian(data.cmd);
  107. // 返回转换后的字节数组
  108. return QByteArray(reinterpret_cast<const char*>(&networkData), sizeof(MSG_HEAD));
  109. }
  110. /**
  111. * @brief GeneralInterface::encodeValue 将数据编码为指定长度的字节数组
  112. * @param data 要编码的数据
  113. * @param length 数据的长度
  114. * @return 编码后的字节数组
  115. */
  116. template<typename T>
  117. QByteArray GeneralInterface::encodeValue(T &data, const uint8_t &length)
  118. {
  119. QByteArray result;
  120. auto tempData = qToBigEndian(data);
  121. result.append(0x80 + sizeof(data));
  122. result.append(length);
  123. result.append(QByteArray(reinterpret_cast<const char*>(&tempData), sizeof(T)));
  124. return result;
  125. }
  126. /**
  127. * @brief GeneralInterface::decodeValue 将字节数组解码为指定类型的数据
  128. * @param data 字节数组
  129. * @return 解码后的数据
  130. */
  131. template<typename T>
  132. T GeneralInterface::decodeValue(const QByteArray &data)
  133. {
  134. return toInt<T>(data);
  135. }
  136. /**
  137. * @brief GeneralInterface::encodeStartChargeGunInfo 将START_CHARGE_CMD结构体编码为字节数组
  138. * @param data START_CHARGE_CMD结构体
  139. * @return 编码后的字节数组
  140. */
  141. QByteArray GeneralInterface::encodeStartChargeGunInfo(const START_CHARGE_CMD &data)
  142. {
  143. QByteArray ctl_array;
  144. ctl_array.append(encodeValue<const uint32_t>(data.GUNID, 1));
  145. ctl_array.append(0x81);
  146. ctl_array.append(sizeof(data.EMID));
  147. ctl_array.append(QByteArray(reinterpret_cast<const char*>(&data.EMID), sizeof(data.EMID)));
  148. ctl_array.append(encodeValue<const uint32_t>(data.requestKWs, 1));
  149. ctl_array.append(encodeValue<const uint32_t>(data.requestMinutes, 1));
  150. ctl_array.append(encodeValue<const uint32_t>(data.requestSOC, 1));
  151. ctl_array.append(encodeValue<const uint32_t>(data.authorizationResult, 1));
  152. return ctl_array;
  153. }
  154. /**
  155. * @brief GeneralInterface::encodeStopChargeGunInfo 将STOP_CHARGE_CMD结构体编码为字节数组
  156. * @param data STOP_CHARGE_CMD结构体
  157. * @return 编码后的字节数组
  158. */
  159. QByteArray GeneralInterface::encodeStopChargeGunInfo(const STOP_CHARGE_CMD &data)
  160. {
  161. QByteArray ctl_array;
  162. ctl_array.append(encodeValue<const uint32_t>(data.GUNID, 1));
  163. ctl_array.append(0x81);
  164. ctl_array.append(sizeof(data.EMID));
  165. ctl_array.append(QByteArray(reinterpret_cast<const char*>(&data.EMID), sizeof(data.EMID)));
  166. ctl_array.append(encodeValue<const uint32_t>(data.authorizated, 1));
  167. return ctl_array;
  168. }
  169. /**
  170. * @brief GeneralInterface::decodeChargeBasicInfo 将字节数组解码为charge_gun_basic_info_t结构体
  171. * @param data 字节数组
  172. * @return charge_gun_basic_info_t结构体
  173. */
  174. charge_gun_basic_info_t GeneralInterface::decodeChargeBasicInfo(const QByteArray &data)
  175. {
  176. charge_gun_basic_info_t basicInfo;
  177. int start_index = 2;
  178. basicInfo.GUNID = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
  179. start_index += (sizeof(uint32_t) + 2);
  180. basicInfo.GUN_Error = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
  181. start_index += (sizeof(uint32_t) + 2);
  182. basicInfo.GUN_State = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
  183. start_index += (sizeof(uint32_t) + 2);
  184. basicInfo.GUN_Type = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
  185. start_index += (sizeof(uint32_t) + 2);
  186. basicInfo.BOX_temp = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
  187. start_index += (sizeof(uint32_t) + 2);
  188. basicInfo.OCPP_online = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
  189. start_index += (sizeof(uint32_t) + 2);
  190. return basicInfo;
  191. }
  192. /**
  193. * @brief GeneralInterface::decodeChargeInfo 将字节数组解码为charge_gun_charge_info_t结构体
  194. * @param data 字节数组
  195. * @return charge_gun_charge_info_t结构体
  196. */
  197. charge_gun_charge_info_t GeneralInterface::decodeChargeInfo(const QByteArray &data)
  198. {
  199. charge_gun_charge_info_t charge_info;
  200. int start_index = 2;
  201. charge_info.GUNID = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
  202. start_index += (sizeof(uint32_t) + 2);
  203. charge_info.transactionId = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
  204. start_index += (sizeof(uint32_t) + 2);
  205. charge_info.SOC = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
  206. start_index += (sizeof(uint32_t) + 2);
  207. charge_info.startUTC = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
  208. start_index += (sizeof(uint32_t) + 2);
  209. charge_info.now_UTC = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
  210. start_index += (sizeof(uint32_t) + 2);
  211. charge_info.startKW = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
  212. start_index += (sizeof(uint32_t) + 2);
  213. charge_info.now_KW = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
  214. start_index += (sizeof(uint32_t) + 2);
  215. charge_info.GUNLine_temp0 = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
  216. start_index += (sizeof(uint32_t) + 2);
  217. charge_info.GUNLine_temp1 = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
  218. start_index += (sizeof(uint32_t) + 2);
  219. charge_info.powerKW = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
  220. start_index += (sizeof(uint32_t) + 2);
  221. charge_info.voltage = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
  222. start_index += (sizeof(uint32_t) + 2);
  223. charge_info.current = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
  224. start_index += (sizeof(uint32_t) + 2);
  225. charge_info.rts = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
  226. return charge_info;
  227. }
  228. /**
  229. * @brief GeneralInterface::decodeReplyInfo 将字节数组解码为REPLY_INFO结构体
  230. * @param data 字节数组
  231. * @return REPLY_INFO结构体
  232. */
  233. REPLY_INFO GeneralInterface::decodeReplyInfo(const QByteArray& data)
  234. {
  235. REPLY_INFO info;
  236. int start_index = 2;
  237. info.result = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
  238. return info;
  239. }
  240. /**
  241. * @brief GeneralInterface::encodeReplyInfo 将REPLY_INFO结构体编码为字节数组
  242. * @param info REPLY_INFO结构体
  243. * @return 编码后的字节数组
  244. */
  245. QByteArray GeneralInterface::encodeReplyInfo(const REPLY_INFO& info)
  246. {
  247. QByteArray result;
  248. result.append(encodeValue<const uint32_t>(info.result, 1));
  249. return result;
  250. }
  251. /**
  252. * @brief GeneralInterface::setCheckBoxChecked 设置widget下所有QCheckBox的checked属性
  253. * @param widget
  254. * @param checked
  255. */
  256. void GeneralInterface::setCheckBoxChecked(const QWidget *widget, const bool &checked)
  257. {
  258. QList<QCheckBox*> checkBoxes = widget->findChildren<QCheckBox*>();
  259. if (checkBoxes.isEmpty()) return;
  260. foreach (QCheckBox* checkBox, checkBoxes) {
  261. checkBox->setChecked(checked);
  262. }
  263. }
  264. /**
  265. * @brief GeneralInterface::setTouchScroller 设置QScrollArea的滚动方式为触摸滚动
  266. * @param area
  267. */
  268. void GeneralInterface::setTouchScroller(QScrollArea *area)
  269. {
  270. QScroller::grabGesture(area, QScroller::TouchGesture);
  271. QScroller::grabGesture(area->viewport(), QScroller::LeftMouseButtonGesture);
  272. }
  273. /**
  274. * @brief GeneralInterface::setTouchScroller 设置QListWidget的滚动方式为触摸滚动
  275. * @param listWidget
  276. */
  277. void GeneralInterface::setTouchScroller(QListWidget *listWidget)
  278. {
  279. QScroller::grabGesture(listWidget, QScroller::TouchGesture);
  280. QScroller::grabGesture(listWidget->viewport(), QScroller::LeftMouseButtonGesture);
  281. }
  282. /**
  283. * @brief GeneralInterface::setTouchScroller 设置QTableWidget的滚动方式为触摸滚动
  284. * @param tableWidget
  285. */
  286. void GeneralInterface::setTouchScroller(QTableWidget *tableWidget)
  287. {
  288. QScroller::grabGesture(tableWidget, QScroller::TouchGesture);
  289. QScroller::grabGesture(tableWidget->viewport(), QScroller::LeftMouseButtonGesture);
  290. }
  291. /**
  292. * @brief GeneralInterface::setTouchScroller 设置QTreeWidget的滚动方式为触摸滚动
  293. * @param treeWidget
  294. */
  295. void GeneralInterface::setTouchScroller(QTreeWidget *treeWidget)
  296. {
  297. QScroller::grabGesture(treeWidget, QScroller::TouchGesture);
  298. QScroller::grabGesture(treeWidget->viewport(), QScroller::LeftMouseButtonGesture);
  299. }
  300. /**
  301. * @brief GeneralInterface::setTouchScroller 设置QTextEdit的滚动方式为触摸滚动
  302. * @param textEdit
  303. */
  304. void GeneralInterface::setTouchScroller(QTextEdit *textEdit)
  305. {
  306. QScroller::grabGesture(textEdit, QScroller::TouchGesture);
  307. QScroller::grabGesture(textEdit->viewport(), QScroller::LeftMouseButtonGesture);
  308. }
  309. /**
  310. * @brief GeneralInterface::setTouchScroller 设置QAbstractScrollArea的滚动方式为触摸滚动
  311. * @param scrollArea
  312. */
  313. void GeneralInterface::setTouchScroller(QAbstractScrollArea *scrollArea)
  314. {
  315. QScroller::grabGesture(scrollArea, QScroller::TouchGesture);
  316. QScroller::grabGesture(scrollArea->viewport(), QScroller::LeftMouseButtonGesture);
  317. }
  318. void GeneralInterface::setControlEnabled(QWidget *control, QWidget *label, const int &userType)
  319. {
  320. // 管理员和根用户都有控制权
  321. const bool hasControl = (/*userType == General::UserType::ADMIN || */userType == General::UserType::ROOT);
  322. if (control) {
  323. control->setEnabled(hasControl);
  324. }
  325. if (label) {
  326. label->setEnabled(hasControl);
  327. }
  328. }
  329. void GeneralInterface::setControlVisiabled(QWidget *control, QWidget *label, const int &userType)
  330. {
  331. // 管理员和根用户都有控制权
  332. const bool hasControl = (userType == General::UserType::ROOT);
  333. if (control) {
  334. control->setVisible(hasControl);
  335. }
  336. if (label) {
  337. label->setVisible(hasControl);
  338. }
  339. }
  340. /**
  341. * @brief GeneralInterface::setAdvancedTouchScroller 设置高级触摸滚动配置
  342. * @param scrollArea 滚动区域
  343. * @param properties 滚动属性
  344. */
  345. void GeneralInterface::setAdvancedTouchScroller(QAbstractScrollArea *scrollArea,
  346. const QScrollerProperties &properties)
  347. {
  348. // 设置基本手势
  349. QScroller::grabGesture(scrollArea, QScroller::TouchGesture);
  350. QScroller::grabGesture(scrollArea->viewport(), QScroller::LeftMouseButtonGesture);
  351. // 应用自定义属性
  352. QScroller *scroller = QScroller::scroller(scrollArea);
  353. if (scroller) {
  354. scroller->setScrollerProperties(properties);
  355. }
  356. }
  357. /**
  358. * @brief GeneralInterface::setTouchScrollerWithProperties 设置带属性的触摸滚动
  359. * @param scrollArea 滚动区域
  360. * @param enableOvershoot 是否启用过度滚动
  361. * @param enableFlick 是否启用轻弹
  362. * @param decelerationFactor 减速度因子
  363. */
  364. void GeneralInterface::setTouchScrollerWithProperties(QAbstractScrollArea *scrollArea,
  365. bool enableOvershoot,
  366. bool enableFlick,
  367. qreal decelerationFactor)
  368. {
  369. // 设置基本手势
  370. QScroller::grabGesture(scrollArea, QScroller::TouchGesture);
  371. QScroller::grabGesture(scrollArea->viewport(), QScroller::LeftMouseButtonGesture);
  372. // 配置滚动属性
  373. QScroller *scroller = QScroller::scroller(scrollArea);
  374. if (scroller) {
  375. QScrollerProperties properties = scroller->scrollerProperties();
  376. // 设置过度滚动
  377. properties.setScrollMetric(QScrollerProperties::OvershootDragResistanceFactor, enableOvershoot ? 0.5 : 0.0);
  378. properties.setScrollMetric(QScrollerProperties::OvershootScrollDistanceFactor, enableOvershoot ? 0.5 : 0.0);
  379. // 设置轻弹
  380. properties.setScrollMetric(QScrollerProperties::DecelerationFactor, enableFlick ? decelerationFactor : 0.0);
  381. // 设置其他优化参数
  382. properties.setScrollMetric(QScrollerProperties::DragVelocitySmoothingFactor, 0.5);
  383. properties.setScrollMetric(QScrollerProperties::AxisLockThreshold, 0.5);
  384. properties.setScrollMetric(QScrollerProperties::ScrollingCurve, QEasingCurve::OutCubic);
  385. scroller->setScrollerProperties(properties);
  386. }
  387. }
  388. /**
  389. * @brief GeneralInterface::setTouchScrollerForChildren 为父控件的所有子控件设置触摸滚动
  390. * @param parent 父控件
  391. * @param className 指定类名(可选)
  392. */
  393. void GeneralInterface::setTouchScrollerForChildren(QWidget *parent, const QString &className)
  394. {
  395. if (!parent) return;
  396. // 查找所有可滚动的子控件
  397. QList<QAbstractScrollArea*> scrollAreas = parent->findChildren<QAbstractScrollArea*>();
  398. foreach (QAbstractScrollArea* area, scrollAreas) {
  399. if (className.isEmpty() || area->metaObject()->className() == className) {
  400. setTouchScroller(area);
  401. }
  402. }
  403. // 查找所有ListWidget
  404. QList<QListWidget*> listWidgets = parent->findChildren<QListWidget*>();
  405. foreach (QListWidget* listWidget, listWidgets) {
  406. if (className.isEmpty() || listWidget->metaObject()->className() == className) {
  407. setTouchScroller(listWidget);
  408. }
  409. }
  410. // 查找所有TableWidget
  411. QList<QTableWidget*> tableWidgets = parent->findChildren<QTableWidget*>();
  412. foreach (QTableWidget* tableWidget, tableWidgets) {
  413. if (className.isEmpty() || tableWidget->metaObject()->className() == className) {
  414. setTouchScroller(tableWidget);
  415. }
  416. }
  417. // 查找所有TreeWidget
  418. QList<QTreeWidget*> treeWidgets = parent->findChildren<QTreeWidget*>();
  419. foreach (QTreeWidget* treeWidget, treeWidgets) {
  420. if (className.isEmpty() || treeWidget->metaObject()->className() == className) {
  421. setTouchScroller(treeWidget);
  422. }
  423. }
  424. // 查找所有TextEdit
  425. QList<QTextEdit*> textEdits = parent->findChildren<QTextEdit*>();
  426. foreach (QTextEdit* textEdit, textEdits) {
  427. if (className.isEmpty() || textEdit->metaObject()->className() == className) {
  428. setTouchScroller(textEdit);
  429. }
  430. }
  431. }
  432. /**
  433. * @brief GeneralInterface::getWindowTitle 获取窗口标题
  434. * @param type 窗口类型
  435. * @return 窗口标题
  436. */
  437. QString GeneralInterface::getWindowTitle(const int &type)
  438. {
  439. switch (type) {
  440. case FormItem::GENERAL: return QCoreApplication::translate("GeneralInterface", "General Log");
  441. case FormItem::OCPP16: return QCoreApplication::translate("GeneralInterface", "OCPP 1.6 Log");
  442. case FormItem::SLAVE: return QCoreApplication::translate("GeneralInterface", "Lower machine log");
  443. default: return QString("");
  444. }
  445. }
  446. /**
  447. * @brief GeneralInterface::getLogFilePath 获取日志文件路径
  448. * @param type 窗口类型
  449. * @return 日志文件路径
  450. */
  451. QString GeneralInterface::getLogFilePath(const int &type)
  452. {
  453. switch (type) {
  454. case FormItem::GENERAL: return ConfigManager::instance()->tcu_cfg().log_config.general_log_path;
  455. case FormItem::OCPP16: return ConfigManager::instance()->tcu_cfg().log_config.ocpp16_log_path;
  456. case FormItem::SLAVE: return ConfigManager::instance()->tcu_cfg().log_config.slave_log_path;
  457. default: return QString("");
  458. }
  459. }
  460. /**
  461. * @brief GeneralInterface::getStateDescriptions 获取状态描述
  462. * @param code 状态码
  463. * @return 状态描述
  464. */
  465. QString GeneralInterface::getStateDescriptions(uint32_t code)
  466. {
  467. switch (code) {
  468. case GUNSTATE_IDLE: return QCoreApplication::translate("GeneralInterface", "Stand By");
  469. case GUN_PLUGOUT: return QCoreApplication::translate("GeneralInterface", "Plug Out");
  470. case GUN_PLUGIN: return QCoreApplication::translate("GeneralInterface", "Plug In");
  471. case GUN_STARTUP: return QCoreApplication::translate("GeneralInterface", "Start Up");
  472. case GUN_ELOCKED: return QCoreApplication::translate("GeneralInterface", "Elocked");
  473. case GUN_AUTHORIZED: return QCoreApplication::translate("GeneralInterface", "Authorized");
  474. case GUN_PARAMETERS: return QCoreApplication::translate("GeneralInterface", "Parameters");
  475. case GUN_INSULATION: return QCoreApplication::translate("GeneralInterface", "Insulation");
  476. case GUN_PRECHARGE: return QCoreApplication::translate("GeneralInterface", "Precharge");
  477. case GUN_CHARGING: return QCoreApplication::translate("GeneralInterface", "Charging");
  478. case GUN_SUSPEND: return QCoreApplication::translate("GeneralInterface", "Suspend");
  479. case GUN_STOPING: return QCoreApplication::translate("GeneralInterface", "Stop");
  480. case GUN_UNKNOW: return QCoreApplication::translate("GeneralInterface", "Unknow");
  481. case GUN_UNAVAILABLE: return QCoreApplication::translate("GeneralInterface", "UnAvailable");
  482. case GUN_INOPERAVIVE: return QCoreApplication::translate("GeneralInterface", "Inoperative");
  483. case GUN_RESERVED: return QCoreApplication::translate("GeneralInterface", "Reserved");
  484. default: return QCoreApplication::translate("GeneralInterface", "NULL");
  485. }
  486. }
  487. /**
  488. * @brief GeneralInterface::getGuiState 根据表单类型和状态码获取GUI状态
  489. * @param form 表单类型
  490. * @param state 状态码
  491. * @return GUI状态
  492. */
  493. gui_state_enum GeneralInterface::getGuiState(const charge_prepare_enum &form, const int &state)
  494. {
  495. switch (form) {
  496. case PLUG_OUT: return CHARGE_GUN_AVAILABLE;
  497. case AUTHENTICATION: {
  498. if (state == 0) {
  499. int authState = getAuthShowType(ConfigManager::instance()->tcu_cfg().auth_type_enable.qr,
  500. ConfigManager::instance()->tcu_cfg().auth_type_enable.nfc,
  501. ConfigManager::instance()->tcu_cfg().auth_type_enable.pos);
  502. return getGuiStateAuthForm(authState);
  503. } else {
  504. return getGuiStateAuthForm(state);
  505. }
  506. }
  507. case CHARGE_PREPARE: return getGuiStatePrepareForm(state);
  508. case CHARGING_FORM: return getGuiStateChargingForm(state);
  509. case FINISH_FORM: return RETURN_GUN;
  510. case ERROR_FORM: return getGuiStateErrorForm();
  511. default: return UNKOWN_STATE;
  512. }
  513. }
  514. /**
  515. * @brief GeneralInterface::getGuiStateAuthForm 根据状态码获取授权表单的GUI状态
  516. * @param state 状态码
  517. * @return 授权表单的GUI状态
  518. */
  519. gui_state_enum GeneralInterface::getGuiStateAuthForm(const int &state)
  520. {
  521. switch (state) {
  522. case AuthType::QR: return AUTHORIZATION_QR;
  523. case AuthType::CARD: return AUTHORIZATION_ID_CARD;
  524. case AuthType::QR_OR_CARD: return AUTHORIZATION_QR_ID_CARD;
  525. case AuthType::NO_CARD: return WAITING_NO_ID_CARD;
  526. case AuthType::NO_QR_OR_CARD: return WAITING_NO_ID_CARD_QR;
  527. default: return UNKOWN_STATE;
  528. }
  529. }
  530. int GeneralInterface::getAuthShowType(const bool &qrEnable, const bool &cardEnable, const bool &posEnable)
  531. {
  532. if (qrEnable && !cardEnable && !posEnable) {
  533. return AuthType::QR;
  534. } else if (qrEnable && cardEnable && !posEnable) {
  535. return AuthType::QR_OR_CARD;
  536. } else if (!qrEnable && cardEnable && !posEnable) {
  537. return AuthType::CARD;
  538. } else if (!qrEnable && !cardEnable && posEnable) {
  539. return AuthType::POS;
  540. }
  541. return -1;
  542. }
  543. /**
  544. * @brief GeneralInterface::getGuiStatePrepareForm 根据状态码获取准备表单的GUI状态
  545. * @param state 状态码
  546. * @return 准备表单的GUI状态
  547. */
  548. gui_state_enum GeneralInterface::getGuiStatePrepareForm(const int &state)
  549. {
  550. switch (state) {
  551. case 0: return RETRY_OR_RETURN_GUN;
  552. case 1: return SCAN_QR_OR_RETURN_GUN;
  553. case 2: return CARD_AUTHORIZATION_FAILED;
  554. case 3: return CHANGE_CARD;
  555. case 4: return BALANCE_NO_START;
  556. case 6: return TOP_UP_RETRY;
  557. case 7: return PREPARE_HANDSHAKING;
  558. case 8: return HANDSHAKING;
  559. case 9: return CONFIGUING;
  560. case 10: return START_CHARGING;
  561. case 11: return UNPLUG_RETRY_OR_CHANGE;
  562. default: return UNKOWN_STATE;
  563. }
  564. }
  565. /**
  566. * @brief GeneralInterface::getGuiStateChargingForm 根据状态码获取充电表单的GUI状态
  567. * @param state 状态码
  568. * @return 充电表单的GUI状态
  569. */
  570. gui_state_enum GeneralInterface::getGuiStateChargingForm(const int &state)
  571. {
  572. switch (state) {
  573. case 0: return RETURN_GUN;
  574. default: return UNKOWN_STATE;
  575. }
  576. }
  577. /**
  578. * @brief GeneralInterface::getGuiStateFinishForm 根据状态码获取完成表单的GUI状态
  579. * @param state 状态码
  580. * @return 完成表单的GUI状态
  581. */
  582. gui_state_enum GeneralInterface::getGuiStateFinishForm(const int &state)
  583. {
  584. switch (state) {
  585. case 0: return RETURN_GUN;
  586. default: return UNKOWN_STATE;
  587. }
  588. }
  589. /**
  590. * @brief GeneralInterface::getGuiStateErrorForm 根据状态码获取错误表单的GUI状态
  591. * @param state 状态码
  592. * @return 错误表单的GUI状态
  593. */
  594. gui_state_enum GeneralInterface::getGuiStateErrorForm(const int &state)
  595. {
  596. switch (state) {
  597. case 0: return RETURN_GUN;
  598. case 1: return CHARGE_GUN_UNAVILABLE;
  599. case 2: return OUT_OF_SERVICE;
  600. case 3: return MAX_POWER_LIMIT;
  601. default: return UNKOWN_STATE;
  602. }
  603. }
  604. /**
  605. * @brief GeneralInterface::getChargeProgress 根据表单类型获取充电进度
  606. * @param form 表单类型
  607. * @return 充电进度
  608. */
  609. charge_progress_enum GeneralInterface::getChargeProgress(const charge_prepare_enum &form)
  610. {
  611. switch (form) {
  612. case PLUG_OUT: return PLUG_IN_PROGRESS;
  613. case CHARGING_FORM: return CHARGING_PROGRESS;
  614. case CHARGE_PREPARE: return AUTHORIZATION_PROGRESS;
  615. case AUTHENTICATION: return AUTHORIZATION_PROGRESS;
  616. case FINISH_FORM: return FINISHED_PROGRESS;
  617. default: return UNKNOWN_PROGRESS;
  618. }
  619. }
  620. /**
  621. * @brief GeneralInterface::getChangedGunID 根据枪ID获取另一把枪的ID
  622. * @param gun_id 枪ID
  623. * @return 另一把枪的ID
  624. */
  625. int GeneralInterface::getChangedGunID(const int &gun_id)
  626. {
  627. switch (gun_id) {
  628. case CHARGE_GUN_DEFAULT_1: return CHARGE_GUN_DEFAULT_2;
  629. case CHARGE_GUN_DEFAULT_2: return CHARGE_GUN_DEFAULT_1;
  630. default: return 0;
  631. }
  632. }
  633. /**
  634. * @brief GeneralInterface::getMaxHeight 获取widget的最大高度
  635. * @param widget
  636. * @return widget的最大高度
  637. */
  638. int GeneralInterface::getMaxHeight(QWidget *widget)
  639. {
  640. if (!widget) return 0;
  641. // 获取widget在全局的底部y坐标
  642. QPoint globalBottomLeft = widget->mapToGlobal(QPoint(0, widget->height()));
  643. #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
  644. // Qt5.10及以上推荐用QScreen
  645. QScreen *screen = widget->screen();
  646. if (!screen) screen = QApplication::primaryScreen();
  647. QRect available = screen->availableGeometry();
  648. #else
  649. // Qt5.9及以下用QDesktopWidget
  650. QRect available = QApplication::desktop()->availableGeometry(widget);
  651. #endif
  652. int maxHeight = available.bottom() - globalBottomLeft.y();
  653. return maxHeight > 0 ? maxHeight : 0;
  654. }
  655. /**
  656. * @brief GeneralInterface::initTimezoneComboBox 初始化时区下拉框
  657. * @param combox
  658. */
  659. void GeneralInterface::initTimezoneComboBox(CustomComboBox *combox)
  660. {
  661. QStringList timezone_list;
  662. timezone_list << "Asia/Shanghai"
  663. << "Asia/Tokyo"
  664. << "Asia/Seoul"
  665. << "Asia/Kolkata"
  666. << "Asia/Singapore"
  667. << "Asia/Bangkok"
  668. << "Asia/Kuala_Lumpur"
  669. << "Europe/London"
  670. << "Europe/Berlin"
  671. << "Europe/Paris"
  672. << "Europe/Rome"
  673. << "Europe/Madrid"
  674. << "Europe/Moscow"
  675. << "America/New_York"
  676. << "America/Los_Angeles"
  677. << "America/Toronto"
  678. << "America/Sao_Paulo"
  679. << "America/Mexico_City";
  680. combox->addItems(timezone_list);
  681. }
  682. /**
  683. * @brief GeneralInterface::initLanguageComboBox 初始化语言下拉框
  684. * @param combox
  685. */
  686. void GeneralInterface::initLanguageComboBox(CustomComboBox *combox)
  687. {
  688. QStringList timezone_list;
  689. timezone_list << "Chinese (Simplified)"
  690. << "English (US)";
  691. combox->addItems(timezone_list);
  692. }
  693. void GeneralInterface::initCurrencySymbolMap()
  694. {
  695. QMap<QString, QString> currencySymbol;
  696. currencySymbol.insert("USD", "$");
  697. currencySymbol.insert("EUR", "€");
  698. currencySymbol.insert("GBP", "£");
  699. currencySymbol.insert("JPY", "¥");
  700. currencySymbol.insert("CNY", "¥");
  701. currencySymbol.insert("AUD", "A$");
  702. currencySymbol.insert("CAD", "C$");
  703. currencySymbol.insert("CHF", "Fr");
  704. currencySymbol.insert("HKD", "HK$");
  705. currencySymbol.insert("SGD", "S$");
  706. currencySymbol.insert("INR", "₹");
  707. currencySymbol.insert("BRL", "R$");
  708. currencySymbol.insert("RUB", "₽");
  709. currencySymbol.insert("KRW", "₩");
  710. currencySymbol.insert("MXN", "Mex$");
  711. currencySymbol.insert("NZD", "NZ$");
  712. currencySymbol.insert("SEK", "kr");
  713. currencySymbol.insert("DKK", "kr");
  714. currencySymbol.insert("NOK", "kr");
  715. currencySymbol.insert("SAR", "﷼");
  716. currencySymbol.insert("AED", "د.إ");
  717. currencySymbol.insert("ZAR", "R");
  718. currencySymbol.insert("TRY", "₺");
  719. currencySymbol.insert("CHF", "Fr");
  720. GLOBALS->setValue(Global::Keys::CURRENCY_SYMBOL_MAP, QVariant::fromValue(currencySymbol));
  721. }
  722. QString GeneralInterface::getCurrencySymbol(const QString &str)
  723. {
  724. auto map = GLOBALS->getValue(Global::Keys::CURRENCY_SYMBOL_MAP).value<QMap<QString, QString>>();
  725. return QString("%1(%2)").arg(str, map.value(str));
  726. }
  727. QString GeneralInterface::getCurrencySymbol(CustomComboBox *combox)
  728. {
  729. auto str = combox->currentText();
  730. auto list = str.split('(');
  731. return list[0];
  732. }
  733. void GeneralInterface::initCurrencySymbolComboBox(CustomComboBox *combox)
  734. {
  735. QStringList currencySymbol;
  736. auto map = GLOBALS->getValue(Global::Keys::CURRENCY_SYMBOL_MAP).value<QMap<QString, QString>>();
  737. foreach (const auto& key, map.keys()) {
  738. currencySymbol.append(QString("%1(%2)").arg(key, map.value(key)));
  739. }
  740. combox->addItems(currencySymbol);
  741. }
  742. /**
  743. * @brief GeneralInterface::clearGridLayoutChiledren 清空QGridLayout的子控件
  744. * @param layout
  745. */
  746. void GeneralInterface::clearGridLayoutChiledren(QGridLayout *layout)
  747. {
  748. if (!layout) return;
  749. // 删除所有子控件(widget)
  750. while (QLayoutItem* item = layout->takeAt(0)) {
  751. if (QWidget* widget = item->widget()) {
  752. layout->removeWidget(widget);
  753. widget->deleteLater(); // 安全删除 widget
  754. } else if (QLayout* childLayout = item->layout()) {
  755. clearGridLayoutChiledren(qobject_cast<QGridLayout*>(childLayout)); // 递归删除子 layout
  756. }
  757. layout->removeItem(item);
  758. delete item; // 删除 QLayoutItem 本身
  759. }
  760. for(int row = 0; row < layout->rowCount(); row ++) {
  761. layout->setRowStretch(row, 0);
  762. }
  763. layout->update();
  764. }
  765. /**
  766. * @brief GeneralInterface::gridLayoutAddWidget 向QGridLayout中添加控件
  767. * @param layout
  768. * @param widget
  769. */
  770. void GeneralInterface::gridLayoutAddWidget(QGridLayout *layout, QWidget *widget, int row, int col)
  771. {
  772. if (row == -1) row = layout->rowCount();
  773. layout->addWidget(widget, row, col);
  774. layout->setRowStretch(row, col);
  775. }
  776. /**
  777. * @brief GeneralInterface::gridLayoutAddStrtch 向QGridLayout中添加弹簧
  778. * @param layout
  779. */
  780. void GeneralInterface::gridLayoutAddStrtch(QGridLayout *layout)
  781. {
  782. int row = layout->rowCount();
  783. // 在最后一行添加弹簧(spacer),让控件靠上
  784. QSpacerItem* vSpacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding);
  785. layout->addItem(vSpacer, row, 0, 1, layout->columnCount());
  786. layout->setRowStretch(row, 1);
  787. }
  788. /**
  789. * @brief GeneralInterface::getChargingProfilePurposeIndex 根据充电配置目的获取索引
  790. * @param purpose 充电配置目的
  791. * @return
  792. */
  793. int GeneralInterface::getChargingProfilePurposeIndex(const QString &purpose)
  794. {
  795. if (purpose == ChargingProfiles::Purpose::CHARGE_POINT_MAX_PROFILE) {
  796. return Workspace::Settings::Ocpp::ChargingProfiles::CHARGE_POINT_MAX_PROFILE;
  797. } else if (purpose == ChargingProfiles::Purpose::TX_DEFAULT_PROFILE) {
  798. return Workspace::Settings::Ocpp::ChargingProfiles::TX_DEFAULT_PROFILE;
  799. } else if (purpose == ChargingProfiles::Purpose::TX_PROFILE) {
  800. return Workspace::Settings::Ocpp::ChargingProfiles::TX_PROFILE;
  801. }
  802. return 0;
  803. }
  804. /**
  805. * @brief GeneralInterface::getChargingProfileByPurpose 根据充电配置目的获取充电配置
  806. * @param data
  807. * @param dataList
  808. * @param purpose
  809. * @return
  810. */
  811. bool GeneralInterface::getChargingProfileByPurpose(charging_profiles_detail_info_t &data, const QList<charging_profiles_detail_info_t>& dataList, const QString &purpose)
  812. {
  813. QMap<QString, QPair<int, charging_profiles_detail_info_t>> stats;
  814. for (const auto& item : std::as_const(dataList)) {
  815. if (stats.contains(item.chargingProfilePurpose)) {
  816. auto& tempData = stats[item.chargingProfilePurpose];
  817. tempData.first++;
  818. if (tempData.second.stackLevel < item.stackLevel) {
  819. tempData.second = item;
  820. }
  821. } else {
  822. stats.insert(item.chargingProfilePurpose, {1, item});
  823. }
  824. }
  825. if (stats.contains(purpose)) {
  826. data = stats.value(purpose).second;
  827. }
  828. return stats.contains(purpose);
  829. }
  830. /**
  831. * @brief GeneralInterface::chargingProfileToMap 充电配置转map
  832. * @param dataList
  833. * @return
  834. */
  835. QVARIANTMAP_INT_MAP GeneralInterface::chargingProfileToMap(const QList<charging_profiles_detail_info_t> &dataList)
  836. {
  837. QVARIANTMAP_INT_MAP result;
  838. if (dataList.isEmpty()) return result;
  839. result = chargingProfileToMapByConnectorId(dataList);
  840. return result;
  841. }
  842. /**
  843. * @brief GeneralInterface::chargingProfileMapToList map转充电配置
  844. * @param dataMap
  845. * @return
  846. */
  847. QList<charging_profiles_detail_info_t> GeneralInterface::chargingProfileMapToList(const QMap<int, QVariant> &dataMap)
  848. {
  849. QList<charging_profiles_detail_info_t> result;
  850. if (dataMap.isEmpty()) return result;
  851. result = chargingProfileMapToListByConnectorId(dataMap);
  852. return result;
  853. }
  854. /**
  855. * @brief GeneralInterface::chargingProfileToMapByConnectorId 根据充电配置ID转map
  856. * @param dataList
  857. * @return
  858. */
  859. QMap<int, QVariant> GeneralInterface::chargingProfileToMapByConnectorId(const QList<charging_profiles_detail_info_t> &dataList)
  860. {
  861. QMap<int, QVariant> result;
  862. foreach (const auto& data, dataList) {
  863. auto map = chargingProfileToMapByPurpose(dataList,
  864. data.connectorId);
  865. result.insert(data.connectorId, QVariant::fromValue(map));
  866. }
  867. return result;
  868. }
  869. /**
  870. * @brief GeneralInterface::chargingProfileMapToListByConnectorId map转充电配置ID
  871. * @param dataMap
  872. * @return
  873. */
  874. QList<charging_profiles_detail_info_t> GeneralInterface::chargingProfileMapToListByConnectorId(const QMap<int, QVariant> &dataMap)
  875. {
  876. QList<charging_profiles_detail_info_t> result;
  877. foreach (const auto& data, dataMap) {
  878. result.append(chargingProfileMapToListByPurpose(data.value<QMap<QString, QVariant>>(), dataMap.key(data)));
  879. }
  880. return result;
  881. }
  882. /**
  883. * @brief GeneralInterface::chargingProfileToMapByPurpose 根据充电配置目的转map
  884. * @param dataList
  885. * @param connectorId 充电配置ID
  886. * @return
  887. */
  888. QMap<QString, QVariant> GeneralInterface::chargingProfileToMapByPurpose(const QList<charging_profiles_detail_info_t> &dataList,
  889. const int &connectorId)
  890. {
  891. QMap<QString, QVariant> result;
  892. foreach (const auto& data, dataList) {
  893. if (data.connectorId == connectorId) {
  894. auto map = chargingProfileToMapByKind(dataList,
  895. data.connectorId,
  896. data.chargingProfilePurpose);
  897. result.insert(data.chargingProfilePurpose, QVariant::fromValue(map));
  898. }
  899. }
  900. return result;
  901. }
  902. /**
  903. * @brief GeneralInterface::chargingProfileMapToListByPurpose map转充电配置目的
  904. * @param dataMap
  905. * @param connectorId
  906. * @return
  907. */
  908. QList<charging_profiles_detail_info_t> GeneralInterface::chargingProfileMapToListByPurpose(const QMap<QString, QVariant> &dataMap,
  909. const int &connectorId)
  910. {
  911. QList<charging_profiles_detail_info_t> result;
  912. foreach (const auto& data, dataMap) {
  913. result.append(chargingProfileMapToListByKind(data.value<QMap<QString, QVariant>>(),
  914. connectorId,
  915. dataMap.key(data)));
  916. }
  917. return result;
  918. }
  919. /**
  920. * @brief GeneralInterface::chargingProfileToMapByKind 根据充电配置类型转map
  921. * @param dataList
  922. * @param connectorId
  923. * @param purpose
  924. * @return
  925. */
  926. QMap<QString, QVariant> GeneralInterface::chargingProfileToMapByKind(const QList<charging_profiles_detail_info_t> &dataList,
  927. const int &connectorId,
  928. const QString &purpose)
  929. {
  930. QMap<QString, QVariant> result;
  931. foreach (const auto& data, dataList) {
  932. if (data.connectorId == connectorId &&
  933. data.chargingProfilePurpose == purpose) {
  934. auto map = chargingProfileToMapByRecurrencyKind(dataList,
  935. data.connectorId,
  936. data.chargingProfilePurpose,
  937. data.chargingProfileKind);
  938. result.insert(data.chargingProfileKind, QVariant::fromValue(map));
  939. }
  940. }
  941. return result;
  942. }
  943. /**
  944. * @brief GeneralInterface::chargingProfileMapToListByKind map转充电配置类型
  945. * @param dataMap
  946. * @param connectorId
  947. * @param purpose
  948. * @return
  949. */
  950. QList<charging_profiles_detail_info_t> GeneralInterface::chargingProfileMapToListByKind(const QMap<QString, QVariant> &dataMap,
  951. const int &connectorId,
  952. const QString &purpose)
  953. {
  954. QList<charging_profiles_detail_info_t> result;
  955. foreach (const auto& data, dataMap) {
  956. result.append(chargingProfileMapToListRecurrencyKind(data.value<QMap<QString, QVariant>>(),
  957. connectorId,
  958. purpose,
  959. dataMap.key(data)));
  960. }
  961. return result;
  962. }
  963. /**
  964. * @brief GeneralInterface::chargingProfileToMapByRecurrencyKind 根据充电配置周期转map
  965. * @param dataList
  966. * @param connectorId
  967. * @param purpose
  968. * @param kind
  969. * @return
  970. */
  971. QMap<QString, QVariant> GeneralInterface::chargingProfileToMapByRecurrencyKind(const QList<charging_profiles_detail_info_t> &dataList,
  972. const int &connectorId,
  973. const QString &purpose,
  974. const QString &kind)
  975. {
  976. QMap<QString, QVariant> result;
  977. foreach (const auto& data, dataList) {
  978. if (data.connectorId == connectorId &&
  979. data.chargingProfilePurpose == purpose &&
  980. data.chargingProfileKind == kind) {
  981. auto variantList = chargingProfileToMapByRecurrencyKind(dataList,
  982. data.connectorId,
  983. data.chargingProfilePurpose,
  984. data.chargingProfileKind,
  985. data.recurrencyKind);
  986. result.insert(data.recurrencyKind, QVariant::fromValue(variantList));
  987. }
  988. }
  989. return result;
  990. }
  991. /**
  992. * @brief GeneralInterface::chargingProfileMapToListRecurrencyKind map转充电配置周期
  993. * @param dataMap
  994. * @param connectorId
  995. * @param purpose
  996. * @param kind
  997. * @return
  998. */
  999. QList<charging_profiles_detail_info_t> GeneralInterface::chargingProfileMapToListRecurrencyKind(const QMap<QString, QVariant> &dataMap,
  1000. const int &connectorId,
  1001. const QString &purpose,
  1002. const QString &kind)
  1003. {
  1004. QList<charging_profiles_detail_info_t> result;
  1005. foreach (const auto& data, dataMap) {
  1006. result.append(chargingProfileMapToListRecurrencyKind(data.value<QMap<int, QVariant>>(),
  1007. connectorId,
  1008. purpose,
  1009. kind,
  1010. dataMap.key(data)));
  1011. }
  1012. return result;
  1013. }
  1014. /**
  1015. * @brief GeneralInterface::chargingProfileToMapByRecurrencyKind 根据充电配置栈级转map
  1016. * @param dataList
  1017. * @param connectorId
  1018. * @param purpose
  1019. * @param kind
  1020. * @param recurrencyKind
  1021. * @return
  1022. */
  1023. QMap<int, QVariant> GeneralInterface::chargingProfileToMapByRecurrencyKind(const QList<charging_profiles_detail_info_t> &dataList,
  1024. const int &connectorId,
  1025. const QString &purpose,
  1026. const QString &kind,
  1027. const QString &recurrencyKind)
  1028. {
  1029. QMap<int, QVariant> result;
  1030. foreach (const auto& data, dataList) {
  1031. if (data.connectorId == connectorId &&
  1032. data.chargingProfilePurpose == purpose &&
  1033. data.chargingProfileKind == kind &&
  1034. data.recurrencyKind == recurrencyKind) {
  1035. auto map = chargingProfileToMapByStackLevel(dataList,
  1036. data.connectorId,
  1037. data.chargingProfilePurpose,
  1038. data.chargingProfileKind,
  1039. data.recurrencyKind,
  1040. data.stackLevel);
  1041. result.insert(data.stackLevel, QVariant::fromValue(map));
  1042. }
  1043. }
  1044. return result;
  1045. }
  1046. /**
  1047. * @brief GeneralInterface::chargingProfileMapToListRecurrencyKind map转充电配置栈级
  1048. * @param dataMap
  1049. * @param connectorId
  1050. * @param purpose
  1051. * @param kind
  1052. * @param recurrencyKind
  1053. * @return
  1054. */
  1055. QList<charging_profiles_detail_info_t> GeneralInterface::chargingProfileMapToListRecurrencyKind(const QMap<int, QVariant> &dataMap,
  1056. const int &connectorId,
  1057. const QString &purpose,
  1058. const QString &kind,
  1059. const QString &recurrencyKind)
  1060. {
  1061. QList<charging_profiles_detail_info_t> result;
  1062. foreach (const auto& data, dataMap) {
  1063. result.append(chargingProfileMapToListByStackLevel(data.value<QVariantList>(),
  1064. connectorId,
  1065. purpose,
  1066. kind,
  1067. recurrencyKind,
  1068. dataMap.key(data)));
  1069. }
  1070. return result;
  1071. }
  1072. /**
  1073. * @brief GeneralInterface::chargingProfileToMapByStackLevel 根据充电配置栈级转map
  1074. * @param dataList
  1075. * @param connectorId
  1076. * @param purpose
  1077. * @param kind
  1078. * @param recurrencyKind
  1079. * @param stackLevel
  1080. * @return
  1081. */
  1082. QVariantList GeneralInterface::chargingProfileToMapByStackLevel(const QList<charging_profiles_detail_info_t> &dataList, const int &connectorId, const QString &purpose, const QString &kind, const QString &recurrencyKind, const int &stackLevel)
  1083. {
  1084. QVariantList result;
  1085. foreach (const auto& data, dataList) {
  1086. if (data.connectorId == connectorId &&
  1087. data.chargingProfilePurpose == purpose &&
  1088. data.chargingProfileKind == kind &&
  1089. data.recurrencyKind == recurrencyKind &&
  1090. data.stackLevel == stackLevel) {
  1091. result.append(QVariant::fromValue(data));
  1092. }
  1093. }
  1094. return result;
  1095. }
  1096. /**
  1097. * @brief GeneralInterface::chargingProfileMapToListByStackLevel map转充电配置栈级
  1098. * @param dataMap
  1099. * @param connectorId
  1100. * @param purpose
  1101. * @param kind
  1102. * @param recurrencyKind
  1103. * @param stackLevel
  1104. * @return
  1105. */
  1106. QList<charging_profiles_detail_info_t> GeneralInterface::chargingProfileMapToListByStackLevel(const QVariantList &dataMap, const int &connectorId, const QString &purpose, const QString &kind, const QString &recurrencyKind, const int &stackLevel)
  1107. {
  1108. QList<charging_profiles_detail_info_t> result;
  1109. foreach (const auto& data, dataMap) {
  1110. if (data.value<charging_profiles_detail_info_t>().connectorId == connectorId &&
  1111. data.value<charging_profiles_detail_info_t>().stackLevel == stackLevel &&
  1112. data.value<charging_profiles_detail_info_t>().chargingProfilePurpose == purpose &&
  1113. data.value<charging_profiles_detail_info_t>().chargingProfileKind == kind &&
  1114. data.value<charging_profiles_detail_info_t>().recurrencyKind == recurrencyKind) {
  1115. result.append(data.value<charging_profiles_detail_info_t>());
  1116. }
  1117. }
  1118. return result;
  1119. }
  1120. /**
  1121. * @brief GeneralInterface::getMaxElecment 获取最大值
  1122. * @param list
  1123. * @return list为空返回-1,否则返回最大值
  1124. */
  1125. int GeneralInterface::getMaxElecment(const QList<int> &list)
  1126. {
  1127. int result = -1;
  1128. if (list.isEmpty()) return result;
  1129. for (const auto& num : list) {
  1130. if (num > result) result = num;
  1131. }
  1132. return result;
  1133. }
  1134. uint32_t GeneralInterface::getMaxElecment(const QList<uint32_t> &list)
  1135. {
  1136. uint32_t result = 0;
  1137. if (list.isEmpty()) return result;
  1138. for (const auto& num : list) {
  1139. if (num > result) result = num;
  1140. }
  1141. return result;
  1142. }
  1143. uint32_t GeneralInterface::getMaxErrorCode(const ERROR_NOTE_LIST &info)
  1144. {
  1145. QList<uint32_t> error_code_list;
  1146. foreach (const auto& data, info) {
  1147. error_code_list.append(data.error_code);
  1148. }
  1149. return getMaxElecment(error_code_list);
  1150. }
  1151. /**
  1152. * @brief GeneralInterface::getCurrentDate 获取当前时间
  1153. * @param seconds 秒数
  1154. * @return 返回"HH:mm:ss"的字符串
  1155. */
  1156. QString GeneralInterface::getCurrentDate(const int &seconds)
  1157. {
  1158. QDate date = QDate::currentDate();
  1159. QTime time = QTime(0, 0, 0).addSecs(seconds);
  1160. QDateTime dt(date, time);
  1161. return dt.toString("HH:mm:ss");
  1162. }
  1163. /**
  1164. * @brief GeneralInterface::getCurrentDate 获取当前时间
  1165. * @param time 时间字符串
  1166. * @return 返回秒数
  1167. */
  1168. int GeneralInterface::getCurrentDate(const QString &time)
  1169. {
  1170. QTime dt = QTime::fromString(time, "HH:mm:ss");
  1171. return QTime(0, 0, 0).secsTo(dt);
  1172. }
  1173. /**
  1174. * @brief GeneralInterface::getCurrentDateOfWeek 获取当前周时间
  1175. * @param startTime 开始时间
  1176. * @param seconds 秒数
  1177. * @return 返回"HH:mm:ss"的字符串
  1178. */
  1179. QString GeneralInterface::getCurrentDateOfWeek(const QString &startTime, const int &seconds)
  1180. {
  1181. QDateTime dt = QDateTime::fromString(startTime, Qt::ISODate);
  1182. dt.setTimeSpec(Qt::UTC);
  1183. dt = dt.addSecs(seconds);
  1184. return dt.toString("HH:mm:ss");
  1185. }
  1186. /**
  1187. * @brief GeneralInterface::getCurrentDateSecondOfWeek 获取当前周时间
  1188. * @param startTime 开始时间
  1189. * @param seconds 秒数
  1190. * @return 返回秒数
  1191. */
  1192. int GeneralInterface::getCurrentDateSecondOfWeek(const QString &startTime, const int &seconds)
  1193. {
  1194. // 1. 解析开始时间
  1195. QDateTime startDt = QDateTime::fromString(startTime, Qt::ISODate);
  1196. startDt.setTimeSpec(Qt::UTC);
  1197. // 2. 计算目标时间
  1198. QDateTime targetDt = startDt.addSecs(seconds);
  1199. // 3. 获取当天00:00:00到目标时间的秒数
  1200. int secondsOfDay = QTime(0, 0, 0).secsTo(targetDt.time());
  1201. return secondsOfDay;
  1202. }
  1203. /**
  1204. * @brief GeneralInterface::getCurrentDateOfWeek 获取当前周时间
  1205. * @param startTime 开始时间
  1206. * @param seconds 秒数
  1207. * @param dayOfWeek 周几
  1208. * @return 返回秒数
  1209. */
  1210. int GeneralInterface::getCurrentDateOfWeek(const QString &startTime, const int &seconds, const int &dayOfWeek)
  1211. {
  1212. // 1. 解析开始时间
  1213. QDateTime startDt = QDateTime::fromString(startTime, Qt::ISODate);
  1214. startDt.setTimeSpec(Qt::UTC);
  1215. // 2. 获取开始时间所在周的周一
  1216. QDate startDate = startDt.date();
  1217. int startDayOfWeek = startDate.dayOfWeek(); // 1=周一
  1218. QDate monday = startDate.addDays(1 - startDayOfWeek);
  1219. // 3. 目标日期 = 本周的 dayOfWeek
  1220. QDate targetDate = monday.addDays(dayOfWeek - 1);
  1221. // 4. 用秒数构造 QTime
  1222. QTime targetTime = QTime(0, 0, 0).addSecs(seconds);
  1223. // 5. 构造目标 QDateTime
  1224. QDateTime targetDt(targetDate, targetTime, Qt::UTC);
  1225. // 6. 计算秒数差
  1226. qint64 secondsDiff = startDt.secsTo(targetDt);
  1227. return static_cast<int>(secondsDiff);
  1228. }
  1229. /**
  1230. * @brief GeneralInterface::getCurrentDateOfWeek 获取当前周时间
  1231. * @param startTime 开始时间
  1232. * @param time 时间字符串
  1233. * @param dayOfWeek 周几
  1234. * @return
  1235. */
  1236. int GeneralInterface::getCurrentDateOfWeek(const QString &startTime, const QString &time, const int& dayOfWeek)
  1237. {
  1238. // 1. 解析开始时间
  1239. QDateTime startDt = QDateTime::fromString(startTime, Qt::ISODate);
  1240. startDt.setTimeSpec(Qt::UTC); // 若有Z,确保为UTC
  1241. // 2. 获取开始时间所在周的周一
  1242. QDate startDate = startDt.date();
  1243. int startDayOfWeek = startDate.dayOfWeek(); // 1=周一
  1244. QDate monday = startDate.addDays(1 - startDayOfWeek);
  1245. // 3. 目标日期 = 本周的 dayOfWeek
  1246. QDate targetDate = monday.addDays(dayOfWeek - 1);
  1247. // 4. 解析当天时间
  1248. QTime targetTime = QTime::fromString(time, "HH:mm:ss");
  1249. // 5. 构造目标 QDateTime
  1250. QDateTime targetDt(targetDate, targetTime, Qt::UTC);
  1251. // 6. 计算秒数差
  1252. qint64 secondsDiff = startDt.secsTo(targetDt);
  1253. return static_cast<int>(secondsDiff);
  1254. }
  1255. /**
  1256. * @brief GeneralInterface::getDayOfWeek 获取当前周几
  1257. * @param time 时间字符串
  1258. * @return 1=周一、2=周二、3=周三、4=周四、5=周五、6=周六、7=周日
  1259. */
  1260. int GeneralInterface::getDayOfWeek(const QString &time)
  1261. {
  1262. QDateTime dt = QDateTime::fromString(time, Qt::ISODate);
  1263. dt.setTimeSpec(Qt::UTC); // 明确为UTC时间
  1264. QDate date = dt.date();
  1265. return date.dayOfWeek();
  1266. }
  1267. /**
  1268. * @brief GeneralInterface::sortByStartPeriod 按开始时间排序
  1269. * @param list
  1270. */
  1271. void GeneralInterface::sortByStartPeriod(QList<charging_schedule_period_info_t> &list)
  1272. {
  1273. std::sort(list.begin(), list.end(), [](const charging_schedule_period_info_t &a, const charging_schedule_period_info_t &b) {
  1274. return a.startPeriod < b.startPeriod;
  1275. });
  1276. }
  1277. /**
  1278. * @brief GeneralInterface::sortByStackLevel 按优先级排序
  1279. * @param list
  1280. */
  1281. void GeneralInterface::sortByStackLevel(QList<charging_profiles_detail_info_t> &list)
  1282. {
  1283. std::sort(list.begin(), list.end(), [](const charging_profiles_detail_info_t &a, const charging_profiles_detail_info_t &b) {
  1284. return a.stackLevel > b.stackLevel;
  1285. });
  1286. }
  1287. /**
  1288. * @brief GeneralInterface::getMaxChargingProfileId 获取最大充电配置ID
  1289. * @param list
  1290. * @return list为空返回-1,否则返回最大值
  1291. */
  1292. int GeneralInterface::getMaxChargingProfileId(QList<charging_profiles_detail_info_t> &list)
  1293. {
  1294. QList<int> chargingProfileIdList;
  1295. foreach (const auto& data, list) {
  1296. chargingProfileIdList.append(data.chargingProfileId);
  1297. }
  1298. return getMaxElecment(chargingProfileIdList);
  1299. }
  1300. /**
  1301. * @brief GeneralInterface::getVersion 获取版本号
  1302. * @param appName
  1303. * @return
  1304. * HW_NAME: 硬件版本号
  1305. * CCU_NAME: CCU版本号
  1306. * TCU_NAME: TCU版本号
  1307. * PCU_NAME: PCU版本号
  1308. */
  1309. QString GeneralInterface::getVersion(const QString &appName)
  1310. {
  1311. QString version;
  1312. if (appName == AppName::HW_NAME) {
  1313. version = VersionManager::getHardwareVersion();
  1314. } else if (appName == AppName::CCU_NAME ||
  1315. appName == AppName::TCU_NAME ||
  1316. appName == AppName::PCU_NAME) {
  1317. AppVersionInfo info = VersionManager::getAppVersion(appName);
  1318. if (info.success) {
  1319. version = QString("V%1.%2.%3").arg(info.major).arg(info.minor).arg(info.build);
  1320. }
  1321. }
  1322. return version;
  1323. }
  1324. static char app_version[128] = {0};
  1325. static const char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  1326. char *GeneralInterface::formatAppVersion()
  1327. {
  1328. int i;
  1329. int month = 0, mday, year, hour, min, sec;
  1330. #define ASCII_CODE(x) ((x)==32? 0:((x)-'0'))
  1331. mday = ASCII_CODE(__DATE__[4])*10 + ASCII_CODE(__DATE__[5]);
  1332. year = ASCII_CODE(__DATE__[7])*1000 + ASCII_CODE(__DATE__[8])*100 + ASCII_CODE(__DATE__[9])*10 + ASCII_CODE(__DATE__[10]);
  1333. hour = ASCII_CODE(__TIME__[0])*10 + ASCII_CODE(__TIME__[1]);
  1334. min = ASCII_CODE(__TIME__[3])*10 + ASCII_CODE(__TIME__[4]);
  1335. sec = ASCII_CODE(__TIME__[6])*10 + ASCII_CODE(__TIME__[7]);
  1336. #undef ASCII_CODE
  1337. for (i = 0; i < 12; i++)
  1338. {
  1339. if (strncmp(__DATE__, months[i], 3)==0)
  1340. {
  1341. month = i + 1;
  1342. break;
  1343. }
  1344. }
  1345. snprintf(app_version, 128, "app_TCU_V1R0B%04d%02d%02d %02d:%02d:%02d", year, month, mday, hour, min, sec);
  1346. return app_version;
  1347. }
  1348. void GeneralInterface::initGlobals()
  1349. {
  1350. // 初始化充电枪基本信息
  1351. for (int i = CHARGE_GUN_DEFAULT_1; i <= CHARGE_GUN_DEFAULT_2; i++) {
  1352. BASIC_INFO basic_info;
  1353. GLOBALS->setValue(i == CHARGE_GUN_DEFAULT_1 ? Global::Keys::GUN_BASIC_INFO_1 : Global::Keys::GUN_BASIC_INFO_2,
  1354. QVariant::fromValue(basic_info));
  1355. CHARGING_INFO charging_info;
  1356. GLOBALS->setValue(i == CHARGE_GUN_DEFAULT_1 ? Global::Keys::CHARGING_INFO_1 : Global::Keys::CHARGING_INFO_2,
  1357. QVariant::fromValue(charging_info));
  1358. UINT32_QSTRING_MAP gun_error;
  1359. GLOBALS->setValue(i == CHARGE_GUN_DEFAULT_1 ? Global::Keys::GUN_ERROR_1 : Global::Keys::GUN_ERROR_2,
  1360. QVariant::fromValue(gun_error));
  1361. UINT32_QSTRING_MAP gun_state;
  1362. GLOBALS->setValue(i == CHARGE_GUN_DEFAULT_1 ? Global::Keys::GUN_STATE_1 : Global::Keys::GUN_STATE_2,
  1363. QVariant::fromValue(gun_state));
  1364. UINT8_QSTRING_MAP gun_type;
  1365. GLOBALS->setValue(i == CHARGE_GUN_DEFAULT_1 ? Global::Keys::GUN_TYPE_1 : Global::Keys::GUN_TYPE_2,
  1366. QVariant::fromValue(gun_type));
  1367. }
  1368. // 初始化其他全局变量
  1369. GLOBALS->setValue(Global::Keys::AUTH_LIST, QVariant::fromValue(AUTH_LIST()));
  1370. GLOBALS->setValue(Global::Keys::CCU_CFG, QVariant::fromValue(CCU_CFG()));
  1371. GLOBALS->setValue(Global::Keys::CHARGING_PROFILES, QVariant::fromValue(CHARGING_PROFILES()));
  1372. GLOBALS->setValue(Global::Keys::CHARGING_PROFILES_MAP, QVariant::fromValue(QVARIANTMAP_INT_MAP()));
  1373. GLOBALS->setValue(Global::Keys::CFG_KEY, QVariant::fromValue(CONFIG_KEY_INFO()));
  1374. GLOBALS->setValue(Global::Keys::OFFLINE_CHARGING_RECORDS, QVariant::fromValue(CHARGING_RECORDS_INFO()));
  1375. GLOBALS->setValue(Global::Keys::TCU_CFG, QVariant::fromValue(TCU_CFG()));
  1376. GLOBALS->setValue(Global::Keys::PCU_CFG, QVariant::fromValue(PCU_CFG()));
  1377. GLOBALS->setValue(Global::Keys::PRICEINFO, QVariant::fromValue(PRICE_INFO()));
  1378. VERSION version_info;
  1379. version_info.ccu_version = GeneralInterface::getVersion(AppName::CCU_NAME);
  1380. version_info.tcu_version = GeneralInterface::getVersion(AppName::TCU_NAME);
  1381. version_info.pcu_version = GeneralInterface::getVersion(AppName::PCU_NAME);
  1382. version_info.hw_version = GeneralInterface::getVersion(AppName::HW_NAME);
  1383. GLOBALS->setValue(Global::Keys::VERSION, QVariant::fromValue(version_info));
  1384. }
  1385. int GeneralInterface::readLoadStyleFile(const QString &filapath)
  1386. {
  1387. QString styleSheetPath = filapath;
  1388. // 检查资源文件是否存在
  1389. QFile file;
  1390. file.setFileName(styleSheetPath);
  1391. if (!file.exists()) {
  1392. LOG_ERROR(QString("Style file not found: %1").arg(styleSheetPath));
  1393. return INIT_GUI_STYLE_LOAD_ERROR;
  1394. }
  1395. // 安全打开文件
  1396. if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
  1397. LOG_ERROR(QString("Failed to open style file: %1, error: %2").arg(
  1398. styleSheetPath, file.errorString()));
  1399. return INIT_GUI_STYLE_LOAD_ERROR;
  1400. }
  1401. // 安全读取文件内容
  1402. QByteArray content;
  1403. try {
  1404. // 设置文件读取缓冲区大小限制,防止大文件导致内存问题
  1405. const qint64 maxSize = 2 * 1024 * 1024; // 2MB
  1406. // 先检查文件大小
  1407. qint64 fileSize = file.size();
  1408. if (fileSize > maxSize) {
  1409. LOG_WARNING(QString("Style file is large: %1 bytes, will limit to %2 bytes").arg(
  1410. fileSize, maxSize));
  1411. }
  1412. // 读取文件内容
  1413. content = file.read(maxSize);
  1414. if (content.isEmpty() && !file.atEnd()) {
  1415. LOG_ERROR("Failed to read style file content");
  1416. file.close();
  1417. return INIT_GUI_STYLE_LOAD_ERROR;
  1418. }
  1419. // 确保文件正确关闭
  1420. file.close();
  1421. // 检查内容是否有效
  1422. if (content.isEmpty()) {
  1423. LOG_WARNING("Style file is empty, skipping");
  1424. return INIT_OK; // 允许程序继续运行
  1425. }
  1426. // 安全地设置样式表
  1427. QString styleSheet = QString::fromUtf8(content);
  1428. // 验证样式表语法是否有效(简单检查)
  1429. if (styleSheet.count('{') != styleSheet.count('}')) {
  1430. LOG_WARNING("Style sheet may have syntax errors, mismatched braces");
  1431. }
  1432. // 应用样式表 - 确保qApp有效
  1433. if (qApp) {
  1434. qApp->setStyleSheet(styleSheet);
  1435. LOG_INFO("Style sheet loaded successfully");
  1436. } else {
  1437. LOG_ERROR("QApplication instance not available when setting style sheet");
  1438. return INIT_GUI_STYLE_LOAD_ERROR;
  1439. }
  1440. } catch (const std::exception& e) {
  1441. // 捕获可能的异常
  1442. LOG_ERROR(QString("Exception while loading style sheet: %1").arg(e.what()));
  1443. file.close();
  1444. return INIT_GUI_STYLE_LOAD_ERROR;
  1445. } catch (...) {
  1446. LOG_ERROR("Unknown exception while loading style sheet");
  1447. file.close();
  1448. return INIT_GUI_STYLE_LOAD_ERROR;
  1449. }
  1450. return INIT_OK;
  1451. }
  1452. // ==================== 二维码生成相关方法 ====================
  1453. /**
  1454. * @brief 使用 libqrencode 生成二维码
  1455. * @param text 要编码的文本内容(通常是URL)
  1456. * @param size 二维码图片的尺寸(像素)
  1457. * @param margin 二维码边距(模块数)
  1458. * @param errorCorrectionLevel 错误纠正级别 (L=7%, M=15%, Q=25%, H=30%)
  1459. * @return 生成的二维码图片,失败时返回空图片
  1460. */
  1461. QPixmap GeneralInterface::generateQRCode(const QString& text, int size, int margin, char errorCorrectionLevel)
  1462. {
  1463. if (text.isEmpty()) {
  1464. return QPixmap();
  1465. }
  1466. // 将 QString 转换为 UTF-8 字节数组
  1467. QByteArray textData = text.toUtf8();
  1468. // 设置错误纠正级别
  1469. QRecLevel level = QR_ECLEVEL_M; // 默认使用 M 级别
  1470. switch (errorCorrectionLevel) {
  1471. case 'L': level = QR_ECLEVEL_L; break;
  1472. case 'M': level = QR_ECLEVEL_M; break;
  1473. case 'Q': level = QR_ECLEVEL_Q; break;
  1474. case 'H': level = QR_ECLEVEL_H; break;
  1475. default: level = QR_ECLEVEL_M; break;
  1476. }
  1477. // 生成二维码数据
  1478. QRcode* qrcode = QRcode_encodeString(textData.constData(), 0, level, QR_MODE_8, 1);
  1479. if (!qrcode) {
  1480. return QPixmap();
  1481. }
  1482. // 计算实际尺寸(包含边距)
  1483. int qrSize = qrcode->width;
  1484. int totalSize = qrSize + 2 * margin;
  1485. // 创建图像
  1486. QImage image(totalSize, totalSize, QImage::Format_ARGB32);
  1487. image.fill(Qt::white);
  1488. // 绘制二维码
  1489. QPainter painter(&image);
  1490. painter.setPen(Qt::black);
  1491. painter.setBrush(Qt::black);
  1492. // 计算每个模块的像素大小
  1493. int moduleSize = size / totalSize;
  1494. if (moduleSize < 1) moduleSize = 1;
  1495. // 绘制二维码模块
  1496. for (int y = 0; y < qrSize; y++) {
  1497. for (int x = 0; x < qrSize; x++) {
  1498. if (qrcode->data[y * qrSize + x] & 1) {
  1499. int pixelX = (x + margin) * moduleSize;
  1500. int pixelY = (y + margin) * moduleSize;
  1501. painter.fillRect(pixelX, pixelY, moduleSize, moduleSize, Qt::black);
  1502. }
  1503. }
  1504. }
  1505. // 释放二维码数据
  1506. QRcode_free(qrcode);
  1507. // 转换为 QPixmap
  1508. QPixmap pixmap = QPixmap::fromImage(image);
  1509. // 如果指定尺寸与计算尺寸不同,进行缩放
  1510. if (pixmap.width() != size) {
  1511. pixmap = pixmap.scaled(size, size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
  1512. }
  1513. return pixmap;
  1514. }
  1515. QPixmap GeneralInterface::generateQRCodeDefault(const QString &text, int size)
  1516. {
  1517. QRcode *qr = QRcode_encodeString(text.toUtf8().constData(), 0, QR_ECLEVEL_L, QR_MODE_8, 1);
  1518. if (!qr) return QPixmap();
  1519. // 计算缩放比例(二维码实际大小可能小于请求的 size)
  1520. int qrSize = qr->width > 0 ? qr->width : 1;
  1521. int scale = size / qrSize;
  1522. if (scale < 1) scale = 1;
  1523. // 创建 QImage 并绘制二维码
  1524. QImage image(qrSize * scale, qrSize * scale, QImage::Format_ARGB32);
  1525. image.fill(QColor(Qt::transparent));
  1526. QPainter painter(&image);
  1527. painter.setPen(Qt::black);
  1528. for (int y = 0; y < qrSize; y++) {
  1529. for (int x = 0; x < qrSize; x++) {
  1530. if (qr->data[y * qrSize + x] & 0x01) {
  1531. painter.fillRect(x * scale, y * scale, scale, scale, Qt::black);
  1532. }
  1533. }
  1534. }
  1535. QRcode_free(qr);
  1536. return QPixmap::fromImage(image);
  1537. }
  1538. QPixmap GeneralInterface::generateQRCodeWithIcon(const QString& text, int size, const QString& iconPath, int iconSize)
  1539. {
  1540. // 生成基础二维码
  1541. QPixmap qrCode = generateQRCode(text, size);
  1542. if (qrCode.isNull()) {
  1543. return QPixmap();
  1544. }
  1545. // 如果未提供图标路径,直接返回基础二维码
  1546. if (iconPath.isEmpty()) {
  1547. return qrCode;
  1548. }
  1549. // 加载图标
  1550. QPixmap icon(iconPath);
  1551. if (icon.isNull()) {
  1552. return qrCode; // 图标加载失败,返回基础二维码
  1553. }
  1554. // 确定图标大小
  1555. int finalIconSize = iconSize;
  1556. if (finalIconSize <= 0) {
  1557. // 默认图标大小为二维码尺寸的1/4
  1558. finalIconSize = size / 4;
  1559. }
  1560. // 缩放图标
  1561. icon = icon.scaled(finalIconSize, finalIconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
  1562. // 在二维码中心绘制图标
  1563. QPainter painter(&qrCode);
  1564. int iconX = (qrCode.width() - icon.width()) / 2;
  1565. int iconY = (qrCode.height() - icon.height()) / 2;
  1566. // 绘制一个白色背景,确保图标清晰可见
  1567. painter.fillRect(iconX - 2, iconY - 2, icon.width() + 4, icon.height() + 4, Qt::white);
  1568. painter.drawPixmap(iconX, iconY, icon);
  1569. return qrCode;
  1570. }
  1571. /**
  1572. * @brief 生成二维码并保存到文件
  1573. * @param text 要编码的文本内容
  1574. * @param filePath 保存文件路径
  1575. * @param size 二维码图片的尺寸(像素)
  1576. * @param margin 二维码边距(模块数)
  1577. * @param errorCorrectionLevel 错误纠正级别
  1578. * @return 是否保存成功
  1579. */
  1580. bool GeneralInterface::generateQRCodeToFile(const QString& text, const QString& filePath, int size, int margin, char errorCorrectionLevel)
  1581. {
  1582. QPixmap qrCode = generateQRCode(text, size, margin, errorCorrectionLevel);
  1583. if (qrCode.isNull()) {
  1584. return false;
  1585. }
  1586. // 根据文件扩展名确定保存格式
  1587. QString extension = filePath.split('.').last().toLower();
  1588. QString format = "PNG"; // 默认格式
  1589. if (extension == "jpg" || extension == "jpeg") {
  1590. format = "JPEG";
  1591. } else if (extension == "bmp") {
  1592. format = "BMP";
  1593. }
  1594. return qrCode.save(filePath, format.toUtf8().constData());
  1595. }
  1596. /**
  1597. * @brief 生成二维码的字节数组(用于网络传输)
  1598. * @param text 要编码的文本内容
  1599. * @param size 二维码图片的尺寸(像素)
  1600. * @param margin 二维码边距(模块数)
  1601. * @param errorCorrectionLevel 错误纠正级别
  1602. * @return 二维码图片的字节数组
  1603. */
  1604. QByteArray GeneralInterface::generateQRCodeBytes(const QString& text, int size, int margin, char errorCorrectionLevel)
  1605. {
  1606. QPixmap qrCode = generateQRCode(text, size, margin, errorCorrectionLevel);
  1607. if (qrCode.isNull()) {
  1608. return QByteArray();
  1609. }
  1610. // 将 QPixmap 转换为字节数组
  1611. QBuffer buffer;
  1612. buffer.open(QIODevice::WriteOnly);
  1613. if (qrCode.save(&buffer, "PNG")) {
  1614. return buffer.data();
  1615. }
  1616. return QByteArray();
  1617. }
  1618. /**
  1619. * @brief GeneralInterface::formatMillisecondDifference 格式化毫秒差
  1620. * @param ms1
  1621. * @param ms2
  1622. * @return
  1623. */
  1624. QString GeneralInterface::formatMillisecondDifference(qint64 ms1, qint64 ms2)
  1625. {
  1626. qint64 diffMs = qAbs(ms1 - ms2); // 取绝对值
  1627. QTime time(0, 0);
  1628. time = time.addMSecs(diffMs);
  1629. return time.toString("HH:mm:ss");
  1630. }
  1631. /**
  1632. * @brief GeneralInterface::makeLabelJump 使标签跳一下
  1633. * @param label
  1634. */
  1635. void GeneralInterface::makeLabelJump(QLabel* label) {
  1636. // 创建动画组
  1637. QParallelAnimationGroup *group = new QParallelAnimationGroup(label);
  1638. // 位置动画
  1639. QPropertyAnimation *posAnim = new QPropertyAnimation(label, "pos", group);
  1640. posAnim->setDuration(800);
  1641. posAnim->setEasingCurve(QEasingCurve::OutQuad);
  1642. posAnim->setKeyValueAt(0, label->pos());
  1643. posAnim->setKeyValueAt(0.5, label->pos() + QPoint(0, -80));
  1644. posAnim->setKeyValueAt(1, label->pos());
  1645. // 缩放动画
  1646. QPropertyAnimation *scaleAnim = new QPropertyAnimation(label, "geometry", group);
  1647. scaleAnim->setDuration(800);
  1648. scaleAnim->setEasingCurve(QEasingCurve::OutQuad);
  1649. QRect startRect = label->geometry();
  1650. scaleAnim->setKeyValueAt(0, startRect);
  1651. scaleAnim->setKeyValueAt(0.5, QRect(
  1652. startRect.x() - 10,
  1653. startRect.y() - 80,
  1654. startRect.width() + 20,
  1655. startRect.height() + 20
  1656. ));
  1657. scaleAnim->setKeyValueAt(1, startRect);
  1658. // 启动动画
  1659. group->start(QAbstractAnimation::DeleteWhenStopped);
  1660. }
  1661. /**
  1662. * @brief GeneralInterface::encodeAuthInfo 编码认证信息
  1663. * @param data
  1664. * @return
  1665. */
  1666. QByteArray GeneralInterface::encodeAuthInfo(const GUN_AUTH &data)
  1667. {
  1668. QByteArray result;
  1669. result.append(encodeValue<const uint32_t>(data.GUNID, 1));
  1670. result.append(0x81);
  1671. result.append(sizeof(data.EMID));
  1672. result.append(QByteArray(reinterpret_cast<const char*>(&data.EMID), sizeof(data.EMID)));
  1673. result.append(encodeValue<const uint32_t>(data.requestKWs, 1));
  1674. return result;
  1675. }
  1676. /**
  1677. * @brief GeneralInterface::getGunIconUrl 获取枪口图标
  1678. * @param type 枪口类型
  1679. * @param isError 是否错误
  1680. * @return 返回枪口图标URL
  1681. */
  1682. QString GeneralInterface::getGunIconUrl(const uint8_t &type, bool isError)
  1683. {
  1684. QString icon_url = "";
  1685. switch (type) {
  1686. case GUNTYPE_NACS:
  1687. icon_url = QString(":/icons/%1.png").arg("nacs" + QString("%1").arg(isError ? "_faild" : ""));
  1688. break;
  1689. case GUNTYPE_CCS1:
  1690. icon_url = QString(":/icons/%1.png").arg("ccs1" + QString("%1").arg(isError ? "_faild" : ""));
  1691. break;
  1692. case GUNTYPE_CCS2:
  1693. icon_url = QString(":/icons/%1.png").arg("ccs2" + QString("%1").arg(isError ? "_faild" : ""));
  1694. break;
  1695. case GUNTYPE_CHADEMO:
  1696. icon_url = QString(":/icons/%1.png").arg("chademo" + QString("%1").arg(isError ? "_faild" : ""));
  1697. break;
  1698. case GUNTYPE_GBDC:
  1699. icon_url = QString(":/icons/%1.png").arg("gbdc" + QString("%1").arg(isError ? "_faild" : ""));
  1700. break;
  1701. default:
  1702. break;
  1703. }
  1704. return icon_url;
  1705. }
  1706. QByteArray GeneralInterface::encodeUpdateConfigInfo(const UPDATE_CONFIG &data)
  1707. {
  1708. QByteArray result;
  1709. result.append(0x81);
  1710. result.append(sizeof(data.config_filename));
  1711. result.append(QByteArray(reinterpret_cast<const char*>(&data.config_filename), sizeof(data.config_filename)));
  1712. return result;
  1713. }
  1714. /**
  1715. * @brief GeneralInterface::isError 判断是否有错误
  1716. * @param error_list 错误列表
  1717. * @return 错误返回true,否则返回false
  1718. */
  1719. bool GeneralInterface::isError(const QList<uint32_t> &error_list)
  1720. {
  1721. return std::any_of(error_list.begin(), error_list.end(),
  1722. [](uint32_t value) { return (value > CHARGE_GUN_ERROR_MAX_INDEX); });
  1723. }
  1724. /**
  1725. * @brief GeneralInterface::getMaxElement 获取最大值
  1726. * @param state_list 状态列表
  1727. * @return
  1728. */
  1729. uint8_t GeneralInterface::getMaxElement(const QList<uint32_t> &state_list)
  1730. {
  1731. if (state_list.isEmpty()) {
  1732. return 0; // 或者抛出异常
  1733. }
  1734. auto it = std::max_element(state_list.begin(), state_list.end());
  1735. return *it;
  1736. }
  1737. /**
  1738. * @brief GeneralInterface::addRotationAnimation 添加旋转动画
  1739. * @param label
  1740. */
  1741. void GeneralInterface::addRotationAnimation(QLabel *label)
  1742. {
  1743. // 创建图形场景和代理
  1744. QGraphicsScene *scene = new QGraphicsScene(label->parentWidget());
  1745. QGraphicsProxyWidget *proxy = scene->addWidget(label);
  1746. // 设置旋转中心为标签中心
  1747. proxy->setTransformOriginPoint(proxy->boundingRect().center());
  1748. // 创建旋转动画
  1749. QPropertyAnimation *animation = new QPropertyAnimation(label, "rotation");
  1750. animation->setDuration(2000); // 动画持续时间(毫秒)
  1751. animation->setStartValue(0); // 起始角度
  1752. animation->setEndValue(360); // 结束角度(360度)
  1753. animation->setLoopCount(-1); // 无限循环
  1754. animation->start();
  1755. }
  1756. /**
  1757. * @brief GeneralInterface::getMaxElementWithQMax 获取最大值
  1758. * @param list
  1759. * @return
  1760. */
  1761. uint8_t GeneralInterface::getMaxElementWithQMax(const QList<uint8_t> &list)
  1762. {
  1763. if (list.isEmpty()) {
  1764. return 0;
  1765. }
  1766. int max = list.first();
  1767. for (int num : list) {
  1768. max = qMax(max, num);
  1769. }
  1770. return max;
  1771. }
  1772. /**
  1773. * @brief GeneralInterface::getTips 获取提示信息
  1774. * @param state 状态码
  1775. * @return
  1776. */
  1777. QString GeneralInterface::getTips(const int &state)
  1778. {
  1779. switch (state) {
  1780. case CHARGE_GUN_AVAILABLE: return QCoreApplication::translate("GeneralInterface", "Please Plug in");
  1781. case AUTHORIZATION_QR: return QCoreApplication::translate("GeneralInterface", "Please scan the QR code");
  1782. case AUTHORIZATION_ID_CARD: return QCoreApplication::translate("GeneralInterface", "Please swipe the card");
  1783. case AUTHORIZATION_QR_ID_CARD: return QCoreApplication::translate("GeneralInterface", "Please swipe the card or scan the QR code");
  1784. case WAITING_NO_ID_CARD: return QCoreApplication::translate("GeneralInterface", "Do not swipe card");
  1785. case WAITING_NO_ID_CARD_QR: return QCoreApplication::translate("GeneralInterface", "Do not swipe card; QR code scan works normally");
  1786. case WAITING_STANDBY: return QCoreApplication::translate("GeneralInterface", "waiting");
  1787. case AUTHORIZING_ONLINE: return QCoreApplication::translate("GeneralInterface", "Authorizing online");
  1788. case RETRY: return QCoreApplication::translate("GeneralInterface", "Retry");
  1789. case TIMEOUT: return QCoreApplication::translate("GeneralInterface", "Timeout");
  1790. case RETRY_OR_RETURN_GUN: return QCoreApplication::translate("GeneralInterface", "Please try again or return the connector");
  1791. case SCAN_QR_OR_RETURN_GUN: return QCoreApplication::translate("GeneralInterface", "Scan the QR code or return the connector");
  1792. case FAILED: return QCoreApplication::translate("GeneralInterface", "Failed");
  1793. case CARD_AUTHORIZATION_FAILED: return QCoreApplication::translate("GeneralInterface", "Charging authorization failed");
  1794. case CHANGE_CARD: return QCoreApplication::translate("GeneralInterface", "Please use another card or return the connector");
  1795. case BALANCE_NO_START: return QCoreApplication::translate("GeneralInterface", "Balance:$0x01, insufficient to start charging");
  1796. case TOP_UP_RETRY: return QCoreApplication::translate("GeneralInterface", "Please top up the funds then try again");
  1797. case PREPARE_HANDSHAKING: return QCoreApplication::translate("GeneralInterface", "Preparing Handshaking");
  1798. case HANDSHAKING: return QCoreApplication::translate("GeneralInterface", "Handshaking");
  1799. case CONFIGUING: return QCoreApplication::translate("GeneralInterface", "Configuring");
  1800. case START_CHARGING: return QCoreApplication::translate("GeneralInterface", "Start Charging");
  1801. case STARTUP_FAILED: return QCoreApplication::translate("GeneralInterface", "Startup Failed");
  1802. case UNPLUG_RETRY_OR_CHANGE: return QCoreApplication::translate("GeneralInterface", "Please try unplug the connector and reconnect it to the vehicle or use another connector");
  1803. case STOP_CHARGING: return QCoreApplication::translate("GeneralInterface", "STOP");
  1804. case TIME_REMAINING: return QCoreApplication::translate("GeneralInterface", "mins remaining");
  1805. case RETURN_GUN: return QCoreApplication::translate("GeneralInterface", "Please return the connector");
  1806. case RESTART_CHARGING: return QCoreApplication::translate("GeneralInterface", "Restart");
  1807. case CHARGING_STOP_ABNORMAL: return QCoreApplication::translate("GeneralInterface", "");
  1808. case UNAVAILABLE: return QCoreApplication::translate("GeneralInterface", "Unavailable");
  1809. case CHARGE_GUN_UNAVILABLE: return QCoreApplication::translate("GeneralInterface", "This connector is currently unavailable. Please use another one.");
  1810. case OUT_OF_SERVICE: return QCoreApplication::translate("GeneralInterface", "This charging station is in out-of-service hours and unable to provide charging services.");
  1811. case MAX_POWER_LIMIT: return QCoreApplication::translate("GeneralInterface", "This charging station has reached its maximum power limit and cannot be activated for charging.");
  1812. default: return QCoreApplication::translate("GeneralInterface", "");
  1813. }
  1814. }
  1815. /**
  1816. * @brief GeneralInterface::isCrossTime 判断时间是否交叉
  1817. * @param start 开始时间
  1818. * @param end 结束时间
  1819. * @return 交叉返回 true,否则返回 false
  1820. */
  1821. bool GeneralInterface::isCrossTime(const uint32_t &start, const uint32_t &end)
  1822. {
  1823. return start > end;
  1824. }
  1825. /**
  1826. * @brief GeneralInterface::getAuthResult 获取授权结果
  1827. * @param cardId 卡号
  1828. * @return 卡号存在且状态为无效且过期则返回 0,否则返回 1
  1829. */
  1830. int GeneralInterface::getAuthResult(const QByteArray &cardId)
  1831. {
  1832. auto auth_list = GLOBALS->getValue(Global::Keys::AUTH_LIST).value<AUTH_LIST>();
  1833. auto cfg_key = GLOBALS->getValue(Global::Keys::CFG_KEY).value<CONFIG_KEY_INFO>();
  1834. int result = 1;
  1835. if (cfg_key.CoreProfile.AuthorizationCacheEnabled) { // auth list cache
  1836. foreach (const auto& value, auth_list.authorizationCache) {
  1837. if (cardId.data() == value.idTag &&
  1838. value.status == "Invalid" &&
  1839. isTimeout(value.expiryDate)) {
  1840. result = 0;
  1841. }
  1842. }
  1843. }
  1844. if (cfg_key.LocalAuthListManagementProfile.LocalAuthListEnabled) { // local auth list
  1845. foreach (const auto& value, auth_list.localAuthorizationList) {
  1846. if (cardId.data() == value.idTag &&
  1847. value.status == "Invalid" &&
  1848. isTimeout(value.expiryDate)) {
  1849. result = 0;
  1850. }
  1851. }
  1852. }
  1853. return result;
  1854. }
  1855. /**
  1856. * @brief GeneralInterface::isTimeout 判断时间是否过期
  1857. * @param date 时间字符串
  1858. * @return 过期返回 true,否则返回 false
  1859. */
  1860. bool GeneralInterface::isTimeout(const QString &date)
  1861. {
  1862. // 将字符串转换为 QDateTime
  1863. QDateTime targetTime = QDateTime::fromString(date, Qt::ISODate);
  1864. if (!targetTime.isValid()) {
  1865. return false;
  1866. }
  1867. // 转换为UTC时间以确保比较准确
  1868. targetTime = targetTime.toUTC();
  1869. QDateTime cur_time = QDateTime::currentDateTimeUtc();
  1870. return targetTime < cur_time;
  1871. }
  1872. QString GeneralInterface::calcTime(const uint32_t& startTime, const uint32_t& endTime)
  1873. {
  1874. QDateTime start = QDateTime::fromSecsSinceEpoch(startTime);
  1875. QDateTime end = QDateTime::fromSecsSinceEpoch(endTime);
  1876. return getCurrentDate(start.secsTo(end));
  1877. }
  1878. bool GeneralInterface::isWidgetInLayout(QWidget* widget, QGridLayout* layout)
  1879. {
  1880. if (!widget || !layout) {
  1881. return false;
  1882. }
  1883. // 遍历布局中的所有控件
  1884. for (int i = 0; i < layout->count(); ++i) {
  1885. QLayoutItem* item = layout->itemAt(i);
  1886. if (item && item->widget() == widget) {
  1887. return true;
  1888. }
  1889. }
  1890. return false;
  1891. }