账单记录器迁移。
17
.clang-format
Normal file
@@ -0,0 +1,17 @@
|
||||
BasedOnStyle: LLVM
|
||||
IndentWidth: 4
|
||||
PointerAlignment: Left
|
||||
AccessModifierOffset: -4
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterFunction: true
|
||||
AfterClass: true
|
||||
Cpp11BracedListStyle: true
|
||||
ReflowComments: true
|
||||
SpacesBeforeTrailingComments: 3
|
||||
TabWidth: 4
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ColumnLimit: 130
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AllowShortEnumsOnASingleLine: false
|
||||
42
.gitignore
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
# Prerequisites
|
||||
*.d
|
||||
.idea
|
||||
cmake-build-*
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
build
|
||||
*.user
|
||||
compile_commands.json
|
||||
.vs
|
||||
out
|
||||
.cache
|
||||
CMakeLists.txt.*
|
||||
build*
|
||||
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "ofen"]
|
||||
path = ofen
|
||||
url = https://www.sinxmiao.cn/taynpg/ofen
|
||||
183
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,183 @@
|
||||
{
|
||||
"files.autoSave": "onFocusChange",
|
||||
"editor.fontSize": 14,
|
||||
"cmake.configureOnOpen": true,
|
||||
"editor.fontFamily": "'Maple Mono NL NF CN Light', 'Maple Mono NL NF CN Light', 'Maple Mono NL NF CN Light'",
|
||||
"cmake.debugConfig": {
|
||||
"console": "externalTerminal",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "-gdb-set charset utf-8",
|
||||
"text": "-gdb-set charset UTF-8"
|
||||
},
|
||||
{
|
||||
"description": "Enable gdb pretty-printing",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
],
|
||||
//"visualizerFile": "${workspaceRoot}/.vscode/qt6.natvis",
|
||||
"args": []
|
||||
},
|
||||
"cmake.environment": {
|
||||
//"EXTER_LIB_DIR": "C:/local"
|
||||
},
|
||||
"cmake.configureSettings": {
|
||||
"CMAKE_PREFIX_PATH": "C:\\Qt\\Qt5.14.2\\5.14.2\\msvc2017_64",
|
||||
//"CMAKE_TOOLCHAIN_FILE": "${env:TT_VCPKG}"
|
||||
},
|
||||
"cmake.configureArgs": [
|
||||
"-Wno-dev"
|
||||
],
|
||||
"cmake.options.statusBarVisibility": "visible",
|
||||
"cmake.generator": "Ninja",
|
||||
"C_Cpp.default.compileCommands": "${workspaceRoot}/build/compile_commands.json",
|
||||
"C_Cpp.default.cppStandard": "c++17",
|
||||
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
|
||||
"editor.inlayHints.enabled": "off",
|
||||
"editor.unicodeHighlight.allowedLocales": {
|
||||
"ja": true,
|
||||
"zh-hant": true,
|
||||
"zh-hans": true
|
||||
},
|
||||
"files.associations": {
|
||||
"string": "cpp",
|
||||
"any": "cpp",
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
"bit": "cpp",
|
||||
"bitset": "cpp",
|
||||
"cctype": "cpp",
|
||||
"charconv": "cpp",
|
||||
"chrono": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"codecvt": "cpp",
|
||||
"compare": "cpp",
|
||||
"concepts": "cpp",
|
||||
"condition_variable": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"deque": "cpp",
|
||||
"forward_list": "cpp",
|
||||
"list": "cpp",
|
||||
"map": "cpp",
|
||||
"set": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"unordered_set": "cpp",
|
||||
"vector": "cpp",
|
||||
"exception": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"functional": "cpp",
|
||||
"iterator": "cpp",
|
||||
"memory": "cpp",
|
||||
"memory_resource": "cpp",
|
||||
"numeric": "cpp",
|
||||
"optional": "cpp",
|
||||
"random": "cpp",
|
||||
"ratio": "cpp",
|
||||
"source_location": "cpp",
|
||||
"string_view": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"format": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iomanip": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"iostream": "cpp",
|
||||
"istream": "cpp",
|
||||
"limits": "cpp",
|
||||
"mutex": "cpp",
|
||||
"new": "cpp",
|
||||
"numbers": "cpp",
|
||||
"ostream": "cpp",
|
||||
"queue": "cpp",
|
||||
"ranges": "cpp",
|
||||
"semaphore": "cpp",
|
||||
"shared_mutex": "cpp",
|
||||
"span": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"stop_token": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"text_encoding": "cpp",
|
||||
"thread": "cpp",
|
||||
"cfenv": "cpp",
|
||||
"cinttypes": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"variant": "cpp",
|
||||
"ios": "cpp",
|
||||
"locale": "cpp",
|
||||
"xfacet": "cpp",
|
||||
"xhash": "cpp",
|
||||
"xiosbase": "cpp",
|
||||
"xlocale": "cpp",
|
||||
"xlocbuf": "cpp",
|
||||
"xlocinfo": "cpp",
|
||||
"xlocmes": "cpp",
|
||||
"xlocmon": "cpp",
|
||||
"xlocnum": "cpp",
|
||||
"xloctime": "cpp",
|
||||
"xmemory": "cpp",
|
||||
"xstring": "cpp",
|
||||
"xtr1common": "cpp",
|
||||
"xutility": "cpp",
|
||||
"coroutine": "cpp",
|
||||
"csignal": "cpp",
|
||||
"future": "cpp",
|
||||
"stdfloat": "cpp",
|
||||
"regex": "cpp",
|
||||
"stack": "cpp",
|
||||
"valarray": "cpp",
|
||||
"filesystem": "cpp",
|
||||
"flat_map": "cpp",
|
||||
"flat_set": "cpp",
|
||||
"stacktrace": "cpp",
|
||||
"singleapplication": "cpp",
|
||||
"strstream": "cpp",
|
||||
"barrier": "cpp",
|
||||
"complex": "cpp",
|
||||
"csetjmp": "cpp",
|
||||
"cuchar": "cpp",
|
||||
"expected": "cpp",
|
||||
"fstream": "cpp",
|
||||
"generator": "cpp",
|
||||
"latch": "cpp",
|
||||
"print": "cpp",
|
||||
"scoped_allocator": "cpp",
|
||||
"spanstream": "cpp",
|
||||
"syncstream": "cpp",
|
||||
"typeindex": "cpp"
|
||||
},
|
||||
"editor.tokenColorCustomizations": {
|
||||
"textMateRules": [
|
||||
{
|
||||
"scope": "googletest.failed",
|
||||
"settings": {
|
||||
"foreground": "#f00"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "googletest.passed",
|
||||
"settings": {
|
||||
"foreground": "#0f0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "googletest.run",
|
||||
"settings": {
|
||||
"foreground": "#0f0"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
92
CMakeLists.txt
Normal file
@@ -0,0 +1,92 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(SimpleAccount VERSION 0.1 LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
if(MSVC)
|
||||
add_compile_options(/utf-8)
|
||||
endif()
|
||||
|
||||
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib/${CMAKE_BUILD_TYPE})
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin/${CMAKE_BUILD_TYPE}/)
|
||||
|
||||
add_definitions(-DFMT_HEADER_ONLY)
|
||||
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Network Sql)
|
||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Network Sql)
|
||||
|
||||
set(QAPPLICATION_CLASS QApplication CACHE STRING "Inheritance class for SingleApplication")
|
||||
add_subdirectory(ofen/SingleApplication)
|
||||
include_directories(ofen)
|
||||
|
||||
set(PROJECT_SOURCES
|
||||
main.cpp
|
||||
mainwidget.cpp
|
||||
mainwidget.h
|
||||
mainwidget.ui
|
||||
SqlOpr.h SqlOpr.cpp
|
||||
filterform.h filterform.cpp filterform.ui
|
||||
recordedit.cpp recordedit.h recordedit.ui
|
||||
repayment.ui repayment.cpp repayment.h
|
||||
resource/SimpleAccount.rc res.qrc
|
||||
resource/qss.qrc
|
||||
statistic.h statistic.cpp
|
||||
util.h util.cpp
|
||||
)
|
||||
|
||||
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
|
||||
qt_add_executable(SimpleAccount
|
||||
MANUAL_FINALIZATION
|
||||
${PROJECT_SOURCES}
|
||||
util.h util.cpp
|
||||
)
|
||||
# Define target properties for Android with Qt 6 as:
|
||||
# set_property(TARGET SimpleAccount APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/android)
|
||||
# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation
|
||||
else()
|
||||
if(ANDROID)
|
||||
add_library(SimpleAccount SHARED
|
||||
${PROJECT_SOURCES}
|
||||
)
|
||||
# Define properties for Android with Qt 5 after find_package() calls as:
|
||||
# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
|
||||
else()
|
||||
add_executable(SimpleAccount
|
||||
${PROJECT_SOURCES}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_link_libraries(SimpleAccount PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Sql Qt${QT_VERSION_MAJOR}::Network)
|
||||
target_link_libraries(SimpleAccount PRIVATE SingleApplication::SingleApplication)
|
||||
|
||||
# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
|
||||
# If you are developing for iOS or macOS you should consider setting an
|
||||
# explicit, fixed bundle identifier manually though.
|
||||
if(${QT_VERSION} VERSION_LESS 6.1.0)
|
||||
set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.example.SimpleAccount)
|
||||
endif()
|
||||
set_target_properties(SimpleAccount PROPERTIES
|
||||
${BUNDLE_ID_OPTION}
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
|
||||
MACOSX_BUNDLE TRUE
|
||||
WIN32_EXECUTABLE TRUE
|
||||
)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
install(TARGETS SimpleAccount
|
||||
BUNDLE DESTINATION .
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
if(QT_VERSION_MAJOR EQUAL 6)
|
||||
qt_finalize_executable(SimpleAccount)
|
||||
endif()
|
||||
495
SqlOpr.cpp
Normal file
@@ -0,0 +1,495 @@
|
||||
#include "SqlOpr.h"
|
||||
#include <QFile>
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlError>
|
||||
#include <QSqlQuery>
|
||||
#include <QVariant>
|
||||
|
||||
ACTSqlOpr::~ACTSqlOpr()
|
||||
{
|
||||
if (db_.isOpen()) {
|
||||
db_.close();
|
||||
}
|
||||
}
|
||||
|
||||
bool ACTSqlOpr::OpenDb(const std::string& path)
|
||||
{
|
||||
dbPath_ = path;
|
||||
db_ = QSqlDatabase::addDatabase("QSQLITE", "account_connection");
|
||||
db_.setDatabaseName(QString::fromStdString(path));
|
||||
|
||||
if (!db_.open()) {
|
||||
lastErr_ = fmt::format("无法打开数据库:{}", db_.lastError().text().toStdString());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!generateDefaultTB()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ACTSqlOpr::UpdateAccount(AccountRecord& record)
|
||||
{
|
||||
QSqlQuery query(db_);
|
||||
query.prepare("UPDATE account_records SET money = ?, pay_type = ?, dt = ?, "
|
||||
"thing = ?, classify = ?, remark = ?, addition_file = ? WHERE id = ?");
|
||||
|
||||
query.addBindValue(record.money);
|
||||
query.addBindValue(QString::fromStdString(record.payType));
|
||||
query.addBindValue(QString::fromStdString(record.dt));
|
||||
query.addBindValue(QString::fromStdString(record.thing));
|
||||
query.addBindValue(QString::fromStdString(record.classify));
|
||||
query.addBindValue(QString::fromStdString(record.remark));
|
||||
query.addBindValue(QString::fromStdString(record.additionFile));
|
||||
query.addBindValue(record.id);
|
||||
|
||||
if (!query.exec()) {
|
||||
lastErr_ = fmt::format("执行更新失败: {}", query.lastError().text().toStdString());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QSqlDatabase& ACTSqlOpr::GetDb()
|
||||
{
|
||||
return db_;
|
||||
}
|
||||
|
||||
const std::string& ACTSqlOpr::GetLastErr()
|
||||
{
|
||||
return lastErr_;
|
||||
}
|
||||
|
||||
bool ACTSqlOpr::AppendAccount(AccountRecord& record)
|
||||
{
|
||||
QSqlQuery query(db_);
|
||||
query.prepare("INSERT INTO account_records "
|
||||
"(money, pay_type, dt, thing, classify, remark, addition_file) "
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?)");
|
||||
|
||||
query.addBindValue(record.money);
|
||||
query.addBindValue(QString::fromStdString(record.payType));
|
||||
query.addBindValue(QString::fromStdString(record.dt));
|
||||
query.addBindValue(QString::fromStdString(record.thing));
|
||||
query.addBindValue(QString::fromStdString(record.classify));
|
||||
query.addBindValue(QString::fromStdString(record.remark));
|
||||
query.addBindValue(QString::fromStdString(record.additionFile));
|
||||
|
||||
if (!query.exec()) {
|
||||
lastErr_ = fmt::format("执行插入失败: {}", query.lastError().text().toStdString());
|
||||
return false;
|
||||
}
|
||||
|
||||
record.id = query.lastInsertId().toInt();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ACTSqlOpr::DeleteAccount(int32_t id)
|
||||
{
|
||||
QSqlQuery query(db_);
|
||||
query.prepare("DELETE FROM account_records WHERE id = ?");
|
||||
query.addBindValue(id);
|
||||
|
||||
if (!query.exec()) {
|
||||
lastErr_ = fmt::format("执行删除失败: {}", query.lastError().text().toStdString());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ACTSqlOpr::GetAccountList(AccountRecordList& ret)
|
||||
{
|
||||
QSqlQuery query(db_);
|
||||
query.prepare("SELECT id, money, pay_type, dt, thing, classify, remark, addition_file "
|
||||
"FROM account_records ORDER BY dt DESC");
|
||||
|
||||
if (!query.exec()) {
|
||||
lastErr_ = fmt::format("查询失败: {}", query.lastError().text().toStdString());
|
||||
return false;
|
||||
}
|
||||
|
||||
ret.clear();
|
||||
while (query.next()) {
|
||||
AccountRecord record;
|
||||
record.id = query.value(0).toInt();
|
||||
record.money = query.value(1).toInt();
|
||||
record.payType = query.value(2).toString().toStdString();
|
||||
record.dt = query.value(3).toString().toStdString();
|
||||
record.thing = query.value(4).toString().toStdString();
|
||||
record.classify = query.value(5).toString().toStdString();
|
||||
record.remark = query.value(6).toString().toStdString();
|
||||
record.additionFile = query.value(7).toString().toStdString();
|
||||
|
||||
ret.push_back(record);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ACTSqlOpr::generateDefaultTB()
|
||||
{
|
||||
QSqlQuery query(db_);
|
||||
QString sql = "CREATE TABLE IF NOT EXISTS account_records ("
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||
"money INTEGER NOT NULL, "
|
||||
"pay_type TEXT NOT NULL, "
|
||||
"dt TEXT NOT NULL, "
|
||||
"thing TEXT, "
|
||||
"classify TEXT, "
|
||||
"remark TEXT, "
|
||||
"addition_file TEXT)";
|
||||
|
||||
if (!query.exec(sql)) {
|
||||
lastErr_ = fmt::format("创建表失败: {}", query.lastError().text().toStdString());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ACTSqlOpr::ACTSqlOpr()
|
||||
{
|
||||
}
|
||||
|
||||
ComSqlOpr::ComSqlOpr(QSqlDatabase& db) : db_(db)
|
||||
{
|
||||
generateDefaultTB();
|
||||
CheckContent();
|
||||
}
|
||||
|
||||
bool ComSqlOpr::GetClassifyList(ClassifyRecordList& ret)
|
||||
{
|
||||
QSqlQuery query(db_);
|
||||
query.prepare("SELECT id, key, value, type, mark FROM common_records WHERE key = '分类'");
|
||||
|
||||
if (!query.exec()) {
|
||||
lastErr_ = fmt::format("查询失败: {}", query.lastError().text().toStdString());
|
||||
return false;
|
||||
}
|
||||
|
||||
ret.clear();
|
||||
while (query.next()) {
|
||||
CommonRecord record;
|
||||
record.id = query.value(0).toInt();
|
||||
record.key = query.value(1).toString().toStdString();
|
||||
record.value = query.value(2).toString().toStdString();
|
||||
record.type = query.value(3).toString().toStdString();
|
||||
record.mark = query.value(4).toString().toStdString();
|
||||
ret.push_back(record);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ComSqlOpr::GetItem(CommonRecord& ret, const std::string& key)
|
||||
{
|
||||
QSqlQuery query(db_);
|
||||
query.prepare("SELECT id, key, value, type, mark FROM common_records "
|
||||
"WHERE key = ? ORDER BY id DESC LIMIT 1");
|
||||
query.addBindValue(QString::fromStdString(key));
|
||||
|
||||
if (!query.exec()) {
|
||||
lastErr_ = fmt::format("查询失败: {}", query.lastError().text().toStdString());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (query.next()) {
|
||||
ret.id = query.value(0).toInt();
|
||||
ret.key = query.value(1).toString().toStdString();
|
||||
ret.value = query.value(2).toString().toStdString();
|
||||
ret.type = query.value(3).toString().toStdString();
|
||||
ret.mark = query.value(4).toString().toStdString();
|
||||
return true;
|
||||
}
|
||||
|
||||
lastErr_ = fmt::format("未找到key为'{}'的记录", key);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ComSqlOpr::UpdateItem(CommonRecord& ret)
|
||||
{
|
||||
if (ret.id <= 0) {
|
||||
lastErr_ = "无效的记录ID";
|
||||
return false;
|
||||
}
|
||||
|
||||
QSqlQuery query(db_);
|
||||
query.prepare("UPDATE common_records SET "
|
||||
"key = ?, value = ?, type = ?, mark = ? "
|
||||
"WHERE id = ?");
|
||||
|
||||
query.addBindValue(QString::fromStdString(ret.key));
|
||||
query.addBindValue(QString::fromStdString(ret.value));
|
||||
query.addBindValue(QString::fromStdString(ret.type));
|
||||
query.addBindValue(QString::fromStdString(ret.mark));
|
||||
query.addBindValue(ret.id);
|
||||
|
||||
if (!query.exec()) {
|
||||
lastErr_ = fmt::format("更新失败: {}", query.lastError().text().toStdString());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ComSqlOpr::InserItem(CommonRecord& ret)
|
||||
{
|
||||
QSqlQuery query(db_);
|
||||
query.prepare("INSERT INTO common_records (key, value, type, mark) "
|
||||
"VALUES (?, ?, ?, ?)");
|
||||
|
||||
query.addBindValue(QString::fromStdString(ret.key));
|
||||
query.addBindValue(QString::fromStdString(ret.value));
|
||||
query.addBindValue(QString::fromStdString(ret.type));
|
||||
query.addBindValue(QString::fromStdString(ret.mark));
|
||||
|
||||
if (!query.exec()) {
|
||||
lastErr_ = fmt::format("插入失败: {}", query.lastError().text().toStdString());
|
||||
return false;
|
||||
}
|
||||
|
||||
ret.id = query.lastInsertId().toInt();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ComSqlOpr::DeleteItem(const std::string& value)
|
||||
{
|
||||
QSqlQuery query(db_);
|
||||
query.prepare("DELETE FROM common_records WHERE value = ? and key = '分类'");
|
||||
query.addBindValue(QString::fromStdString(value));
|
||||
|
||||
if (!query.exec()) {
|
||||
lastErr_ = fmt::format("删除失败: {}", query.lastError().text().toStdString());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (query.numRowsAffected() == 0) {
|
||||
lastErr_ = fmt::format("未找到value为'{}'的记录", value);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ComSqlOpr::CheckContent()
|
||||
{
|
||||
if (!db_.transaction()) {
|
||||
lastErr_ = fmt::format("开始事务失败: {}", db_.lastError().text().toStdString());
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::vector<std::tuple<std::string, std::string>> defaultCategories = {{"分类", "默认"}};
|
||||
|
||||
for (const auto& [key, val] : defaultCategories) {
|
||||
if (!CheckAndInsert(key, val, "", "")) {
|
||||
db_.rollback();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!db_.commit()) {
|
||||
lastErr_ = fmt::format("提交事务失败: {}", db_.lastError().text().toStdString());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ComSqlOpr::CheckClassifyExist(const std::string& value)
|
||||
{
|
||||
QSqlQuery query(db_);
|
||||
query.prepare("SELECT 1 FROM common_records WHERE value = ? and key = '分类'");
|
||||
query.addBindValue(QString::fromStdString(value));
|
||||
|
||||
if (!query.exec()) {
|
||||
lastErr_ = fmt::format("查询失败: {}", query.lastError().text().toStdString());
|
||||
return false;
|
||||
}
|
||||
return query.next();
|
||||
}
|
||||
|
||||
const std::string& ComSqlOpr::GetLastErr()
|
||||
{
|
||||
return lastErr_;
|
||||
}
|
||||
|
||||
bool ComSqlOpr::CheckAndInsert(const std::string& key, const std::string& value, const std::string& type, const std::string& mark)
|
||||
{
|
||||
QSqlQuery query(db_);
|
||||
query.prepare("SELECT 1 FROM common_records WHERE key = ? LIMIT 1");
|
||||
query.addBindValue(QString::fromStdString(key));
|
||||
|
||||
if (!query.exec()) {
|
||||
lastErr_ = fmt::format("查询失败: {}", query.lastError().text().toStdString());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (query.next()) {
|
||||
return true; // 记录已存在
|
||||
}
|
||||
|
||||
query.prepare("INSERT INTO common_records (key, value, type, mark) VALUES (?, ?, ?, ?)");
|
||||
query.addBindValue(QString::fromStdString(key));
|
||||
query.addBindValue(QString::fromStdString(value));
|
||||
query.addBindValue(QString::fromStdString(type));
|
||||
query.addBindValue(QString::fromStdString(mark));
|
||||
|
||||
if (!query.exec()) {
|
||||
lastErr_ = fmt::format("插入失败: {}", query.lastError().text().toStdString());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ComSqlOpr::generateDefaultTB()
|
||||
{
|
||||
QSqlQuery query(db_);
|
||||
QString sql = "CREATE TABLE IF NOT EXISTS common_records ("
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||
"key TEXT NOT NULL, "
|
||||
"value TEXT, "
|
||||
"type TEXT, "
|
||||
"mark TEXT)";
|
||||
|
||||
if (!query.exec(sql)) {
|
||||
lastErr_ = fmt::format("创建表失败: {}", query.lastError().text().toStdString());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
RepaySqlOpr::RepaySqlOpr(QSqlDatabase& db) : db_(db)
|
||||
{
|
||||
generateDefaultTB();
|
||||
}
|
||||
|
||||
bool RepaySqlOpr::GetRepayResult(RepayRecordList& ret, int32_t accID)
|
||||
{
|
||||
ret.clear();
|
||||
lastErr_.clear();
|
||||
|
||||
if (!db_.isOpen()) {
|
||||
lastErr_ = "Database is not open";
|
||||
return false;
|
||||
}
|
||||
|
||||
QSqlQuery query(db_);
|
||||
query.prepare("SELECT id, accID, money, dt, remark FROM repay_record WHERE accID = :accID");
|
||||
query.bindValue(":accID", accID);
|
||||
|
||||
if (!query.exec()) {
|
||||
lastErr_ = query.lastError().text().toStdString();
|
||||
return false;
|
||||
}
|
||||
|
||||
while (query.next()) {
|
||||
RepayRecord record;
|
||||
record.id = query.value("id").toInt();
|
||||
record.accID = query.value("accID").toInt();
|
||||
record.money = query.value("money").toInt();
|
||||
record.dt = query.value("dt").toString().toStdString();
|
||||
record.remark = query.value("remark").toString().toStdString();
|
||||
ret.push_back(record);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RepaySqlOpr::InsertRepayRecord(RepayRecord& ret)
|
||||
{
|
||||
lastErr_.clear();
|
||||
|
||||
if (!db_.isOpen()) {
|
||||
lastErr_ = "Database is not open";
|
||||
return false;
|
||||
}
|
||||
|
||||
QSqlQuery query(db_);
|
||||
query.prepare("INSERT INTO repay_record (accID, money, dt, remark) "
|
||||
"VALUES (:accID, :money, :dt, :remark)");
|
||||
query.bindValue(":accID", ret.accID);
|
||||
query.bindValue(":money", ret.money);
|
||||
query.bindValue(":dt", QString::fromStdString(ret.dt));
|
||||
query.bindValue(":remark", QString::fromStdString(ret.remark));
|
||||
|
||||
if (!query.exec()) {
|
||||
lastErr_ = query.lastError().text().toStdString();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the auto-generated id
|
||||
ret.id = query.lastInsertId().toInt();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RepaySqlOpr::updateRepayRecord(RepayRecord& ret)
|
||||
{
|
||||
lastErr_.clear();
|
||||
|
||||
if (!db_.isOpen()) {
|
||||
lastErr_ = "Database is not open";
|
||||
return false;
|
||||
}
|
||||
|
||||
QSqlQuery query(db_);
|
||||
query.prepare("UPDATE repay_record SET accID = :accID, money = :money, "
|
||||
"dt = :dt, remark = :remark WHERE id = :id");
|
||||
query.bindValue(":accID", ret.accID);
|
||||
query.bindValue(":money", ret.money);
|
||||
query.bindValue(":dt", QString::fromStdString(ret.dt));
|
||||
query.bindValue(":remark", QString::fromStdString(ret.remark));
|
||||
query.bindValue(":id", ret.id);
|
||||
|
||||
if (!query.exec()) {
|
||||
lastErr_ = query.lastError().text().toStdString();
|
||||
return false;
|
||||
}
|
||||
|
||||
return query.numRowsAffected() > 0;
|
||||
}
|
||||
|
||||
bool RepaySqlOpr::deleteRepayRecord(int32_t id)
|
||||
{
|
||||
lastErr_.clear();
|
||||
|
||||
if (!db_.isOpen()) {
|
||||
lastErr_ = "Database is not open";
|
||||
return false;
|
||||
}
|
||||
|
||||
QSqlQuery query(db_);
|
||||
query.prepare("DELETE FROM repay_record WHERE id = :id");
|
||||
query.bindValue(":id", id);
|
||||
|
||||
if (!query.exec()) {
|
||||
lastErr_ = query.lastError().text().toStdString();
|
||||
return false;
|
||||
}
|
||||
|
||||
return query.numRowsAffected() > 0;
|
||||
}
|
||||
|
||||
const std::string& RepaySqlOpr::GetLastErr()
|
||||
{
|
||||
return lastErr_;
|
||||
}
|
||||
|
||||
bool RepaySqlOpr::generateDefaultTB()
|
||||
{
|
||||
lastErr_.clear();
|
||||
|
||||
if (!db_.isOpen()) {
|
||||
lastErr_ = "Database is not open";
|
||||
return false;
|
||||
}
|
||||
|
||||
QSqlQuery query(db_);
|
||||
QString createTable = "CREATE TABLE IF NOT EXISTS repay_record ("
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||
"accID INTEGER NOT NULL, "
|
||||
"money INTEGER NOT NULL, "
|
||||
"dt TEXT NOT NULL, "
|
||||
"remark TEXT)";
|
||||
|
||||
if (!query.exec(createTable)) {
|
||||
lastErr_ = query.lastError().text().toStdString();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
111
SqlOpr.h
Normal file
@@ -0,0 +1,111 @@
|
||||
#ifndef SQL_OPR_H
|
||||
#define SQL_OPR_H
|
||||
|
||||
#include <QSqlDatabase>
|
||||
#include <cstdint>
|
||||
#include <fmt/format.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct AccountRecord {
|
||||
int32_t id{};
|
||||
int32_t money{};
|
||||
std::string payType{};
|
||||
std::string dt;
|
||||
std::string thing;
|
||||
std::string classify;
|
||||
std::string remark;
|
||||
std::string additionFile{};
|
||||
};
|
||||
|
||||
struct CommonRecord {
|
||||
int32_t id{};
|
||||
std::string key;
|
||||
std::string value;
|
||||
std::string type;
|
||||
std::string mark;
|
||||
};
|
||||
|
||||
struct RepayRecord {
|
||||
int32_t id{};
|
||||
int32_t accID{};
|
||||
int32_t money{};
|
||||
std::string dt;
|
||||
std::string remark;
|
||||
};
|
||||
|
||||
using ClassifyRecordList = std::vector<CommonRecord>;
|
||||
using AccountRecordList = std::vector<AccountRecord>;
|
||||
using RepayRecordList = std::vector<RepayRecord>;
|
||||
|
||||
class ACTSqlOpr
|
||||
{
|
||||
public:
|
||||
ACTSqlOpr();
|
||||
~ACTSqlOpr();
|
||||
|
||||
public:
|
||||
bool OpenDb(const std::string& path);
|
||||
bool GetAccountList(AccountRecordList& ret);
|
||||
bool AppendAccount(AccountRecord& ret);
|
||||
bool DeleteAccount(int32_t id);
|
||||
bool UpdateAccount(AccountRecord& ret);
|
||||
QSqlDatabase& GetDb();
|
||||
const std::string& GetLastErr();
|
||||
|
||||
private:
|
||||
bool generateDefaultTB();
|
||||
|
||||
private:
|
||||
QSqlDatabase db_;
|
||||
std::string dbPath_{};
|
||||
std::string lastErr_{};
|
||||
};
|
||||
|
||||
class ComSqlOpr
|
||||
{
|
||||
public:
|
||||
ComSqlOpr(QSqlDatabase& db);
|
||||
|
||||
public:
|
||||
bool GetClassifyList(ClassifyRecordList& ret);
|
||||
bool GetItem(CommonRecord& ret, const std::string& key);
|
||||
bool UpdateItem(CommonRecord& ret);
|
||||
bool InserItem(CommonRecord& ret);
|
||||
bool DeleteItem(const std::string& value);
|
||||
bool CheckContent();
|
||||
bool CheckClassifyExist(const std::string& value);
|
||||
const std::string& GetLastErr();
|
||||
|
||||
private:
|
||||
bool CheckAndInsert(const std::string& key, const std::string& value, const std::string& type, const std::string& mark);
|
||||
|
||||
private:
|
||||
bool generateDefaultTB();
|
||||
|
||||
private:
|
||||
QSqlDatabase& db_;
|
||||
std::string lastErr_{};
|
||||
};
|
||||
|
||||
class RepaySqlOpr
|
||||
{
|
||||
public:
|
||||
RepaySqlOpr(QSqlDatabase& db);
|
||||
|
||||
public:
|
||||
bool GetRepayResult(RepayRecordList& ret, int32_t accID);
|
||||
bool InsertRepayRecord(RepayRecord& ret);
|
||||
bool updateRepayRecord(RepayRecord& ret);
|
||||
bool deleteRepayRecord(int32_t id);
|
||||
const std::string& GetLastErr();
|
||||
|
||||
private:
|
||||
bool generateDefaultTB();
|
||||
|
||||
private:
|
||||
QSqlDatabase& db_;
|
||||
std::string lastErr_{};
|
||||
};
|
||||
|
||||
#endif // SQL_OPR_H
|
||||
439
filterform.cpp
Normal file
@@ -0,0 +1,439 @@
|
||||
#include "filterform.h"
|
||||
|
||||
#include "recordedit.h"
|
||||
#include "ui_filterform.h"
|
||||
#include <QDesktopServices>
|
||||
#include <QDir>
|
||||
#include <QMessageBox>
|
||||
#include <QRegularExpressionValidator>
|
||||
#include <QShowEvent>
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
#include <QDateTime>
|
||||
|
||||
FilterForm::FilterForm(QWidget* parent, std::unique_ptr<ACTSqlOpr>& sqlOpr, std::unique_ptr<ComSqlOpr>& comSqlOpr,
|
||||
std::unique_ptr<RepaySqlOpr>& repaySqlOpr)
|
||||
: QDialog(parent), ui(new Ui::FilterForm), sqlOpr_(sqlOpr), comSqlOpr_(comSqlOpr), repaySqlOpr_(repaySqlOpr)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
statistic_ = std::make_shared<Statistic>(repaySqlOpr_);
|
||||
Init();
|
||||
setWindowTitle("结果");
|
||||
}
|
||||
|
||||
FilterForm::~FilterForm()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
int FilterForm::exec()
|
||||
{
|
||||
ShowResult();
|
||||
if (!over_) {
|
||||
return QDialog::Rejected;
|
||||
}
|
||||
return QDialog::exec();
|
||||
}
|
||||
|
||||
void FilterForm::Init()
|
||||
{
|
||||
auto* lay = new QVBoxLayout(this);
|
||||
tw_ = new QTableWidget(this);
|
||||
|
||||
QStringList headers;
|
||||
headers << "ID" << "类型" << "分类" << "金额" << "日期" << "内容" << "备注";
|
||||
|
||||
tw_->setColumnCount(headers.size());
|
||||
tw_->setHorizontalHeaderLabels(headers);
|
||||
tw_->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
|
||||
tw_->setColumnWidth(0, 50);
|
||||
tw_->setColumnWidth(1, 100);
|
||||
tw_->setColumnWidth(2, 100);
|
||||
tw_->setColumnWidth(3, 100);
|
||||
tw_->setColumnWidth(4, 150);
|
||||
tw_->setColumnWidth(5, 300);
|
||||
tw_->setColumnWidth(6, 100);
|
||||
|
||||
lay->addWidget(tw_);
|
||||
ui->widget->setLayout(lay);
|
||||
|
||||
ui->edCashIn->setReadOnly(true);
|
||||
ui->edCashOut->setReadOnly(true);
|
||||
ui->edCreditIn->setReadOnly(true);
|
||||
ui->edCreditOut->setReadOnly(true);
|
||||
ui->edCreditCash->setReadOnly(true);
|
||||
|
||||
tw_->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(tw_, &QTableWidget::customContextMenuRequested, this, &FilterForm::ShowContextMenu);
|
||||
}
|
||||
|
||||
void FilterForm::ShowResult()
|
||||
{
|
||||
over_ = false;
|
||||
AccountRecordList list;
|
||||
if (!sqlOpr_->GetAccountList(list)) {
|
||||
QMessageBox::warning(this, "错误", QString::fromStdString(sqlOpr_->GetLastErr()));
|
||||
return;
|
||||
}
|
||||
|
||||
result_.clear();
|
||||
if (!Filter(list, result_)) {
|
||||
QMessageBox::warning(this, "错误", "筛选失败");
|
||||
return;
|
||||
}
|
||||
|
||||
if (result_.empty()) {
|
||||
QMessageBox::warning(this, "提示", "没有符合条件的记录");
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& item : result_) {
|
||||
tw_->insertRow(tw_->rowCount());
|
||||
int row = tw_->rowCount() - 1;
|
||||
|
||||
auto* i1 = new QTableWidgetItem(QString::number(item.id));
|
||||
i1->setFlags(i1->flags() & ~Qt::ItemIsEditable);
|
||||
|
||||
auto* i2 = new QTableWidgetItem(QString::fromStdString(item.payType));
|
||||
i2->setFlags(i2->flags() & ~Qt::ItemIsEditable);
|
||||
|
||||
auto* i3 = new QTableWidgetItem(QString::fromStdString(item.classify));
|
||||
i3->setFlags(i3->flags() & ~Qt::ItemIsEditable);
|
||||
|
||||
auto* i4 = new QTableWidgetItem(QString::number(item.money / 100.0));
|
||||
i4->setFlags(i4->flags() & ~Qt::ItemIsEditable);
|
||||
|
||||
auto* i5 = new QTableWidgetItem(QString::fromStdString(item.dt));
|
||||
i5->setFlags(i5->flags() & ~Qt::ItemIsEditable);
|
||||
|
||||
auto* i6 = new QTableWidgetItem(QString::fromStdString(item.thing));
|
||||
i6->setFlags(i6->flags() & ~Qt::ItemIsEditable);
|
||||
|
||||
auto* i7 = new QTableWidgetItem(QString::fromStdString(item.remark));
|
||||
i7->setFlags(i7->flags() & ~Qt::ItemIsEditable);
|
||||
|
||||
tw_->setItem(row, 0, i1);
|
||||
tw_->setItem(row, 1, i2);
|
||||
tw_->setItem(row, 2, i3);
|
||||
tw_->setItem(row, 3, i4);
|
||||
tw_->setItem(row, 4, i5);
|
||||
tw_->setItem(row, 5, i6);
|
||||
tw_->setItem(row, 6, i7);
|
||||
}
|
||||
CalcShow();
|
||||
over_ = true;
|
||||
}
|
||||
|
||||
void FilterForm::CalcShow()
|
||||
{
|
||||
statistic_->Calculate(result_);
|
||||
auto* d = SharedData::instance();
|
||||
ui->edCashIn->setText(QString::number(d->ttCashIn_ / 100.0));
|
||||
ui->edCashOut->setText(QString::number(d->ttCashOut_ / 100.0));
|
||||
ui->edCreditIn->setText(QString::number(d->ttCreditIn_ / 100.0));
|
||||
ui->edCreditOut->setText(QString::number(d->ttCreditOut_ / 100.0));
|
||||
ui->edCreditCash->setText(QString::number(d->ttCreditCash_ / 100.0));
|
||||
ui->edCreditPay->setText(QString::number(d->ttCashPay_ / 100.0));
|
||||
|
||||
auto ret1 = GetClassifyCash(result_, true);
|
||||
auto ret2 = GetClassifyCash(result_, false);
|
||||
|
||||
ui->lwCashCl->clear();
|
||||
for (const auto& item : ret1) {
|
||||
ui->lwCashCl->addItem(QString("%1 => %2/%3")
|
||||
.arg(QString::fromStdString(item.first))
|
||||
.arg(QString::number(item.second.first / 100.0))
|
||||
.arg(QString::number(item.second.second / 100.0)));
|
||||
}
|
||||
ui->lwCreditCl->clear();
|
||||
for (const auto& item : ret2) {
|
||||
ui->lwCreditCl->addItem(QString("%1 => %2/%3")
|
||||
.arg(QString::fromStdString(item.first))
|
||||
.arg(QString::number(item.second.first / 100.0))
|
||||
.arg(QString::number(item.second.second / 100.0)));
|
||||
}
|
||||
}
|
||||
|
||||
int32_t FilterForm::rePayValue(int accID)
|
||||
{
|
||||
RepayRecordList reuslt;
|
||||
if (!repaySqlOpr_->GetRepayResult(reuslt, accID)) {
|
||||
return 0;
|
||||
}
|
||||
int32_t sum = 0;
|
||||
for (const auto& item : reuslt) {
|
||||
sum += item.money;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
bool FilterForm::Filter(const AccountRecordList& list, AccountRecordList& result)
|
||||
{
|
||||
auto* d = SharedData::instance();
|
||||
result.clear();
|
||||
for (const auto& item : list) {
|
||||
if (d->flType) {
|
||||
if (item.payType != d->type.toStdString()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (d->flKeys) {
|
||||
auto qkeys = d->key.toUpper();
|
||||
auto skeys = QString::fromStdString(item.thing).toUpper();
|
||||
if (!skeys.contains(qkeys)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
switch (d->filter) {
|
||||
case CashFilter::FIL_BETWEEN: {
|
||||
if (item.money < d->lowMoney || item.money > d->highMoney) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CashFilter::FIL_HIGHER: {
|
||||
if (item.money <= d->highMoney) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CashFilter::FIL_LOWER: {
|
||||
if (item.money >= d->lowMoney) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (d->flClassify) {
|
||||
auto qkeys = d->classify.toUpper();
|
||||
auto skeys = QString::fromStdString(item.classify).toUpper();
|
||||
if (!skeys.contains(qkeys)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (d->flDays) {
|
||||
auto days = d->days;
|
||||
QDateTime datetime = QDateTime::fromString(QString::fromStdString(item.dt), "yyyy-MM-dd hh:mm:ss");
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
if (datetime.daysTo(now) > days) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
result.push_back(item);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, std::pair<uint32_t, uint32_t>>> FilterForm::GetClassifyCash(const AccountRecordList& list,
|
||||
bool isCash)
|
||||
{
|
||||
std::vector<std::pair<std::string, std::pair<uint32_t, uint32_t>>> ret;
|
||||
std::unordered_map<std::string, std::pair<uint32_t, uint32_t>> classifyMap;
|
||||
for (const auto& item : list) {
|
||||
if (isCash) {
|
||||
if (item.payType == "现金支出") {
|
||||
if (!classifyMap.count(item.classify)) {
|
||||
classifyMap[item.classify] = {0, 0};
|
||||
}
|
||||
classifyMap[item.classify].first += item.money;
|
||||
} else if (item.payType == "现金收入") {
|
||||
if (!classifyMap.count(item.classify)) {
|
||||
classifyMap[item.classify] = {0, 0};
|
||||
}
|
||||
classifyMap[item.classify].second += item.money;
|
||||
}
|
||||
} else {
|
||||
if (item.payType == "信用支出") {
|
||||
if (!classifyMap.count(item.classify)) {
|
||||
classifyMap[item.classify] = {0, 0};
|
||||
}
|
||||
classifyMap[item.classify].first += item.money;
|
||||
} else if (item.payType == "信用收入") {
|
||||
if (!classifyMap.count(item.classify)) {
|
||||
classifyMap[item.classify] = {0, 0};
|
||||
}
|
||||
classifyMap[item.classify].second += item.money;
|
||||
} else if (item.payType == "信用借款") {
|
||||
// 信用借款
|
||||
if (!classifyMap.count(item.classify)) {
|
||||
classifyMap[item.classify] = {0, 0};
|
||||
}
|
||||
classifyMap[item.classify].first += item.money;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto& item : classifyMap) {
|
||||
ret.emplace_back(item.first, item.second);
|
||||
}
|
||||
std::sort(ret.begin(), ret.end(),
|
||||
[](const std::pair<std::string, std::pair<uint32_t, uint32_t>>& a,
|
||||
const std::pair<std::string, std::pair<uint32_t, uint32_t>>& b) {
|
||||
auto at = a.second.first + a.second.second;
|
||||
auto bt = b.second.first + b.second.second;
|
||||
return at > bt;
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
void FilterForm::ShowContextMenu(const QPoint& pos)
|
||||
{
|
||||
QList<QTableWidgetItem*> selectedItems = tw_->selectedItems();
|
||||
if (selectedItems.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QMenu menu(this);
|
||||
|
||||
if (selectedItems.size() != 7) {
|
||||
return;
|
||||
}
|
||||
QAction* acFile = menu.addAction("查看附件");
|
||||
int id = selectedItems[0]->text().toInt();
|
||||
QString fileName;
|
||||
|
||||
for (const auto& item : result_) {
|
||||
if (item.id == id) {
|
||||
fileName = QString::fromStdString(item.additionFile);
|
||||
break;
|
||||
}
|
||||
}
|
||||
TransMenu(id, menu, selectedItems[1]);
|
||||
connect(acFile, &QAction::triggered, [this, selectedItems, id, fileName]() {
|
||||
if (fileName.isEmpty()) {
|
||||
QMessageBox::warning(this, "警告", "附件文件名为空");
|
||||
return;
|
||||
}
|
||||
QString mediaDir = QString::fromStdString(Util::GetMediaDir());
|
||||
QString filePath = QDir(mediaDir).filePath(fileName);
|
||||
if (!QFile::exists(filePath)) {
|
||||
QMessageBox::critical(this, "错误", QString("文件不存在: %1").arg(filePath));
|
||||
return;
|
||||
}
|
||||
if (!QDesktopServices::openUrl(QUrl::fromLocalFile(filePath))) {
|
||||
QMessageBox::critical(nullptr, "错误", "无法打开图片文件");
|
||||
}
|
||||
});
|
||||
QAction* acEdit = menu.addAction("编辑");
|
||||
connect(acEdit, &QAction::triggered, [this, id, selectedItems]() {
|
||||
RecordEdit* re = new RecordEdit(this, comSqlOpr_, repaySqlOpr_);
|
||||
AccountRecord* recPtr = nullptr;
|
||||
for (auto& item : result_) {
|
||||
if (item.id == id) {
|
||||
re->record_ = item;
|
||||
recPtr = &item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
re->exec();
|
||||
|
||||
// headers << "ID" << "类型" << "分类" << "金额" << "日期" << "内容" << "备注";
|
||||
if (!re->modify_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sqlOpr_->UpdateAccount(re->record_)) {
|
||||
QMessageBox::warning(this, "错误", QString::fromStdString(sqlOpr_->GetLastErr()));
|
||||
return;
|
||||
}
|
||||
|
||||
selectedItems[1]->setText(QString::fromStdString(re->record_.payType));
|
||||
selectedItems[2]->setText(QString::fromStdString(re->record_.classify));
|
||||
selectedItems[3]->setText(QString::number(re->record_.money / 100.0));
|
||||
selectedItems[4]->setText(QString::fromStdString(re->record_.dt));
|
||||
selectedItems[5]->setText(QString::fromStdString(re->record_.thing));
|
||||
selectedItems[6]->setText(QString::fromStdString(re->record_.remark));
|
||||
|
||||
*recPtr = re->record_;
|
||||
CalcShow();
|
||||
});
|
||||
|
||||
QAction* acDelete = menu.addAction("删除");
|
||||
connect(acDelete, &QAction::triggered, [this, id, selectedItems]() {
|
||||
if (QMessageBox::question(this, "确认删除", "确定删除记录吗?") != QMessageBox::Yes) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sqlOpr_->DeleteAccount(id)) {
|
||||
QMessageBox::warning(this, "错误", QString::fromStdString(sqlOpr_->GetLastErr()));
|
||||
return;
|
||||
}
|
||||
|
||||
// 从结果列表中移除记录
|
||||
for (auto it = result_.begin(); it != result_.end(); ++it) {
|
||||
if (it->id == id) {
|
||||
result_.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 从表格中移除行
|
||||
tw_->removeRow(selectedItems[0]->row());
|
||||
CalcShow();
|
||||
});
|
||||
|
||||
menu.exec(tw_->viewport()->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
void FilterForm::TransMenu(int id, QMenu& menu, QTableWidgetItem* item)
|
||||
{
|
||||
QString payType;
|
||||
for (const auto& item : result_) {
|
||||
if (item.id == id) {
|
||||
payType = QString::fromStdString(item.payType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (payType.isEmpty()) {
|
||||
QMessageBox::warning(this, "警告", QString("未找到ID为%1的支付类型。").arg(id));
|
||||
return;
|
||||
}
|
||||
|
||||
// 根据支付类型执行不同操作
|
||||
QAction* acFile = nullptr;
|
||||
QString pur;
|
||||
if (payType == "现金支出") {
|
||||
acFile = menu.addAction("转为信用支出");
|
||||
pur = "信用支出";
|
||||
} else if (payType == "现金收入") {
|
||||
acFile = menu.addAction("转为信用收入");
|
||||
pur = "信用收入";
|
||||
} else if (payType == "信用支出") {
|
||||
acFile = menu.addAction("转为现金支出");
|
||||
pur = "现金支出";
|
||||
} else if (payType == "信用收入") {
|
||||
acFile = menu.addAction("转为现金收入");
|
||||
pur = "现金收入";
|
||||
}
|
||||
|
||||
if (acFile == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
connect(acFile, &QAction::triggered, [this, id, pur, item]() {
|
||||
// 执行支付类型转换逻辑
|
||||
if (QMessageBox::question(this, "确认转换", QString("确定将ID为%1的记录转为%2吗?").arg(id).arg(pur),
|
||||
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
|
||||
// 1. 更新数据库中的支付类型
|
||||
bool done = false;
|
||||
for (auto& item : result_) {
|
||||
if (item.id != id) {
|
||||
continue;
|
||||
}
|
||||
item.payType = pur.toStdString();
|
||||
if (!sqlOpr_->UpdateAccount(item)) {
|
||||
QMessageBox::critical(this, "错误", "更新数据库失败");
|
||||
return;
|
||||
}
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
if (done) {
|
||||
item->setText(pur);
|
||||
CalcShow();
|
||||
QMessageBox::information(this, "成功", QString("ID为%1的记录已成功转为%2。").arg(id).arg(pur));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
52
filterform.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef FILTERFORM_H
|
||||
#define FILTERFORM_H
|
||||
|
||||
#include "SqlOpr.h"
|
||||
#include "statistic.h"
|
||||
#include "util.h"
|
||||
#include <QDialog>
|
||||
#include <QMenu>
|
||||
#include <QTableWidget>
|
||||
#include <vector>
|
||||
|
||||
namespace Ui {
|
||||
class FilterForm;
|
||||
}
|
||||
|
||||
class FilterForm : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FilterForm(QWidget* parent, std::unique_ptr<ACTSqlOpr>& sqlOpr, std::unique_ptr<ComSqlOpr>& comSqlOpr,
|
||||
std::unique_ptr<RepaySqlOpr>& repaySqlOpr);
|
||||
~FilterForm();
|
||||
int exec() override;
|
||||
|
||||
public:
|
||||
static bool Filter(const AccountRecordList& list, AccountRecordList& result);
|
||||
static std::vector<std::pair<std::string, std::pair<uint32_t, uint32_t>>> GetClassifyCash(const AccountRecordList& list,
|
||||
bool isCash);
|
||||
|
||||
private:
|
||||
void Init();
|
||||
|
||||
private:
|
||||
void ShowResult();
|
||||
void ShowContextMenu(const QPoint& pos);
|
||||
void TransMenu(int id, QMenu& menu, QTableWidgetItem* item);
|
||||
void CalcShow();
|
||||
int32_t rePayValue(int accID);
|
||||
|
||||
private:
|
||||
bool over_{};
|
||||
QTableWidget* tw_{};
|
||||
AccountRecordList result_;
|
||||
std::shared_ptr<Statistic> statistic_;
|
||||
std::unique_ptr<ACTSqlOpr>& sqlOpr_;
|
||||
std::unique_ptr<ComSqlOpr>& comSqlOpr_;
|
||||
std::unique_ptr<RepaySqlOpr>& repaySqlOpr_;
|
||||
Ui::FilterForm* ui;
|
||||
};
|
||||
|
||||
#endif // FILTERFORM_H
|
||||
248
filterform.ui
Normal file
@@ -0,0 +1,248 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>FilterForm</class>
|
||||
<widget class="QDialog" name="FilterForm">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1472</width>
|
||||
<height>710</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>1.清单</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnPrePage">
|
||||
<property name="text">
|
||||
<string>上一页</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="edCurPage">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="edTotalPage">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnNextPage">
|
||||
<property name="text">
|
||||
<string>下一页</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>2.统计</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>总计现金支出:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="edCashOut"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>总计现金收入:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="edCashIn"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>总计信用支出:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="edCreditOut"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>总计信用收入:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="edCreditIn"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>总计信用借款:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="edCreditCash"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>总计信用还款:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="edCreditPay"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>现金分类占比(支出/收入):</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="lwCashCl"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>信用分类占比(支出/收入):</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="lwCreditCl"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
31
main.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "mainwidget.h"
|
||||
#include <QApplication>
|
||||
#include <QFile>
|
||||
#include <SingleApplication>
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
SingleApplication a(argc, argv);
|
||||
// a.setStyle("fusion");
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
#endif
|
||||
|
||||
MainWidget w;
|
||||
|
||||
QObject::connect(&a, &SingleApplication::instanceStarted, &w, [&w]() {
|
||||
w.showNormal();
|
||||
w.raise();
|
||||
w.activateWindow();
|
||||
});
|
||||
|
||||
|
||||
QFile file(":/qss/flatgray.css");
|
||||
if (file.open(QFile::ReadOnly)) {
|
||||
a.setStyleSheet(file.readAll());
|
||||
}
|
||||
|
||||
w.show();
|
||||
return a.exec();
|
||||
}
|
||||
344
mainwidget.cpp
Normal file
@@ -0,0 +1,344 @@
|
||||
#include "mainwidget.h"
|
||||
#include "./ui_mainwidget.h"
|
||||
#include "filterform.h"
|
||||
#include <QDir>
|
||||
#include <QFileDialog>
|
||||
#include <QInputDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QPainter>
|
||||
#include <QProcess>
|
||||
|
||||
MainWidget::MainWidget(QWidget* parent) : QDialog(parent), ui(new Ui::MainWidget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
BaseInit();
|
||||
Init();
|
||||
RefreshData();
|
||||
setWindowTitle("账单记录器V1.0.5");
|
||||
Calculate();
|
||||
|
||||
auto size = Util::GetMainSize();
|
||||
resize(size.first, size.second);
|
||||
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowMaximizeButtonHint);
|
||||
setWindowIcon(QIcon("://resource/ico.ico"));
|
||||
}
|
||||
|
||||
MainWidget::~MainWidget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void MainWidget::Init()
|
||||
{
|
||||
Util::Init();
|
||||
auto dbPath = Util::GetWorkDir() + "/account.db";
|
||||
sqlOpr_ = std::make_unique<ACTSqlOpr>();
|
||||
if (!sqlOpr_->OpenDb(dbPath)) {
|
||||
QMessageBox::warning(this, "错误", QString::fromStdString(sqlOpr_->GetLastErr()));
|
||||
return;
|
||||
}
|
||||
comSqlOpr_ = std::make_unique<ComSqlOpr>(sqlOpr_->GetDb());
|
||||
repaySqlOpr_ = std::make_unique<RepaySqlOpr>(sqlOpr_->GetDb());
|
||||
statistic_ = std::make_shared<Statistic>(repaySqlOpr_);
|
||||
|
||||
auto mediaDir = Util::GetMediaDir();
|
||||
if (!QDir(QString::fromStdString(mediaDir)).exists()) {
|
||||
QDir().mkdir(QString::fromStdString(mediaDir));
|
||||
}
|
||||
ui->timeEdit->setDisplayFormat("HH:mm:ss");
|
||||
ui->rbNoLimit->setChecked(true);
|
||||
ui->btnRecord->setStyleSheet("background-color: #b1a5ccff;");
|
||||
ui->dateEdit->setDate(QDate::currentDate());
|
||||
ui->timeEdit->setTime(QTime::currentTime());
|
||||
ui->cbClassify->setEditable(true);
|
||||
|
||||
ui->edCash->setValidator(new QDoubleValidator(0.0, 10000000.0, 2, this));
|
||||
ui->edHighCash->setValidator(new QDoubleValidator(0.0, 10000000.0, 2, this));
|
||||
ui->edLowCash->setValidator(new QDoubleValidator(0.0, 10000000.0, 2, this));
|
||||
ui->edDays->setValidator(new QIntValidator(0, 10000000, this));
|
||||
|
||||
ui->lbTotal->setStyleSheet("QLabel {"
|
||||
"font-size: 20px;"
|
||||
"color: blue;"
|
||||
"}");
|
||||
|
||||
ui->lbCurCash->setStyleSheet("QLabel {"
|
||||
"color: blue;"
|
||||
"}");
|
||||
ui->lbCredit->setStyleSheet("QLabel {"
|
||||
"color: blue;"
|
||||
"}");
|
||||
|
||||
connect(ui->btnClassifyAdd, &QPushButton::clicked, this, &MainWidget::AddClassify);
|
||||
connect(ui->btnClassifyDel, &QPushButton::clicked, this, &MainWidget::DelClassify);
|
||||
connect(ui->btnRecord, &QPushButton::clicked, this, &MainWidget::Record);
|
||||
connect(ui->btnSet, &QPushButton::clicked, this, [this]() {
|
||||
QProcess process;
|
||||
auto editor = Util::GetEditor();
|
||||
QStringList args;
|
||||
args << QString::fromStdString(Util::GetConfigPath());
|
||||
process.startDetached(QString::fromStdString(editor), args);
|
||||
process.waitForStarted();
|
||||
});
|
||||
connect(ui->btnSearch, &QPushButton::clicked, this, &MainWidget::Search);
|
||||
connect(ui->btnSetNow, &QPushButton::clicked, this, [this]() {
|
||||
ui->dateEdit->setDate(QDate::currentDate());
|
||||
ui->timeEdit->setTime(QTime::currentTime());
|
||||
});
|
||||
connect(ui->btnAddFile, &QPushButton::clicked, this, &MainWidget::SelectImg);
|
||||
connect(ui->btnClearFile, &QPushButton::clicked, this, [this]() { ui->edFile->clear(); });
|
||||
}
|
||||
|
||||
bool MainWidget::RefreshData()
|
||||
{
|
||||
if (!RefreshClassify()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MainWidget::Calculate()
|
||||
{
|
||||
AccountRecordList list;
|
||||
if (!sqlOpr_->GetAccountList(list)) {
|
||||
QMessageBox::warning(this, "错误", QString::fromStdString(sqlOpr_->GetLastErr()));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 计算账户余额等信息
|
||||
statistic_->Calculate(list);
|
||||
|
||||
auto* d = SharedData::instance();
|
||||
auto curCash = static_cast<int32_t>(Util::GetCurCash() * 100);
|
||||
auto curSave = static_cast<int32_t>(Util::GetCurSave() * 100);
|
||||
|
||||
auto curRemain = d->ttCashIn_ - d->ttCashOut_ + curCash - d->ttCashPay_ + d->ttCreditCash_;
|
||||
ui->lbCurCash->setText(QString::number(curRemain / 100.0));
|
||||
|
||||
auto creditOutTotal = d->ttCreditOut_ - d->ttCashPay_ + d->ttCreditCash_;
|
||||
QString credit = QString("%1/%2").arg(creditOutTotal / 100.0, 0, 'f', 2).arg(d->ttCreditIn_ / 100.0, 0, 'f', 2);
|
||||
ui->lbCredit->setText(credit);
|
||||
|
||||
auto youHave = curRemain + d->ttCreditIn_ - (d->ttCreditOut_ + d->ttCreditCash_ - d->ttCashPay_);
|
||||
ui->lbTotal->setText("¥" + QString::number(youHave / 100.0));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MainWidget::closeEvent(QCloseEvent* event)
|
||||
{
|
||||
auto size = this->size();
|
||||
Util::SetMainSize(size.width(), size.height());
|
||||
QWidget::closeEvent(event);
|
||||
}
|
||||
|
||||
void MainWidget::BaseInit()
|
||||
{
|
||||
ui->cbCashType->addItem("现金支出");
|
||||
ui->cbCashType->addItem("现金收入");
|
||||
ui->cbCashType->addItem("信用支出");
|
||||
ui->cbCashType->addItem("信用收入");
|
||||
ui->cbCashType->addItem("信用借款");
|
||||
ui->cbCashType->setCurrentIndex(0);
|
||||
}
|
||||
|
||||
bool MainWidget::RefreshClassify()
|
||||
{
|
||||
ClassifyRecordList classifyList;
|
||||
if (!comSqlOpr_->GetClassifyList(classifyList)) {
|
||||
QMessageBox::warning(this, "错误", QString::fromStdString(comSqlOpr_->GetLastErr()));
|
||||
return false;
|
||||
}
|
||||
ui->cbClassify->clear();
|
||||
for (const auto& classify : classifyList) {
|
||||
ui->cbClassify->addItem(QString::fromStdString(classify.value));
|
||||
}
|
||||
if (!classifyList.empty()) {
|
||||
ui->cbClassify->setCurrentIndex(0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MainWidget::SelectImg()
|
||||
{
|
||||
QString imagePath =
|
||||
QFileDialog::getOpenFileName(this, "选择图片", QDir::homePath(), "图片文件 (*.jpg *.jpeg *.png *.bmp *.gif)");
|
||||
if (imagePath.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ui->edFile->setText(imagePath);
|
||||
}
|
||||
|
||||
bool MainWidget::AddClassify()
|
||||
{
|
||||
// 弹出输入对话框
|
||||
bool ok;
|
||||
QString text = QInputDialog::getText(this, tr("添加分类"), tr("请输入分类名称:"), QLineEdit::Normal, "", &ok);
|
||||
text = text.trimmed();
|
||||
|
||||
if (!ok || text.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 先检查是否已存在
|
||||
if (comSqlOpr_->CheckClassifyExist(text.toStdString())) {
|
||||
QMessageBox::warning(this, tr("错误"), tr("分类已存在"));
|
||||
return false;
|
||||
}
|
||||
|
||||
CommonRecord record;
|
||||
record.key = "分类";
|
||||
record.value = text.toStdString();
|
||||
record.type = "";
|
||||
|
||||
if (!comSqlOpr_->InserItem(record)) {
|
||||
QMessageBox::warning(this, tr("错误"), tr("添加分类失败"));
|
||||
return false;
|
||||
}
|
||||
RefreshClassify();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MainWidget::DelClassify()
|
||||
{
|
||||
auto curClassify = ui->cbClassify->currentText();
|
||||
if (curClassify == "默认") {
|
||||
QMessageBox::warning(this, "错误", "默认分类无法删除");
|
||||
return false;
|
||||
}
|
||||
if (QMessageBox::question(this, "删除分类", QString("确定删除分类<%1>吗?").arg(curClassify)) != QMessageBox::Yes) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!comSqlOpr_->DeleteItem(curClassify.toStdString())) {
|
||||
QMessageBox::warning(this, "错误", QString::fromStdString(comSqlOpr_->GetLastErr()));
|
||||
return false;
|
||||
}
|
||||
RefreshClassify();
|
||||
return true;
|
||||
}
|
||||
|
||||
void MainWidget::Record()
|
||||
{
|
||||
// 确认添加
|
||||
if (QMessageBox::question(this, "确认添加", "确定添加记录吗?") != QMessageBox::Yes) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 款项分类
|
||||
auto curType = ui->cbCashType->currentText();
|
||||
|
||||
// 基础分类
|
||||
auto curClassify = ui->cbClassify->currentText();
|
||||
|
||||
// 记录事项
|
||||
auto thing = ui->lineEdit->text().trimmed();
|
||||
if (thing.isEmpty()) {
|
||||
QMessageBox::warning(this, "错误", "记录事项不能为空");
|
||||
return;
|
||||
}
|
||||
|
||||
// 时间日期
|
||||
auto date = ui->dateEdit->date();
|
||||
auto time = ui->timeEdit->time();
|
||||
QDateTime dateTime(date, time);
|
||||
auto dateTimeStr = dateTime.toString("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
// 金额
|
||||
// 查看附件
|
||||
auto attach = ui->edFile->text().trimmed();
|
||||
if (!attach.isEmpty()) {
|
||||
QFile file(attach);
|
||||
if (!file.exists()) {
|
||||
QMessageBox::warning(this, "错误", "附件文件不存在");
|
||||
return;
|
||||
}
|
||||
}
|
||||
AccountRecord record;
|
||||
record.money = Util::CashInt(ui->edCash->text().toDouble());
|
||||
record.thing = thing.toStdString();
|
||||
record.dt = dateTimeStr.toStdString();
|
||||
record.classify = curClassify.toStdString();
|
||||
record.payType = curType.toStdString();
|
||||
if (!attach.isEmpty()) {
|
||||
record.additionFile = Util::NewUUIDName(attach).toStdString();
|
||||
}
|
||||
if (!sqlOpr_->AppendAccount(record)) {
|
||||
QMessageBox::warning(this, "错误", QString::fromStdString(sqlOpr_->GetLastErr()));
|
||||
return;
|
||||
}
|
||||
if (!attach.isEmpty()) {
|
||||
QFile::copy(attach, QString::fromStdString(Util::GetMediaDir() + "/" + record.additionFile));
|
||||
};
|
||||
Calculate();
|
||||
QMessageBox::information(this, "提示", "添加成功");
|
||||
}
|
||||
|
||||
void MainWidget::Search()
|
||||
{
|
||||
auto* d = SharedData::instance();
|
||||
if (ui->ckType->isChecked()) {
|
||||
d->flType = true;
|
||||
d->type = ui->cbCashType->currentText();
|
||||
} else {
|
||||
d->flType = false;
|
||||
}
|
||||
if (ui->ckKey->isChecked()) {
|
||||
d->flKeys = true;
|
||||
d->key = ui->edKey->text().trimmed();
|
||||
if (d->key.isEmpty()) {
|
||||
QMessageBox::warning(this, "错误", "搜索关键字不能为空");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
d->flKeys = false;
|
||||
}
|
||||
if (ui->ckDays->isChecked()) {
|
||||
d->flDays = true;
|
||||
if (ui->edDays->text().isEmpty()) {
|
||||
QMessageBox::warning(this, "错误", "天数不能为空");
|
||||
return;
|
||||
}
|
||||
d->days = ui->edDays->text().toInt();
|
||||
} else {
|
||||
d->flDays = false;
|
||||
}
|
||||
if (ui->rbBetween->isChecked()) {
|
||||
d->filter = CashFilter::FIL_BETWEEN;
|
||||
if (ui->edLowCash->text().isEmpty() || ui->edHighCash->text().isEmpty()) {
|
||||
QMessageBox::warning(this, "错误", "金额范围不能为空");
|
||||
return;
|
||||
}
|
||||
d->lowMoney = static_cast<int>(ui->edLowCash->text().toDouble() * 100);
|
||||
d->highMoney = static_cast<int>(ui->edHighCash->text().toDouble() * 100);
|
||||
} else if (ui->rbHigh->isChecked()) {
|
||||
d->filter = CashFilter::FIL_HIGHER;
|
||||
if (ui->edHighCash->text().isEmpty()) {
|
||||
QMessageBox::warning(this, "错误", "金额高范围不能为空");
|
||||
return;
|
||||
}
|
||||
d->highMoney = static_cast<int>(ui->edHighCash->text().toDouble() * 100);
|
||||
} else if (ui->rbLow->isChecked()) {
|
||||
d->filter = CashFilter::FIL_LOWER;
|
||||
if (ui->edLowCash->text().isEmpty()) {
|
||||
QMessageBox::warning(this, "错误", "金额低范围不能为空");
|
||||
return;
|
||||
}
|
||||
d->lowMoney = static_cast<int>(ui->edLowCash->text().toDouble() * 100);
|
||||
} else {
|
||||
d->filter = CashFilter::FIL_NO_LIMIT;
|
||||
}
|
||||
|
||||
if (ui->ckClassify->isChecked()) {
|
||||
d->flClassify = true;
|
||||
d->classify = ui->cbClassify->currentText();
|
||||
} else {
|
||||
d->flClassify = false;
|
||||
}
|
||||
|
||||
FilterForm* filterForm = new FilterForm(this, sqlOpr_, comSqlOpr_, repaySqlOpr_);
|
||||
filterForm->exec();
|
||||
|
||||
Calculate();
|
||||
}
|
||||
50
mainwidget.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#ifndef MAINWIDGET_H
|
||||
#define MAINWIDGET_H
|
||||
|
||||
#include "SqlOpr.h"
|
||||
#include "util.h"
|
||||
#include "statistic.h"
|
||||
#include <QDialog>
|
||||
#include <memory>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui {
|
||||
class MainWidget;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class MainWidget : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainWidget(QWidget* parent = nullptr);
|
||||
~MainWidget();
|
||||
|
||||
public:
|
||||
void Init();
|
||||
|
||||
private:
|
||||
bool RefreshData();
|
||||
bool Calculate();
|
||||
void closeEvent(QCloseEvent* event) override;
|
||||
|
||||
private:
|
||||
void BaseInit();
|
||||
bool RefreshClassify();
|
||||
void SelectImg();
|
||||
|
||||
private:
|
||||
bool AddClassify();
|
||||
bool DelClassify();
|
||||
void Record();
|
||||
void Search();
|
||||
|
||||
private:
|
||||
std::shared_ptr<Statistic> statistic_;
|
||||
std::unique_ptr<ACTSqlOpr> sqlOpr_;
|
||||
std::unique_ptr<ComSqlOpr> comSqlOpr_;
|
||||
std::unique_ptr<RepaySqlOpr> repaySqlOpr_;
|
||||
Ui::MainWidget* ui;
|
||||
};
|
||||
#endif // MAINWIDGET_H
|
||||
341
mainwidget.ui
Normal file
@@ -0,0 +1,341 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWidget</class>
|
||||
<widget class="QDialog" name="MainWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>687</width>
|
||||
<height>237</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWidget</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="lbTotal">
|
||||
<property name="text">
|
||||
<string>NULL</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>剩余总现金(元):</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lbCurCash">
|
||||
<property name="text">
|
||||
<string>NULL</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>信用收支(元)(支出/收入):</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lbCredit">
|
||||
<property name="text">
|
||||
<string>NULL</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>款项类型:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cbCashType">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDateEdit" name="dateEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTimeEdit" name="timeEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnSetNow">
|
||||
<property name="text">
|
||||
<string>设置为现在</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnClassifyAdd">
|
||||
<property name="text">
|
||||
<string>分类增</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnClassifyDel">
|
||||
<property name="text">
|
||||
<string>分类删</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnSet">
|
||||
<property name="text">
|
||||
<string>设定</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>记录事项:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>金额(元):</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="edCash">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cbClassify">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnRecord">
|
||||
<property name="text">
|
||||
<string>记录</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="ckType">
|
||||
<property name="text">
|
||||
<string>款项筛选</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="ckDays">
|
||||
<property name="text">
|
||||
<string>最近天数</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QCheckBox" name="ckKey">
|
||||
<property name="text">
|
||||
<string>关键字筛</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QCheckBox" name="ckClassify">
|
||||
<property name="text">
|
||||
<string>分类筛选</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>金额小:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="5">
|
||||
<widget class="QLineEdit" name="edLowCash"/>
|
||||
</item>
|
||||
<item row="0" column="6">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>金额大:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="7">
|
||||
<widget class="QLineEdit" name="edHighCash">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QRadioButton" name="rbHigh">
|
||||
<property name="text">
|
||||
<string>金额大于</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QRadioButton" name="rbLow">
|
||||
<property name="text">
|
||||
<string>金额小于</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QRadioButton" name="rbBetween">
|
||||
<property name="text">
|
||||
<string>金额之间</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QRadioButton" name="rbNoLimit">
|
||||
<property name="text">
|
||||
<string>金额不限</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>关键字:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="5">
|
||||
<widget class="QLineEdit" name="edKey"/>
|
||||
</item>
|
||||
<item row="1" column="6">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>天范围:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="7">
|
||||
<widget class="QLineEdit" name="edDays"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnClearFile">
|
||||
<property name="text">
|
||||
<string>清除</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnAddFile">
|
||||
<property name="text">
|
||||
<string>添加附件图</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="edFile"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnSearch">
|
||||
<property name="text">
|
||||
<string>筛选查找</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
1
ofen
Submodule
133
recordedit.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
#include "recordedit.h"
|
||||
|
||||
#include "repayment.h"
|
||||
#include "ui_recordedit.h"
|
||||
#include "util.h"
|
||||
#include <QDateTime>
|
||||
#include <QMessageBox>
|
||||
|
||||
RecordEdit::RecordEdit(QWidget* parent, std::unique_ptr<ComSqlOpr>& comSqlOpr, std::unique_ptr<RepaySqlOpr>& repaySqlOpr)
|
||||
: QDialog(parent), ui(new Ui::RecordEdit), comSqlOpr_(comSqlOpr), repaySqlOpr_(repaySqlOpr)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->cbCalssify->setEditable(true);
|
||||
ui->timeEdit->setDisplayFormat("HH:mm:ss");
|
||||
ui->edCash->setValidator(new QDoubleValidator(0.0, 10000000.0, 2, this));
|
||||
ui->edId->setReadOnly(true);
|
||||
connect(ui->btnModify, &QPushButton::clicked, this, &RecordEdit::Modify);
|
||||
connect(ui->btnCancel, &QPushButton::clicked, this, &RecordEdit::reject);
|
||||
|
||||
connect(ui->btnCurDate, &QPushButton::clicked, this, [this]() {
|
||||
auto curContent = ui->pedMark->toPlainText();
|
||||
curContent += "\n";
|
||||
auto curDt = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
|
||||
curContent += curDt;
|
||||
ui->pedMark->setPlainText(curContent);
|
||||
});
|
||||
|
||||
connect(ui->btnYiHuanQing, &QPushButton::clicked, this, [this]() {
|
||||
auto curContent = ui->pedMark->toPlainText();
|
||||
if (curContent.contains("已还清")) {
|
||||
return;
|
||||
}
|
||||
curContent += "\n";
|
||||
curContent += "已还清。";
|
||||
ui->pedMark->setPlainText(curContent);
|
||||
});
|
||||
|
||||
connect(ui->btnRepay, &QPushButton::clicked, this, [this]() {
|
||||
QString info;
|
||||
info.append(QString::number(record_.id));
|
||||
info.append(" ");
|
||||
info.append(QString::fromStdString(record_.payType));
|
||||
info.append(" ");
|
||||
info.append(QString::fromStdString(record_.dt));
|
||||
info.append(" ");
|
||||
info.append(QString::fromStdString(record_.classify));
|
||||
|
||||
auto* payment = new Repayment(this, repaySqlOpr_);
|
||||
payment->SetInformation(info);
|
||||
payment->SetRecord(record_);
|
||||
payment->exec();
|
||||
});
|
||||
|
||||
setWindowTitle("编辑");
|
||||
}
|
||||
|
||||
RecordEdit::~RecordEdit()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
int RecordEdit::exec()
|
||||
{
|
||||
modify_ = false;
|
||||
ShowData();
|
||||
if (!over_) {
|
||||
return QDialog::Rejected;
|
||||
}
|
||||
return QDialog::exec();
|
||||
}
|
||||
|
||||
void RecordEdit::ShowData()
|
||||
{
|
||||
over_ = false;
|
||||
ClassifyRecordList classifyList;
|
||||
if (!comSqlOpr_->GetClassifyList(classifyList)) {
|
||||
QMessageBox::warning(this, "错误", QString::fromStdString(comSqlOpr_->GetLastErr()));
|
||||
return;
|
||||
}
|
||||
ui->cbCalssify->clear();
|
||||
for (const auto& classify : classifyList) {
|
||||
ui->cbCalssify->addItem(QString::fromStdString(classify.value));
|
||||
}
|
||||
if (!classifyList.empty()) {
|
||||
ui->cbCalssify->setCurrentText(QString::fromStdString(record_.classify));
|
||||
}
|
||||
ui->edId->setText(QString::number(record_.id));
|
||||
ui->cbType->addItem("现金支出");
|
||||
ui->cbType->addItem("现金收入");
|
||||
ui->cbType->addItem("信用支出");
|
||||
ui->cbType->addItem("信用收入");
|
||||
ui->cbType->addItem("信用借款");
|
||||
QDateTime datetime = QDateTime::fromString(QString::fromStdString(record_.dt), "yyyy-MM-dd hh:mm:ss");
|
||||
ui->dateEdit->setDate(datetime.date());
|
||||
ui->timeEdit->setTime(datetime.time());
|
||||
|
||||
ui->edCash->setText(QString::number(record_.money / 100.0));
|
||||
ui->pedContent->setPlainText(QString::fromStdString(record_.thing));
|
||||
ui->pedMark->setPlainText(QString::fromStdString(record_.remark));
|
||||
|
||||
ui->cbType->setCurrentText(QString::fromStdString(record_.payType));
|
||||
if (record_.payType == "现金支出" || record_.payType == "现金收入") {
|
||||
ui->btnRepay->setEnabled(false);
|
||||
} else {
|
||||
ui->btnRepay->setEnabled(true);
|
||||
}
|
||||
|
||||
over_ = true;
|
||||
}
|
||||
|
||||
void RecordEdit::GetData()
|
||||
{
|
||||
record_.classify = ui->cbCalssify->currentText().toStdString();
|
||||
record_.payType = ui->cbType->currentText().toStdString();
|
||||
QDateTime datetime;
|
||||
datetime.setDate(ui->dateEdit->date());
|
||||
datetime.setTime(ui->timeEdit->time());
|
||||
auto strMoney = ui->edCash->text();
|
||||
record_.money = Util::CashInt(strMoney.toDouble());
|
||||
record_.dt = datetime.toString("yyyy-MM-dd hh:mm:ss").toStdString();
|
||||
record_.thing = ui->pedContent->toPlainText().toStdString();
|
||||
record_.remark = ui->pedMark->toPlainText().toStdString();
|
||||
}
|
||||
|
||||
void RecordEdit::Modify()
|
||||
{
|
||||
if (QMessageBox::question(this, "确认修改", "确定修改记录吗?") != QMessageBox::Yes) {
|
||||
return;
|
||||
}
|
||||
modify_ = true;
|
||||
GetData();
|
||||
accept();
|
||||
}
|
||||
39
recordedit.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#ifndef RECORDEDIT_H
|
||||
#define RECORDEDIT_H
|
||||
|
||||
#include "SqlOpr.h"
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class RecordEdit;
|
||||
}
|
||||
|
||||
class RecordEdit : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit RecordEdit(QWidget* parent, std::unique_ptr<ComSqlOpr>& comSqlOpr, std::unique_ptr<RepaySqlOpr>& repaySqlOpr);
|
||||
~RecordEdit();
|
||||
|
||||
public:
|
||||
int exec() override;
|
||||
|
||||
public:
|
||||
bool modify_ = false;
|
||||
AccountRecord record_;
|
||||
|
||||
private:
|
||||
void ShowData();
|
||||
void GetData();
|
||||
void Modify();
|
||||
|
||||
private:
|
||||
bool autoChange_{false};
|
||||
bool over_{};
|
||||
std::unique_ptr<RepaySqlOpr>& repaySqlOpr_;
|
||||
std::unique_ptr<ComSqlOpr>& comSqlOpr_;
|
||||
Ui::RecordEdit* ui;
|
||||
};
|
||||
|
||||
#endif // RECORDEDIT_H
|
||||
206
recordedit.ui
Normal file
@@ -0,0 +1,206 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>RecordEdit</class>
|
||||
<widget class="QDialog" name="RecordEdit">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>305</width>
|
||||
<height>386</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>序号:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="edId"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>类型:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cbType">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>分类:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cbCalssify">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>金额:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="edCash"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>日期:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDateEdit" name="dateEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTimeEdit" name="timeEdit"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>内容:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="pedContent"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>备注:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnYiHuanQing">
|
||||
<property name="text">
|
||||
<string>已还清</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnRepay">
|
||||
<property name="text">
|
||||
<string>还款</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnCurDate">
|
||||
<property name="text">
|
||||
<string>当前时间</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="pedMark"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnModify">
|
||||
<property name="text">
|
||||
<string>修改</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnCancel">
|
||||
<property name="text">
|
||||
<string>取消</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
225
repayment.cpp
Normal file
@@ -0,0 +1,225 @@
|
||||
#include "repayment.h"
|
||||
#include "ui_repayment.h"
|
||||
#include "util.h"
|
||||
#include <QDateTime>
|
||||
#include <QInputDialog>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
|
||||
Repayment::Repayment(QWidget* parent, std::unique_ptr<RepaySqlOpr>& repaySqlOpr)
|
||||
: QDialog(parent), ui(new Ui::Repayment), repaySqlOpr_(repaySqlOpr)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
Init();
|
||||
setWindowTitle("还款情况");
|
||||
resize(800, 600);
|
||||
}
|
||||
|
||||
Repayment::~Repayment()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
int Repayment::exec()
|
||||
{
|
||||
ui->lbInfo->setText(info_);
|
||||
ShowData();
|
||||
if (!over_) {
|
||||
return QDialog::Rejected;
|
||||
}
|
||||
return QDialog::exec();
|
||||
}
|
||||
|
||||
void Repayment::SetInformation(const QString& info)
|
||||
{
|
||||
info_ = info;
|
||||
}
|
||||
|
||||
void Repayment::SetRecord(const AccountRecord& record)
|
||||
{
|
||||
record_ = record;
|
||||
}
|
||||
|
||||
void Repayment::ShowData()
|
||||
{
|
||||
over_ = false;
|
||||
RepayRecordList reuslt;
|
||||
if (!repaySqlOpr_->GetRepayResult(reuslt, record_.id)) {
|
||||
QMessageBox::critical(this, "错误", "获取还款记录失败");
|
||||
return;
|
||||
}
|
||||
|
||||
tw_->setRowCount(reuslt.size());
|
||||
for (int row = 0; row < reuslt.size(); ++row) {
|
||||
QTableWidgetItem* item = new QTableWidgetItem(QString::number(reuslt[row].id));
|
||||
item->setFlags(item->flags() & ~Qt::ItemIsEditable);
|
||||
tw_->setItem(row, 0, item);
|
||||
|
||||
item = new QTableWidgetItem(QString::number(reuslt[row].accID));
|
||||
item->setFlags(item->flags() & ~Qt::ItemIsEditable);
|
||||
tw_->setItem(row, 1, item);
|
||||
|
||||
item = new QTableWidgetItem(QString::number(Util::CashDouble(reuslt[row].money)));
|
||||
tw_->setItem(row, 2, item);
|
||||
|
||||
item = new QTableWidgetItem(QString::fromStdString(reuslt[row].dt));
|
||||
tw_->setItem(row, 3, item);
|
||||
|
||||
item = new QTableWidgetItem(QString::fromStdString(reuslt[row].remark));
|
||||
tw_->setItem(row, 4, item);
|
||||
}
|
||||
|
||||
ui->edPay->setText(QString::number(Util::CashDouble(record_.money)) + "元");
|
||||
|
||||
// 统计还了多少钱
|
||||
BasicAnasys(reuslt);
|
||||
over_ = true;
|
||||
}
|
||||
|
||||
void Repayment::Init()
|
||||
{
|
||||
ui->edPay->setReadOnly(true);
|
||||
ui->edResult->setReadOnly(true);
|
||||
|
||||
auto* lay = new QVBoxLayout(this);
|
||||
tw_ = new QTableWidget(this);
|
||||
|
||||
QStringList headers;
|
||||
headers << "ID" << "记录ID" << "金额" << "日期" << "备注";
|
||||
|
||||
tw_->setColumnCount(headers.size());
|
||||
tw_->setHorizontalHeaderLabels(headers);
|
||||
tw_->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
|
||||
tw_->setColumnWidth(0, 50);
|
||||
tw_->setColumnWidth(1, 50);
|
||||
tw_->setColumnWidth(2, 100);
|
||||
tw_->setColumnWidth(3, 150);
|
||||
tw_->setColumnWidth(4, 100);
|
||||
|
||||
lay->addWidget(tw_);
|
||||
ui->widget->setLayout(lay);
|
||||
tw_->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(tw_, &QTableWidget::customContextMenuRequested, this, &Repayment::ShowContextMenu);
|
||||
connect(ui->btnSave, &QPushButton::clicked, this, &Repayment::Save);
|
||||
}
|
||||
|
||||
void Repayment::ShowContextMenu(const QPoint& pos)
|
||||
{
|
||||
QList<QTableWidgetItem*> selectedItems = tw_->selectedItems();
|
||||
if (selectedItems.isEmpty()) {
|
||||
QAction* acAdd = new QAction("添加", this);
|
||||
QMenu menu(this);
|
||||
connect(acAdd, &QAction::triggered, this, [this]() {
|
||||
bool ok = false;
|
||||
double amount =
|
||||
QInputDialog::getDouble(this, "录入金额", "请输入金额:", 0.0, 0.0, 1000000.0, 2, &ok, Qt::WindowFlags(), 1.0);
|
||||
|
||||
if (!ok || amount <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int row = tw_->rowCount();
|
||||
tw_->insertRow(row);
|
||||
|
||||
QString currentDateTime = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss");
|
||||
auto* nId = new QTableWidgetItem("");
|
||||
nId->setFlags(nId->flags() & ~Qt::ItemIsEditable);
|
||||
tw_->setItem(row, 0, nId);
|
||||
|
||||
auto* rIdItem = new QTableWidgetItem(QString::number(record_.id));
|
||||
rIdItem->setFlags(rIdItem->flags() & ~Qt::ItemIsEditable);
|
||||
|
||||
tw_->setItem(row, 1, rIdItem);
|
||||
tw_->setItem(row, 2, new QTableWidgetItem(QString::number(amount, 'f', 2)));
|
||||
|
||||
auto* dateCur = new QTableWidgetItem(currentDateTime);
|
||||
dateCur->setFlags(dateCur->flags() & ~Qt::ItemIsEditable);
|
||||
|
||||
tw_->setItem(row, 3, dateCur);
|
||||
tw_->setItem(row, 4, new QTableWidgetItem(""));
|
||||
|
||||
tw_->resizeRowToContents(row);
|
||||
tw_->scrollToItem(tw_->item(row, 0));
|
||||
});
|
||||
menu.addAction(acAdd);
|
||||
menu.exec(tw_->viewport()->mapToGlobal(pos));
|
||||
return;
|
||||
}
|
||||
if (selectedItems.size() == 5) {
|
||||
QAction* acDel = new QAction("删除", this);
|
||||
QMenu menu(this);
|
||||
connect(acDel, &QAction::triggered, this, [this, selectedItems]() {
|
||||
auto strId = selectedItems[0]->text();
|
||||
if (strId.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
int id = strId.toInt();
|
||||
// 确认
|
||||
if (QMessageBox::No == QMessageBox::question(this, "删除", "确定删除吗?")) {
|
||||
return;
|
||||
}
|
||||
if (!repaySqlOpr_->deleteRepayRecord(id)) {
|
||||
QMessageBox::critical(this, "错误", "删除失败");
|
||||
return;
|
||||
}
|
||||
tw_->removeRow(selectedItems[0]->row());
|
||||
});
|
||||
menu.addAction(acDel);
|
||||
menu.exec(tw_->viewport()->mapToGlobal(pos));
|
||||
}
|
||||
}
|
||||
void Repayment::Save()
|
||||
{
|
||||
int rowCount = tw_->rowCount();
|
||||
if (rowCount < 1) {
|
||||
return;
|
||||
}
|
||||
for (int row = 0; row < rowCount; ++row) {
|
||||
auto* id = tw_->item(row, 0);
|
||||
auto* rId = tw_->item(row, 1);
|
||||
auto* amount = tw_->item(row, 2);
|
||||
auto* date = tw_->item(row, 3);
|
||||
auto* note = tw_->item(row, 4);
|
||||
|
||||
auto idText = id->text();
|
||||
if (idText.isEmpty()) {
|
||||
RepayRecord rd;
|
||||
rd.dt = date->text().toStdString();
|
||||
rd.accID = record_.id;
|
||||
rd.money = Util::CashInt(amount->text().toDouble());
|
||||
rd.remark = note->text().toStdString();
|
||||
if (!repaySqlOpr_->InsertRepayRecord(rd)) {
|
||||
QMessageBox::critical(this, "错误", "添加还款记录失败");
|
||||
return;
|
||||
}
|
||||
id->setText(QString::number(rd.id));
|
||||
} else {
|
||||
RepayRecord rd;
|
||||
rd.id = idText.toInt();
|
||||
rd.dt = date->text().toStdString();
|
||||
rd.accID = record_.id;
|
||||
rd.money = Util::CashInt(amount->text().toDouble());
|
||||
rd.remark = note->text().toStdString();
|
||||
if (!repaySqlOpr_->updateRepayRecord(rd)) {
|
||||
QMessageBox::critical(this, "错误", "更新还款记录失败");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QMessageBox::information(this, "提示", "保存成功");
|
||||
}
|
||||
|
||||
void Repayment::BasicAnasys(const RepayRecordList& rList)
|
||||
{
|
||||
int32_t total{};
|
||||
for (const auto& rd : rList) {
|
||||
total += rd.money;
|
||||
}
|
||||
if (total >= record_.money) {
|
||||
ui->edResult->setText("剩余" + QString::number(Util::CashDouble(total - record_.money)) + "元,已还清。");
|
||||
} else {
|
||||
ui->edResult->setText("剩余" + QString::number(Util::CashDouble(record_.money - total)) + "元,未还清。");
|
||||
}
|
||||
}
|
||||
41
repayment.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef REPAYMENT_H
|
||||
#define REPAYMENT_H
|
||||
|
||||
#include "SqlOpr.h"
|
||||
#include <QDialog>
|
||||
#include <QTableWidget>
|
||||
|
||||
namespace Ui {
|
||||
class Repayment;
|
||||
}
|
||||
|
||||
class Repayment : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Repayment(QWidget* parent, std::unique_ptr<RepaySqlOpr>& repaySqlOpr);
|
||||
~Repayment();
|
||||
|
||||
public:
|
||||
int exec() override;
|
||||
void SetInformation(const QString& info);
|
||||
void SetRecord(const AccountRecord& record);
|
||||
|
||||
private:
|
||||
void ShowData();
|
||||
void Init();
|
||||
void ShowContextMenu(const QPoint& pos);
|
||||
void Save();
|
||||
void BasicAnasys(const RepayRecordList& rList);
|
||||
|
||||
private:
|
||||
bool over_{};
|
||||
QString info_;
|
||||
Ui::Repayment* ui;
|
||||
AccountRecord record_;
|
||||
QTableWidget* tw_{};
|
||||
std::unique_ptr<RepaySqlOpr>& repaySqlOpr_;
|
||||
};
|
||||
|
||||
#endif // REPAYMENT_H
|
||||
86
repayment.ui
Normal file
@@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Repayment</class>
|
||||
<widget class="QDialog" name="Repayment">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>476</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>统计</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="lbInfo">
|
||||
<property name="text">
|
||||
<string>NULL</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>总白条:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="edPay"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>结果:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="edResult"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnSave">
|
||||
<property name="text">
|
||||
<string>保存</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>详情</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
5
res.qrc
Normal file
@@ -0,0 +1,5 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>resource/ico.ico</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
1
resource/SimpleAccount.rc
Normal file
@@ -0,0 +1 @@
|
||||
IDI_APP_ICON ICON "ico.ico"
|
||||
BIN
resource/ico.ico
Normal file
|
After Width: | Height: | Size: 66 KiB |
28
resource/qss.qrc
Normal file
@@ -0,0 +1,28 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>qss/flatgray.css</file>
|
||||
<file>qss/flatgray/add_bottom.png</file>
|
||||
<file>qss/flatgray/add_left.png</file>
|
||||
<file>qss/flatgray/add_right.png</file>
|
||||
<file>qss/flatgray/add_top.png</file>
|
||||
<file>qss/flatgray/arrow_bottom.png</file>
|
||||
<file>qss/flatgray/arrow_left.png</file>
|
||||
<file>qss/flatgray/arrow_right.png</file>
|
||||
<file>qss/flatgray/arrow_top.png</file>
|
||||
<file>qss/flatgray/branch_close.png</file>
|
||||
<file>qss/flatgray/branch_open.png</file>
|
||||
<file>qss/flatgray/calendar_nextmonth.png</file>
|
||||
<file>qss/flatgray/calendar_prevmonth.png</file>
|
||||
<file>qss/flatgray/checkbox_checked.png</file>
|
||||
<file>qss/flatgray/checkbox_checked_disable.png</file>
|
||||
<file>qss/flatgray/checkbox_parcial.png</file>
|
||||
<file>qss/flatgray/checkbox_parcial_disable.png</file>
|
||||
<file>qss/flatgray/checkbox_unchecked.png</file>
|
||||
<file>qss/flatgray/checkbox_unchecked_disable.png</file>
|
||||
<file>qss/flatgray/menu_checked.png</file>
|
||||
<file>qss/flatgray/radiobutton_checked.png</file>
|
||||
<file>qss/flatgray/radiobutton_checked_disable.png</file>
|
||||
<file>qss/flatgray/radiobutton_unchecked.png</file>
|
||||
<file>qss/flatgray/radiobutton_unchecked_disable.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
694
resource/qss/flatgray.css
Normal file
@@ -0,0 +1,694 @@
|
||||
QPalette{background:#FFFFFF;}*{outline:0px;color:#57595B;}
|
||||
|
||||
QGraphicsView{
|
||||
border:1px solid #B6B6B6;
|
||||
qproperty-backgroundBrush:#FFFFFF;
|
||||
}
|
||||
|
||||
QWidget[form="true"],QLabel[frameShape="1"]{
|
||||
border:1px solid #B6B6B6;
|
||||
border-radius:0px;
|
||||
}
|
||||
|
||||
QWidget[form="bottom"]{
|
||||
background:#E4E4E4;
|
||||
}
|
||||
|
||||
QWidget[form="bottom"] .QFrame{
|
||||
border:1px solid #57595B;
|
||||
}
|
||||
|
||||
QWidget[form="bottom"] QLabel,QWidget[form="title"] QLabel{
|
||||
border-radius:0px;
|
||||
color:#57595B;
|
||||
background:none;
|
||||
border-style:none;
|
||||
}
|
||||
|
||||
QWidget[form="title"],QWidget[nav="left"],QWidget[nav="top"] QAbstractButton{
|
||||
border-style:none;
|
||||
border-radius:0px;
|
||||
padding:5px;
|
||||
color:#57595B;
|
||||
background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 #E4E4E4,stop:1 #E4E4E4);
|
||||
}
|
||||
|
||||
QWidget[nav="top"] QAbstractButton:hover,QWidget[nav="top"] QAbstractButton:pressed,QWidget[nav="top"] QAbstractButton:checked{
|
||||
border-style:solid;
|
||||
border-width:0px 0px 2px 0px;
|
||||
padding:4px 4px 2px 4px;
|
||||
border-color:#575959;
|
||||
background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 #F6F6F6,stop:1 #F6F6F6);
|
||||
}
|
||||
|
||||
QWidget[nav="left"] QAbstractButton{
|
||||
border-radius:0px;
|
||||
color:#57595B;
|
||||
background:none;
|
||||
border-style:none;
|
||||
}
|
||||
|
||||
QWidget[nav="left"] QAbstractButton:hover{
|
||||
color:#FFFFFF;
|
||||
background-color:#575959;
|
||||
}
|
||||
|
||||
QWidget[nav="left"] QAbstractButton:checked,QWidget[nav="left"] QAbstractButton:pressed{
|
||||
color:#57595B;
|
||||
border-style:solid;
|
||||
border-width:0px 0px 0px 2px;
|
||||
padding:4px 4px 4px 2px;
|
||||
border-color:#575959;
|
||||
background-color:#FFFFFF;
|
||||
}
|
||||
|
||||
QWidget[video="true"] QLabel{
|
||||
color:#57595B;
|
||||
border:1px solid #B6B6B6;
|
||||
background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 #E4E4E4,stop:1 #E4E4E4);
|
||||
}
|
||||
|
||||
QWidget[video="true"] QLabel:focus{
|
||||
border:1px solid #575959;
|
||||
background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 #F6F6F6,stop:1 #F6F6F6);
|
||||
}
|
||||
|
||||
QLineEdit:read-only{
|
||||
background-color:#E4E4E4;
|
||||
}
|
||||
|
||||
QLineEdit,QTextEdit,QPlainTextEdit,QSpinBox,QDoubleSpinBox,QComboBox,QDateEdit,QTimeEdit,QDateTimeEdit{
|
||||
border:1px solid #B6B6B6;
|
||||
border-radius:3px;
|
||||
padding:2px;
|
||||
background:none;
|
||||
selection-background-color:#575959;
|
||||
selection-color:#FFFFFF;
|
||||
}
|
||||
|
||||
QLineEdit:focus,QTextEdit:focus,QPlainTextEdit:focus,QSpinBox:focus,QDoubleSpinBox:focus,QComboBox:focus,QDateEdit:focus,QTimeEdit:focus,QDateTimeEdit:focus,QLineEdit:hover,QTextEdit:hover,QPlainTextEdit:hover,QSpinBox:hover,QDoubleSpinBox:hover,QComboBox:hover,QDateEdit:hover,QTimeEdit:hover,QDateTimeEdit:hover{
|
||||
border:1px solid #B6B6B6;
|
||||
}
|
||||
|
||||
QLineEdit[echoMode="2"]{
|
||||
lineedit-password-character:9679;
|
||||
}
|
||||
|
||||
.QFrame{
|
||||
border:1px solid #B6B6B6;
|
||||
border-radius:3px;
|
||||
}
|
||||
|
||||
.QGroupBox{
|
||||
border:1px solid #B6B6B6;
|
||||
border-radius:5px;
|
||||
margin-top:9px;
|
||||
}
|
||||
|
||||
.QGroupBox::title{
|
||||
subcontrol-origin:margin;
|
||||
position:relative;
|
||||
left:10px;
|
||||
}
|
||||
|
||||
.QPushButton,.QToolButton{
|
||||
border-style:none;
|
||||
border:1px solid #B6B6B6;
|
||||
color:#57595B;
|
||||
padding:5px;
|
||||
min-height:15px;
|
||||
border-radius:5px;
|
||||
background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 #E4E4E4,stop:1 #E4E4E4);
|
||||
}
|
||||
|
||||
.QPushButton:hover,.QToolButton:hover{
|
||||
background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 #F6F6F6,stop:1 #F6F6F6);
|
||||
}
|
||||
|
||||
.QPushButton:pressed,.QToolButton:pressed{
|
||||
background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 #E4E4E4,stop:1 #E4E4E4);
|
||||
}
|
||||
|
||||
.QToolButton::menu-indicator{
|
||||
image:None;
|
||||
}
|
||||
|
||||
QToolButton#btnMenu,QPushButton#btnMenu_Min,QPushButton#btnMenu_Max,QPushButton#btnMenu_Close{
|
||||
border-radius:3px;
|
||||
color:#57595B;
|
||||
padding:3px;
|
||||
margin:0px;
|
||||
background:none;
|
||||
border-style:none;
|
||||
}
|
||||
|
||||
QToolButton#btnMenu:hover,QPushButton#btnMenu_Min:hover,QPushButton#btnMenu_Max:hover{
|
||||
color:#FFFFFF;
|
||||
margin:1px 1px 2px 1px;
|
||||
background-color:rgba(51,127,209,230);
|
||||
}
|
||||
|
||||
QPushButton#btnMenu_Close:hover{
|
||||
color:#FFFFFF;
|
||||
margin:1px 1px 2px 1px;
|
||||
background-color:rgba(238,0,0,128);
|
||||
}
|
||||
|
||||
QRadioButton::indicator{
|
||||
width:15px;
|
||||
height:15px;
|
||||
}
|
||||
|
||||
QRadioButton::indicator::unchecked{
|
||||
image:url(:/qss/flatgray/radiobutton_unchecked.png);
|
||||
}
|
||||
|
||||
QRadioButton::indicator::unchecked:disabled{
|
||||
image:url(:/qss/flatgray/radiobutton_unchecked_disable.png);
|
||||
}
|
||||
|
||||
QRadioButton::indicator::checked{
|
||||
image:url(:/qss/flatgray/radiobutton_checked.png);
|
||||
}
|
||||
|
||||
QRadioButton::indicator::checked:disabled{
|
||||
image:url(:/qss/flatgray/radiobutton_checked_disable.png);
|
||||
}
|
||||
|
||||
QGroupBox::indicator,QTreeView::indicator,QListView::indicator,QTableView::indicator{
|
||||
padding:0px 0px 0px 0px;
|
||||
}
|
||||
|
||||
QCheckBox::indicator,QGroupBox::indicator,QTreeView::indicator,QListView::indicator,QTableView::indicator{
|
||||
width:13px;
|
||||
height:13px;
|
||||
}
|
||||
|
||||
QCheckBox::indicator:unchecked,QGroupBox::indicator:unchecked,QTreeView::indicator:unchecked,QListView::indicator:unchecked,QTableView::indicator:unchecked{
|
||||
image:url(:/qss/flatgray/checkbox_unchecked.png);
|
||||
}
|
||||
|
||||
QCheckBox::indicator:unchecked:disabled,QGroupBox::indicator:unchecked:disabled,QTreeView::indicator:unchecked:disabled,QListView::indicator:unchecked:disabled,QTableView::indicator:unchecked:disabled{
|
||||
image:url(:/qss/flatgray/checkbox_unchecked_disable.png);
|
||||
}
|
||||
|
||||
QCheckBox::indicator:checked,QGroupBox::indicator:checked,QTreeView::indicator:checked,QListView::indicator:checked,QTableView::indicator:checked{
|
||||
image:url(:/qss/flatgray/checkbox_checked.png);
|
||||
}
|
||||
|
||||
QCheckBox::indicator:checked:disabled,QGroupBox::indicator:checked:disabled,QTreeView::indicator:checked:disabled,QListView::indicator:checked:disabled,QTableView::indicator:checked:disabled{
|
||||
image:url(:/qss/flatgray/checkbox_checked_disable.png);
|
||||
}
|
||||
|
||||
QCheckBox::indicator:indeterminate,QGroupBox::indicator:indeterminate,QTreeView::indicator:indeterminate,QListView::indicator:indeterminate,QTableView::indicator:indeterminate{
|
||||
image:url(:/qss/flatgray/checkbox_parcial.png);
|
||||
}
|
||||
|
||||
QCheckBox::indicator:indeterminate:disabled,QGroupBox::indicator:indeterminate:disabled,QTreeView::indicator:indeterminate:disabled,QListView::indicator:indeterminate:disabled,QTableView::indicator:indeterminate:disabled{
|
||||
image:url(:/qss/flatgray/checkbox_parcial_disable.png);
|
||||
}
|
||||
|
||||
QTimeEdit::up-button,QDateEdit::up-button,QDateTimeEdit::up-button,QDoubleSpinBox::up-button,QSpinBox::up-button{
|
||||
image:url(:/qss/flatgray/add_top.png);
|
||||
width:10px;
|
||||
height:10px;
|
||||
padding:2px 5px 0px 0px;
|
||||
}
|
||||
|
||||
QTimeEdit::down-button,QDateEdit::down-button,QDateTimeEdit::down-button,QDoubleSpinBox::down-button,QSpinBox::down-button{
|
||||
image:url(:/qss/flatgray/add_bottom.png);
|
||||
width:10px;
|
||||
height:10px;
|
||||
padding:0px 5px 2px 0px;
|
||||
}
|
||||
|
||||
QTimeEdit::up-button:pressed,QDateEdit::up-button:pressed,QDateTimeEdit::up-button:pressed,QDoubleSpinBox::up-button:pressed,QSpinBox::up-button:pressed{
|
||||
top:-2px;
|
||||
}
|
||||
|
||||
QTimeEdit::down-button:pressed,QDateEdit::down-button:pressed,QDateTimeEdit::down-button:pressed,QDoubleSpinBox::down-button:pressed,QSpinBox::down-button:pressed,QSpinBox::down-button:pressed{
|
||||
bottom:-2px;
|
||||
}
|
||||
|
||||
QComboBox::down-arrow,QDateEdit[calendarPopup="true"]::down-arrow,QTimeEdit[calendarPopup="true"]::down-arrow,QDateTimeEdit[calendarPopup="true"]::down-arrow{
|
||||
image:url(:/qss/flatgray/add_bottom.png);
|
||||
width:10px;
|
||||
height:10px;
|
||||
right:2px;
|
||||
}
|
||||
|
||||
QComboBox::drop-down,QDateEdit::drop-down,QTimeEdit::drop-down,QDateTimeEdit::drop-down{
|
||||
subcontrol-origin:padding;
|
||||
subcontrol-position:top right;
|
||||
width:15px;
|
||||
border-left-width:0px;
|
||||
border-left-style:solid;
|
||||
border-top-right-radius:3px;
|
||||
border-bottom-right-radius:3px;
|
||||
border-left-color:#B6B6B6;
|
||||
}
|
||||
|
||||
QComboBox::drop-down:on{
|
||||
top:1px;
|
||||
}
|
||||
|
||||
QMenuBar::item{
|
||||
color:#57595B;
|
||||
background-color:#E4E4E4;
|
||||
margin:0px;
|
||||
padding:3px 10px;
|
||||
}
|
||||
|
||||
QMenu,QMenuBar,QMenu:disabled,QMenuBar:disabled{
|
||||
color:#57595B;
|
||||
background-color:#E4E4E4;
|
||||
border:1px solid #B6B6B6;
|
||||
margin:0px;
|
||||
}
|
||||
|
||||
QMenu::item{
|
||||
padding:3px 20px;
|
||||
}
|
||||
|
||||
QMenu::indicator{
|
||||
width:20px;
|
||||
height:13px;
|
||||
}
|
||||
|
||||
QMenu::indicator::checked{
|
||||
image:url(:/qss/flatgray/menu_checked.png);
|
||||
}
|
||||
|
||||
QMenu::right-arrow{
|
||||
image:url(:/qss/flatgray/arrow_right.png);
|
||||
width:13px;
|
||||
height:13px;
|
||||
padding:0px 3px 0px 0px;
|
||||
}
|
||||
|
||||
QMenu::item:selected,QMenuBar::item:selected{
|
||||
color:#57595B;
|
||||
border:0px solid #B6B6B6;
|
||||
background:#F6F6F6;
|
||||
}
|
||||
|
||||
QMenu::separator{
|
||||
height:1px;
|
||||
background:#B6B6B6;
|
||||
}
|
||||
|
||||
QProgressBar{
|
||||
min-height:10px;
|
||||
background:#E4E4E4;
|
||||
border-radius:5px;
|
||||
text-align:center;
|
||||
border:1px solid #E4E4E4;
|
||||
}
|
||||
|
||||
QProgressBar:chunk{
|
||||
border-radius:5px;
|
||||
background-color:#B6B6B6;
|
||||
}
|
||||
|
||||
QSlider::groove:horizontal{
|
||||
height:8px;
|
||||
border-radius:4px;
|
||||
background:#E4E4E4;
|
||||
}
|
||||
|
||||
QSlider::add-page:horizontal{
|
||||
height:8px;
|
||||
border-radius:4px;
|
||||
background:#E4E4E4;
|
||||
}
|
||||
|
||||
QSlider::sub-page:horizontal{
|
||||
height:8px;
|
||||
border-radius:4px;
|
||||
background:#B6B6B6;
|
||||
}
|
||||
|
||||
QSlider::handle:horizontal{
|
||||
width:13px;
|
||||
margin-top:-3px;
|
||||
margin-bottom:-3px;
|
||||
border-radius:6px;
|
||||
background:qradialgradient(spread:pad,cx:0.5,cy:0.5,radius:0.5,fx:0.5,fy:0.5,stop:0.6 #FFFFFF,stop:0.8 #B6B6B6);
|
||||
}
|
||||
|
||||
QSlider::groove:vertical{
|
||||
width:8px;
|
||||
border-radius:4px;
|
||||
background:#E4E4E4;
|
||||
}
|
||||
|
||||
QSlider::add-page:vertical{
|
||||
width:8px;
|
||||
border-radius:4px;
|
||||
background:#B6B6B6;
|
||||
}
|
||||
|
||||
QSlider::sub-page:vertical{
|
||||
width:8px;
|
||||
border-radius:4px;
|
||||
background:#E4E4E4;
|
||||
}
|
||||
|
||||
QSlider::handle:vertical{
|
||||
height:14px;
|
||||
margin-left:-3px;
|
||||
margin-right:-3px;
|
||||
border-radius:6px;
|
||||
background:qradialgradient(spread:pad,cx:0.5,cy:0.5,radius:0.5,fx:0.5,fy:0.5,stop:0.6 #FFFFFF,stop:0.8 #B6B6B6);
|
||||
}
|
||||
|
||||
QScrollBar:horizontal{
|
||||
background:#E4E4E4;
|
||||
padding:0px;
|
||||
border-radius:6px;
|
||||
max-height:12px;
|
||||
}
|
||||
|
||||
QScrollBar::handle:horizontal{
|
||||
background:#B6B6B6;
|
||||
min-width:50px;
|
||||
border-radius:6px;
|
||||
}
|
||||
|
||||
QScrollBar::handle:horizontal:hover{
|
||||
background:#575959;
|
||||
}
|
||||
|
||||
QScrollBar::handle:horizontal:pressed{
|
||||
background:#575959;
|
||||
}
|
||||
|
||||
QScrollBar::add-page:horizontal{
|
||||
background:none;
|
||||
}
|
||||
|
||||
QScrollBar::sub-page:horizontal{
|
||||
background:none;
|
||||
}
|
||||
|
||||
QScrollBar::add-line:horizontal{
|
||||
background:none;
|
||||
}
|
||||
|
||||
QScrollBar::sub-line:horizontal{
|
||||
background:none;
|
||||
}
|
||||
|
||||
QScrollBar:vertical{
|
||||
background:#E4E4E4;
|
||||
padding:0px;
|
||||
border-radius:6px;
|
||||
max-width:12px;
|
||||
}
|
||||
|
||||
QScrollBar::handle:vertical{
|
||||
background:#B6B6B6;
|
||||
min-height:50px;
|
||||
border-radius:6px;
|
||||
}
|
||||
|
||||
QScrollBar::handle:vertical:hover{
|
||||
background:#575959;
|
||||
}
|
||||
|
||||
QScrollBar::handle:vertical:pressed{
|
||||
background:#575959;
|
||||
}
|
||||
|
||||
QScrollBar::add-page:vertical{
|
||||
background:none;
|
||||
}
|
||||
|
||||
QScrollBar::sub-page:vertical{
|
||||
background:none;
|
||||
}
|
||||
|
||||
QScrollBar::add-line:vertical{
|
||||
background:none;
|
||||
}
|
||||
|
||||
QScrollBar::sub-line:vertical{
|
||||
background:none;
|
||||
}
|
||||
|
||||
QScrollArea{
|
||||
border:0px;
|
||||
}
|
||||
|
||||
QTreeView,QListView,QTableView,QTabWidget::pane{
|
||||
border:1px solid #B6B6B6;
|
||||
selection-background-color:#F6F6F6;
|
||||
selection-color:#57595B;
|
||||
alternate-background-color:#F6F6F6;
|
||||
gridline-color:#B6B6B6;
|
||||
}
|
||||
|
||||
QTreeView::branch:closed:has-children{
|
||||
margin:4px;
|
||||
border-image:url(:/qss/flatgray/branch_open.png);
|
||||
}
|
||||
|
||||
QTreeView::branch:open:has-children{
|
||||
margin:4px;
|
||||
border-image:url(:/qss/flatgray/branch_close.png);
|
||||
}
|
||||
|
||||
QTreeView,QListView,QTableView,QSplitter::handle,QTreeView::branch{
|
||||
background:#FFFFFF;
|
||||
}
|
||||
|
||||
QTableView::item:selected,QListView::item:selected,QTreeView::item:selected{
|
||||
color:#57595B;
|
||||
background:#E4E4E4;
|
||||
}
|
||||
|
||||
QTableView::item:hover,QListView::item:hover,QTreeView::item:hover,QHeaderView,QHeaderView::section,QTableCornerButton:section{
|
||||
color:#57595B;
|
||||
background:#F6F6F6;
|
||||
}
|
||||
|
||||
QTableView::item,QListView::item,QTreeView::item{
|
||||
padding:1px;
|
||||
margin:0px;
|
||||
border:0px;
|
||||
}
|
||||
|
||||
QHeaderView::section,QTableCornerButton:section{
|
||||
padding:3px;
|
||||
margin:0px;
|
||||
border:1px solid #B6B6B6;
|
||||
border-left-width:0px;
|
||||
border-right-width:1px;
|
||||
border-top-width:0px;
|
||||
border-bottom-width:1px;
|
||||
}
|
||||
|
||||
QTabBar::tab{
|
||||
border:1px solid #B6B6B6;
|
||||
color:#57595B;
|
||||
margin:0px;
|
||||
background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 #F6F6F6,stop:1 #F6F6F6);
|
||||
}
|
||||
|
||||
QTabBar::tab:selected{
|
||||
border-style:solid;
|
||||
border-color:#575959;
|
||||
background:#FFFFFF;
|
||||
}
|
||||
|
||||
QTabBar::tab:top,QTabBar::tab:bottom{
|
||||
padding:3px 8px 3px 8px;
|
||||
}
|
||||
|
||||
QTabBar::tab:left,QTabBar::tab:right{
|
||||
padding:8px 3px 8px 3px;
|
||||
}
|
||||
|
||||
QTabBar::tab:top:selected{
|
||||
border-width:2px 0px 0px 0px;
|
||||
}
|
||||
|
||||
QTabBar::tab:right:selected{
|
||||
border-width:0px 0px 0px 2px;
|
||||
}
|
||||
|
||||
QTabBar::tab:bottom:selected{
|
||||
border-width:0px 0px 2px 0px;
|
||||
}
|
||||
|
||||
QTabBar::tab:left:selected{
|
||||
border-width:0px 2px 0px 0px;
|
||||
}
|
||||
|
||||
QTabBar::tab:first:top:selected,QTabBar::tab:first:bottom:selected{
|
||||
border-left-width:1px;
|
||||
border-left-color:#B6B6B6;
|
||||
}
|
||||
|
||||
QTabBar::tab:first:left:selected,QTabBar::tab:first:right:selected{
|
||||
border-top-width:1px;
|
||||
border-top-color:#B6B6B6;
|
||||
}
|
||||
|
||||
QTabBar::tab:last:top:selected,QTabBar::tab:last:bottom:selected{
|
||||
border-right-width:1px;
|
||||
border-right-color:#B6B6B6;
|
||||
}
|
||||
|
||||
QTabBar::tab:last:left:selected,QTabBar::tab:last:right:selected{
|
||||
border-bottom-width:1px;
|
||||
border-bottom-color:#B6B6B6;
|
||||
}
|
||||
|
||||
QStatusBar::item{
|
||||
border:0px solid #E4E4E4;
|
||||
border-radius:3px;
|
||||
}
|
||||
|
||||
QToolBox::tab,QWidget[form="panel"]{
|
||||
padding:3px;
|
||||
border-radius:5px;
|
||||
color:#57595B;
|
||||
background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 #E4E4E4,stop:1 #E4E4E4);
|
||||
}
|
||||
|
||||
QWidget[flag="paneltitle"]{
|
||||
border-bottom-left-radius:0px;
|
||||
border-bottom-right-radius:0px;
|
||||
}
|
||||
|
||||
QWidget[flag="panelcontrol"]{
|
||||
border-top-width:0px;
|
||||
border-top-left-radius:0px;
|
||||
border-top-right-radius:0px;
|
||||
}
|
||||
|
||||
QToolTip{
|
||||
border:0px solid #57595B;
|
||||
padding:1px;
|
||||
color:#57595B;
|
||||
background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 #E4E4E4,stop:1 #E4E4E4);
|
||||
}
|
||||
|
||||
QToolBox::tab:selected{
|
||||
background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 #F6F6F6,stop:1 #F6F6F6);
|
||||
}
|
||||
|
||||
QPrintPreviewDialog QToolButton{
|
||||
border:0px solid #57595B;
|
||||
border-radius:0px;
|
||||
margin:0px;
|
||||
padding:3px;
|
||||
background:none;
|
||||
}
|
||||
|
||||
QColorDialog QPushButton,QFileDialog QPushButton{
|
||||
min-width:80px;
|
||||
}
|
||||
|
||||
QToolButton#qt_calendar_prevmonth{
|
||||
icon-size:0px;
|
||||
min-width:20px;
|
||||
image:url(:/qss/flatgray/calendar_prevmonth.png);
|
||||
}
|
||||
|
||||
QToolButton#qt_calendar_nextmonth{
|
||||
icon-size:0px;
|
||||
min-width:20px;
|
||||
image:url(:/qss/flatgray/calendar_nextmonth.png);
|
||||
}
|
||||
|
||||
QToolButton#qt_calendar_prevmonth,QToolButton#qt_calendar_nextmonth,QToolButton#qt_calendar_monthbutton,QToolButton#qt_calendar_yearbutton{
|
||||
border:0px solid #57595B;
|
||||
border-radius:3px;
|
||||
margin:3px 3px 3px 3px;
|
||||
padding:3px;
|
||||
background:none;
|
||||
}
|
||||
|
||||
QToolButton#qt_calendar_prevmonth:hover,QToolButton#qt_calendar_nextmonth:hover,QToolButton#qt_calendar_monthbutton:hover,QToolButton#qt_calendar_yearbutton:hover,QToolButton#qt_calendar_prevmonth:pressed,QToolButton#qt_calendar_nextmonth:pressed,QToolButton#qt_calendar_monthbutton:pressed,QToolButton#qt_calendar_yearbutton:pressed{
|
||||
border:1px solid #B6B6B6;
|
||||
}
|
||||
|
||||
QCalendarWidget QSpinBox#qt_calendar_yearedit{
|
||||
margin:2px;
|
||||
}
|
||||
|
||||
QCalendarWidget QToolButton::menu-indicator{
|
||||
image:None;
|
||||
}
|
||||
|
||||
QCalendarWidget QTableView{
|
||||
border-width:0px;
|
||||
}
|
||||
|
||||
QCalendarWidget QWidget#qt_calendar_navigationbar{
|
||||
border:1px solid #B6B6B6;
|
||||
border-width:1px 1px 0px 1px;
|
||||
background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 #E4E4E4,stop:1 #E4E4E4);
|
||||
}
|
||||
|
||||
QTableView[model="true"]::item{
|
||||
padding:0px;
|
||||
margin:0px;
|
||||
}
|
||||
|
||||
QTableView QLineEdit,QTableView QComboBox,QTableView QSpinBox,QTableView QDoubleSpinBox,QTableView QDateEdit,QTableView QTimeEdit,QTableView QDateTimeEdit{
|
||||
border-width:0px;
|
||||
border-radius:0px;
|
||||
}
|
||||
|
||||
QTableView QLineEdit:focus,QTableView QComboBox:focus,QTableView QSpinBox:focus,QTableView QDoubleSpinBox:focus,QTableView QDateEdit:focus,QTableView QTimeEdit:focus,QTableView QDateTimeEdit:focus{
|
||||
border-width:0px;
|
||||
border-radius:0px;
|
||||
}
|
||||
|
||||
QLineEdit,QTextEdit,QPlainTextEdit,QSpinBox,QDoubleSpinBox,QComboBox,QDateEdit,QTimeEdit,QDateTimeEdit{
|
||||
background:#FFFFFF;
|
||||
}
|
||||
|
||||
QTabWidget::pane:top{top:-1px;}
|
||||
QTabWidget::pane:bottom{bottom:-1px;}
|
||||
QTabWidget::pane:left{right:-1px;}
|
||||
QTabWidget::pane:right{left:-1px;}
|
||||
|
||||
QDialog,QDial,#QUIWidgetMain{
|
||||
background-color:#FFFFFF;
|
||||
color:#57595B;
|
||||
}
|
||||
|
||||
QDialogButtonBox>QPushButton{
|
||||
min-width:50px;
|
||||
}
|
||||
|
||||
QListView[noborder="true"],QTreeView[noborder="true"],QTabWidget[noborder="true"]::pane{
|
||||
border-width:0px;
|
||||
}
|
||||
|
||||
QToolBar>*,QStatusBar>*{
|
||||
margin:2px;
|
||||
}
|
||||
|
||||
*:disabled,QMenu::item:disabled,QTabBar:tab:disabled,QHeaderView::section:disabled{
|
||||
background:#FFFFFF;
|
||||
border-color:#E4E4E4;
|
||||
color:#B6B6B6;
|
||||
}
|
||||
|
||||
QLabel:disabled{
|
||||
background:none;
|
||||
}
|
||||
|
||||
/*TextColor:#57595B*/
|
||||
/*PanelColor:#FFFFFF*/
|
||||
/*BorderColor:#B6B6B6*/
|
||||
/*NormalColorStart:#E4E4E4*/
|
||||
/*NormalColorEnd:#E4E4E4*/
|
||||
/*DarkColorStart:#F6F6F6*/
|
||||
/*DarkColorEnd:#F6F6F6*/
|
||||
/*HighColor:#575959*/
|
||||
BIN
resource/qss/flatgray/add_bottom.png
Normal file
|
After Width: | Height: | Size: 336 B |
BIN
resource/qss/flatgray/add_left.png
Normal file
|
After Width: | Height: | Size: 370 B |
BIN
resource/qss/flatgray/add_right.png
Normal file
|
After Width: | Height: | Size: 358 B |
BIN
resource/qss/flatgray/add_top.png
Normal file
|
After Width: | Height: | Size: 332 B |
BIN
resource/qss/flatgray/arrow_bottom.png
Normal file
|
After Width: | Height: | Size: 337 B |
BIN
resource/qss/flatgray/arrow_left.png
Normal file
|
After Width: | Height: | Size: 376 B |
BIN
resource/qss/flatgray/arrow_right.png
Normal file
|
After Width: | Height: | Size: 360 B |
BIN
resource/qss/flatgray/arrow_top.png
Normal file
|
After Width: | Height: | Size: 361 B |
BIN
resource/qss/flatgray/branch_close.png
Normal file
|
After Width: | Height: | Size: 263 B |
BIN
resource/qss/flatgray/branch_open.png
Normal file
|
After Width: | Height: | Size: 444 B |
BIN
resource/qss/flatgray/calendar_nextmonth.png
Normal file
|
After Width: | Height: | Size: 655 B |
BIN
resource/qss/flatgray/calendar_prevmonth.png
Normal file
|
After Width: | Height: | Size: 740 B |
BIN
resource/qss/flatgray/checkbox_checked.png
Normal file
|
After Width: | Height: | Size: 616 B |
BIN
resource/qss/flatgray/checkbox_checked_disable.png
Normal file
|
After Width: | Height: | Size: 639 B |
BIN
resource/qss/flatgray/checkbox_parcial.png
Normal file
|
After Width: | Height: | Size: 341 B |
BIN
resource/qss/flatgray/checkbox_parcial_disable.png
Normal file
|
After Width: | Height: | Size: 331 B |
BIN
resource/qss/flatgray/checkbox_unchecked.png
Normal file
|
After Width: | Height: | Size: 612 B |
BIN
resource/qss/flatgray/checkbox_unchecked_disable.png
Normal file
|
After Width: | Height: | Size: 646 B |
BIN
resource/qss/flatgray/menu_checked.png
Normal file
|
After Width: | Height: | Size: 542 B |
BIN
resource/qss/flatgray/radiobutton_checked.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
resource/qss/flatgray/radiobutton_checked_disable.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
resource/qss/flatgray/radiobutton_unchecked.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
resource/qss/flatgray/radiobutton_unchecked_disable.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
42
statistic.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
#include "statistic.h"
|
||||
#include "util.h"
|
||||
|
||||
Statistic::Statistic(std::unique_ptr<RepaySqlOpr>& repaySqlOpr) : repaySqlOpr_(repaySqlOpr)
|
||||
{
|
||||
}
|
||||
|
||||
Statistic::~Statistic()
|
||||
{
|
||||
}
|
||||
|
||||
void Statistic::Calculate(const AccountRecordList& list)
|
||||
{
|
||||
auto* d = SharedData::instance();
|
||||
d->ClearTt();
|
||||
|
||||
for (const auto& item : list) {
|
||||
if (item.payType == "现金支出") {
|
||||
d->ttCashOut_ += item.money;
|
||||
} else if (item.payType == "现金收入") {
|
||||
d->ttCashIn_ += item.money;
|
||||
} else if (item.payType == "信用支出") {
|
||||
d->ttCreditOut_ += item.money;
|
||||
RepayRecordList repayList;
|
||||
if (repaySqlOpr_->GetRepayResult(repayList, item.id)) {
|
||||
for (const auto& repay : repayList) {
|
||||
d->ttCashPay_ += repay.money;
|
||||
}
|
||||
}
|
||||
} else if (item.payType == "信用收入") {
|
||||
d->ttCreditIn_ += item.money;
|
||||
} else if (item.payType == "信用借款") {
|
||||
d->ttCreditCash_ += item.money;
|
||||
RepayRecordList repayList;
|
||||
if (repaySqlOpr_->GetRepayResult(repayList, item.id)) {
|
||||
for (const auto& repay : repayList) {
|
||||
d->ttCashPay_ += repay.money;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
19
statistic.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef STATISTIC_H
|
||||
#define STATISTIC_H
|
||||
|
||||
#include "SqlOpr.h"
|
||||
|
||||
class Statistic
|
||||
{
|
||||
public:
|
||||
Statistic(std::unique_ptr<RepaySqlOpr>& repaySqlOpr);
|
||||
~Statistic();
|
||||
|
||||
public:
|
||||
void Calculate(const AccountRecordList& list);
|
||||
|
||||
private:
|
||||
std::unique_ptr<RepaySqlOpr>& repaySqlOpr_;
|
||||
};
|
||||
|
||||
#endif // STATISTIC_H
|
||||
145
util.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
#include "util.h"
|
||||
#include <QDir>
|
||||
#include <QUuid>
|
||||
#include <fstream>
|
||||
|
||||
static std::string gConfigPath;
|
||||
static std::string gWorkDir;
|
||||
static nlohmann::json gConfig;
|
||||
|
||||
void GenerateDefaultConfig(const std::string& path)
|
||||
{
|
||||
nlohmann::json config;
|
||||
config["MainWidth"] = 1000;
|
||||
config["MainHeight"] = 600;
|
||||
config["Editor"] = "Notepad";
|
||||
config["MediaDir"] = "./Media";
|
||||
config["CurCash"] = 0;
|
||||
config["CurSave"] = 0;
|
||||
std::ofstream configFile(path);
|
||||
configFile << config.dump(4);
|
||||
configFile.close();
|
||||
gConfig = config;
|
||||
}
|
||||
|
||||
Util::Util()
|
||||
{
|
||||
}
|
||||
|
||||
bool Util::Init()
|
||||
{
|
||||
gWorkDir = QDir::homePath().toStdString() + "/.config/SimpleAccount";
|
||||
if (!QDir(QString::fromStdString(gWorkDir)).exists()) {
|
||||
QDir().mkdir(QString::fromStdString(gWorkDir));
|
||||
}
|
||||
gConfigPath = gWorkDir + "/config.json";
|
||||
return LoadConfig();
|
||||
}
|
||||
|
||||
std::string Util::GetWorkDir()
|
||||
{
|
||||
return gWorkDir;
|
||||
}
|
||||
|
||||
std::string Util::GetMediaDir()
|
||||
{
|
||||
return gConfig["MediaDir"].get<std::string>();
|
||||
}
|
||||
|
||||
std::string Util::GetConfigPath()
|
||||
{
|
||||
return gConfigPath;
|
||||
}
|
||||
|
||||
std::pair<int, int> Util::GetMainSize()
|
||||
{
|
||||
return std::make_pair(gConfig["MainWidth"].get<int>(), gConfig["MainHeight"].get<int>());
|
||||
}
|
||||
|
||||
bool Util::SetMainSize(int w, int h)
|
||||
{
|
||||
LoadConfig();
|
||||
|
||||
gConfig["MainWidth"] = w;
|
||||
gConfig["MainHeight"] = h;
|
||||
|
||||
std::ofstream configFile(gConfigPath);
|
||||
if (!configFile.is_open()) {
|
||||
return false;
|
||||
}
|
||||
configFile << gConfig.dump(4);
|
||||
configFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string Util::GetEditor()
|
||||
{
|
||||
return gConfig["Editor"].get<std::string>();
|
||||
}
|
||||
|
||||
QString Util::NewUUIDName(const QString& path)
|
||||
{
|
||||
QFileInfo fileInfo(path);
|
||||
QString originalSuffix = fileInfo.suffix();
|
||||
QString newName = QUuid::createUuid().toString(QUuid::WithoutBraces);
|
||||
if (!originalSuffix.isEmpty()) {
|
||||
newName += "." + originalSuffix;
|
||||
}
|
||||
return newName;
|
||||
}
|
||||
|
||||
double Util::GetCurCash()
|
||||
{
|
||||
return gConfig["CurCash"].get<double>();
|
||||
}
|
||||
|
||||
double Util::GetCurSave()
|
||||
{
|
||||
return gConfig["CurSave"].get<double>();
|
||||
}
|
||||
|
||||
int Util::CashInt(double cash)
|
||||
{
|
||||
return static_cast<int32_t>(round(cash * 100));
|
||||
}
|
||||
|
||||
double Util::CashDouble(int cash)
|
||||
{
|
||||
return static_cast<double>(cash) / 100.0;
|
||||
}
|
||||
|
||||
bool Util::LoadConfig()
|
||||
{
|
||||
QFile file(QString::fromStdString(gConfigPath));
|
||||
if (file.exists()) {
|
||||
std::ifstream configFile(gConfigPath);
|
||||
if (!configFile.is_open()) {
|
||||
return false;
|
||||
}
|
||||
gConfig = nlohmann::json::parse(configFile);
|
||||
configFile.close();
|
||||
} else {
|
||||
GenerateDefaultConfig(gConfigPath);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
SharedData::~SharedData()
|
||||
{
|
||||
}
|
||||
|
||||
SharedData* SharedData::instance()
|
||||
{
|
||||
static SharedData data;
|
||||
return &data;
|
||||
}
|
||||
|
||||
void SharedData::ClearTt()
|
||||
{
|
||||
ttCashOut_ = 0;
|
||||
ttCashIn_ = 0;
|
||||
ttCreditIn_ = 0;
|
||||
ttCreditOut_ = 0;
|
||||
ttCreditCash_ = 0;
|
||||
ttCashPay_ = 0;
|
||||
}
|
||||
79
util.h
Normal file
@@ -0,0 +1,79 @@
|
||||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QString>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <string>
|
||||
|
||||
class Util
|
||||
{
|
||||
public:
|
||||
Util();
|
||||
|
||||
public:
|
||||
static bool Init();
|
||||
|
||||
public:
|
||||
static std::string GetWorkDir();
|
||||
static std::string GetMediaDir();
|
||||
static std::string GetConfigPath();
|
||||
static std::pair<int, int> GetMainSize();
|
||||
static bool SetMainSize(int w, int h);
|
||||
static std::string GetEditor();
|
||||
static QString NewUUIDName(const QString& path);
|
||||
static double GetCurCash();
|
||||
static double GetCurSave();
|
||||
static int CashInt(double cash);
|
||||
static double CashDouble(int cash);
|
||||
|
||||
private:
|
||||
static bool LoadConfig();
|
||||
};
|
||||
|
||||
enum CashFilter {
|
||||
FIL_NO_LIMIT = 0,
|
||||
FIL_LOWER,
|
||||
FIL_HIGHER,
|
||||
FIL_BETWEEN
|
||||
};
|
||||
|
||||
class SharedData
|
||||
{
|
||||
private:
|
||||
SharedData() = default;
|
||||
~SharedData();
|
||||
|
||||
public:
|
||||
static SharedData* instance();
|
||||
|
||||
// 条件
|
||||
public:
|
||||
bool flType{};
|
||||
QString type{};
|
||||
bool flDays{};
|
||||
bool flKeys{};
|
||||
bool flClassify{};
|
||||
QString classify{};
|
||||
QString key{};
|
||||
int days{};
|
||||
int lowMoney{};
|
||||
int highMoney{};
|
||||
CashFilter filter{};
|
||||
|
||||
public:
|
||||
void ClearTt();
|
||||
|
||||
// 结果
|
||||
public:
|
||||
int32_t ttCashOut_{};
|
||||
int32_t ttCashIn_{};
|
||||
int32_t ttCreditIn_{};
|
||||
int32_t ttCreditOut_{};
|
||||
int32_t ttCreditCash_{};
|
||||
// 还款金额
|
||||
int32_t ttCashPay_{};
|
||||
// 不计算现有现金的理论现金
|
||||
int32_t ttCash_{};
|
||||
};
|
||||
#endif // UTIL_H
|
||||