完善移动端布局与发布配置
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Jitianye
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -421,3 +421,7 @@ X-Encrypted-Response: true
|
||||
- 如果服务端加密参数变化,需要同步修改 `src/CryptoUtils.cpp`。
|
||||
- 如果要发布桌面版本,建议使用 Qt 部署工具收集运行时依赖。
|
||||
- 如果要发布 Android 版本,建议补充签名配置和 release 构建流程。
|
||||
|
||||
## 13. 开源协议
|
||||
|
||||
本项目采用 MIT License 开源,详见 `LICENSE` 文件。
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQmlContext>
|
||||
#include <QQuickStyle>
|
||||
#include <QQuickWindow>
|
||||
|
||||
#include "src/AppController.h"
|
||||
|
||||
@@ -24,6 +25,10 @@ int main(int argc, char *argv[])
|
||||
QCoreApplication::setOrganizationName("STM32 Face Recognition");
|
||||
QQuickStyle::setStyle("Basic");
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
QQuickWindow::setTextRenderType(QQuickWindow::NativeTextRendering);
|
||||
#endif
|
||||
|
||||
AppController controller;
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
|
||||
+94
-77
@@ -29,6 +29,8 @@ ApplicationWindow {
|
||||
readonly property color goldSoft: "#f5e8c6"
|
||||
readonly property color successColor: "#1f7a4d"
|
||||
readonly property color dangerColor: "#b9382f"
|
||||
readonly property string appFontFamily: Qt.platform.os === "android" ? "sans-serif" : "Microsoft YaHei UI"
|
||||
readonly property int appBoldWeight: Qt.platform.os === "android" ? Font.Medium : Font.Bold
|
||||
|
||||
property string statisticsPreset: "最近30天"
|
||||
property int editingTimeSlotIndex: -1
|
||||
@@ -46,7 +48,7 @@ ApplicationWindow {
|
||||
readonly property bool phoneLayout: width < 560
|
||||
readonly property int sidebarWidth: slimLayout ? 0 : (compactLayout ? 212 : 240)
|
||||
|
||||
font.family: "Microsoft YaHei UI"
|
||||
font.family: appFontFamily
|
||||
|
||||
onWidthChanged: {
|
||||
resizingWindow = true
|
||||
@@ -174,7 +176,7 @@ ApplicationWindow {
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
color: control.labelColor
|
||||
font.pixelSize: 13
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,7 +203,7 @@ ApplicationWindow {
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
color: control.labelColor
|
||||
font.pixelSize: 13
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,7 +294,7 @@ ApplicationWindow {
|
||||
text: badgeText
|
||||
color: accent
|
||||
font.pixelSize: emptyState.tightState ? 18 : 22
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,7 +305,7 @@ ApplicationWindow {
|
||||
wrapMode: Text.WordWrap
|
||||
color: ink900
|
||||
font.pixelSize: emptyState.tightState ? 18 : 20
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
}
|
||||
|
||||
Label {
|
||||
@@ -335,7 +337,7 @@ ApplicationWindow {
|
||||
text: parent.textValue
|
||||
color: parent.tintColor
|
||||
font.pixelSize: 11
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,7 +369,7 @@ ApplicationWindow {
|
||||
Layout.fillWidth: true
|
||||
text: sectionHeader.title
|
||||
font.pixelSize: phoneLayout ? 20 : 22
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
color: ink900
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
@@ -403,7 +405,7 @@ ApplicationWindow {
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
color: control.checked ? "#f6fbfb" : ink700
|
||||
font.pixelSize: 13
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
@@ -426,7 +428,7 @@ ApplicationWindow {
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
color: control.checked ? "#f6fbfb" : ink700
|
||||
font.pixelSize: phoneLayout ? 12 : 13
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
@@ -576,7 +578,7 @@ ApplicationWindow {
|
||||
Label {
|
||||
text: "确定要清空服务器上的所有签到记录吗?"
|
||||
font.pixelSize: 20
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
color: ink900
|
||||
}
|
||||
|
||||
@@ -682,7 +684,7 @@ ApplicationWindow {
|
||||
text: "确定删除 ID 为 " + pendingDeleteFaceId + " 的人脸信息吗?"
|
||||
wrapMode: Text.WordWrap
|
||||
font.pixelSize: 18
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
color: ink900
|
||||
}
|
||||
|
||||
@@ -734,7 +736,7 @@ ApplicationWindow {
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.WordWrap
|
||||
font.pixelSize: compactLayout ? 17 : 19
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
color: "#ffffff"
|
||||
}
|
||||
}
|
||||
@@ -801,7 +803,7 @@ ApplicationWindow {
|
||||
anchors.centerIn: parent
|
||||
text: modelData.icon
|
||||
color: navButton.selected ? tealColor : "#d6e4e9"
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
}
|
||||
}
|
||||
|
||||
@@ -814,7 +816,7 @@ ApplicationWindow {
|
||||
text: modelData.title
|
||||
color: navButton.selected ? ink900 : "#f4fbff"
|
||||
font.pixelSize: compactLayout ? 14 : 15
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
}
|
||||
|
||||
@@ -885,7 +887,7 @@ ApplicationWindow {
|
||||
Layout.fillWidth: true
|
||||
text: ["考勤记录总览", "统计分析面板", "配置与同步中心", "人脸资料管理", "关于"][window.currentPageIndex]
|
||||
font.pixelSize: slimLayout ? 20 : (compactLayout ? 24 : 28)
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
color: ink900
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
@@ -1013,7 +1015,7 @@ ApplicationWindow {
|
||||
Label {
|
||||
text: appController.totalRecords
|
||||
font.pixelSize: slimLayout ? 22 : (compactLayout ? 30 : 34)
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
color: ink900
|
||||
}
|
||||
}
|
||||
@@ -1048,7 +1050,7 @@ ApplicationWindow {
|
||||
Label {
|
||||
text: appController.todayRecords
|
||||
font.pixelSize: slimLayout ? 22 : (compactLayout ? 30 : 34)
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
color: tealColor
|
||||
}
|
||||
}
|
||||
@@ -1083,7 +1085,7 @@ ApplicationWindow {
|
||||
Label {
|
||||
text: appController.filteredCount + " / " + appController.loadedRecords
|
||||
font.pixelSize: slimLayout ? 20 : (compactLayout ? 26 : 30)
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
color: goldColor
|
||||
}
|
||||
}
|
||||
@@ -1117,9 +1119,9 @@ ApplicationWindow {
|
||||
|
||||
Column {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: phoneLayout ? 0 : 150
|
||||
Layout.preferredWidth: phoneLayout ? 1 : 150
|
||||
spacing: 6
|
||||
Label { text: "班级"; color: ink700; font.bold: true; font.pixelSize: 12 }
|
||||
Label { text: "班级"; color: ink700; font.weight: appBoldWeight; font.pixelSize: 12 }
|
||||
AppComboBox {
|
||||
id: classFilter
|
||||
width: parent.width
|
||||
@@ -1130,9 +1132,9 @@ ApplicationWindow {
|
||||
|
||||
Column {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: phoneLayout ? 0 : 160
|
||||
Layout.preferredWidth: phoneLayout ? 1 : 160
|
||||
spacing: 6
|
||||
Label { text: "学号"; color: ink700; font.bold: true; font.pixelSize: 12 }
|
||||
Label { text: "学号"; color: ink700; font.weight: appBoldWeight; font.pixelSize: 12 }
|
||||
AppComboBox {
|
||||
id: studentFilter
|
||||
width: parent.width
|
||||
@@ -1143,9 +1145,9 @@ ApplicationWindow {
|
||||
|
||||
Column {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: phoneLayout ? 0 : 190
|
||||
Layout.preferredWidth: phoneLayout ? 1 : 190
|
||||
spacing: 6
|
||||
Label { text: "姓名"; color: ink700; font.bold: true; font.pixelSize: 12 }
|
||||
Label { text: "姓名"; color: ink700; font.weight: appBoldWeight; font.pixelSize: 12 }
|
||||
AppTextField {
|
||||
id: nameFilter
|
||||
width: parent.width
|
||||
@@ -1156,9 +1158,9 @@ ApplicationWindow {
|
||||
|
||||
Column {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: phoneLayout ? 0 : 160
|
||||
Layout.preferredWidth: phoneLayout ? 1 : 160
|
||||
spacing: 6
|
||||
Label { text: "日期"; color: ink700; font.bold: true; font.pixelSize: 12 }
|
||||
Label { text: "日期"; color: ink700; font.weight: appBoldWeight; font.pixelSize: 12 }
|
||||
AppComboBox {
|
||||
id: dateFilter
|
||||
width: parent.width
|
||||
@@ -1170,12 +1172,12 @@ ApplicationWindow {
|
||||
|
||||
Column {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: phoneLayout ? 0 : 150
|
||||
Layout.preferredWidth: phoneLayout ? 1 : 150
|
||||
width: dateFilter.currentIndex === 4 ? implicitWidth : 0
|
||||
height: dateFilter.currentIndex === 4 ? implicitHeight : 0
|
||||
visible: dateFilter.currentIndex === 4
|
||||
spacing: 6
|
||||
Label { text: "指定日期"; color: ink700; font.bold: true; font.pixelSize: 12 }
|
||||
Label { text: "指定日期"; color: ink700; font.weight: appBoldWeight; font.pixelSize: 12 }
|
||||
AppTextField {
|
||||
id: specificDateField
|
||||
width: parent.width
|
||||
@@ -1185,25 +1187,24 @@ ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
Flow {
|
||||
GridLayout {
|
||||
Layout.columnSpan: slimLayout ? 2 : 1
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignBottom
|
||||
height: implicitHeight
|
||||
spacing: 8
|
||||
columns: phoneLayout ? 2 : 2
|
||||
columnSpacing: 8
|
||||
rowSpacing: 10
|
||||
|
||||
SecondaryButton {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: 1
|
||||
text: "刷新"
|
||||
onClicked: appController.refreshRecords()
|
||||
}
|
||||
|
||||
PrimaryButton {
|
||||
text: "导出"
|
||||
fillColor: tealColor
|
||||
onClicked: recordExportDialog.open()
|
||||
}
|
||||
|
||||
DangerButton {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: 1
|
||||
text: "清空记录"
|
||||
onClicked: clearDialog.open()
|
||||
}
|
||||
@@ -1245,24 +1246,24 @@ ApplicationWindow {
|
||||
anchors.rightMargin: 16
|
||||
spacing: 12
|
||||
|
||||
Label { text: "签到时间"; Layout.preferredWidth: recordTableCard.timeColWidth; font.bold: true; color: ink900 }
|
||||
Label { text: "签到时间"; Layout.preferredWidth: recordTableCard.timeColWidth; font.weight: appBoldWeight; color: ink900 }
|
||||
Label {
|
||||
text: "班级"
|
||||
visible: recordTableCard.showClassColumn
|
||||
Layout.preferredWidth: recordTableCard.classColWidth
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
color: ink900
|
||||
}
|
||||
Label { text: "学号"; Layout.preferredWidth: recordTableCard.studentColWidth; font.bold: true; color: ink900 }
|
||||
Label { text: "姓名"; Layout.preferredWidth: recordTableCard.nameColWidth; font.bold: true; color: ink900 }
|
||||
Label { text: "学号"; Layout.preferredWidth: recordTableCard.studentColWidth; font.weight: appBoldWeight; color: ink900 }
|
||||
Label { text: "姓名"; Layout.preferredWidth: recordTableCard.nameColWidth; font.weight: appBoldWeight; color: ink900 }
|
||||
Label {
|
||||
text: "置信度"
|
||||
visible: recordTableCard.showConfidenceColumn
|
||||
Layout.preferredWidth: recordTableCard.confidenceColWidth
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
color: ink900
|
||||
}
|
||||
Label { text: "状态"; Layout.preferredWidth: recordTableCard.statusColWidth; font.bold: true; color: ink900 }
|
||||
Label { text: "状态"; Layout.preferredWidth: recordTableCard.statusColWidth; font.weight: appBoldWeight; color: ink900 }
|
||||
Item { Layout.fillWidth: true }
|
||||
}
|
||||
}
|
||||
@@ -1305,7 +1306,7 @@ ApplicationWindow {
|
||||
color: ink700
|
||||
}
|
||||
Label { text: model.studentId; Layout.preferredWidth: recordTableCard.studentColWidth; color: ink700; elide: Text.ElideRight }
|
||||
Label { text: model.name; Layout.preferredWidth: recordTableCard.nameColWidth; color: ink900; font.bold: true; elide: Text.ElideRight }
|
||||
Label { text: model.name; Layout.preferredWidth: recordTableCard.nameColWidth; color: ink900; font.weight: appBoldWeight; elide: Text.ElideRight }
|
||||
Label {
|
||||
text: model.confidenceText
|
||||
visible: recordTableCard.showConfidenceColumn
|
||||
@@ -1322,7 +1323,7 @@ ApplicationWindow {
|
||||
anchors.centerIn: parent
|
||||
text: model.statusText
|
||||
color: model.success ? successColor : dangerColor
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
}
|
||||
}
|
||||
Item { Layout.fillWidth: true }
|
||||
@@ -1364,7 +1365,7 @@ ApplicationWindow {
|
||||
radius: 8
|
||||
color: panelStrong
|
||||
border.color: lineColor
|
||||
Layout.preferredHeight: phoneLayout ? 186 : (slimLayout ? 150 : 78)
|
||||
Layout.preferredHeight: phoneLayout ? 150 : (slimLayout ? 150 : 78)
|
||||
clip: true
|
||||
|
||||
GridLayout {
|
||||
@@ -1378,7 +1379,7 @@ ApplicationWindow {
|
||||
AppComboBox {
|
||||
id: quickStatisticsFilter
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: phoneLayout ? 0 : 150
|
||||
Layout.preferredWidth: phoneLayout ? 1 : 150
|
||||
model: ["今天", "最近7天", "最近30天", "本月"]
|
||||
currentIndex: 2
|
||||
onCurrentTextChanged: {
|
||||
@@ -1390,7 +1391,7 @@ ApplicationWindow {
|
||||
AppTextField {
|
||||
id: statsStartField
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: phoneLayout ? 0 : 150
|
||||
Layout.preferredWidth: phoneLayout ? 1 : 150
|
||||
placeholderText: "开始日期"
|
||||
onEditingFinished: appController.updateStatisticsRange(text, statsEndField.text)
|
||||
}
|
||||
@@ -1398,31 +1399,29 @@ ApplicationWindow {
|
||||
AppTextField {
|
||||
id: statsEndField
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: phoneLayout ? 0 : 150
|
||||
Layout.preferredWidth: phoneLayout ? 1 : 150
|
||||
placeholderText: "结束日期"
|
||||
onEditingFinished: appController.updateStatisticsRange(statsStartField.text, text)
|
||||
}
|
||||
|
||||
SecondaryButton {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: phoneLayout ? 1 : implicitWidth
|
||||
text: "刷新统计"
|
||||
onClicked: appController.updateStatisticsRange(statsStartField.text, statsEndField.text)
|
||||
}
|
||||
|
||||
PrimaryButton {
|
||||
text: "导出统计报表"
|
||||
onClicked: statisticsExportDialog.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
Layout.fillWidth: true
|
||||
columns: phoneLayout ? 1 : (slimLayout ? 3 : (compactLayout ? 1 : 3))
|
||||
columns: phoneLayout ? 2 : (slimLayout ? 3 : (compactLayout ? 1 : 3))
|
||||
rowSpacing: 10
|
||||
columnSpacing: 14
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: phoneLayout ? 1 : 100
|
||||
Layout.preferredHeight: phoneLayout ? 68 : (slimLayout ? 74 : 100)
|
||||
radius: 8
|
||||
color: panelStrong
|
||||
@@ -1437,7 +1436,7 @@ ApplicationWindow {
|
||||
anchors.rightMargin: slimLayout ? 12 : 18
|
||||
spacing: 6
|
||||
Label { text: "统计学生数"; color: ink500 }
|
||||
Label { text: appController.statisticsStudentCount; font.pixelSize: slimLayout ? 22 : (compactLayout ? 28 : 32); font.bold: true; color: ink900 }
|
||||
Label { text: appController.statisticsStudentCount; font.pixelSize: slimLayout ? 22 : (compactLayout ? 28 : 32); font.weight: appBoldWeight; color: ink900 }
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -1453,6 +1452,7 @@ ApplicationWindow {
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: phoneLayout ? 1 : 100
|
||||
Layout.preferredHeight: phoneLayout ? 68 : (slimLayout ? 74 : 100)
|
||||
radius: 8
|
||||
color: panelStrong
|
||||
@@ -1467,7 +1467,7 @@ ApplicationWindow {
|
||||
anchors.rightMargin: slimLayout ? 12 : 18
|
||||
spacing: 6
|
||||
Label { text: "统计记录数"; color: ink500 }
|
||||
Label { text: appController.statisticsRecordCount; font.pixelSize: slimLayout ? 22 : (compactLayout ? 28 : 32); font.bold: true; color: tealColor }
|
||||
Label { text: appController.statisticsRecordCount; font.pixelSize: slimLayout ? 22 : (compactLayout ? 28 : 32); font.weight: appBoldWeight; color: tealColor }
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -1482,6 +1482,7 @@ ApplicationWindow {
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.columnSpan: phoneLayout ? 2 : 1
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: phoneLayout ? 68 : (slimLayout ? 74 : 100)
|
||||
radius: 8
|
||||
@@ -1500,7 +1501,7 @@ ApplicationWindow {
|
||||
Label {
|
||||
text: appController.statisticsRangeText
|
||||
font.pixelSize: slimLayout ? 14 : (compactLayout ? 18 : 20)
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
color: goldColor
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
@@ -1553,26 +1554,26 @@ ApplicationWindow {
|
||||
anchors.rightMargin: 16
|
||||
spacing: 12
|
||||
|
||||
Label { text: "学号"; Layout.preferredWidth: statisticsTableCard.studentColWidth; font.bold: true }
|
||||
Label { text: "姓名"; Layout.preferredWidth: statisticsTableCard.nameColWidth; font.bold: true }
|
||||
Label { text: "总签到次数"; Layout.preferredWidth: statisticsTableCard.totalColWidth; font.bold: true }
|
||||
Label { text: "学号"; Layout.preferredWidth: statisticsTableCard.studentColWidth; font.weight: appBoldWeight }
|
||||
Label { text: "姓名"; Layout.preferredWidth: statisticsTableCard.nameColWidth; font.weight: appBoldWeight }
|
||||
Label { text: "总签到次数"; Layout.preferredWidth: statisticsTableCard.totalColWidth; font.weight: appBoldWeight }
|
||||
Label {
|
||||
text: "今日签到"
|
||||
visible: statisticsTableCard.showTodayColumn
|
||||
Layout.preferredWidth: statisticsTableCard.todayColWidth
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
}
|
||||
Label {
|
||||
text: "最后签到时间"
|
||||
visible: statisticsTableCard.showLastColumn
|
||||
Layout.preferredWidth: statisticsTableCard.lastColWidth
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
}
|
||||
Label {
|
||||
text: "平均置信度"
|
||||
visible: statisticsTableCard.showAverageColumn
|
||||
Layout.preferredWidth: statisticsTableCard.avgColWidth
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
}
|
||||
Item { Layout.fillWidth: true }
|
||||
}
|
||||
@@ -1609,7 +1610,7 @@ ApplicationWindow {
|
||||
spacing: 12
|
||||
|
||||
Label { text: model.studentId; Layout.preferredWidth: statisticsTableCard.studentColWidth; color: ink700 }
|
||||
Label { text: model.name; Layout.preferredWidth: statisticsTableCard.nameColWidth; color: ink900; font.bold: true }
|
||||
Label { text: model.name; Layout.preferredWidth: statisticsTableCard.nameColWidth; color: ink900; font.weight: appBoldWeight }
|
||||
Label { text: model.totalCount; Layout.preferredWidth: statisticsTableCard.totalColWidth; color: ink700 }
|
||||
Label {
|
||||
text: model.todayCount
|
||||
@@ -1628,7 +1629,7 @@ ApplicationWindow {
|
||||
visible: statisticsTableCard.showAverageColumn
|
||||
Layout.preferredWidth: statisticsTableCard.avgColWidth
|
||||
color: tealColor
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
}
|
||||
Item { Layout.fillWidth: true }
|
||||
}
|
||||
@@ -1691,7 +1692,7 @@ ApplicationWindow {
|
||||
Label {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
text: "服务器地址"
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
color: ink700
|
||||
}
|
||||
AppTextField {
|
||||
@@ -1785,10 +1786,10 @@ ApplicationWindow {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
Label { text: "名称"; Layout.preferredWidth: 220; font.bold: true }
|
||||
Label { text: "开始"; Layout.preferredWidth: 120; font.bold: true }
|
||||
Label { text: "结束"; Layout.preferredWidth: 120; font.bold: true }
|
||||
Label { text: "状态"; Layout.preferredWidth: 100; font.bold: true }
|
||||
Label { text: "名称"; Layout.preferredWidth: 220; font.weight: appBoldWeight }
|
||||
Label { text: "开始"; Layout.preferredWidth: 120; font.weight: appBoldWeight }
|
||||
Label { text: "结束"; Layout.preferredWidth: 120; font.weight: appBoldWeight }
|
||||
Label { text: "状态"; Layout.preferredWidth: 100; font.weight: appBoldWeight }
|
||||
Item { Layout.fillWidth: true }
|
||||
}
|
||||
}
|
||||
@@ -1829,7 +1830,7 @@ ApplicationWindow {
|
||||
text: model.enabled ? "启用" : "禁用"
|
||||
Layout.preferredWidth: 100
|
||||
color: model.enabled ? successColor : goldColor
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
}
|
||||
Item { Layout.fillWidth: true }
|
||||
SecondaryButton { text: "编辑"; onClicked: openTimeSlotDialog(index) }
|
||||
@@ -2163,7 +2164,7 @@ ApplicationWindow {
|
||||
visible: !model.hasPhoto
|
||||
text: "无照片"
|
||||
color: goldColor
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2171,7 +2172,7 @@ ApplicationWindow {
|
||||
text: "ID: " + model.faceId
|
||||
color: ink900
|
||||
font.pixelSize: compactLayout ? 15 : 16
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
}
|
||||
|
||||
AppTextField {
|
||||
@@ -2192,7 +2193,7 @@ ApplicationWindow {
|
||||
text: model.hasPhoto ? "照片已同步" : "仅检测到记录,无照片"
|
||||
color: model.hasPhoto ? successColor : goldColor
|
||||
font.pixelSize: narrowLayout ? 11 : 12
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2281,7 +2282,7 @@ ApplicationWindow {
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: phoneLayout ? 124 : 108
|
||||
Layout.preferredHeight: phoneLayout ? 188 : 164
|
||||
radius: 8
|
||||
color: "#f8fafb"
|
||||
border.color: lineColor
|
||||
@@ -2296,7 +2297,7 @@ ApplicationWindow {
|
||||
text: "毕业设计说明"
|
||||
color: ink900
|
||||
font.pixelSize: 16
|
||||
font.bold: true
|
||||
font.weight: appBoldWeight
|
||||
}
|
||||
|
||||
Label {
|
||||
@@ -2314,6 +2315,22 @@ ApplicationWindow {
|
||||
color: ink500
|
||||
font.pixelSize: 12
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: "仓库地址:https://git.yzfh.eu.cc/yzfh/qt.git"
|
||||
wrapMode: Text.WrapAnywhere
|
||||
color: ink500
|
||||
font.pixelSize: 12
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: "查看账号:jtybishe 查看密码:jtybishe"
|
||||
wrapMode: Text.WordWrap
|
||||
color: ink500
|
||||
font.pixelSize: 12
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-3
@@ -91,10 +91,9 @@ bool ApiClient::isConnectionError(QNetworkReply::NetworkError error) const
|
||||
|
||||
void ApiClient::emitNetworkError(const QString &prefix, QNetworkReply *reply)
|
||||
{
|
||||
const QString message = QStringLiteral("%1: %2").arg(prefix, reply->errorString());
|
||||
emit networkError(message);
|
||||
emit networkError(prefix);
|
||||
if (isConnectionError(reply->error())) {
|
||||
emit connectionUnavailable(message);
|
||||
emit connectionUnavailable(prefix);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+20
-10
@@ -42,6 +42,18 @@ bool isSuccessStatus(const QString &status)
|
||||
|| normalized == QStringLiteral("签到成功")
|
||||
|| normalized == QStringLiteral("正常");
|
||||
}
|
||||
|
||||
QString conciseStatusMessage(const QString &message)
|
||||
{
|
||||
if (message.contains(QStringLiteral("Error transferring"), Qt::CaseInsensitive)
|
||||
|| message.contains(QStringLiteral("Connection refused"), Qt::CaseInsensitive)
|
||||
|| message.contains(QStringLiteral("Host not found"), Qt::CaseInsensitive)
|
||||
|| message.contains(QStringLiteral("Network unreachable"), Qt::CaseInsensitive)
|
||||
|| message.contains(QStringLiteral("timed out"), Qt::CaseInsensitive)) {
|
||||
return QStringLiteral("服务器未连接,稍后重试");
|
||||
}
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
AppController::AppController(QObject *parent)
|
||||
@@ -673,32 +685,30 @@ void AppController::mergeFaceItems()
|
||||
|
||||
void AppController::setStatusMessage(const QString &message)
|
||||
{
|
||||
if (message == m_statusMessage) {
|
||||
const QString displayMessage = conciseStatusMessage(message);
|
||||
if (displayMessage == m_statusMessage) {
|
||||
return;
|
||||
}
|
||||
m_statusMessage = message;
|
||||
m_statusMessage = displayMessage;
|
||||
emit statusMessageChanged();
|
||||
}
|
||||
|
||||
void AppController::startReconnect(const QString &reason)
|
||||
{
|
||||
Q_UNUSED(reason)
|
||||
|
||||
if (!m_reconnecting) {
|
||||
m_reconnecting = true;
|
||||
m_reconnectAttempt = 0;
|
||||
emit reconnectStateChanged();
|
||||
}
|
||||
|
||||
const QString detail = reason.trimmed();
|
||||
if (m_reconnectCheckInFlight || m_reconnectTimer.isActive()) {
|
||||
setStatusMessage(detail.isEmpty()
|
||||
? QStringLiteral("服务器连接失败,正在等待自动重连")
|
||||
: QStringLiteral("服务器连接失败,正在等待自动重连: %1").arg(detail));
|
||||
setStatusMessage(QStringLiteral("服务器未连接,稍后重试"));
|
||||
return;
|
||||
}
|
||||
|
||||
setStatusMessage(detail.isEmpty()
|
||||
? QStringLiteral("服务器连接失败,%1 秒后自动重连").arg(ReconnectIntervalMs / 1000)
|
||||
: QStringLiteral("服务器连接失败,%1 秒后自动重连: %2").arg(ReconnectIntervalMs / 1000).arg(detail));
|
||||
setStatusMessage(QStringLiteral("服务器未连接,稍后重试"));
|
||||
scheduleReconnect();
|
||||
}
|
||||
|
||||
@@ -729,6 +739,6 @@ void AppController::runReconnectCheck()
|
||||
m_reconnectCheckInFlight = true;
|
||||
++m_reconnectAttempt;
|
||||
emit reconnectStateChanged();
|
||||
setStatusMessage(QStringLiteral("正在重连服务器,第 %1 次").arg(m_reconnectAttempt));
|
||||
setStatusMessage(QStringLiteral("正在重连服务器"));
|
||||
m_apiClient.checkHealth();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user