DbTreeViewManager.cpp 96 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760
  1. #include "DbTreeViewManager.h"
  2. #include "OriginalWnd/OriginalWnd.h"
  3. #include "OriginalWnd/NonInteractiveCheckDelegate.h"
  4. #include <QFile>
  5. #include <QTextStream>
  6. #include <QDateTime>
  7. // 构造函数
  8. DbTreeViewManager::DbTreeViewManager(OriginalWnd* originalWnd, QWidget* widget2, QWidget* parent)
  9. : QWidget(parent),
  10. m_originalWnd(originalWnd),
  11. widget2(widget2),
  12. treeViewDown(new QTreeView(this)),
  13. model(new QStandardItemModel(this)),
  14. restoring(false),
  15. m_blockItemChanged(false)
  16. {
  17. if (!widget2) {
  18. // qWarning() << "DbTreeViewManager: widget2 未初始化";
  19. return;
  20. }
  21. // 设置模型
  22. treeViewDown->setModel(model);
  23. treeViewDown->setHeaderHidden(true);
  24. treeViewDown->setEditTriggers(QAbstractItemView::NoEditTriggers);
  25. // 设置树视图的几何位置
  26. treeViewDown->setGeometry(16, 106, widget2->width() - 16, widget2->height() - 106);
  27. // 安装事件过滤器以自定义绘制虚线
  28. treeViewDown->viewport()->installEventFilter(this);
  29. // 创建统一分隔线
  30. lineFrame1 = createUnifiedSeparator(widget2, 2);
  31. lineFrame1->setGeometry(16, 100, 460, 2);
  32. // 创建按钮并设置布局
  33. setupButton();
  34. // 创建导航栏
  35. navigationWidget = new QWidget(widget2);
  36. navigationWidget->setGeometry(15, 15, 300, 74);
  37. // 连接目录前的复选框信号与槽
  38. connect(model, &QStandardItemModel::itemChanged, this, &DbTreeViewManager::onItemChanged);
  39. // 目录树连接点击信号
  40. connect(treeViewDown, &QTreeView::clicked, this, &DbTreeViewManager::onTreeViewClicked);
  41. // 连接目录 expanded 和 collapsed 信号
  42. connect(treeViewDown, &QTreeView::expanded, this, [=](const QModelIndex &index) {
  43. QStandardItem *item = model->itemFromIndex(index);
  44. if (!item) return;
  45. QStringList path = buildItemPath(item);
  46. expandedPaths.insert(path.join("/"));
  47. updateSeparatorLine();
  48. // 保存展开路径
  49. saveExpandedPaths();
  50. });
  51. connect(treeViewDown, &QTreeView::collapsed, this, [=](const QModelIndex &index) {
  52. QStandardItem *item = model->itemFromIndex(index);
  53. if (!item) return;
  54. QStringList path = buildItemPath(item);
  55. expandedPaths.remove(path.join("/"));
  56. updateSeparatorLine();
  57. // 保存展开路径
  58. saveExpandedPaths();
  59. });
  60. // 所有展开操作完成后更新分隔线
  61. QTimer::singleShot(0, this, [=]() {
  62. QStandardItem *rootItem = model->invisibleRootItem();
  63. QStandardItem *thirdItem = findFirstThirdLevelItemDFS(rootItem);
  64. if (thirdItem) {
  65. QJsonObject thirdLevelObj = thirdItem->data(Qt::UserRole + 2).toJsonObject();
  66. if (thirdLevelObj.contains("IsThirdLevel") && thirdLevelObj["IsThirdLevel"].toBool()) {
  67. loadButtonConfigForThirdLevel(thirdLevelObj);
  68. }
  69. }
  70. });
  71. // 应用自定义只读复选框委托
  72. treeViewDown->setItemDelegate(new NonInteractiveCheckDelegate(treeViewDown));
  73. menuArray[0] = {2, false,-1};
  74. menuArray[1] = {5, false,-1};
  75. menuArray[2] = {3, false,-1};
  76. menuArray[3] = {4, false,-1};
  77. menuArray[4] = {6, false,-1};
  78. currentMenuId = -1;
  79. }
  80. DbTreeViewManager::~DbTreeViewManager()
  81. {
  82. }
  83. // 创建横线样式
  84. QFrame* DbTreeViewManager::createUnifiedSeparator(QWidget *parent, int height)
  85. {
  86. QFrame *separator = new QFrame(parent);
  87. separator->setFrameShape(QFrame::NoFrame); // 移除默认框架
  88. separator->setFixedHeight(height); // 设置固定高度
  89. separator->setStyleSheet("background-color: #C7CAEB;");
  90. separator->hide(); // 初始化为隐藏
  91. return separator;
  92. }
  93. // 目录树样式
  94. void DbTreeViewManager::applyCustomStyles() {
  95. treeViewDown->setStyleSheet(R"(
  96. /* 设置分支图标 */
  97. QTreeView::branch:closed:has-children {
  98. border-image: none;
  99. image: url(:/images/home_add.png);
  100. }
  101. QTreeView::branch:open:has-children {
  102. border-image: none;
  103. image: url(:/images/home_minus.png);
  104. }
  105. /* 设置多选框 */
  106. QTreeView::indicator:unchecked {
  107. image: url(:/images/home_NotSelecte.png);
  108. }
  109. QTreeView::indicator:checked {
  110. image: url(:/images/home_selected.png);
  111. }
  112. /* 背景透明,行间距 */
  113. QTreeView {
  114. background: transparent;
  115. border: none;
  116. }
  117. /* 设置项目选中的背景色 */
  118. QTreeView::item:selected {
  119. background-color: #A9B4FF;
  120. }
  121. /* 设置项目的行间距 */
  122. QTreeView::item {
  123. padding-top: 5px; /* 上边距 */
  124. padding-bottom: 5px; /* 下边距 */
  125. }
  126. )");
  127. }
  128. // 检查权限
  129. bool DbTreeViewManager::hasPrivilege(const int &UserGrade, const int &userPrivilege)
  130. {
  131. bool hasPriv;
  132. // UserGrade 是以逗号分隔的字符串,如 "1,2,3"
  133. if(UserGrade==userPrivilege){
  134. hasPriv = true;
  135. }else{
  136. hasPriv = false;
  137. }
  138. // qDebug() << "Checking privilege. UserGrade:" << UserGrade << "userPrivilege:" << userPrivilege << "result:" << hasPriv;
  139. return hasPriv;
  140. }
  141. void DbTreeViewManager::updateDb(const QString &TableName, const int &Id,const QString currentValue){
  142. QSqlDatabase db = QSqlDatabase::database();
  143. if (!db.isOpen()) {
  144. qWarning() << "数据库未打开";
  145. }
  146. QString sql = QString("UPDATE %1 SET currentValue = :newValue WHERE id = :id").arg(TableName);
  147. QSqlQuery query;
  148. query.prepare(sql);
  149. query.bindValue(":newValue", currentValue);
  150. query.bindValue(":id", Id);
  151. // 执行更新操作
  152. if (!query.exec()) {
  153. qWarning() << "Failed to update currentValue:" << query.lastError().text();
  154. } else {
  155. qDebug() << "currentValue updated successfully.";
  156. }
  157. }
  158. void DbTreeViewManager::initializeTree(int configId, const int &userPrivilege)
  159. {
  160. qDebug() << "Initializing tree with configId:" << configId << "and userPrivilege:" << userPrivilege;
  161. m_currentConfigId = configId; // 设置当前配置ID
  162. // 先清空历史
  163. clearHistory();
  164. // 保存之前的选中/展开状态
  165. m_blockItemChanged = true;
  166. restoring = true;
  167. // 清理当前的分隔线
  168. clearAllSeparators();
  169. // 清空已有模型数据和相关记录
  170. model->clear();
  171. firstLevelSeparators.clear();
  172. expandedPaths.clear();
  173. // 清理并隐藏三级目录窗口
  174. clearThirdLevelMenu();
  175. // **Home 界面逻辑**
  176. if (configId == 1) {
  177. // 隐藏目录树和分隔线
  178. treeViewDown->hide();
  179. for (auto separator : firstLevelSeparators) {
  180. if (separator)
  181. separator->hide();
  182. }
  183. // 隐藏导航栏
  184. navigationWidget->hide();
  185. // 隐藏按钮
  186. updateButtonsVisibility(); // 将按钮隐藏
  187. // 隐藏特定的分隔线 lineFrame1
  188. if (lineFrame1) {
  189. lineFrame1->hide();
  190. }
  191. // 从 BondHead 和 Buttons 表中加载 DirectoryId = 1 的数据
  192. QJsonObject data = fetchThirdLevelData(1, userPrivilege);
  193. displayThirdLevelFields(data, true); // 传递参数表示 Home 界面
  194. // 把当前页面压到 m_backStack 里
  195. PageState st;
  196. st.path << "Home";
  197. st.isThirdLevel = true;
  198. st.directoryId = 1;
  199. m_backStack.append(st);
  200. if(m_backStack.size() >= 2){
  201. buttonLeft->setIcon(QIcon(":/images/home_left.png"));
  202. }
  203. } else {
  204. // **其他配置逻辑**
  205. // 设置 treeViewDown 的几何位置
  206. treeViewDown->setGeometry(16, 106, widget2->width() - 16, widget2->height() - 106);
  207. // 显示目录树和分隔线
  208. treeViewDown->show();
  209. for (auto separator : firstLevelSeparators) {
  210. if (separator)
  211. separator->show();
  212. }
  213. // 应用自定义样式
  214. applyCustomStyles();
  215. // 显示导航栏
  216. navigationWidget->show();
  217. // 显示按钮
  218. updateButtonsVisibility();
  219. // 显示特定的分隔线 lineFrame1
  220. if (lineFrame1) {
  221. lineFrame1->show();
  222. }
  223. // 加载目录数据 并进行权限判断
  224. loadDirectories(configId, userPrivilege);
  225. // 更新分隔线
  226. updateSeparatorLine();
  227. m_blockItemChanged = false;
  228. restoring = false;
  229. // qDebug() << "Tree initialization completed.";
  230. // 恢复展开路径
  231. loadExpandedPaths();
  232. // 恢复复选框状态
  233. loadCheckedPaths();
  234. // 自动选中第一个根目录项并更新导航栏
  235. QStandardItem *rootItem = model->invisibleRootItem()->child(0);
  236. if (rootItem) {
  237. QModelIndex rootIndex = model->indexFromItem(rootItem);
  238. treeViewDown->setCurrentIndex(rootIndex);
  239. updateNavigationBar(rootIndex);
  240. // 如果当前根目录是三级目录,则加载其字段内容
  241. QVariant dataVar = rootItem->data(Qt::UserRole + 2).toJsonObject();
  242. bool isThirdLevel = false;
  243. int directoryId = -1;
  244. if (dataVar.canConvert<QJsonObject>()) {
  245. QJsonObject thirdLevelObj = dataVar.toJsonObject();
  246. if (thirdLevelObj.contains("IsThirdLevel") && thirdLevelObj["IsThirdLevel"].toBool()) {
  247. isThirdLevel = true;
  248. if (thirdLevelObj.contains("Id")) {
  249. directoryId = thirdLevelObj["Id"].toInt();
  250. }
  251. }
  252. }
  253. if (isThirdLevel) {
  254. if (directoryId == -1) {
  255. // qWarning() << "无效的 DirectoryId,无法加载第三层目录内容。";
  256. return;
  257. }
  258. // userPrivilege 同样传递
  259. QJsonObject data = fetchThirdLevelData(directoryId, userPrivilege);
  260. displayThirdLevelFields(data, false); // 传递参数表示非 Home 界面
  261. // 把当前状态压入 m_backStack
  262. PageState st;
  263. st.path = buildItemPath(rootItem);
  264. st.isThirdLevel = true;
  265. st.directoryId = directoryId;
  266. m_backStack.append(st);
  267. if(m_backStack.size() >= 2){
  268. buttonLeft->setIcon(QIcon(":/images/home_left.png"));
  269. }
  270. }
  271. } else {
  272. // qWarning() << "树形模型中没有根目录项。";
  273. }
  274. // 自动找第一个三级目录
  275. QStandardItem *rootItem1 = model->invisibleRootItem();
  276. QStandardItem *firstThirdItem = findFirstThirdLevelItemDFS(rootItem1);
  277. if (!firstThirdItem) {
  278. // qDebug() << "[initializeTree] No third-level item found, do nothing.";
  279. return;
  280. }
  281. // QStandardItem 里获取它的目录信息
  282. QVariant dataVar = firstThirdItem->data(Qt::UserRole + 2);
  283. if (!dataVar.canConvert<QJsonObject>()) {
  284. // qWarning() << "[initializeTree] firstThirdItem->data 无法转换为 QJsonObject";
  285. return;
  286. }
  287. QJsonObject dirObj = dataVar.toJsonObject();
  288. if (!dirObj.contains("Id")) {
  289. // qWarning() << "[initializeTree] 第一个三级目录无 Id 字段,无法加载";
  290. return;
  291. }
  292. int directoryId = dirObj["Id"].toInt();
  293. // 数据库BondHead/Buttons
  294. QJsonObject data = fetchThirdLevelData(directoryId, userPrivilege);
  295. if (!data.contains("buttons")) {
  296. // 第三层没有 buttons 字段
  297. qWarning() << "[initializeTree] fetchThirdLevelData: no 'buttons', skip";
  298. return;
  299. }
  300. // singleShot 在所有展开操作完成后更新分隔线
  301. QTimer::singleShot(0, this, &DbTreeViewManager::updateSeparatorLine);
  302. // loadButtonConfigForThirdLevel 显示按钮
  303. loadButtonConfigForThirdLevel(data);
  304. }
  305. }
  306. // 从数据库加载目录 包含权限判断
  307. void DbTreeViewManager::loadDirectories(int configId, const int &userPrivilege)
  308. {
  309. // qDebug() << "Loading directories for configId:" << configId << "with userPrivilege:" << userPrivilege;
  310. QSqlDatabase db = QSqlDatabase::database();
  311. if (!db.isOpen()) {
  312. qWarning() << "数据库未打开";
  313. return;
  314. }
  315. QSqlQuery query(db);
  316. query.prepare(R"(
  317. SELECT Id, Name, ParentId, IsThirdLevel, Separator, UserGrade, Circle
  318. FROM Directories
  319. WHERE ConfigId = :configId
  320. )");
  321. query.bindValue(":configId", configId);
  322. if (!query.exec()) {
  323. qWarning() << "查询 Directories 失败:" << query.lastError().text();
  324. return;
  325. }
  326. // 以 QJsonObject 保存所有目录
  327. QList<QJsonObject> directories;
  328. while (query.next()) {
  329. QJsonObject obj;
  330. int id = query.value("Id").toInt();
  331. obj["Id"] = id;
  332. obj["Name"] = query.value("Name").toString();
  333. obj["ParentId"] = query.value("ParentId").isNull() ? -1 : query.value("ParentId").toInt();
  334. obj["IsThirdLevel"] = query.value("IsThirdLevel").toBool();
  335. obj["Separator"] = query.value("Separator").toInt();
  336. obj["UserGrade"] = query.value("UserGrade").toString();
  337. obj["Circle"] = query.value("Circle").toInt();
  338. qDebug() << "加载目录:"<< obj["Name"].toString() << " ParentId:" << obj["ParentId"].toInt()<< " Separator:" << obj["Separator"].toInt();
  339. qDebug() << " Circle:" << obj["Circle"].toInt();
  340. // 权限判断:只有当记录的 UserGrade 中包含当前用户权限时才加入
  341. bool ok;
  342. if (hasPrivilege(obj["UserGrade"].toString().toInt(&ok,16), userPrivilege))
  343. directories.append(obj);
  344. else
  345. qDebug() << "目录跳过(权限不足):" << obj["Name"].toString();
  346. }
  347. // qDebug() << "Loaded directories count:" << directories.size();
  348. // 根据目录列表构建树模型
  349. buildTreeFromDirectories(directories);
  350. }
  351. void DbTreeViewManager::buildTreeFromDirectories(const QList<QJsonObject> &directories)
  352. {
  353. // 建立 Id->QStandardItem 的映射
  354. QMap<int, QStandardItem*> idItemMap;
  355. for (const QJsonObject &dir : directories) {
  356. QStandardItem *item = new QStandardItem(dir["Name"].toString());
  357. item->setData(dir["Id"].toInt(), Qt::UserRole + 1); // 保存目录Id
  358. // 如果是三级目录,将整个 JSON 对象存到 UserRole+2
  359. if (dir["IsThirdLevel"].toBool()) {
  360. item->setData(dir, Qt::UserRole + 2);
  361. } else {
  362. item->setData(false, Qt::UserRole + 2); // 标记为非三级目录
  363. }
  364. item->setCheckable(true);
  365. // 复选框状态由程序逻辑设置
  366. item->setCheckState(Qt::Unchecked);
  367. idItemMap.insert(dir["Id"].toInt(), item);
  368. }
  369. // 建立父子关系
  370. for (const QJsonObject &dir : directories) {
  371. int parentId = dir["ParentId"].toInt();
  372. int currentId = dir["Id"].toInt();
  373. QStandardItem *childItem = idItemMap.value(currentId);
  374. if (parentId == -1) {
  375. // 说明这是一级目录
  376. model->invisibleRootItem()->appendRow(childItem);
  377. // 如果一级目录的 "Separator" == 1,则为其创建一条分割线
  378. if (dir["Separator"].toInt() == 1) {
  379. QFrame *sep = createUnifiedSeparator(widget2, 2);
  380. sep->hide();
  381. firstLevelSeparators.insert(childItem, sep);
  382. }
  383. } else {
  384. // 非一级目录 => 子目录
  385. QStandardItem *parentItem = idItemMap.value(parentId);
  386. if (parentItem)
  387. parentItem->appendRow(childItem);
  388. else
  389. qWarning() << "无法找到 ParentId:" << parentId << "的父目录项";
  390. }
  391. }
  392. }
  393. // 查询三级目录下的 BondHead 和 Buttons 数据 均判断权限
  394. QJsonObject DbTreeViewManager::fetchThirdLevelData(int directoryId, const int &userPrivilege)
  395. {
  396. QJsonObject data;
  397. QJsonArray fieldsArray;
  398. QJsonArray buttonsArray;
  399. QString temp;
  400. bool allChangeFlag = true; // 默认所有 ChangeFlag 为 true
  401. QSqlDatabase db = QSqlDatabase::database();
  402. if (!db.isOpen()) {
  403. qWarning() << "数据库未打开";
  404. return data;
  405. }
  406. // 查询 TableName 表
  407. QSqlQuery queryBondtest(db);
  408. queryBondtest.prepare(R"(
  409. SELECT TableName
  410. FROM Directories
  411. WHERE Id = :dirId
  412. )");
  413. queryBondtest.bindValue(":dirId",directoryId);
  414. if (queryBondtest.exec()) {
  415. while (queryBondtest.next()) {
  416. temp = queryBondtest.value("TableName").toString();
  417. }
  418. }
  419. QStringList tableName = temp.split(",");
  420. QString currentTableName;
  421. for (const QString &item : tableName) {
  422. if (item.isEmpty()) {
  423. qDebug() << "Encountered an empty string, stopping traversal.";
  424. break; // 遇到空字符串时退出循环
  425. }else{
  426. currentTableName = item;
  427. QString sql = QString("SELECT Id, DirectoryId, Describe, Type, Value,CurrentValue,UpLimit,DownLimit,units, Groupld, UserGrade, ChangeFlag FROM %1 WHERE DirectoryId = :dirId").arg(currentTableName);
  428. // 查询 BondHead 表
  429. QSqlQuery queryBond(db);
  430. queryBond.prepare(sql);
  431. queryBond.bindValue(":dirId", directoryId);
  432. if (queryBond.exec()) {
  433. while (queryBond.next()) {
  434. bool ok;
  435. int dbUserGrade = queryBond.value("UserGrade").toString().toInt(&ok, 16);
  436. // 只有当数据库记录的 UserGrade 包含当前用户权限时才加载该字段
  437. if (!hasPrivilege(dbUserGrade, userPrivilege))
  438. continue;
  439. QJsonObject field;
  440. field["Id"] = queryBond.value("Id").toInt();
  441. field["DirectoryId"] = queryBond.value("DirectoryId").toInt();
  442. field["Describe"] = queryBond.value("Describe").toString();
  443. field["Type"] = queryBond.value("Type").toString();
  444. field["Value"] = queryBond.value("Value").toString();
  445. field["CurrentValue"] = queryBond.value("CurrentValue").toString();
  446. field["UpLimit"] = queryBond.value("UpLimit").toString();
  447. field["DownLimit"] = queryBond.value("DownLimit").toString();
  448. field["units"] = queryBond.value("units").toString();
  449. field["Groupld"] = queryBond.value("Groupld").toInt();
  450. field["ChangeFlag"] = queryBond.value("ChangeFlag").toInt();
  451. field["TableName"] = currentTableName;
  452. fieldsArray.append(field);
  453. // 如果有任一字段 ChangeFlag 为 0,则 allChangeFlag = false
  454. if (queryBond.value("ChangeFlag").toInt() == 0)
  455. allChangeFlag = false;
  456. }
  457. // qDebug() << "Fetched fields:" << fieldsArray;
  458. } else {
  459. qWarning() << "查询 BondHead 失败:" << queryBond.lastError().text();
  460. }
  461. }
  462. }
  463. //QString sql = QString("SELECT Id, DirectoryId, Describe, Type, Value,units, Groupld, UserGrade, ChangeFlag FROM %1 WHERE DirectoryId = :dirId").arg(currentTableName);
  464. // // 查询 BondHead 表
  465. // QSqlQuery queryBond(db);
  466. // queryBond.prepare(sql);
  467. // queryBond.bindValue(":dirId", directoryId);
  468. // if (queryBond.exec()) {
  469. // while (queryBond.next()) {
  470. // bool ok;
  471. // int dbUserGrade = queryBond.value("UserGrade").toString().toInt(&ok, 16);
  472. // // 只有当数据库记录的 UserGrade 包含当前用户权限时才加载该字段
  473. // if (!hasPrivilege(dbUserGrade, userPrivilege))
  474. // continue;
  475. // QJsonObject field;
  476. // field["Id"] = queryBond.value("Id").toInt();
  477. // field["DirectoryId"] = queryBond.value("DirectoryId").toInt();
  478. // field["Describe"] = queryBond.value("Describe").toString();
  479. // field["Type"] = queryBond.value("Type").toString();
  480. // field["Value"] = queryBond.value("Value").toString();
  481. // field["units"] = queryBond.value("units").toString();
  482. // field["Groupld"] = queryBond.value("Groupld").toInt();
  483. // field["ChangeFlag"] = queryBond.value("ChangeFlag").toInt();
  484. // fieldsArray.append(field);
  485. // // 如果有任一字段 ChangeFlag 为 0,则 allChangeFlag = false
  486. // if (queryBond.value("ChangeFlag").toInt() == 0)
  487. // allChangeFlag = false;
  488. // }
  489. // // qDebug() << "Fetched fields:" << fieldsArray;
  490. // } else {
  491. // qWarning() << "查询 BondHead 失败:" << queryBond.lastError().text();
  492. // }
  493. // 查询 Buttons 表
  494. QSqlQuery queryBtn(db);
  495. queryBtn.prepare(R"(
  496. SELECT ButtonId, Icon, Text, Enabled, UserGrade
  497. FROM Buttons
  498. WHERE DirectoryId = :dirId
  499. )");
  500. queryBtn.bindValue(":dirId", directoryId);
  501. if (queryBtn.exec()) {
  502. while (queryBtn.next()) {
  503. bool ok;
  504. int btnUserGrade = queryBtn.value("UserGrade").toString().toInt(&ok, 16);
  505. if (!hasPrivilege(btnUserGrade, userPrivilege))
  506. continue;
  507. QJsonObject button;
  508. button["id"] = queryBtn.value("ButtonId").toString();
  509. button["icon"] = queryBtn.value("Icon").toString();
  510. button["text"] = queryBtn.value("Text").toString();
  511. button["enabled"] = queryBtn.value("Enabled").toBool();
  512. buttonsArray.append(button);
  513. }
  514. // qDebug() << "Fetched buttons:" << buttonsArray;
  515. } else {
  516. qWarning() << "查询 Buttons 失败:" << queryBtn.lastError().text();
  517. }
  518. data["fields"] = fieldsArray;
  519. data["buttons"] = buttonsArray;
  520. data["IsThirdLevel"] = true;
  521. data["allChangeFlag"] = allChangeFlag;
  522. return data;
  523. }
  524. // 事件过滤器,用于自定义绘制虚线
  525. bool DbTreeViewManager::eventFilter(QObject *watched, QEvent *event)
  526. {
  527. // 拦截 Paint 事件
  528. if (watched == treeViewDown->viewport() && event->type() == QEvent::Paint)
  529. {
  530. // 进行默认绘制
  531. bool handled = QWidget::eventFilter(watched, event);
  532. // 使用 QPainter 叠加画“拐角线”
  533. QPainter painter(treeViewDown->viewport());
  534. if (!painter.isActive()) {
  535. qWarning() << "Painter not active";
  536. return handled;
  537. }
  538. painter.save();
  539. painter.setPen(QPen(Qt::gray, 1, Qt::DashLine)); // 灰色、1px 宽、虚线
  540. // 调用递归函数,绘制所有分支
  541. paintAllBranches(QModelIndex(), painter);
  542. painter.restore();
  543. return handled;
  544. }
  545. // 其余事件交给父类默认处理
  546. return QWidget::eventFilter(watched, event);
  547. }
  548. // 递归绘制所有分支
  549. void DbTreeViewManager::paintAllBranches(const QModelIndex &parentIndex, QPainter &painter)
  550. {
  551. int rowCount = model->rowCount(parentIndex);
  552. for(int i = 0; i < rowCount; ++i)
  553. {
  554. // 当前子节点
  555. QModelIndex childIndex = model->index(i, 0, parentIndex);
  556. if (!childIndex.isValid()) continue;
  557. // 1) 父->子拐角线
  558. drawParentChildLine(childIndex, painter);
  559. // 2) 兄弟延续竖线(如果本节点不是最后一个兄弟,就在拐点列画条向下的线)
  560. if (i < rowCount - 1) {
  561. drawSiblingLine(childIndex, painter);
  562. }
  563. // 3) 递归处理子节点
  564. paintAllBranches(childIndex, painter);
  565. }
  566. }
  567. // 在“父节点 -> 子节点”间画一条“L”型拐角线,调整横向线段的长度
  568. void DbTreeViewManager::drawParentChildLine(const QModelIndex &childIndex, QPainter &painter)
  569. {
  570. QModelIndex parentIndex = childIndex.parent();
  571. if (!parentIndex.isValid()) {
  572. // “顶层节点”定义一个固定的起点 (rootX, rootY)
  573. int indent = treeViewDown->indentation();
  574. int depth = 0; // 顶层节点深度为0
  575. int branchX = (depth + 1) * indent - indent / 2; // 计算 branchX 基于缩进和深度
  576. // 定义 rootY 为节点中心 Y
  577. QRect childRect = treeViewDown->visualRect(childIndex);
  578. if (!childRect.isValid())
  579. return;
  580. int rootY = childRect.center().y();
  581. // 定义横向偏移量
  582. const int hOffset = -20;
  583. // 绘制竖线
  584. painter.drawLine(QPoint(branchX, rootY),
  585. QPoint(branchX, childRect.center().y()));
  586. // 计算新的横线终点
  587. int newX = childRect.left() + hOffset;
  588. // 绘制横线
  589. painter.drawLine(QPoint(branchX, childRect.center().y()),
  590. QPoint(newX, childRect.center().y()));
  591. return;
  592. }
  593. QRect parentRect = treeViewDown->visualRect(parentIndex);
  594. QRect childRect = treeViewDown->visualRect(childIndex);
  595. if (!parentRect.isValid() || !childRect.isValid()) {
  596. // 父或子超出可视区域
  597. return;
  598. }
  599. int pMidY = parentRect.center().y();
  600. int cMidY = childRect.center().y();
  601. // 计算节点深度
  602. int depth = 0;
  603. QModelIndex p = parentIndex;
  604. while (p.isValid()) {
  605. depth++;
  606. p = p.parent();
  607. }
  608. int indent = treeViewDown->indentation();
  609. int branchX = depth * indent - indent / 2;
  610. // branchX 不超出视图范围
  611. branchX = std::max(branchX, 0);
  612. // 定义横向偏移量
  613. const int hOffset = -15;
  614. // 绘制竖线
  615. painter.drawLine(QPoint(branchX, pMidY), QPoint(branchX, cMidY));
  616. // 计算新的横线终点
  617. int newX = childRect.left() + hOffset;
  618. // 绘制横线
  619. painter.drawLine(QPoint(branchX, cMidY), QPoint(newX, cMidY));
  620. }
  621. // 节点下面还有兄弟,则在拐点列那里继续往下画竖线
  622. void DbTreeViewManager::drawSiblingLine(const QModelIndex &childIndex, QPainter &painter)
  623. {
  624. QModelIndex parentIndex = childIndex.parent();
  625. if (!parentIndex.isValid()) {
  626. return; // 没有父节点
  627. }
  628. // 下一个兄弟
  629. int row = childIndex.row();
  630. int lastRow = model->rowCount(parentIndex) - 1;
  631. if (row >= lastRow) {
  632. return; // 说明是最后一个兄弟,不用画延伸线
  633. }
  634. QModelIndex nextSibling = model->index(row + 1, 0, parentIndex);
  635. QRect currRect = treeViewDown->visualRect(childIndex);
  636. QRect nextRect = treeViewDown->visualRect(nextSibling);
  637. if (!currRect.isValid() || !nextRect.isValid()) {
  638. return;
  639. }
  640. // 计算节点深度
  641. int depth = 0;
  642. QModelIndex p = parentIndex;
  643. while (p.isValid()) {
  644. depth++;
  645. p = p.parent();
  646. }
  647. int indent = treeViewDown->indentation();
  648. int branchX = depth * indent - indent / 2;
  649. // 确保 branchX 不超出视图范围
  650. branchX = std::max(branchX, 0);
  651. // 从当前节点底部向下延伸到下一个兄弟节点顶部
  652. int startY = currRect.bottom();
  653. int endY = nextRect.top();
  654. painter.drawLine(QPoint(branchX, startY), QPoint(branchX, endY));
  655. }
  656. // 递归查找第一个三级目录项
  657. QStandardItem* DbTreeViewManager::findFirstThirdLevelItemDFS(QStandardItem *parentItem)
  658. {
  659. if (!parentItem) {
  660. return nullptr;
  661. }
  662. // 遍历当前 parentItem 的所有子
  663. for (int i = 0; i < parentItem->rowCount(); ++i) {
  664. QStandardItem *child = parentItem->child(i);
  665. if (!child) continue;
  666. // 检查这个子节点是否是三级目录
  667. QVariant data = child->data(Qt::UserRole + 2);
  668. if (data.canConvert<QJsonObject>()) {
  669. QJsonObject obj = data.toJsonObject();
  670. if (obj.contains("IsThirdLevel") && obj["IsThirdLevel"].toBool()) {
  671. // 找到第一个 IsThirdLevel = true 的节点就返回
  672. return child;
  673. }
  674. }
  675. // 如果不是 IsThirdLevel,继续往子节点里找
  676. QStandardItem* deeperFound = findFirstThirdLevelItemDFS(child);
  677. if (deeperFound) {
  678. return deeperFound;
  679. }
  680. }
  681. return nullptr;
  682. }
  683. void DbTreeViewManager::onItemChanged(QStandardItem *item)
  684. {
  685. if (m_blockItemChanged || restoring) {
  686. return; // 防止递归和恢复期间触发
  687. }
  688. m_blockItemChanged = true;
  689. Qt::CheckState state = item->checkState();
  690. // 更新所有子项的复选框状态
  691. for (int i = 0; i < item->rowCount(); ++i) {
  692. QStandardItem *child = item->child(i);
  693. if (child) {
  694. child->setCheckState(state);
  695. // 递归更新子项
  696. onItemChanged(child);
  697. }
  698. }
  699. // 更新所有父项的复选框状态
  700. QModelIndex parentIndex = item->index().parent();
  701. while (parentIndex.isValid()) {
  702. QStandardItem *parentItem = model->itemFromIndex(parentIndex);
  703. if (!parentItem) break;
  704. int checkedCount = 0;
  705. int totalCount = parentItem->rowCount();
  706. for (int i = 0; i < totalCount; ++i) {
  707. QStandardItem *child = parentItem->child(i);
  708. if (child && child->checkState() == Qt::Checked) {
  709. checkedCount++;
  710. }
  711. }
  712. if (checkedCount == totalCount) {
  713. parentItem->setCheckState(Qt::Checked);
  714. }
  715. else {
  716. parentItem->setCheckState(Qt::Unchecked);
  717. }
  718. parentIndex = parentIndex.parent();
  719. }
  720. m_blockItemChanged = false;
  721. // 记录复选框状态
  722. saveCheckedPaths();
  723. }
  724. // 初始化和设置按钮
  725. void DbTreeViewManager::setupButton()
  726. {
  727. // 创建按钮并设置属性
  728. auto createButton = [&](QPushButton*& button, const QString& iconPath, const QRect& geometry) {
  729. button = new QPushButton(this);
  730. button->setIcon(QIcon(iconPath));
  731. button->setGeometry(geometry);
  732. button->setStyleSheet(R"(
  733. QPushButton {
  734. position: absolute;
  735. border-radius: 6px;
  736. opacity: 1;
  737. background: #FFFFFF;
  738. border: 1px solid #BABBDC;
  739. }
  740. QPushButton:hover {
  741. background-color: #A9B4FF; /* 鼠标悬停效果 */
  742. }
  743. )");
  744. button->show();
  745. };
  746. // 根据原始代码调整按钮的位置和大小
  747. createButton(ButtonBack, ":/images/home_openFile.png", QRect(328, 6, 76, 30));
  748. createButton(buttonUp, ":/images/home_up.png", QRect(408, 6, 36, 30));
  749. createButton(buttonDown, ":/images/home_down.png", QRect(408, 40, 36, 30));
  750. createButton(buttonLeft, ":/images/home_left_hide.png", QRect(328, 40, 36, 30));
  751. createButton(buttonRight, ":/images/home_right.png", QRect(368, 40, 36, 30));
  752. // 连接按钮的点击信号到相应的槽函数
  753. connect(ButtonBack, &QPushButton::clicked, this, &DbTreeViewManager::onButtonBackClicked);
  754. connect(buttonUp, &QPushButton::clicked, this, &DbTreeViewManager::onButtonUpClicked);
  755. connect(buttonDown, &QPushButton::clicked, this, &DbTreeViewManager::onButtonDownClicked);
  756. connect(buttonLeft, &QPushButton::clicked, this, &DbTreeViewManager::onButtonLeftClicked);
  757. connect(buttonRight, &QPushButton::clicked, this, &DbTreeViewManager::onButtonRightClicked);
  758. }
  759. void DbTreeViewManager::updateButtonsVisibility()
  760. {
  761. if (m_currentConfigId == 1) {
  762. // Home 界面,隐藏所有按钮
  763. ButtonBack->hide();
  764. buttonUp->hide();
  765. buttonDown->hide();
  766. buttonLeft->hide();
  767. buttonRight->hide();
  768. }
  769. else {
  770. // 其他配置,显示所有按钮
  771. ButtonBack->show();
  772. buttonUp->show();
  773. buttonDown->show();
  774. buttonLeft->show();
  775. buttonRight->show();
  776. }
  777. }
  778. QStandardItem* DbTreeViewManager::deepCopyItem(const QStandardItem *item){
  779. if (!item) {
  780. return nullptr;
  781. }
  782. // 创建一个新的 QStandardItem
  783. QStandardItem *newItem = new QStandardItem(item->text());
  784. newItem->setIcon(item->icon());
  785. newItem->setToolTip(item->toolTip());
  786. newItem->setEditable(item->isEditable());
  787. newItem->setCheckable(item->isCheckable());
  788. newItem->setCheckState(item->checkState());
  789. // 递归复制子项
  790. for (int i = 0; i < item->rowCount(); ++i) {
  791. QStandardItem *childItem = item->child(i);
  792. QStandardItem *newChildItem = deepCopyItem(childItem);
  793. newItem->appendRow(newChildItem);
  794. }
  795. return newItem;
  796. }
  797. void DbTreeViewManager::loadpage(const int &configId){
  798. for(int i=0;i<5;i++){
  799. if(configId == menuArray[i].menuId){
  800. QJsonObject data = fetchThirdLevelData(menuArray[i].index, 0x1);
  801. displayThirdLevelFields(data, false);
  802. }
  803. }
  804. }
  805. void DbTreeViewManager::onTreeViewClicked(const QModelIndex &index)
  806. {
  807. QStandardItem *item = model->itemFromIndex(index);
  808. if (!item) return;
  809. // 是否第三层
  810. bool isThird = false;
  811. int dirId = -1;
  812. QVariant dataVar = item->data(Qt::UserRole + 2);
  813. if (dataVar.canConvert<QJsonObject>()) {
  814. QJsonObject obj = dataVar.toJsonObject();
  815. if (obj.contains("IsThirdLevel") && obj["IsThirdLevel"].toBool()) {
  816. isThird = true;
  817. if (obj.contains("Id")) {
  818. dirId = obj["Id"].toInt();
  819. }
  820. }
  821. }
  822. updateNavigationBar(index);
  823. if (isThird) {
  824. int userPrivilege = 0x1; // 示例
  825. if (dirId < 0) {
  826. qWarning() << "无效directoryId";
  827. return;
  828. }
  829. QJsonObject data = fetchThirdLevelData(dirId, userPrivilege);
  830. displayThirdLevelFields(data, false);
  831. for(int i=0;i<5;i++){
  832. if(currentMenuId == menuArray[i].menuId){
  833. menuArray[i].isthird = true;
  834. menuArray[i].index = dirId;
  835. }
  836. }
  837. // 将“新页面”压入后退栈, 并清空前进栈
  838. PageState st;
  839. st.path = buildItemPath(item);
  840. st.isThirdLevel = true;
  841. st.directoryId = dirId;
  842. m_backStack.append(st);
  843. if(m_backStack.size() >= 2){
  844. buttonLeft->setIcon(QIcon(":/images/home_left.png"));
  845. }
  846. m_forwardStack.clear();
  847. buttonRight->setIcon(QIcon(":/images/home_right.png"));
  848. } else {
  849. // 不是第三层,只是选中目录
  850. // 清理第三层窗口
  851. if (m_thirdLevelFieldWnd) {
  852. m_thirdLevelFieldWnd->close();
  853. m_thirdLevelFieldWnd->deleteLater();
  854. m_thirdLevelFieldWnd = nullptr;
  855. }
  856. // 同样更新历史
  857. PageState st;
  858. st.path = buildItemPath(item);
  859. st.isThirdLevel = false;
  860. st.directoryId = -1;
  861. m_backStack.append(st);
  862. if(m_backStack.size() >= 2){
  863. buttonLeft->setIcon(QIcon(":/images/home_left.png"));
  864. }
  865. m_forwardStack.clear();
  866. buttonRight->setIcon(QIcon(":/images/home_right.png"));
  867. }
  868. }
  869. void DbTreeViewManager::onTreeViewClicked_updown(const QModelIndex &index){
  870. QStandardItem *item = model->itemFromIndex(index);
  871. if (!item) return;
  872. // 是否第三层
  873. bool isThird = false;
  874. int dirId = -1;
  875. QVariant dataVar = item->data(Qt::UserRole + 2);
  876. if (dataVar.canConvert<QJsonObject>()) {
  877. QJsonObject obj = dataVar.toJsonObject();
  878. if (obj.contains("IsThirdLevel") && obj["IsThirdLevel"].toBool()) {
  879. isThird = true;
  880. if (obj.contains("Id")) {
  881. dirId = obj["Id"].toInt();
  882. }
  883. }
  884. }
  885. updateNavigationBar(index);
  886. if (isThird) {
  887. int userPrivilege = 0x1; // 示例
  888. if (dirId < 0) {
  889. qWarning() << "无效directoryId";
  890. return;
  891. }
  892. QJsonObject data = fetchThirdLevelData(dirId, userPrivilege);
  893. displayThirdLevelFields(data, false);
  894. // 将“新页面”压入后退栈, 并清空前进栈
  895. PageState st;
  896. st.path = buildItemPath(item);
  897. st.isThirdLevel = true;
  898. st.directoryId = dirId;
  899. m_backStack.append(st);
  900. if(m_backStack.size() >= 2){
  901. buttonLeft->setIcon(QIcon(":/images/home_left.png"));
  902. }
  903. m_forwardStack.clear();
  904. buttonRight->setIcon(QIcon(":/images/home_right.png"));
  905. } else {
  906. // 不是第三层,只是选中目录
  907. // 清理第三层窗口
  908. if (m_thirdLevelFieldWnd) {
  909. m_thirdLevelFieldWnd->close();
  910. m_thirdLevelFieldWnd->deleteLater();
  911. m_thirdLevelFieldWnd = nullptr;
  912. }
  913. // 同样更新历史
  914. PageState st;
  915. st.path = buildItemPath(item);
  916. st.isThirdLevel = false;
  917. st.directoryId = -1;
  918. m_backStack.append(st);
  919. if(m_backStack.size() >= 2){
  920. buttonLeft->setIcon(QIcon(":/images/home_left.png"));
  921. }
  922. m_forwardStack.clear();
  923. buttonRight->setIcon(QIcon(":/images/home_right.png"));
  924. }
  925. }
  926. void DbTreeViewManager::updateNavigationBar(const QModelIndex &index)
  927. {
  928. QStandardItem *item = model->itemFromIndex(index);
  929. if (!item) {
  930. qWarning() << "导航栏更新失败:未找到对应项";
  931. return;
  932. }
  933. // 清理现有布局
  934. if (navigationWidget->layout()) {
  935. QLayoutItem *child;
  936. while ((child = navigationWidget->layout()->takeAt(0)) != nullptr) {
  937. if (child->widget()) {
  938. child->widget()->deleteLater();
  939. }
  940. delete child;
  941. }
  942. delete navigationWidget->layout();
  943. }
  944. // 构建路径列表,从当前项回溯到根节点
  945. QList<QStandardItem *> path;
  946. QStandardItem *temp = item;
  947. while (temp) {
  948. path.prepend(temp); // 从根节点开始
  949. temp = temp->parent();
  950. }
  951. QVBoxLayout *newLayout = new QVBoxLayout; // 创建新的导航栏布局
  952. newLayout->setContentsMargins(0, 0, 3, 3);
  953. newLayout->setSpacing(0);
  954. // 确保显示三行
  955. for (int i = 0; i < 3; ++i) {
  956. QLabel *label = new QLabel;
  957. if (i < path.size()) {
  958. QString text = path[i]->text();
  959. if (i == 1) text = " " + text; // 二级目录缩进
  960. if (i == 2) text = " " + text; // 三级目录缩进
  961. label->setText(text);
  962. } else {
  963. label->setText(""); // 填充空白行
  964. }
  965. QFont font = label->font(); // 设置字体和样式
  966. font.setPointSize(14);
  967. font.setFamily("思源黑体");
  968. font.setBold(true); // 设置文字为粗体
  969. font.setLetterSpacing(QFont::PercentageSpacing,105); // 设置字间距100%为默认
  970. label->setFont(font);
  971. label->setFixedHeight(navigationWidget->height() / 3);
  972. newLayout->addWidget(label);
  973. }
  974. // 设置布局并更新导航栏
  975. navigationWidget->setLayout(newLayout);
  976. navigationWidget->update();
  977. }
  978. void DbTreeViewManager::clearAllSeparators()
  979. {
  980. // 遍历 firstLevelSeparators 中所有 QFrame,
  981. // 隐藏后调用 deleteLater()
  982. for (auto separator : firstLevelSeparators.values()) {
  983. if(separator) {
  984. separator->hide();
  985. separator->deleteLater();
  986. }
  987. }
  988. // 清空映射
  989. firstLevelSeparators.clear();
  990. }
  991. void DbTreeViewManager::updateSeparatorLine()
  992. {
  993. // 如果目录树被隐藏,就把分割线都藏起来
  994. if (!treeViewDown->isVisible()) {
  995. for (auto it = firstLevelSeparators.begin(); it != firstLevelSeparators.end(); ++it) {
  996. QFrame *sep = it.value();
  997. if (sep) sep->hide();
  998. }
  999. return;
  1000. }
  1001. // 遍历所有“一级目录”与其分隔线
  1002. for (auto it = firstLevelSeparators.begin(); it != firstLevelSeparators.end(); ++it) {
  1003. QStandardItem *firstLevelItem = it.key();
  1004. QFrame *separator = it.value();
  1005. if (!firstLevelItem || !separator) continue;
  1006. // 拿到可视区域
  1007. QModelIndex firstLevelIndex = model->indexFromItem(firstLevelItem);
  1008. QRect firstLevelRect = treeViewDown->visualRect(firstLevelIndex);
  1009. // 如果这个一级目录滚动到看不见了,就把分割线也藏起来
  1010. if (!firstLevelRect.isValid()) {
  1011. separator->hide();
  1012. continue;
  1013. }
  1014. // 如果展开并且它有子节点,就找“最后一个可见子项”
  1015. if (treeViewDown->isExpanded(firstLevelIndex) && firstLevelItem->hasChildren()) {
  1016. QModelIndex lastVisibleChild = findLastVisibleChild(firstLevelIndex);
  1017. if (lastVisibleChild.isValid()) {
  1018. QRect lastChildRect = treeViewDown->visualRect(lastVisibleChild);
  1019. if (lastChildRect.isValid()) {
  1020. // 将分割线放在最后一个子项下面
  1021. separator->setGeometry(16,lastChildRect.bottom() + 115,widget2->width() - 40,1);
  1022. separator->show();
  1023. continue;
  1024. }
  1025. }
  1026. }
  1027. // 如果收起或找不到可见子项,就放在本一级目录下面
  1028. separator->setGeometry(16,firstLevelRect.bottom() + 115,widget2->width() - 40,1);
  1029. separator->show();
  1030. }
  1031. }
  1032. QModelIndex DbTreeViewManager::findLastVisibleChild(const QModelIndex &parentIndex) {
  1033. if (!parentIndex.isValid()) return QModelIndex();
  1034. int childCount = model->rowCount(parentIndex);
  1035. QModelIndex lastVisible;
  1036. for (int i = childCount - 1; i >= 0; --i) {
  1037. QModelIndex childIndex = model->index(i, 0, parentIndex);
  1038. if (!treeViewDown->isRowHidden(i, parentIndex)) {
  1039. if (treeViewDown->isExpanded(childIndex) && model->rowCount(childIndex) > 0) {
  1040. QModelIndex deeper = findLastVisibleChild(childIndex);
  1041. if (deeper.isValid()) {
  1042. return deeper;
  1043. }
  1044. }
  1045. lastVisible = childIndex;
  1046. break;
  1047. }
  1048. }
  1049. return lastVisible;
  1050. }
  1051. void DbTreeViewManager::displayThirdLevelFields(const QJsonObject &data, bool isHome)
  1052. {
  1053. if (data.isEmpty()) {
  1054. qWarning() << "字段数据为空,无法显示";
  1055. return;
  1056. }
  1057. if (!data.contains("IsThirdLevel") || !data["IsThirdLevel"].toBool()) {
  1058. qWarning() << "不是三级目录,跳过按钮加载";
  1059. return;
  1060. }
  1061. bool allChangeFlag = false;
  1062. if (data.contains("allChangeFlag") && data["allChangeFlag"].isBool()) {
  1063. allChangeFlag = data["allChangeFlag"].toBool();
  1064. }
  1065. else {
  1066. qWarning() << "数据中缺少 'allChangeFlag' 字段或类型不正确";
  1067. }
  1068. // 若已有第三层窗口,先关闭并释放
  1069. if (m_thirdLevelFieldWnd) {
  1070. m_thirdLevelFieldWnd->close();
  1071. m_thirdLevelFieldWnd->deleteLater();
  1072. m_thirdLevelFieldWnd = nullptr;
  1073. }
  1074. // 获取当前选中的目录项,设置状态
  1075. QModelIndex currentIndex = treeViewDown->currentIndex();
  1076. if (currentIndex.isValid()) {
  1077. QStandardItem* currentItem = model->itemFromIndex(currentIndex);
  1078. if (currentItem) {
  1079. currentItem->setCheckState(allChangeFlag ? Qt::Checked : Qt::Unchecked);
  1080. qDebug() << "设置当前目录项复选框状态为:" << (allChangeFlag ? "Checked" : "Unchecked");
  1081. }
  1082. }
  1083. else {
  1084. qWarning() << "当前没有选中的目录项";
  1085. }
  1086. // 隐藏目录树及所有分隔线
  1087. treeViewDown->hide();
  1088. for (auto separator : firstLevelSeparators) {
  1089. if (separator)
  1090. separator->hide();
  1091. }
  1092. // 显示按钮
  1093. loadButtonConfigForThirdLevel(data);
  1094. // 清理之前的控件列表
  1095. m_fieldWidgets.clear();
  1096. // 创建新的 "字段展示" 窗口,并赋值给 m_thirdLevelFieldWnd
  1097. m_thirdLevelFieldWnd = new QWidget(widget2);
  1098. m_thirdLevelFieldWnd->setWindowTitle("字段展示");
  1099. m_thirdLevelFieldWnd->setStyleSheet("background-color: transparent;");
  1100. if (isHome) {
  1101. // Home 界面,填满 widget2
  1102. m_thirdLevelFieldWnd->setGeometry(0, 0, widget2->width(), widget2->height());
  1103. }
  1104. else {
  1105. // 其他配置界面,设置与 treeViewDown 相同的几何位置
  1106. m_thirdLevelFieldWnd->setGeometry(treeViewDown->geometry());
  1107. }
  1108. // 创建滚动区域
  1109. QScrollArea *scrollArea = new QScrollArea(m_thirdLevelFieldWnd);
  1110. scrollArea->setWidgetResizable(true);
  1111. scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
  1112. // 创建滚动容器并设置布局
  1113. QWidget *scrollWidget = new QWidget;
  1114. scrollWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
  1115. QVBoxLayout *scrollLayout = new QVBoxLayout(scrollWidget);
  1116. scrollLayout->setSpacing(10);
  1117. scrollLayout->setContentsMargins(10, 10, 10, 10);
  1118. int previousGroupId = -1;
  1119. // 遍历字段数组
  1120. if (data.contains("fields") && data["fields"].isArray()) {
  1121. QJsonArray fields = data["fields"].toArray();
  1122. for (const QJsonValue &val : fields) {
  1123. QJsonObject field = val.toObject();
  1124. int fieldId = field["Id"].toInt();
  1125. QString fieldName = field["Describe"].toString();
  1126. QString fieldType = field["Type"].toString();
  1127. QString fieldValue = field["Value"].toString();
  1128. QString fieldCurrentValue = field["CurrentValue"].toString();
  1129. QString fieldTableName = field["TableName"].toString();
  1130. QString fieldUpLimit = field["UpLimit"].toString();
  1131. QString fieldDownLimit = field["DownLimit"].toString();
  1132. QString fieldUnits = field["units"].toString();
  1133. int groupId = field["Groupld"].toInt();
  1134. // 如果组变化,插入分隔线
  1135. if (previousGroupId != -1 && groupId != previousGroupId) {
  1136. QFrame *separator = createUnifiedSeparator(scrollWidget, 2);
  1137. QHBoxLayout *separatorLayout = new QHBoxLayout;
  1138. separatorLayout->setContentsMargins(0, 5, 0, 5);
  1139. separatorLayout->addWidget(separator);
  1140. scrollLayout->addLayout(separatorLayout);
  1141. separator->show();
  1142. }
  1143. previousGroupId = groupId;
  1144. // 每个字段一行
  1145. QHBoxLayout *fieldLayout = new QHBoxLayout;
  1146. fieldLayout->setSpacing(5);
  1147. QLabel *label = new QLabel(fieldName);
  1148. label->setAlignment(Qt::AlignVCenter | Qt::AlignLeft);
  1149. label->setFixedHeight(24);
  1150. label->setMinimumWidth(120);
  1151. fieldLayout->addWidget(label);
  1152. fieldLayout->addStretch(1);
  1153. QWidget *rightWidget = new QWidget;
  1154. QHBoxLayout *rightLayout = new QHBoxLayout(rightWidget);
  1155. rightLayout->setContentsMargins(0, 0, 20, 0);
  1156. rightLayout->setSpacing(5);
  1157. QWidget *createdWidget = nullptr;
  1158. if (fieldType == "input") {
  1159. // 检查 Value 中是否包含逗号分隔(比如 "请输入内容1,分钟")
  1160. if (fieldUnits!= "") {
  1161. // // 采用逗号分割,trim去除空白
  1162. // QStringList parts = fieldValue.split(",", Qt::SkipEmptyParts);
  1163. // QString leftText = parts.at(0).trimmed();
  1164. // QString rightText = (parts.size() > 1 ? parts.at(1).trimmed() : QString());
  1165. // 创建 QLineEdit 显示左边文本
  1166. QLineEdit *lineEdit = new QLineEdit();
  1167. if((fieldUpLimit=="")&&(fieldDownLimit=="")){
  1168. lineEdit->setText(fieldCurrentValue);
  1169. lineEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
  1170. lineEdit->setFixedSize(105, 28);
  1171. lineEdit->setAlignment(Qt::AlignLeft);
  1172. lineEdit->setStyleSheet(R"(
  1173. QLineEdit {
  1174. background: #FFFFFF;
  1175. border: 1px solid #BABBDC;
  1176. border-radius: 6px;
  1177. padding: 2px 5px;
  1178. }
  1179. )");
  1180. }else{//上下限至少设置了一个值
  1181. if(fieldCurrentValue == ""){
  1182. lineEdit->setPlaceholderText("请输入数字");
  1183. }else{
  1184. lineEdit->setText(fieldCurrentValue);
  1185. }
  1186. lineEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
  1187. lineEdit->setFixedSize(105, 28);
  1188. lineEdit->setAlignment(Qt::AlignLeft);
  1189. lineEdit->setStyleSheet(R"(
  1190. QLineEdit {
  1191. background: #FFFFFF;
  1192. border: 1px solid #BABBDC;
  1193. border-radius: 6px;
  1194. padding: 2px 5px;
  1195. }
  1196. )");
  1197. }
  1198. // 创建 QLabel 显示右边文本(比如 "分钟")
  1199. QLabel *unitLabel = new QLabel(fieldUnits);
  1200. unitLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
  1201. unitLabel->setFixedHeight(28);
  1202. unitLabel->setStyleSheet("QLabel { font-size: 14px; }");
  1203. // 把 QLineEdit 和 QLabel 水平排列,确保 Qlabel 显示在 QLineEdit 右侧
  1204. QHBoxLayout *inputLayout = new QHBoxLayout;
  1205. inputLayout->setSpacing(10);
  1206. inputLayout->setContentsMargins(0,0,0,0);
  1207. inputLayout->addWidget(lineEdit);
  1208. inputLayout->addWidget(unitLabel);
  1209. // 用一个容器部件来装下这个布局
  1210. QWidget *inputWidget = new QWidget;
  1211. inputWidget->setLayout(inputLayout);
  1212. rightLayout->addWidget(inputWidget);
  1213. // 保存控件指针到 m_fieldWidgets(可选)
  1214. m_fieldWidgets.append(lineEdit);
  1215. m_fieldWidgets.append(unitLabel);
  1216. createdWidget = inputWidget;
  1217. // // 连接 textChanged 信号到 lambda 函数
  1218. connect(lineEdit, &QLineEdit::textChanged, [this,lineEdit,fieldTableName,fieldId,fieldUpLimit,fieldDownLimit]() {
  1219. if((fieldUpLimit!="")&&(fieldDownLimit!="")){
  1220. int uplimit = fieldUpLimit.toInt();
  1221. int downlimit = fieldDownLimit.toInt();
  1222. int inputvalue = (lineEdit->text()).toInt();
  1223. if((inputvalue<=uplimit)&&(inputvalue>=downlimit)){
  1224. updateDb(fieldTableName,fieldId,lineEdit->text());
  1225. }else{
  1226. lineEdit->setPlaceholderText("超出设定范围,请重新输入");
  1227. }
  1228. }else if(fieldDownLimit!=""){
  1229. int downlimit = fieldDownLimit.toInt();
  1230. int inputvalue = (lineEdit->text()).toInt();
  1231. if(inputvalue>=downlimit){
  1232. updateDb(fieldTableName,fieldId,lineEdit->text());
  1233. }else{
  1234. lineEdit->setPlaceholderText("超出设定范围,请重新输入");
  1235. }
  1236. }else if(fieldUpLimit!=""){
  1237. int uplimit = fieldUpLimit.toInt();
  1238. int inputvalue = (lineEdit->text()).toInt();
  1239. if(inputvalue<=uplimit){
  1240. updateDb(fieldTableName,fieldId,lineEdit->text());
  1241. }else{
  1242. lineEdit->setPlaceholderText("超出设定范围,请重新输入");
  1243. }
  1244. }else{
  1245. updateDb(fieldTableName,fieldId,lineEdit->text());
  1246. }
  1247. });
  1248. } else {
  1249. // 如果不包含逗号,按原有逻辑只创建 QLineEdit
  1250. QLineEdit *lineEdit1 = new QLineEdit(fieldCurrentValue);
  1251. lineEdit1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
  1252. lineEdit1->setFixedSize(140, 28);
  1253. lineEdit1->setAlignment(Qt::AlignLeft);
  1254. lineEdit1->setStyleSheet(R"(
  1255. QLineEdit {
  1256. background: #FFFFFF;
  1257. border: 1px solid #BABBDC;
  1258. border-radius: 6px;
  1259. padding: 2px 5px;
  1260. }
  1261. )");
  1262. rightLayout->addWidget(lineEdit1);
  1263. createdWidget = lineEdit1;
  1264. // // 连接 textChanged 信号到 lambda 函数
  1265. connect(lineEdit1, &QLineEdit::textChanged, [this,lineEdit1,fieldTableName,fieldId]() {
  1266. updateDb(fieldTableName,fieldId,lineEdit1->text());
  1267. loginput(fieldTableName,fieldId,lineEdit1->text());
  1268. });
  1269. }
  1270. }
  1271. else if (fieldType == "radio") {
  1272. // 用逗号分隔的选项
  1273. QStringList optionList = fieldValue.split(QRegExp("[,,]"), Qt::SkipEmptyParts);
  1274. QHBoxLayout *radioLayout = new QHBoxLayout;
  1275. radioLayout->setSpacing(5);
  1276. QButtonGroup *radioGroup = new QButtonGroup(rightWidget);
  1277. for (const QString &optionText : optionList) {
  1278. QString trimmedOpt = optionText.trimmed();
  1279. if (trimmedOpt.isEmpty()) continue;
  1280. QRadioButton *radioButton = new QRadioButton(trimmedOpt);
  1281. radioGroup->addButton(radioButton);
  1282. radioLayout->addWidget(radioButton);
  1283. m_fieldWidgets.append(radioButton);
  1284. if(fieldCurrentValue == trimmedOpt){
  1285. radioButton->setChecked(true);
  1286. }
  1287. }
  1288. // 使用Lambda函数连接 buttonToggled 信号
  1289. connect(radioGroup, static_cast<void (QButtonGroup::*)(QAbstractButton *, bool)>(&QButtonGroup::buttonToggled),[this,fieldTableName,fieldId](QAbstractButton *button,bool checked) {
  1290. if (checked) {
  1291. // qDebug() << "Button toggled:" << button->text();
  1292. // 在这里添加你想要执行的操作
  1293. updateDb(fieldTableName,fieldId,button->text());
  1294. }
  1295. });
  1296. rightLayout->addLayout(radioLayout);
  1297. }
  1298. else if (fieldType == "checkbox") {
  1299. bool isChecked;
  1300. if(fieldCurrentValue == ""){
  1301. isChecked = (fieldValue == "1");
  1302. }else{
  1303. isChecked = (fieldCurrentValue == "1");
  1304. }
  1305. QCheckBox *checkBox = new QCheckBox;
  1306. checkBox->setChecked(isChecked);
  1307. checkBox->setStyleSheet(R"(
  1308. QCheckBox::indicator {
  1309. width: 20px;
  1310. height: 20px;
  1311. }
  1312. QCheckBox::indicator:unchecked {
  1313. background-color: #FFFFFF;
  1314. border: 1px solid #BABBDC;
  1315. border-radius: 2px;
  1316. }
  1317. QCheckBox::indicator:checked {
  1318. image: url(:/images/three_Selecte.png);
  1319. }
  1320. QCheckBox {
  1321. spacing: 0px;
  1322. }
  1323. )");
  1324. rightLayout->addWidget(checkBox);
  1325. createdWidget = checkBox;
  1326. connect(checkBox, &QCheckBox::stateChanged, [this,fieldTableName,fieldId](int state) {
  1327. if (state == Qt::Checked) {
  1328. // qDebug() << "CheckBox is checked"<<fieldId;
  1329. updateDb(fieldTableName,fieldId,"1");
  1330. } else if (state == Qt::Unchecked) {
  1331. // qDebug() << "CheckBox is unchecked"<<fieldId;
  1332. // 在这里添加你想要执行的操作
  1333. updateDb(fieldTableName,fieldId,"0");
  1334. } else if (state == Qt::PartiallyChecked) {
  1335. qDebug() << "CheckBox is partially checked";
  1336. // 在这里添加你想要执行的操作
  1337. }
  1338. });
  1339. }
  1340. else if (fieldType == "dropdown") {
  1341. QStringList optionList = fieldValue.split(QRegExp("[,,]"), Qt::SkipEmptyParts);
  1342. QComboBox *comboBox = new QComboBox;
  1343. comboBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
  1344. comboBox->setFixedSize(140, 28);
  1345. comboBox->setStyleSheet(R"(
  1346. QComboBox {
  1347. background: #FFFFFF;
  1348. border: 1px solid #BABBDC;
  1349. border-radius: 6px;
  1350. padding: 2px 5px;
  1351. }
  1352. QComboBox::drop-down {
  1353. width: 20px;
  1354. }
  1355. )");
  1356. // int newIndex = -1;
  1357. for (const QString &opt : optionList) {
  1358. QString trimmedOpt = opt.trimmed();
  1359. if (!trimmedOpt.isEmpty())
  1360. comboBox->addItem(trimmedOpt);
  1361. }
  1362. if(fieldCurrentValue == ""){
  1363. comboBox->setCurrentIndex(0);
  1364. }else{
  1365. comboBox->setCurrentIndex(fieldCurrentValue.toInt());
  1366. }
  1367. rightLayout->addWidget(comboBox);
  1368. createdWidget = comboBox;
  1369. // 使用Lambda函数连接 currentIndexChanged 信号
  1370. connect(comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), [this,comboBox,fieldTableName,fieldId](int index) {
  1371. QString selectedText = comboBox->itemText(index);
  1372. QString indexString = QString::number(index);
  1373. // qDebug() << "ComboBox index changed to:" << index << "Text:" << selectedText;
  1374. updateDb(fieldTableName,fieldId,indexString);
  1375. // 在这里添加你想要执行的操作
  1376. });
  1377. }
  1378. else if (fieldType == "time") {
  1379. QTimeEdit *timeEdit = new QTimeEdit;
  1380. timeEdit->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
  1381. timeEdit->setFixedSize(120, 28);
  1382. timeEdit->setStyleSheet(R"(
  1383. QTimeEdit {
  1384. background: #FFFFFF;
  1385. border: 1px solid #BABBDC;
  1386. border-radius: 6px;
  1387. padding: 2px 5px;
  1388. }
  1389. )");
  1390. timeEdit->setDisplayFormat("HH:mm:ss");
  1391. timeEdit->setTime(QTime::fromString(fieldValue, "HH:mm:ss"));
  1392. rightLayout->addWidget(timeEdit);
  1393. createdWidget = timeEdit;
  1394. }
  1395. else if (fieldType == "switch") {
  1396. QWidget *switchContainer = new QWidget;
  1397. QHBoxLayout *switchLayout = new QHBoxLayout(switchContainer);
  1398. switchLayout->setSpacing(5);
  1399. switchLayout->setContentsMargins(0, 0, 0, 0);
  1400. QCheckBox *switchBox = new QCheckBox;
  1401. switchBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
  1402. switchBox->setFixedSize(30, 30);
  1403. switchBox->setStyleSheet(R"(
  1404. QCheckBox::indicator {
  1405. width: 30px;
  1406. height: 30px;
  1407. }
  1408. QCheckBox::indicator:unchecked {
  1409. background-color: #BABBDC;
  1410. border-radius: 6px;
  1411. }
  1412. QCheckBox::indicator:checked {
  1413. background-color: #4CAF50;
  1414. border-radius: 6px;
  1415. }
  1416. )");
  1417. QString switchValue;
  1418. if(fieldCurrentValue==""){
  1419. switchValue = fieldValue.toLower();
  1420. }else{
  1421. switchValue = fieldCurrentValue.toLower();
  1422. }
  1423. if (switchValue == "on")
  1424. switchBox->setChecked(true);
  1425. else
  1426. switchBox->setChecked(false);
  1427. QLabel *switchLabel = new QLabel(switchBox->isChecked() ? "开" : "关");
  1428. switchLabel->setAlignment(Qt::AlignVCenter | Qt::AlignLeft);
  1429. switchLabel->setStyleSheet("font-size: 14px;");
  1430. connect(switchBox, &QCheckBox::stateChanged, [fieldTableName,fieldId,switchLabel, this](int state){
  1431. if (state == Qt::Checked){
  1432. switchLabel->setText("开");
  1433. updateDb(fieldTableName,fieldId,"on");
  1434. }else{
  1435. switchLabel->setText("关");
  1436. updateDb(fieldTableName,fieldId,"off");
  1437. }
  1438. });
  1439. switchLayout->addWidget(switchBox);
  1440. switchLayout->addWidget(switchLabel);
  1441. rightLayout->addWidget(switchContainer);
  1442. createdWidget = switchBox;
  1443. }
  1444. else if (fieldType == "combined") {
  1445. // 用逗号分隔
  1446. QStringList parts = fieldValue.split(QRegExp("[,,]"), Qt::SkipEmptyParts);
  1447. QString inputText = (parts.size() >= 1 ? parts.at(0).trimmed() : QString());
  1448. QString button1Text = (parts.size() >= 2 ? parts.at(1).trimmed() : QStringLiteral("获取"));
  1449. QString button2Text = (parts.size() >= 3 ? parts.at(2).trimmed() : QStringLiteral("设置"));
  1450. QLineEdit *comboInput = new QLineEdit(inputText);
  1451. comboInput->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
  1452. comboInput->setFixedHeight(28);
  1453. comboInput->setStyleSheet(R"(
  1454. QLineEdit {
  1455. background: #FFFFFF;
  1456. border: 1px solid #BABBDC;
  1457. border-radius: 5px;
  1458. padding: 2px 5px;
  1459. }
  1460. )");
  1461. m_fieldWidgets.append(comboInput);
  1462. QWidget *combinedWidget = new QWidget;
  1463. QHBoxLayout *combinedLayout = new QHBoxLayout(combinedWidget);
  1464. combinedLayout->setSpacing(5);
  1465. combinedLayout->setContentsMargins(0, 0, 0, 0);
  1466. QPushButton *btnGet = new QPushButton(button1Text, combinedWidget);
  1467. btnGet->setFixedSize(80, 28);
  1468. btnGet->setStyleSheet(R"(
  1469. QPushButton {
  1470. background: #FFFFFF;
  1471. border: 1px solid #BABBDC;
  1472. border-radius: 5px;
  1473. }
  1474. QPushButton:hover {
  1475. background-color: #F0F0F0;
  1476. }
  1477. )");
  1478. m_fieldWidgets.append(btnGet);
  1479. QPushButton *btnSet = new QPushButton(button2Text, combinedWidget);
  1480. btnSet->setFixedSize(80, 28);
  1481. btnSet->setStyleSheet(R"(
  1482. QPushButton {
  1483. background: #FFFFFF;
  1484. border: 1px solid #BABBDC;
  1485. border-radius: 5px;
  1486. }
  1487. QPushButton:hover {
  1488. background-color: #F0F0F0;
  1489. }
  1490. )");
  1491. m_fieldWidgets.append(btnSet);
  1492. combinedLayout->addWidget(comboInput);
  1493. combinedLayout->addWidget(btnGet);
  1494. combinedLayout->addWidget(btnSet);
  1495. combinedLayout->addStretch();
  1496. rightLayout->addWidget(combinedWidget);
  1497. }
  1498. else {
  1499. qWarning() << "未知字段类型:" << fieldType;
  1500. }
  1501. if (createdWidget)
  1502. m_fieldWidgets.append(createdWidget);
  1503. fieldLayout->addWidget(rightWidget);
  1504. scrollLayout->addLayout(fieldLayout);
  1505. }
  1506. }
  1507. scrollLayout->addStretch();
  1508. scrollArea->setWidget(scrollWidget);
  1509. QVBoxLayout *mainLayout = new QVBoxLayout(m_thirdLevelFieldWnd);
  1510. mainLayout->setContentsMargins(0, 0, 0, 0);
  1511. mainLayout->addWidget(scrollArea);
  1512. m_thirdLevelFieldWnd->show();
  1513. }
  1514. void DbTreeViewManager::updateParentCheckState(QStandardItem *item)
  1515. {
  1516. if (!item)
  1517. return;
  1518. QStandardItem *parentItem = item->parent();
  1519. if (!parentItem)
  1520. return;
  1521. bool allChecked = true;
  1522. bool noneChecked = true;
  1523. for (int i = 0; i < parentItem->rowCount(); ++i) {
  1524. QStandardItem *child = parentItem->child(i);
  1525. if (child->checkState() != Qt::Checked) {
  1526. allChecked = false;
  1527. }
  1528. if (child->checkState() == Qt::Checked) {
  1529. noneChecked = false;
  1530. }
  1531. }
  1532. if (allChecked) {
  1533. parentItem->setCheckState(Qt::Checked);
  1534. } else {
  1535. parentItem->setCheckState(Qt::Unchecked);
  1536. }
  1537. if (noneChecked) {
  1538. qDebug() << "noneChecked状态为:" << noneChecked;
  1539. }
  1540. // 递归更新上一级
  1541. updateParentCheckState(parentItem);
  1542. }
  1543. void DbTreeViewManager::onButtonBackClicked()
  1544. {
  1545. if (m_thirdLevelFieldWnd) {
  1546. // 当前在第三层目录,返回到上一层目录
  1547. qDebug() << "当前在第三层目录,准备返回上一层。";
  1548. for(int i=0;i<5;i++){
  1549. if(currentMenuId == menuArray[i].menuId){
  1550. menuArray[i].isthird = false;
  1551. }
  1552. }
  1553. // 关闭并销毁字段展示窗口
  1554. m_thirdLevelFieldWnd->close();
  1555. m_thirdLevelFieldWnd->deleteLater();
  1556. m_thirdLevelFieldWnd = nullptr;
  1557. // 显示目录树和分隔线
  1558. treeViewDown->show();
  1559. for (auto separator : firstLevelSeparators) {
  1560. if (separator)
  1561. separator->show();
  1562. }
  1563. // 获取当前导航路径
  1564. QStringList path;
  1565. QLayout* layout = navigationWidget->layout();
  1566. if (!layout) {
  1567. qWarning() << "导航栏没有布局,无法获取路径。";
  1568. return;
  1569. }
  1570. for (int i = 0; i < layout->count(); ++i) {
  1571. QLayoutItem* item = layout->itemAt(i);
  1572. if (item && item->widget()) {
  1573. QLabel* label = qobject_cast<QLabel*>(item->widget());
  1574. if (label) {
  1575. QString text = label->text().trimmed();
  1576. if (!text.isEmpty()) {
  1577. path << text;
  1578. }
  1579. }
  1580. }
  1581. }
  1582. if (path.isEmpty()) {
  1583. qWarning() << "导航路径为空,无法返回上一层。";
  1584. return;
  1585. }
  1586. // 移除最后一个目录名称以返回上一层
  1587. path.removeLast();
  1588. if (path.isEmpty()) {
  1589. qDebug() << "已经在根目录,无法返回。";
  1590. return;
  1591. }
  1592. // 根据新的路径查找对应的 QModelIndex
  1593. QModelIndex parentIndex = findItemByPath(path);
  1594. if (!parentIndex.isValid()) {
  1595. qWarning() << "无法找到路径对应的目录项:" << path;
  1596. return;
  1597. }
  1598. // 选中父目录项
  1599. treeViewDown->setCurrentIndex(parentIndex);
  1600. treeViewDown->scrollTo(parentIndex);
  1601. // 更新导航栏
  1602. updateNavigationBar(parentIndex);
  1603. // 检查父目录是否为第三层目录
  1604. QStandardItem* parentItem = model->itemFromIndex(parentIndex);
  1605. if (!parentItem) {
  1606. qWarning() << "父目录项无效。";
  1607. return;
  1608. }
  1609. QVariant dataVar = parentItem->data(Qt::UserRole + 2);
  1610. bool isThirdLevel = false;
  1611. int directoryId = -1;
  1612. if (dataVar.canConvert<QJsonObject>()) {
  1613. QJsonObject dataObj = dataVar.toJsonObject();
  1614. if (dataObj.contains("IsThirdLevel") && dataObj["IsThirdLevel"].toBool()) {
  1615. isThirdLevel = true;
  1616. if (dataObj.contains("Id")) {
  1617. directoryId = dataObj["Id"].toInt();
  1618. }
  1619. }
  1620. }
  1621. if (isThirdLevel) {
  1622. if (directoryId == -1) {
  1623. qWarning() << "无效的 DirectoryId,无法加载第三层目录内容。";
  1624. return;
  1625. }
  1626. int userPrivilege = 0x1; // 当前用户的权限等级
  1627. // 获取第三层目录的数据
  1628. QJsonObject data = fetchThirdLevelData(directoryId, userPrivilege);
  1629. // 显示字段展示窗口
  1630. displayThirdLevelFields(data, false); // 传递参数表示非 Home 界面
  1631. } else {
  1632. // 父目录不是第三层目录,确保目录树和分隔线可见
  1633. treeViewDown->show();
  1634. for (auto separator : firstLevelSeparators) {
  1635. if (separator)
  1636. separator->show();
  1637. }
  1638. }
  1639. return;
  1640. }
  1641. // 如果不在第三层目录,则在目录树中返回上一层
  1642. qDebug() << "当前不在第三层目录,尝试在目录树中返回上一层。";
  1643. QModelIndex currentIndex = treeViewDown->currentIndex();
  1644. if (!currentIndex.isValid()) {
  1645. qWarning() << "当前没有选中的目录项,无法返回。";
  1646. return;
  1647. }
  1648. QStandardItem* currentItem = model->itemFromIndex(currentIndex);
  1649. if (!currentItem) {
  1650. qWarning() << "当前选中的目录项无效。";
  1651. return;
  1652. }
  1653. QStandardItem* parentItem = currentItem->parent();
  1654. if (!parentItem) {
  1655. qDebug() << "当前已经在根目录,无法返回。";
  1656. return;
  1657. }
  1658. QModelIndex parentIndex = model->indexFromItem(parentItem);
  1659. if (!parentIndex.isValid()) {
  1660. qWarning() << "父目录的 QModelIndex 无效。";
  1661. return;
  1662. }
  1663. // 选中父目录项
  1664. treeViewDown->setCurrentIndex(parentIndex);
  1665. treeViewDown->scrollTo(parentIndex);
  1666. // 更新导航栏
  1667. updateNavigationBar(parentIndex);
  1668. // 检查父目录是否为第三层目录
  1669. QVariant dataVar = parentItem->data(Qt::UserRole + 2);
  1670. bool isThirdLevel = false;
  1671. int directoryId = -1;
  1672. if (dataVar.canConvert<QJsonObject>()) {
  1673. QJsonObject dataObj = dataVar.toJsonObject();
  1674. if (dataObj.contains("IsThirdLevel") && dataObj["IsThirdLevel"].toBool()) {
  1675. isThirdLevel = true;
  1676. if (dataObj.contains("Id")) {
  1677. directoryId = dataObj["Id"].toInt();
  1678. }
  1679. }
  1680. }
  1681. if (isThirdLevel) {
  1682. if (directoryId == -1) {
  1683. qWarning() << "无效的 DirectoryId,无法加载第三层目录内容。";
  1684. return;
  1685. }
  1686. int userPrivilege = 0x1; // 根据实际情况获取当前用户的权限等级
  1687. QJsonObject data = fetchThirdLevelData(directoryId, userPrivilege);
  1688. displayThirdLevelFields(data, false); // 传递参数表示非 Home 界面
  1689. }
  1690. }
  1691. QList<QStandardItem*> DbTreeViewManager::collectAllThirdLevelItems()
  1692. {
  1693. QList<QStandardItem*> result;
  1694. // 从根节点开始递归搜集
  1695. QStandardItem *root = model->invisibleRootItem();
  1696. if (!root) return result;
  1697. std::function<void(QStandardItem*)> dfsCollectThirdLevel;
  1698. dfsCollectThirdLevel = [&](QStandardItem* parentItem)
  1699. {
  1700. if (!parentItem) return;
  1701. int rowCount = parentItem->rowCount();
  1702. for (int i = 0; i < rowCount; ++i) {
  1703. QStandardItem *child = parentItem->child(i);
  1704. if (!child) continue;
  1705. // 判断是否是第三层
  1706. QVariant dataVar = child->data(Qt::UserRole + 2);
  1707. if (dataVar.canConvert<QJsonObject>()) {
  1708. QJsonObject obj = dataVar.toJsonObject();
  1709. if (obj.contains("IsThirdLevel") && obj["IsThirdLevel"].toBool()) {
  1710. // 收集这个第三层节点
  1711. result.append(child);
  1712. }
  1713. }
  1714. // 即使不是第三层,也要继续往下找子节点
  1715. dfsCollectThirdLevel(child);
  1716. }
  1717. };
  1718. dfsCollectThirdLevel(root);
  1719. return result;
  1720. }
  1721. void DbTreeViewManager::onButtonDownClicked()
  1722. {
  1723. // 1) 收集所有 第三层 节点
  1724. QList<QStandardItem*> thirdLevelList = collectAllThirdLevelItems();
  1725. if (thirdLevelList.isEmpty()) {
  1726. qDebug() << "[onButtonDownClicked] 没有任何三级目录,无法遍历。";
  1727. return;
  1728. }
  1729. // 2) 找到 当前选中的节点 在 thirdLevelList 里的索引
  1730. QModelIndex curIndex = treeViewDown->currentIndex();
  1731. if (!curIndex.isValid()) {
  1732. qDebug() << "[onButtonDownClicked] 当前没有选中节点,默认跳到第一个三级目录。";
  1733. // 如果想默认跳到第一个
  1734. QStandardItem *firstItem = thirdLevelList.first();
  1735. QModelIndex idx = model->indexFromItem(firstItem);
  1736. treeViewDown->setCurrentIndex(idx);
  1737. // 模拟点击一下
  1738. onTreeViewClicked_updown(idx);
  1739. // 保存复选框状态
  1740. saveCheckedPaths();
  1741. // 保存展开路径
  1742. saveExpandedPaths();
  1743. return;
  1744. }
  1745. QStandardItem *curItem = model->itemFromIndex(curIndex);
  1746. if (!curItem) {
  1747. qWarning() << "[onButtonDownClicked] currentItem 无效。";
  1748. return;
  1749. }
  1750. // 若不是三级目录,就先找它最近的父级是不是三级目录,否则当做没找到。
  1751. int currentPos = -1;
  1752. {
  1753. // 在 thirdLevelList 里找到 curItem
  1754. currentPos = thirdLevelList.indexOf(curItem);
  1755. if (currentPos < 0) {
  1756. qDebug() << "[onButtonDownClicked] 当前节点不是三级目录,尝试找父级是不是三级目录…";
  1757. // 向上找父节点是否在 thirdLevelList 里
  1758. QStandardItem *temp = curItem->parent();
  1759. while (temp) {
  1760. int pos = thirdLevelList.indexOf(temp);
  1761. if (pos >= 0) {
  1762. currentPos = pos;
  1763. break;
  1764. }
  1765. temp = temp->parent();
  1766. }
  1767. if (currentPos < 0) {
  1768. qDebug() << "还是找不到,说明当前目录不属于任何三级目录,直接跳到第一个";
  1769. QStandardItem *firstItem = thirdLevelList.first();
  1770. QModelIndex idx = model->indexFromItem(firstItem);
  1771. treeViewDown->setCurrentIndex(idx);
  1772. onTreeViewClicked_updown(idx);
  1773. // 保存复选框状态
  1774. saveCheckedPaths();
  1775. // 保存展开路径
  1776. saveExpandedPaths();
  1777. return;
  1778. }
  1779. }
  1780. }
  1781. // 尝试下一个
  1782. int nextPos = currentPos + 1;
  1783. if (nextPos >= thirdLevelList.size()) {
  1784. qDebug() << "[onButtonDownClicked] 已经是最后一个三级目录了,无法再向下。";
  1785. return;
  1786. }
  1787. // 跳到下一个
  1788. QStandardItem *nextItem = thirdLevelList[nextPos];
  1789. QModelIndex nextIndex = model->indexFromItem(nextItem);
  1790. treeViewDown->setCurrentIndex(nextIndex);
  1791. // 相当于模拟点击
  1792. onTreeViewClicked_updown(nextIndex);
  1793. // 保存复选框状态
  1794. saveCheckedPaths();
  1795. // 保存展开路径
  1796. saveExpandedPaths();
  1797. }
  1798. void DbTreeViewManager::onButtonUpClicked()
  1799. {
  1800. // 1) 收集所有 第三层 节点
  1801. QList<QStandardItem*> thirdLevelList = collectAllThirdLevelItems();
  1802. if (thirdLevelList.isEmpty()) {
  1803. qDebug() << "[onButtonUpClicked] 没有任何三级目录,无法遍历。";
  1804. return;
  1805. }
  1806. // 2) 找到 当前选中的节点
  1807. QModelIndex curIndex = treeViewDown->currentIndex();
  1808. if (!curIndex.isValid()) {
  1809. qDebug() << "[onButtonUpClicked] 当前无选中节点,默认跳到最后一个三级目录。";
  1810. // 跳到最后一个
  1811. QStandardItem *lastItem = thirdLevelList.last();
  1812. QModelIndex idx = model->indexFromItem(lastItem);
  1813. treeViewDown->setCurrentIndex(idx);
  1814. // 模拟点击
  1815. onTreeViewClicked_updown(idx);
  1816. // 保存复选框状态
  1817. saveCheckedPaths();
  1818. // 保存展开路径
  1819. saveExpandedPaths();
  1820. return;
  1821. }
  1822. QStandardItem *curItem = model->itemFromIndex(curIndex);
  1823. if (!curItem) {
  1824. qWarning() << "[onButtonUpClicked] currentItem 无效。";
  1825. return;
  1826. }
  1827. // 如果当前节点不是三级目录, 向上查找
  1828. int currentPos = thirdLevelList.indexOf(curItem);
  1829. if (currentPos < 0) {
  1830. qDebug() << "[onButtonUpClicked] 当前节点不是三级目录,尝试找父级是不是三级目录。";
  1831. QStandardItem *temp = curItem->parent();
  1832. while (temp) {
  1833. int pos = thirdLevelList.indexOf(temp);
  1834. if (pos >= 0) {
  1835. currentPos = pos;
  1836. break;
  1837. }
  1838. temp = temp->parent();
  1839. }
  1840. if (currentPos < 0) {
  1841. qDebug() << "找不到任何三级目录,直接跳到最后一个。";
  1842. QStandardItem *lastItem = thirdLevelList.last();
  1843. QModelIndex idx = model->indexFromItem(lastItem);
  1844. treeViewDown->setCurrentIndex(idx);
  1845. onTreeViewClicked_updown(idx);
  1846. // 保存复选框状态
  1847. saveCheckedPaths();
  1848. // 保存展开路径
  1849. saveExpandedPaths();
  1850. return;
  1851. }
  1852. }
  1853. // 尝试上一个
  1854. int prevPos = currentPos - 1;
  1855. if (prevPos < 0) {
  1856. qDebug() << "[onButtonUpClicked] 已经是第一个三级目录了,无法再向上。";
  1857. return;
  1858. }
  1859. // 跳到上一个
  1860. QStandardItem *prevItem = thirdLevelList[prevPos];
  1861. QModelIndex prevIndex = model->indexFromItem(prevItem);
  1862. treeViewDown->setCurrentIndex(prevIndex);
  1863. // 模拟点击
  1864. onTreeViewClicked_updown(prevIndex);
  1865. // 保存复选框状态
  1866. saveCheckedPaths();
  1867. // 保存展开路径
  1868. saveExpandedPaths();
  1869. }
  1870. void DbTreeViewManager::onButtonRightClicked()
  1871. {
  1872. if (m_forwardStack.isEmpty()) {
  1873. qDebug() << "[Forward] 已经没有可以前进的页面";
  1874. buttonRight->setIcon(QIcon(":/images/home_right.png"));
  1875. return;
  1876. }
  1877. // 1. 弹出 forwardStack 的最后一个
  1878. PageState st = m_forwardStack.takeLast();
  1879. // 2. 把当前页面 push 到 backStack
  1880. PageState cur = getCurrentPageState();
  1881. m_backStack.append(cur);
  1882. if(m_backStack.size() >= 2){
  1883. buttonLeft->setIcon(QIcon(":/images/home_left.png"));
  1884. }
  1885. // 3. 加载 st
  1886. loadPageState(st, true);
  1887. }
  1888. void DbTreeViewManager::onButtonLeftClicked()
  1889. {
  1890. if (m_backStack.size() < 2) {
  1891. qDebug() << "[Back] 已经无法再后退";
  1892. buttonLeft->setIcon(QIcon(":/images/home_left_hide.png"));
  1893. return;
  1894. }
  1895. // 1. 先把当前页面(相当于 m_backStack 最后一个)弹出,放到 forwardStack
  1896. PageState cur = m_backStack.takeLast();
  1897. if(m_backStack.size() >= 2){
  1898. buttonLeft->setIcon(QIcon(":/images/home_left.png"));
  1899. }else{
  1900. buttonLeft->setIcon(QIcon(":/images/home_left_hide.png"));
  1901. }
  1902. m_forwardStack.append(cur);
  1903. buttonRight->setIcon(QIcon(":/images/home_right_show.png"));
  1904. // 2. 拿到新的 m_backStack 末尾(即上一次看的页面)
  1905. const PageState &prev = m_backStack.last();
  1906. // 3. 加载 prev
  1907. loadPageState(prev, true );
  1908. }
  1909. // 构建节点的完整路径
  1910. QStringList DbTreeViewManager::buildItemPath(QStandardItem *item)
  1911. {
  1912. QStringList path;
  1913. QStandardItem *currentItem = item;
  1914. while (currentItem) {
  1915. path.prepend(currentItem->text());
  1916. currentItem = currentItem->parent();
  1917. }
  1918. return path;
  1919. }
  1920. // 根据路径查找对应的节点
  1921. QModelIndex DbTreeViewManager::findItemByPath(const QStringList &path)
  1922. {
  1923. if (path.isEmpty()) return QModelIndex();
  1924. QStandardItem *currentItem = model->invisibleRootItem();
  1925. QModelIndex currentIndex;
  1926. for (const QString &part : path) {
  1927. bool found = false;
  1928. for (int i = 0; i < currentItem->rowCount(); ++i) {
  1929. QStandardItem *child = currentItem->child(i);
  1930. if (child->text() == part) {
  1931. currentIndex = model->indexFromItem(child);
  1932. currentItem = child;
  1933. found = true;
  1934. qDebug() << "找到路径部分:" << part;
  1935. break;
  1936. }
  1937. }
  1938. if (!found) {
  1939. qWarning() << "路径部分未找到:" << part;
  1940. return QModelIndex();
  1941. }
  1942. }
  1943. return currentIndex;
  1944. }
  1945. void DbTreeViewManager::setCheckedPaths(const QStringList &checkedPathsList)
  1946. {
  1947. m_blockItemChanged = true;
  1948. for (const QString &pathStr : checkedPathsList) {
  1949. QStringList path = pathStr.split("/");
  1950. QModelIndex idx = findItemByPath(path);
  1951. if (idx.isValid()) {
  1952. QStandardItem *item = model->itemFromIndex(idx);
  1953. if (item) {
  1954. item->setCheckState(Qt::Checked);
  1955. qDebug() << " Setting item:" << item->text() << "to Checked";
  1956. }
  1957. } else {
  1958. qDebug() << "Path not found:" << pathStr;
  1959. }
  1960. }
  1961. m_blockItemChanged = false;
  1962. }
  1963. // 递归收集被选中的路径
  1964. QStringList DbTreeViewManager::collectCheckedPathsRecursive(QStandardItem *item, QStringList path)
  1965. {
  1966. QStringList checkedList;
  1967. if (!item) {
  1968. item = model->invisibleRootItem();
  1969. }
  1970. for (int i = 0; i < item->rowCount(); ++i) {
  1971. QStandardItem *child = item->child(i);
  1972. if (child) {
  1973. QStringList currentPath = path;
  1974. currentPath << child->text();
  1975. if (child->checkState() == Qt::Checked) {
  1976. checkedList << currentPath.join("/");
  1977. }
  1978. // 递归收集子项
  1979. checkedList << collectCheckedPathsRecursive(child, currentPath);
  1980. }
  1981. }
  1982. return checkedList;
  1983. }
  1984. // 收集所有被选中的复选框路径
  1985. QStringList DbTreeViewManager::collectCheckedPaths()
  1986. {
  1987. return collectCheckedPathsRecursive(model->invisibleRootItem(), QStringList());
  1988. }
  1989. // 更新父项的复选框状态
  1990. void DbTreeViewManager::updateParentItems(QStandardItem *parentItem)
  1991. {
  1992. if (!parentItem)
  1993. return;
  1994. int checkedCount = 0;
  1995. int totalCount = parentItem->rowCount();
  1996. qDebug() << "Updating child items of:" << parentItem->text();
  1997. for (int i = 0; i < totalCount; ++i)
  1998. {
  1999. QStandardItem *child = parentItem->child(i);
  2000. if (child && child->checkState() == Qt::Checked)
  2001. {
  2002. checkedCount++;
  2003. }
  2004. }
  2005. if (checkedCount == totalCount)
  2006. {
  2007. parentItem->setCheckState(Qt::Checked);
  2008. }
  2009. else
  2010. {
  2011. parentItem->setCheckState(Qt::Unchecked);
  2012. }
  2013. // 递归更新上层父项
  2014. updateParentItems(parentItem->parent());
  2015. }
  2016. // 加载并显示三级目录对应按钮配置信息
  2017. void DbTreeViewManager::loadButtonConfigForThirdLevel(const QJsonObject &thirdLevelObj)
  2018. {
  2019. if (!m_originalWnd) {
  2020. qWarning() << "OriginalWnd 指针为空,无法加载按钮配置";
  2021. return;
  2022. }
  2023. if (!thirdLevelObj.contains("buttons")) {
  2024. qWarning() << "三级目录配置中不包含 'buttons' 字段";
  2025. return;
  2026. }
  2027. QJsonArray buttonsArray = thirdLevelObj.value("buttons").toArray();
  2028. // 获取 widget_left
  2029. QWidget* widgetLeft = m_originalWnd->getWidgetLeft();
  2030. if (!widgetLeft) {
  2031. qWarning() << "无法访问 widget_left";
  2032. return;
  2033. }
  2034. // 清空 widget_left 中由 loadButtonConfigForThirdLevel 创建的按钮
  2035. QList<QPushButton*> existingButtons = widgetLeft->findChildren<QPushButton*>();
  2036. for (QPushButton* button : existingButtons) {
  2037. if (button->objectName().startsWith("thirdLevelBtn_")) { // 仅删除特定按钮
  2038. button->deleteLater();
  2039. }
  2040. }
  2041. // 使用绝对定位创建按钮
  2042. for (int i = 0; i < buttonsArray.size() && i < 12; ++i) {
  2043. QJsonObject buttonObj = buttonsArray[i].toObject();
  2044. QString buttonId = buttonObj.value("id").toString();
  2045. QString buttonIcon = buttonObj.value("icon").toString();
  2046. QString buttonText = buttonObj.value("text").toString();
  2047. bool isEnabled = buttonObj.value("enabled").toBool();
  2048. // 创建按钮
  2049. QPushButton *button = new QPushButton(widgetLeft);
  2050. button->setObjectName("thirdLevelBtn_" + buttonId); // 设置带前缀的对象名称
  2051. // 设置按钮的样式,调整图标和文本的位置
  2052. button->setStyleSheet(R"(
  2053. QPushButton {
  2054. position: absolute;
  2055. border-radius: 6px;
  2056. opacity: 1;
  2057. background: #CBD0FF;
  2058. border: none;
  2059. }
  2060. QPushButton:hover {
  2061. background-color: #A9B4FF; /* 鼠标悬停效果 */
  2062. }
  2063. )");
  2064. // 设置按钮的位置和大小
  2065. int x = 16;
  2066. int y = 245 + i * (48 + 13); // 第一个按钮 y=245,后续每个按钮间隔13px
  2067. button->setGeometry(x, y, 158, 48);
  2068. // 设置按钮的可见性,根据 "enabled" 字段显示或隐藏按钮
  2069. button->setVisible(isEnabled);
  2070. // 创建图标标签
  2071. QLabel *iconLabel = new QLabel(button);
  2072. iconLabel->setPixmap(QIcon(buttonIcon).pixmap(16, 16));
  2073. iconLabel->setGeometry(10, 16, 16, 16); // 图标距离左边10px,顶部16px
  2074. iconLabel->setFixedSize(16, 16);
  2075. iconLabel->setStyleSheet("background-color: transparent;");
  2076. iconLabel->setVisible(isEnabled); // 根据按钮的可见性设置图标的可见性
  2077. // 创建文本标签
  2078. QLabel *textLabel = new QLabel(buttonText, button);
  2079. textLabel->setGeometry(34, 0, 90, 48); // 文本距离左边34px
  2080. textLabel->setWordWrap(true); // 允许换行
  2081. textLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
  2082. textLabel->setStyleSheet(R"(
  2083. QLabel {
  2084. background: transparent;
  2085. font-family: "思源黑体";
  2086. font-size: 14px;
  2087. font-weight: 500;
  2088. color: #4E51CE;
  2089. }
  2090. )");
  2091. textLabel->setVisible(isEnabled); // 根据按钮的可见性设置文本的可见性
  2092. // 创建 F1-F12 标签
  2093. QString fLabelText = QString("F%1").arg(i + 1); // F1, F2, ..., F12
  2094. QLabel *fLabel = new QLabel(fLabelText, button);
  2095. fLabel->setFixedSize(21, 16); // 设置大小为21x16
  2096. fLabel->setAlignment(Qt::AlignCenter);
  2097. fLabel->setStyleSheet(R"(
  2098. QLabel {
  2099. background-color: transparent;
  2100. color: #2A7ED8;
  2101. font-size: 12px;
  2102. font-weight: bold;
  2103. }
  2104. )");
  2105. // 设置标签的位置
  2106. int fX = 134;
  2107. int fY = 2;
  2108. fLabel->setGeometry(fX, fY, 14, 16);
  2109. fLabel->setVisible(isEnabled); // 根据按钮的可见性设置标签的可见性
  2110. // 将按钮、图标、文本和标签添加到控件列表
  2111. m_fieldWidgets.append(button);
  2112. m_fieldWidgets.append(iconLabel);
  2113. m_fieldWidgets.append(textLabel);
  2114. m_fieldWidgets.append(fLabel);
  2115. }
  2116. }
  2117. // 清理并隐藏三级目录菜单内容
  2118. void DbTreeViewManager::clearThirdLevelMenu()
  2119. {
  2120. // 遍历所有子控件,找到标题为 "字段展示" 的窗口并关闭
  2121. foreach (QObject *child, widget2->children()) {
  2122. QWidget *childWidget = qobject_cast<QWidget*>(child);
  2123. if (childWidget && childWidget->windowTitle() == "字段展示") {
  2124. qDebug() << "关闭现有的字段展示窗口";
  2125. childWidget->close();
  2126. }
  2127. }
  2128. // 显示主目录树和分隔线
  2129. treeViewDown->show();
  2130. for (auto separator : firstLevelSeparators) {
  2131. separator->show();
  2132. }
  2133. }
  2134. // 保存选中路径
  2135. void DbTreeViewManager::saveCheckedPaths()
  2136. {
  2137. if (m_currentConfigId == -1) {
  2138. qWarning() << "当前配置ID无效,无法保存复选框状态。";
  2139. return;
  2140. }
  2141. QSettings settings("RunCloudTech", "David");
  2142. QString configKey = QString::number(m_currentConfigId);
  2143. settings.beginGroup("TreeViewCheckedState");
  2144. // 保存选中路径
  2145. QString keyChecked = QString("checkedPaths/%1").arg(configKey);
  2146. QStringList checkedList = collectCheckedPaths();
  2147. settings.setValue(keyChecked, checkedList);
  2148. settings.endGroup();
  2149. qDebug() << "保存复选框状态路径:" << checkedList;
  2150. }
  2151. // 加载选中路径
  2152. void DbTreeViewManager::loadCheckedPaths()
  2153. {
  2154. if (m_currentConfigId == -1) {
  2155. qWarning() << "当前配置ID无效,无法加载复选框状态。";
  2156. return;
  2157. }
  2158. QSettings settings("RunCloudTech", "David");
  2159. QString configKey = QString::number(m_currentConfigId);
  2160. settings.beginGroup("TreeViewCheckedState");
  2161. // 读取选中路径
  2162. QString keyChecked = QString("checkedPaths/%1").arg(configKey);
  2163. QStringList loadedChecked = settings.value(keyChecked).toStringList();
  2164. settings.endGroup();
  2165. qDebug() << "加载复选框状态路径:" << loadedChecked;
  2166. m_blockItemChanged = true;
  2167. setCheckedPaths(loadedChecked);
  2168. m_blockItemChanged = false;
  2169. // 更新导航栏
  2170. if (!loadedChecked.isEmpty()) {
  2171. QString lastPathStr = loadedChecked.last();
  2172. QStringList lastPath = lastPathStr.split("/");
  2173. QModelIndex lastIdx = findItemByPath(lastPath);
  2174. if (lastIdx.isValid()) {
  2175. treeViewDown->setCurrentIndex(lastIdx);
  2176. updateNavigationBar(lastIdx);
  2177. }
  2178. } else {
  2179. // 如果没有加载到任何路径,自动选择第一个目录
  2180. QStandardItem *rootItem = model->invisibleRootItem();
  2181. if (rootItem->rowCount() > 0) {
  2182. QModelIndex firstIndex = model->index(0, 0, QModelIndex());
  2183. if (firstIndex.isValid()) {
  2184. treeViewDown->setCurrentIndex(firstIndex);
  2185. treeViewDown->expand(firstIndex); // 展开第一个目录
  2186. QStandardItem *firstItem = model->itemFromIndex(firstIndex);
  2187. QVariant data = firstItem->data(Qt::UserRole + 2);
  2188. if (data.canConvert<QJsonObject>()) {
  2189. QJsonObject thirdLevelObj = data.toJsonObject();
  2190. if (thirdLevelObj.contains("IsThirdLevel") && thirdLevelObj["IsThirdLevel"].toBool()) {
  2191. loadButtonConfigForThirdLevel(thirdLevelObj);
  2192. }
  2193. }
  2194. }
  2195. }
  2196. }
  2197. }
  2198. // 保存展开路径
  2199. void DbTreeViewManager::saveExpandedPaths()
  2200. {
  2201. if (m_currentConfigId == -1) {
  2202. qWarning() << "当前配置ID无效,无法保存展开路径。";
  2203. return;
  2204. }
  2205. QSettings settings("RunCloudTech", "David");
  2206. QString configKey = QString::number(m_currentConfigId);
  2207. settings.beginGroup("TreeViewExpandedState");
  2208. // 保存展开路径
  2209. QString keyExpanded = QString("expandedPaths/%1").arg(configKey);
  2210. QStringList expandedList = QStringList(expandedPaths.begin(), expandedPaths.end());
  2211. settings.setValue(keyExpanded, expandedList);
  2212. settings.endGroup();
  2213. qDebug() << "保存展开路径:" << expandedList;
  2214. }
  2215. // 加载展开路径
  2216. void DbTreeViewManager::loadExpandedPaths()
  2217. {
  2218. if (m_currentConfigId == -1) {
  2219. qWarning() << "当前配置ID无效,无法加载展开路径。";
  2220. return;
  2221. }
  2222. QSettings settings("RunCloudTech", "David");
  2223. QString configKey = QString::number(m_currentConfigId);
  2224. settings.beginGroup("TreeViewExpandedState");
  2225. // 读取展开路径
  2226. QString keyExpanded = QString("expandedPaths/%1").arg(configKey);
  2227. QStringList loadedExpanded = settings.value(keyExpanded).toStringList();
  2228. settings.endGroup();
  2229. qDebug() << "加载展开路径:" << loadedExpanded;
  2230. m_blockItemChanged = true;
  2231. // 恢复展开路径
  2232. for (const QString &p : loadedExpanded) {
  2233. QStringList path = p.split("/");
  2234. QModelIndex idx = findItemByPath(path);
  2235. if (idx.isValid()) {
  2236. treeViewDown->expand(idx);
  2237. expandedPaths.insert(p);
  2238. qDebug() << "成功恢复展开路径:" << p;
  2239. } else {
  2240. qDebug() << "未找到展开路径部分: " << p;
  2241. }
  2242. }
  2243. m_blockItemChanged = false;
  2244. }
  2245. // 清空历史
  2246. void DbTreeViewManager::clearHistory()
  2247. {
  2248. m_backStack.clear();
  2249. m_forwardStack.clear();
  2250. buttonLeft->setIcon(QIcon(":/images/home_left_hide.png"));
  2251. buttonRight->setIcon(QIcon(":/images/home_right.png"));
  2252. }
  2253. // 获取当前页面的 PageState
  2254. DbTreeViewManager::PageState DbTreeViewManager::getCurrentPageState()
  2255. {
  2256. PageState st;
  2257. st.isThirdLevel = false;
  2258. st.directoryId = -1;
  2259. // 判断是否在第三层窗口中
  2260. if (m_thirdLevelFieldWnd && m_thirdLevelFieldWnd->isVisible()) {
  2261. // 如果此时是在第三层界面,则用当前导航栏 or 目录树的 “选中项” 来获取路径
  2262. QModelIndex curIndex = treeViewDown->currentIndex();
  2263. if (!curIndex.isValid()) {
  2264. st.path << "未知目录";
  2265. } else {
  2266. QStandardItem* item = model->itemFromIndex(curIndex);
  2267. st.path = buildItemPath(item);
  2268. }
  2269. // 如果能拿到 DirectoryId,则置为第三层
  2270. QVariant dataVar = model->itemFromIndex(treeViewDown->currentIndex())->data(Qt::UserRole + 2);
  2271. if (dataVar.canConvert<QJsonObject>()) {
  2272. QJsonObject obj = dataVar.toJsonObject();
  2273. if (obj.contains("IsThirdLevel") && obj["IsThirdLevel"].toBool()) {
  2274. st.isThirdLevel = true;
  2275. st.directoryId = obj.value("Id").toInt(-1);
  2276. }
  2277. }
  2278. }
  2279. else {
  2280. // 当前是目录树界面,就看 treeView 选中项
  2281. QModelIndex curIndex = treeViewDown->currentIndex();
  2282. if (curIndex.isValid()) {
  2283. QStandardItem* item = model->itemFromIndex(curIndex);
  2284. st.path = buildItemPath(item);
  2285. // 检查是否第三层
  2286. QVariant dataVar = item->data(Qt::UserRole + 2);
  2287. if (dataVar.canConvert<QJsonObject>()) {
  2288. QJsonObject obj = dataVar.toJsonObject();
  2289. if (obj.contains("IsThirdLevel") && obj["IsThirdLevel"].toBool()) {
  2290. st.isThirdLevel = true;
  2291. st.directoryId = obj.value("Id").toInt(-1);
  2292. }
  2293. }
  2294. }
  2295. }
  2296. return st;
  2297. }
  2298. //加载指定的 PageState:相当于“回到该路径”或“跳转到这个第三层”
  2299. void DbTreeViewManager::loadPageState(const PageState &st, bool isByHistoryNav)
  2300. {
  2301. // 先根据 st.path 找到对应的节点
  2302. QModelIndex idx = findItemByPath(st.path);
  2303. if (!idx.isValid()) {
  2304. qWarning() << "[loadPageState] 未找到路径" << st.path;
  2305. return;
  2306. }
  2307. // 选中该节点
  2308. treeViewDown->setCurrentIndex(idx);
  2309. treeViewDown->scrollTo(idx);
  2310. // 更新导航栏
  2311. updateNavigationBar(idx);
  2312. // 如果是第三层,就加载对应的数据窗口
  2313. if (st.isThirdLevel && st.directoryId != -1) {
  2314. // 如果当前已在一个第三层窗口,先关闭它
  2315. if (m_thirdLevelFieldWnd) {
  2316. m_thirdLevelFieldWnd->close();
  2317. m_thirdLevelFieldWnd->deleteLater();
  2318. m_thirdLevelFieldWnd = nullptr;
  2319. }
  2320. int userPrivilege = 0x1;
  2321. QJsonObject data = fetchThirdLevelData(st.directoryId, userPrivilege);
  2322. displayThirdLevelFields(data, (m_currentConfigId == 1));
  2323. } else {
  2324. // 否则,显示目录树
  2325. if (m_thirdLevelFieldWnd) {
  2326. m_thirdLevelFieldWnd->close();
  2327. m_thirdLevelFieldWnd->deleteLater();
  2328. m_thirdLevelFieldWnd = nullptr;
  2329. }
  2330. treeViewDown->show();
  2331. for (auto sep : firstLevelSeparators) {
  2332. if (sep) sep->show();
  2333. }
  2334. }
  2335. if (!isByHistoryNav) {
  2336. m_forwardStack.clear();
  2337. buttonRight->setIcon(QIcon(":/images/home_right.png"));
  2338. // 把新状态压入后退栈
  2339. m_backStack.append(st);
  2340. if(m_backStack.size() >= 2){
  2341. buttonLeft->setIcon(QIcon(":/images/home_left.png"));
  2342. }
  2343. }
  2344. }
  2345. void DbTreeViewManager::loginput(const QString& fieldTableName,const int& fieldId,const QString& modifies){
  2346. // 获取当前时间并格式化
  2347. QDateTime currentDateTime = QDateTime::currentDateTime();
  2348. QString timestamp = currentDateTime.toString("yyyy-MM-dd hh:mm:ss");
  2349. QString logMessage = QString("%1 :fieldTableName is %2 and fieldId is %3 ,currentvalue is modified %4" ).arg(timestamp).arg(fieldTableName).arg(fieldId).arg(modifies);
  2350. QString pathoflog = "C:\\Users\\Administrator\\Desktop\\qt\\merge\\gujiangdong\\die-bonder-ui0218\\die-bonder-ui\\log/log.txt";
  2351. writeLogToFile(logMessage,pathoflog);
  2352. }
  2353. void DbTreeViewManager::writeLogToFile(const QString& logMessage, const QString& filePath) {
  2354. QFile logFile(filePath);
  2355. if (!logFile.open(QIODevice::Append | QIODevice::Text)) {
  2356. qWarning() << "Cannot open file for writing:" << filePath;
  2357. return;
  2358. }
  2359. QTextStream out(&logFile);
  2360. out << logMessage << "\n";
  2361. logFile.close();
  2362. }