main.qml 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857
  1. import QtQuick 2.15
  2. import QtQuick.Controls 2.12
  3. import QtQuick.Layouts 1.12
  4. import QtQuick.VirtualKeyboard 2.12
  5. import QtQuick.Window 2.12
  6. import "."
  7. import "./components"
  8. import Loto 1.0
  9. ApplicationWindow {
  10. id: appWindow
  11. visible: true
  12. width: 1920
  13. height: 1080
  14. visibility: Window.FullScreen // 设置窗口为全屏
  15. //visibility: Window.Windowed // 窗口模式,非全屏
  16. flags: Qt.FramelessWindowHint // 设置窗口无边框
  17. property int defaultLogoutSeconds: 120 + 1
  18. property int startLogoutInterval: 20
  19. // 访问StackView
  20. default property alias appStackView: stackView
  21. property alias appAlertDialog: __alertDialog
  22. property alias appShowHome: appWindow.showHome
  23. property alias appBlurItem: contentWrapper
  24. property string appTitle: qsTr("智能锁控系统")
  25. property bool appShowLogout: false
  26. property int appLogoutSeconds: defaultLogoutSeconds
  27. property bool appControlLogoutSecondsFlag: false
  28. property string appLogoutText: "退出登录"
  29. property alias appHttpGetJobTickets: httpGetJobTickets
  30. property string logoLabelText: "博士能量隔离系统"
  31. property var advertisementImageModel: [
  32. "qrc:/resources/png/a.jpeg",
  33. "qrc:/resources/png/b.jpeg",
  34. "qrc:/resources/png/c.jpeg"
  35. ]
  36. property int currentIndex: 0
  37. property bool showHome: true
  38. property int pressX: 0 // 记录鼠标上次位置,目的是模仿onPositionChanged事件
  39. property int pressY: 0
  40. // ============ 首页刷卡登录相关属性 ============
  41. property bool homeCardLoginLoading: false // 首页刷卡登录loading状态
  42. property bool homeCardLoginSuccess: false // 首页刷卡登录成功标志
  43. property var homeCardLoginErrorDialog: null // 错误提示对话框对象
  44. property bool homeCardLoginSkipLoginPage: false // 首页刷卡登录成功后跳过登录页
  45. // ============ 导航栏刷新作业列表相关属性 ============
  46. property bool navBarRefreshJobTickets: false // 从导航栏刷新作业列表标志
  47. // ============ API 超时弹窗(408)与 loading ============
  48. property var homeTimeoutDialog: null
  49. property int homeTimeoutCountdown: 10
  50. property var homeTimeoutRefreshCallback: null
  51. property bool getUserInfoLoading: false // 获取用户信息 loading
  52. // 首页刷卡登录:关闭错误提示对话框
  53. function closeHomeCardLoginErrorDialog() {
  54. console.log("[main.qml] 关闭首页刷卡登录错误提示");
  55. if (homeCardLoginErrorDialog !== null) {
  56. homeCardLoginErrorDialog.visible = false;
  57. homeCardLoginErrorDialog.destroy();
  58. homeCardLoginErrorDialog = null;
  59. }
  60. homeCardLoginErrorAutoCloseTimer.stop();
  61. }
  62. // 关闭 API 超时弹窗并执行刷新回调
  63. function closeHomeTimeoutDialog() {
  64. homeTimeoutAutoCloseTimer.stop();
  65. if (homeTimeoutDialog !== null) {
  66. homeTimeoutDialog.visible = false;
  67. homeTimeoutDialog.destroy();
  68. homeTimeoutDialog = null;
  69. }
  70. homeTimeoutRefreshCallback = null;
  71. }
  72. // 显示 API 超时弹窗:处理超时,请稍后重试。确认(10) 倒计时,关闭后执行 refreshCallback
  73. function showHomeTimeoutDialog(refreshCallback) {
  74. closeHomeTimeoutDialog();
  75. homeTimeoutCountdown = 10;
  76. homeTimeoutRefreshCallback = refreshCallback || null;
  77. var component = Qt.createComponent("components/AlertDialog.qml");
  78. if (component.status === Component.Ready) {
  79. homeTimeoutDialog = component.createObject(appAlertDialog, {
  80. messageTypeName: "",
  81. messageValue: "处理超时,请稍后重试。",
  82. messageIconCharacter: "\uf071",
  83. confirmBtnText: "确认(10)"
  84. });
  85. homeTimeoutDialog.parent = appAlertDialog;
  86. homeTimeoutDialog.confirm.connect(function () {
  87. if (typeof homeTimeoutRefreshCallback === "function")
  88. homeTimeoutRefreshCallback();
  89. closeHomeTimeoutDialog();
  90. });
  91. homeTimeoutAutoCloseTimer.restart();
  92. }
  93. }
  94. // 首页刷卡登录:显示错误提示对话框
  95. function showHomeCardLoginErrorDialog(errorMsg) {
  96. console.log("[main.qml] 显示首页刷卡登录错误提示:", errorMsg);
  97. closeHomeCardLoginErrorDialog();
  98. var component = Qt.createComponent("components/AlertDialog.qml");
  99. if (component.status === Component.Ready) {
  100. homeCardLoginErrorDialog = component.createObject(appAlertDialog, {
  101. messageTypeName: "登录失败",
  102. messageValue: errorMsg,
  103. messageIconCharacter: "\uf071"
  104. });
  105. homeCardLoginErrorDialog.parent = appAlertDialog;
  106. homeCardLoginErrorDialog.confirm.connect(function () {
  107. console.log("[main.qml] 用户点击确认按钮");
  108. closeHomeCardLoginErrorDialog();
  109. });
  110. homeCardLoginErrorAutoCloseTimer.restart();
  111. console.log("[main.qml] 启动3秒自动关闭定时器");
  112. }
  113. }
  114. // 首页刷卡登录:处理键盘输入
  115. function homeSetCardIDByKey(keyValue) {
  116. switch(keyValue) {
  117. case Qt.Key_0: homeHttpCardLogin.cardID = homeHttpCardLogin.cardID + "0"; break;
  118. case Qt.Key_1: homeHttpCardLogin.cardID = homeHttpCardLogin.cardID + "1"; break;
  119. case Qt.Key_2: homeHttpCardLogin.cardID = homeHttpCardLogin.cardID + "2"; break;
  120. case Qt.Key_3: homeHttpCardLogin.cardID = homeHttpCardLogin.cardID + "3"; break;
  121. case Qt.Key_4: homeHttpCardLogin.cardID = homeHttpCardLogin.cardID + "4"; break;
  122. case Qt.Key_5: homeHttpCardLogin.cardID = homeHttpCardLogin.cardID + "5"; break;
  123. case Qt.Key_6: homeHttpCardLogin.cardID = homeHttpCardLogin.cardID + "6"; break;
  124. case Qt.Key_7: homeHttpCardLogin.cardID = homeHttpCardLogin.cardID + "7"; break;
  125. case Qt.Key_8: homeHttpCardLogin.cardID = homeHttpCardLogin.cardID + "8"; break;
  126. case Qt.Key_9: homeHttpCardLogin.cardID = homeHttpCardLogin.cardID + "9"; break;
  127. case Qt.Key_A: homeHttpCardLogin.cardID = homeHttpCardLogin.cardID + "A"; break;
  128. case Qt.Key_B: homeHttpCardLogin.cardID = homeHttpCardLogin.cardID + "B"; break;
  129. case Qt.Key_C: homeHttpCardLogin.cardID = homeHttpCardLogin.cardID + "C"; break;
  130. case Qt.Key_D: homeHttpCardLogin.cardID = homeHttpCardLogin.cardID + "D"; break;
  131. case Qt.Key_E: homeHttpCardLogin.cardID = homeHttpCardLogin.cardID + "E"; break;
  132. case Qt.Key_F: homeHttpCardLogin.cardID = homeHttpCardLogin.cardID + "F"; break;
  133. case Qt.Key_Return: {
  134. if (homeHttpCardLogin.cardID.length > 0) {
  135. console.log("[main.qml] 首页刷卡回车,卡号:", homeHttpCardLogin.cardID);
  136. closeHomeCardLoginErrorDialog();
  137. console.log("[main.qml] 显示loading");
  138. homeCardLoginLoading = true;
  139. console.log("[main.qml] 启动登录线程");
  140. homeHttpCardLogin.start();
  141. }
  142. return;
  143. }
  144. }
  145. }
  146. // ============================================
  147. MTheme {
  148. id: theme
  149. }
  150. FontLoader {
  151. id: iconFont
  152. source: "qrc:/resources/fonts/fontawesome-free-5.15.4-desktop/otfs/FontAwesome5Free-Solid-900.otf"
  153. }
  154. HttpClient {
  155. id: httpClientThread
  156. Component.onCompleted: {
  157. httpClientThread.start();
  158. }
  159. }
  160. // ============ 首页刷卡登录HTTP组件 ============
  161. HttpCardLogin {
  162. id: homeHttpCardLogin
  163. Component.onCompleted: {
  164. // 首页刷卡登录信号连接(只在首页时生效)
  165. connectHomeCardLoginSignals();
  166. }
  167. Component.onDestruction: {
  168. disconnectHomeCardLoginSignals();
  169. }
  170. }
  171. // 连接首页刷卡登录信号
  172. function connectHomeCardLoginSignals() {
  173. // 先断开再连接,避免重复连接
  174. disconnectHomeCardLoginSignals();
  175. homeHttpCardLogin.signalPostRequestData.connect(httpClientThread.slotPostRequestData);
  176. httpClientThread.signalResponseCardLoginData.connect(homeHttpCardLogin.slotHttpResponseCardLogin);
  177. console.log("[main.qml] 首页刷卡登录信号已连接");
  178. }
  179. // 断开首页刷卡登录信号
  180. function disconnectHomeCardLoginSignals() {
  181. try {
  182. homeHttpCardLogin.signalPostRequestData.disconnect(httpClientThread.slotPostRequestData);
  183. } catch(e) {}
  184. try {
  185. httpClientThread.signalResponseCardLoginData.disconnect(homeHttpCardLogin.slotHttpResponseCardLogin);
  186. } catch(e) {}
  187. console.log("[main.qml] 首页刷卡登录信号已断开");
  188. }
  189. Connections {
  190. target: homeHttpCardLogin
  191. function onSignalLoginReturnStat(stat, data) {
  192. homeCardLoginLoading = false;
  193. if (stat === 0) {
  194. homeCardLoginSuccess = true;
  195. } else if (stat === 408) {
  196. showHomeTimeoutDialog(function () { });
  197. } else {
  198. showHomeCardLoginErrorDialog(data);
  199. }
  200. }
  201. }
  202. // 首页刷卡登录成功后获取作业票
  203. HttpGetJobTickets {
  204. id: homeHttpGetJobTickets
  205. Component.onCompleted: {
  206. // 首页获取作业票信号连接(只在首页刷卡登录成功时使用)
  207. connectHomeGetJobTicketsSignals();
  208. }
  209. Component.onDestruction: {
  210. disconnectHomeGetJobTicketsSignals();
  211. }
  212. }
  213. // 连接首页获取作业票信号
  214. function connectHomeGetJobTicketsSignals() {
  215. // 先断开再连接,避免重复连接
  216. disconnectHomeGetJobTicketsSignals();
  217. homeHttpGetJobTickets.signalGetRequestData.connect(httpClientThread.slotGetRequestData);
  218. httpClientThread.signalResponseGetJobTickets.connect(homeHttpGetJobTickets.slotHttpResponseGetJobTickets);
  219. console.log("[main.qml] 首页获取作业票信号已连接");
  220. }
  221. // 断开首页获取作业票信号
  222. function disconnectHomeGetJobTicketsSignals() {
  223. try {
  224. homeHttpGetJobTickets.signalGetRequestData.disconnect(httpClientThread.slotGetRequestData);
  225. } catch(e) {}
  226. try {
  227. httpClientThread.signalResponseGetJobTickets.disconnect(homeHttpGetJobTickets.slotHttpResponseGetJobTickets);
  228. } catch(e) {}
  229. console.log("[main.qml] 首页获取作业票信号已断开");
  230. }
  231. Connections {
  232. target: homeHttpGetJobTickets
  233. function onSignalJobTicketsReturnStat(stat, msg) {
  234. // 408 超时:显示超时弹窗,确认后刷新(重新请求作业票)
  235. if (stat === 408) {
  236. showHomeTimeoutDialog(function () {
  237. connectHomeGetJobTicketsSignals();
  238. homeHttpGetJobTickets.start();
  239. });
  240. return;
  241. }
  242. // 从导航栏刷新的情况
  243. if (navBarRefreshJobTickets) {
  244. navBarRefreshJobTickets = false;
  245. // 断开信号
  246. disconnectHomeGetJobTicketsSignals();
  247. // stackView 结构:[广告页(0)] -> [Login.qml(1)] -> [JobTicketPage.qml(2)] -> [WorkingPage.qml(3)]
  248. // 我们需要保留 [广告页] 和 [Login.qml],pop 掉后面的页面
  249. // 使用 pop(item) 直接 pop 到 Login.qml(索引 1)
  250. if (stackView.depth > 2) {
  251. // 获取 Login.qml 页面(索引 1),pop 到该页面
  252. var loginPage = stackView.get(1);
  253. if (loginPage) {
  254. stackView.pop(loginPage);
  255. }
  256. }
  257. // 然后 push 列表页
  258. if (stat !== 0 || JobTicketModel.rowCount() === 0) {
  259. stackView.push("components/NoJobTicketDialog.qml");
  260. } else {
  261. stackView.push("JobTicketPage.qml");
  262. }
  263. return;
  264. }
  265. // 首页刷卡登录的情况
  266. if (stat !== 0 || JobTicketModel.rowCount() === 0) {
  267. stackView.push("components/NoJobTicketDialog.qml");
  268. } else {
  269. stackView.push("JobTicketPage.qml");
  270. }
  271. }
  272. }
  273. // 首页刷卡登录成功处理
  274. onHomeCardLoginSuccessChanged: {
  275. if (homeCardLoginSuccess) {
  276. console.log("[main.qml] 处理首页刷卡登录成功");
  277. homeCardLoginLoading = false;
  278. closeHomeCardLoginErrorDialog();
  279. // 设置标志:跳过登录页面
  280. homeCardLoginSkipLoginPage = true;
  281. // 关闭首页,进入作业流程
  282. showHome = false;
  283. homeMouseArea.visible = false;
  284. appShowLogout = true;
  285. // 重置标志
  286. homeCardLoginSuccess = false;
  287. }
  288. }
  289. // ============================================
  290. Component {
  291. id: adPage
  292. Item {
  293. width: appWindow.width
  294. height: appWindow.height
  295. property string adImageSource: ""
  296. Image {
  297. id: sourceItem
  298. anchors.fill: parent
  299. fillMode: Image.PreserveAspectCrop
  300. cache: true
  301. asynchronous: true
  302. visible: true
  303. sourceSize.width: appWindow.width
  304. sourceSize.height: appWindow.height
  305. source: adImageSource
  306. }
  307. }
  308. }
  309. function showAlertDialog(msgTypeName, msgValue, msgIconChar, callbackFunc) {
  310. var component = Qt.createComponent("components/AlertDialog.qml");
  311. if (component.status === Component.Ready) {
  312. // 创建实例并添加到场景中
  313. var alertDialogComp = component.createObject(appAlertDialog, {
  314. messageTypeName: msgTypeName,
  315. messageValue: msgValue,
  316. messageIconCharacter: msgIconChar
  317. });
  318. alertDialogComp.parent = appAlertDialog; // 将提示对话框挂载在appAlterDialog Loader加载器上
  319. // 处理提示对话框的事件
  320. alertDialogComp.confirm.connect(function () { callbackFunc(alertDialogComp); });
  321. } else {
  322. console.log("Error loading component:", component.errorString());
  323. }
  324. }
  325. function negativeAlertDialogCallback(componentObj) {
  326. componentObj.visible = false;
  327. appAlertDialog.sourceComponent = null;
  328. componentObj.destroy();
  329. }
  330. HttpGetUserInfo {
  331. id: httpGetUserInfo
  332. Component.onCompleted: {
  333. httpGetUserInfo.signalGetRequestData.connect(httpClientThread.slotGetRequestData);
  334. httpClientThread.signalResponseGetUserInfoUrl.connect(httpGetUserInfo.slotHttpResponseGetUserInfo);
  335. }
  336. Component.onDestruction: {
  337. httpGetUserInfo.signalGetRequestData.disconnect(httpClientThread.slotGetRequestData);
  338. httpClientThread.signalResponseGetUserInfoUrl.disconnect(httpGetUserInfo.slotHttpResponseGetUserInfo);
  339. }
  340. }
  341. Connections {
  342. target: InteractiveData
  343. function onRequestTimedOut() {
  344. showHomeTimeoutDialog(function () { });
  345. }
  346. }
  347. Connections {
  348. target: httpGetUserInfo
  349. function onSignalUserInfoReturnStat(stat, msg) {
  350. getUserInfoLoading = false;
  351. if (stat === 408) {
  352. showHomeTimeoutDialog(function () {
  353. getUserInfoLoading = true;
  354. httpGetUserInfo.start();
  355. });
  356. return;
  357. }
  358. if (stat !== 0) {
  359. showAlertDialog("提示", msg, "\uf071", negativeAlertDialogCallback);
  360. } else {
  361. stackView.push("SettingPage.qml");
  362. }
  363. }
  364. }
  365. // 作业票
  366. HttpGetJobTickets {
  367. id: httpGetJobTickets
  368. Component.onCompleted: {
  369. httpGetJobTickets.signalGetRequestData.connect(httpClientThread.slotGetRequestData);
  370. httpClientThread.signalResponseGetJobTickets.connect(httpGetJobTickets.slotHttpResponseGetJobTickets);
  371. }
  372. Component.onDestruction: {
  373. httpGetJobTickets.signalGetRequestData.disconnect(httpClientThread.slotGetRequestData);
  374. httpClientThread.signalResponseGetJobTickets.disconnect(httpGetJobTickets.slotHttpResponseGetJobTickets);
  375. }
  376. }
  377. Item {
  378. id: contentWrapper
  379. anchors.fill: parent
  380. Image {
  381. id: __backgroundImage
  382. x: 0
  383. y: 0
  384. width: parent.width
  385. height: parent.height
  386. source: "qrc:/resources/png/backgroundImage.png"
  387. fillMode: Image.PreserveAspectFit
  388. }
  389. Rectangle {
  390. id: logoArea
  391. x: 52
  392. y: 42
  393. width: 211
  394. height: 64
  395. z: 65535
  396. color: "transparent"
  397. Image {
  398. id: logoImage
  399. anchors.fill: parent
  400. fillMode: Image.PreserveAspectFit
  401. cache: true
  402. asynchronous: true
  403. visible: true
  404. source: "qrc:/resources/png/bozz.png"
  405. }
  406. Text {
  407. id: __logoLabel
  408. x: 0
  409. y: 71
  410. width: 211
  411. height: 32
  412. text: qsTr(logoLabelText)
  413. opacity: 1
  414. color: "#40a9ff"
  415. font.pixelSize: 24
  416. font.bold: true
  417. verticalAlignment: Text.AlignVCenter
  418. }
  419. }
  420. RowLayout {
  421. id: logout_settings
  422. visible: appShowLogout
  423. x: 1449
  424. y: 80
  425. width: 418
  426. height: 52
  427. z: 1000
  428. spacing: 14
  429. MButton {
  430. id: jobTicketBtn
  431. Layout.preferredWidth: 118
  432. Layout.preferredHeight: 52
  433. buttonColor: "#CC0F1929"
  434. text: qsTr("作业")
  435. textColor: "white"
  436. iconCharacter: "\uf0ae"
  437. iconColor: "#40a9ff"
  438. onClicked: {
  439. console.log("[main.qml] 导航栏点击作业按钮,跳转到列表页");
  440. // 直接替换当前页面为列表页,不重新请求数据,禁用自动跳转详情
  441. if (JobTicketModel.rowCount() === 0) {
  442. stackView.replace("components/NoJobTicketDialog.qml");
  443. } else {
  444. stackView.replace("JobTicketPage.qml", { autoNavigateToDetail: false });
  445. }
  446. }
  447. }
  448. MButton {
  449. Layout.preferredWidth: 118
  450. Layout.preferredHeight: 52
  451. buttonColor: "#CC0F1929"
  452. text: qsTr("设置")
  453. textColor: "white"
  454. iconCharacter: "\uf013"
  455. iconColor: "#40a9ff"
  456. onClicked: {
  457. getUserInfoLoading = true;
  458. httpGetUserInfo.start();
  459. }
  460. }
  461. MButton {
  462. Layout.preferredWidth: 180
  463. Layout.preferredHeight: 52
  464. buttonColor: "#33FF4D4F"
  465. backgroundOpacity: 0.2
  466. text: appLogoutSeconds % defaultLogoutSeconds === 0 ? qsTr(appLogoutText) :
  467. qsTr(appLogoutText + "(" + appLogoutSeconds.toString() + "秒)")
  468. textColor: "white"
  469. iconCharacter: "\uf2f5"
  470. iconColor: "red"
  471. onClicked: {
  472. showHome = true;
  473. }
  474. }
  475. }
  476. StackView {
  477. id: stackView
  478. anchors.fill: parent
  479. initialItem: adPage.createObject(appWindow, {adImageSource: advertisementImageModel[0]})
  480. focus: true
  481. Component.onCompleted: {
  482. currentItem.focus = true
  483. }
  484. // 定义淡入淡出效果
  485. pushEnter: Transition {
  486. PropertyAnimation {
  487. property: "opacity"
  488. from: 0
  489. to:1
  490. duration: 500
  491. }
  492. }
  493. pushExit: Transition {
  494. PropertyAnimation {
  495. property: "opacity"
  496. from: 1
  497. to:0
  498. duration: 500
  499. }
  500. }
  501. popEnter: Transition {
  502. PropertyAnimation {
  503. property: "opacity"
  504. from: 0
  505. to:1
  506. duration: 500
  507. }
  508. }
  509. popExit: Transition {
  510. PropertyAnimation {
  511. property: "opacity"
  512. from: 1
  513. to:0
  514. duration: 500
  515. }
  516. }
  517. }
  518. MButton {
  519. id: homeAreaTip
  520. height: 82
  521. visible: showHome
  522. anchors.bottom: parent.bottom
  523. anchors.bottomMargin: 160
  524. anchors.horizontalCenter: parent.horizontalCenter
  525. buttonColor: "#808080"
  526. backgroundOpacity: 0.8
  527. text: "请点击屏幕进行操作"
  528. btnHoverEanabled: false
  529. }
  530. MouseArea {
  531. id: homeMouseArea
  532. anchors.fill: parent
  533. onClicked: {
  534. // 点击进入登录页面前,清空可能已输入的卡号
  535. homeHttpCardLogin.cardID = "";
  536. showHome = false;
  537. homeMouseArea.visible = false;
  538. }
  539. }
  540. }
  541. Loader {
  542. id: __alertDialog
  543. z: 99999 // 确保弹窗始终置于最上层,不被 loginInput 人脸框等遮挡
  544. anchors.fill: parent
  545. }
  546. Loader {
  547. id: loginInput
  548. visible: false
  549. anchors.fill: parent
  550. // anchors.verticalCenter: parent.verticalCenter
  551. // anchors.horizontalCenter: parent.horizontalCenter
  552. }
  553. Loader {
  554. id: __returnKeyLockProcess
  555. visible: ReturnKeyLockManager.isVisible
  556. z: 999
  557. anchors.fill: parent
  558. asynchronous: true
  559. }
  560. Connections {
  561. target: ReturnKeyLockManager
  562. function onIsVisibleChanged() {
  563. if (ReturnKeyLockManager.isVisible) {
  564. __returnKeyLockProcess.source = "components/ReturnKeyLockProcess.qml";
  565. } else {
  566. __returnKeyLockProcess.sourceComponent = null;
  567. __returnKeyLockProcess.source = "";
  568. }
  569. }
  570. }
  571. Timer {
  572. id: swipeTimer
  573. interval: 3000
  574. repeat: true
  575. running: true
  576. onTriggered: {
  577. stackView.push(adPage.createObject(appWindow, {adImageSource: advertisementImageModel[(++currentIndex)%advertisementImageModel.length]}));
  578. }
  579. }
  580. onShowHomeChanged: {
  581. if (!showHome) {
  582. swipeTimer.stop();
  583. appControlLogoutSecondsFlag = false
  584. __startLogoutTimer.restart();
  585. // 离开首页时,重置首页刷卡登录状态
  586. homeHttpCardLogin.cardID = "";
  587. homeCardLoginLoading = false;
  588. closeHomeCardLoginErrorDialog();
  589. // 检查是否是首页刷卡登录成功导致的页面切换
  590. if (homeCardLoginSkipLoginPage) {
  591. console.log("[main.qml] 首页刷卡登录成功,跳过登录页,直接获取作业票");
  592. homeCardLoginSkipLoginPage = false;
  593. // 首页刷卡登录成功,不 push Login.qml(避免信号冲突)
  594. // 直接获取作业票
  595. homeHttpGetJobTickets.start();
  596. } else {
  597. // 正常点击屏幕进入登录页,断开首页信号避免冲突
  598. disconnectHomeCardLoginSignals();
  599. disconnectHomeGetJobTicketsSignals();
  600. // 进入登录页
  601. stackView.push("Login.qml");
  602. // 确保Login页面获取焦点
  603. if (stackView.currentItem) {
  604. stackView.currentItem.forceActiveFocus();
  605. }
  606. }
  607. } else {
  608. InteractiveData.clearToken();
  609. stackView.clear();
  610. stackView.push(adPage.createObject(appWindow, {adImageSource: advertisementImageModel[0]}));
  611. homeMouseArea.visible = true;
  612. appShowLogout = false
  613. swipeTimer.restart();
  614. // 回到首页登录倒计时停止
  615. __startLogoutTimer.stop();
  616. __logoutCountTimer.stop();
  617. // 回到首页时,重置首页刷卡登录状态并让键盘监听获取焦点
  618. homeHttpCardLogin.cardID = "";
  619. homeCardLoginLoading = false;
  620. homeCardLoginSuccess = false;
  621. homeCardLoginSkipLoginPage = false;
  622. closeHomeCardLoginErrorDialog();
  623. // 重新连接首页信号
  624. connectHomeCardLoginSignals();
  625. connectHomeGetJobTicketsSignals();
  626. homeKeyboardListener.forceActiveFocus();
  627. }
  628. }
  629. onAppLogoutSecondsChanged: {
  630. if (appLogoutSeconds === 0) {
  631. showHome = true;
  632. appLogoutSeconds = defaultLogoutSeconds;
  633. }
  634. }
  635. onAppControlLogoutSecondsFlagChanged: {
  636. if (appControlLogoutSecondsFlag) {
  637. appLogoutSeconds = defaultLogoutSeconds;
  638. __logoutCountTimer.restart();
  639. } else {
  640. __logoutCountTimer.stop();
  641. }
  642. }
  643. MouseArea {
  644. id: __screenArea
  645. anchors.fill: parent
  646. visible: !showHome
  647. acceptedButtons: Qt.AllButtons
  648. hoverEnabled: true
  649. onPositionChanged: {
  650. // 滑动屏幕重新计时
  651. __startLogoutTimer.restart();
  652. appControlLogoutSecondsFlag = false
  653. appLogoutSeconds = defaultLogoutSeconds;
  654. }
  655. onClicked: function(mouse) {mouse.accepted = false;}
  656. onPressed: function(mouse) {
  657. if (appWindow.pressX !== mouse.x || appWindow.pressY !== mouse.y) {
  658. // 模仿onPositionChanged事件
  659. __startLogoutTimer.restart();
  660. appControlLogoutSecondsFlag = false
  661. appLogoutSeconds = defaultLogoutSeconds;
  662. }
  663. appWindow.pressX = mouse.x;
  664. appWindow.pressY = mouse.y;
  665. mouse.accepted = false;
  666. }
  667. onReleased: function(mouse) {mouse.accepted = false;}
  668. onWheel: function(mouse) {mouse.accepted = false;}
  669. onDoubleClicked: function(mouse) {mouse.accepted = false;}
  670. onCanceled: function(mouse) {mouse.accepted = false;}
  671. onPressAndHold: function(mouse) {mouse.accepted = false;}
  672. }
  673. Timer {
  674. id: __startLogoutTimer
  675. interval: startLogoutInterval * 1000
  676. repeat: true
  677. running: false
  678. onTriggered: {
  679. // console.log("emit logout timer")
  680. appControlLogoutSecondsFlag = true && !showHome;
  681. }
  682. }
  683. Timer {
  684. id: __logoutCountTimer
  685. interval: 1000
  686. repeat: true
  687. running: false
  688. onTriggered: {
  689. appLogoutSeconds--;
  690. }
  691. }
  692. // ============ 首页刷卡登录:键盘监听 ============
  693. // 让窗口获取焦点并监听键盘事件
  694. Item {
  695. id: homeKeyboardListener
  696. focus: showHome // 首页时获取焦点
  697. Keys.enabled: showHome
  698. Keys.onPressed: function(event) {
  699. if (showHome) {
  700. homeSetCardIDByKey(event.key);
  701. event.accepted = true; // 防止事件继续传递
  702. }
  703. }
  704. Component.onCompleted: {
  705. // 启动时让键盘监听获取焦点
  706. if (showHome) {
  707. forceActiveFocus();
  708. }
  709. }
  710. }
  711. // 首页刷卡登录错误提示自动关闭定时器(3秒)
  712. Timer {
  713. id: homeCardLoginErrorAutoCloseTimer
  714. interval: 3000
  715. running: false
  716. repeat: false
  717. onTriggered: {
  718. closeHomeCardLoginErrorDialog();
  719. }
  720. }
  721. // API 超时弹窗 10 秒倒计时定时器
  722. Timer {
  723. id: homeTimeoutAutoCloseTimer
  724. interval: 1000
  725. repeat: true
  726. running: false
  727. onTriggered: {
  728. homeTimeoutCountdown--;
  729. if (homeTimeoutDialog !== null)
  730. homeTimeoutDialog.confirmBtnText = "确认(" + Math.max(0, homeTimeoutCountdown) + ")";
  731. if (homeTimeoutCountdown <= 0) {
  732. if (typeof homeTimeoutRefreshCallback === "function")
  733. homeTimeoutRefreshCallback();
  734. closeHomeTimeoutDialog();
  735. }
  736. }
  737. }
  738. // 首页刷卡登录 Loading
  739. LoadingDialog {
  740. id: homeCardLoginLoadingDialog
  741. loadingText: "登录中,请稍后..."
  742. showLoading: homeCardLoginLoading
  743. }
  744. // 获取用户信息 Loading
  745. LoadingDialog {
  746. id: getUserInfoLoadingDialog
  747. loadingText: "处理中..."
  748. showLoading: getUserInfoLoading
  749. }
  750. // ============================================
  751. }