增加网络配置界面

This commit is contained in:
2026-09-10 11:36:33 +08:00
parent 020278d4e3
commit 8e1fd3b2b8
44 changed files with 2488 additions and 332 deletions
+73 -12
View File
@@ -12,6 +12,14 @@
* 2026-09-08 王建锋 按代码规范 V1.0 补全分区注释与关键行注释;函数定义括号改 K&R 风格(同行)
* 2026-09-08 王建锋 4 层容器→单一持久容器(焦点/键唯一入口;键回调深度改取
* s_depth,去掉 user_data=depth;container/focus 调用去参)
* 2026-09-09 王建锋 密码页路由:需密码叶子(ui_menu_tab_has_pwd)ENTER
* → 先密码页;确认一致由 menu_password_ok 续做原"进入"动作
* (内容屏/子框)
* 2026-09-09 王建锋 权限模型:密码检查提到内容页判断之前(带内容页的受保护
* 叶子也先经密码页,修复"内容页叶子绕过密码"路由缺口);表 pwd
* 列改布尔"需密码"(行尾 #P);密码页按所输密码授权(查看→只读
* / 修改→可修改),授权经回调随开页传给内容页(页面经
* is_editable 判编辑);无密码叶子直接进、默认只读
*/
/* 头文件包含区 */
@@ -23,8 +31,12 @@
#include "ui_content_page.h"
#include "ui_page_password.h"
#include "ui_menu_tab.h"
#include "ui_pwd_def.h"
#include "lvgl.h"
#define DBG_TAG "[UI_MENU]"
@@ -95,15 +107,54 @@ static void menu_back(void) {
* 入口参数:node - 菜单节点下标 uint8_t
* 返回值:内容页 ID content_page_id_t;无内容页 = CONTENT_PAGE_COUNT
* 限定条件:无
* 函数说明:仅部分叶子有内容页(参考图 10/20/21);下标对应 ui_menu_tab.c
* node 1=装置信息、3=交流量、4=直流量(表序变更时须同步本映射)
* 函数说明:仅部分叶子有内容页(参考图 10/20/21 + 网口设置);下标对应
* ui_menu_tab.c
* node 1=装置信息、3=交流量、4=直流量、30=网口设置(表序变更时须同步本映射)
*/
static content_page_id_t menu_content_page_for(uint8_t node) {
switch (node) {
case 1u: return CONTENT_PAGE_DEVICE_INFO; /* 装置信息(L1 叶子) */
case 3u: return CONTENT_PAGE_AC; /* 交流量(实时数据子项) */
case 4u: return CONTENT_PAGE_DC; /* 直流量(实时数据子项) */
default: return (content_page_id_t)CONTENT_PAGE_COUNT; /* 无内容页 */
case 1u: return CONTENT_PAGE_DEVICE_INFO; /* 装置信息(L1 叶子) */
case 3u: return CONTENT_PAGE_AC; /* 交流量(实时数据子项) */
case 4u: return CONTENT_PAGE_DC; /* 直流量(实时数据子项) */
case 30u: return CONTENT_PAGE_NET_CFG; /* 网口设置(通讯参数子项,需密码) */
default: return (content_page_id_t)CONTENT_PAGE_COUNT; /* 无内容页 */
}
}
/*
* 函数功能:密码页确认一致回调(预装进密码页模块;uiTask 上下文调用)
* 入口参数:perm - 密码页按所输密码授予的权限 ui_perm_t(UI_PERM_MODIFY/UI_PERM_VIEW)
* 返回值:无
* 限定条件:密码页打开中;导航状态未变(选中条目仍为该受保护叶子)
* 函数说明: 1. 先关密码页(焦点回菜单容器、切回菜单屏;与 ESC 路径同模式,
* 事件内删对象由 LVGL e->deleted 机制保证安全)
* 2. 再沿未变的导航状态续做"进入"动作:有内容页 → 开内容页(携授予的
* 权限;页面经 is_editable 判只读/可编辑);否则压层进子框
* (叶子 → 空白终点框,权限不涉及)
* 3. 防御:状态异常 / 最深层无子层可压时仅停在菜单屏(页已关)
*/
static void menu_password_ok(uint8_t perm) {
ui_content_page_close(); /* 先关密码页回菜单屏,后续动作才不会落在被盖住的菜单屏上 */
uint8_t depth = s_depth;
uint8_t kids[MENU_ITEM_MAX];
uint8_t cnt = ui_menu_tab_children(s_path[depth], kids, MENU_ITEM_MAX);
if (cnt == 0u || s_sel[depth] >= cnt) {
return; /* 防御:状态异常,页已关,停在菜单屏 */
}
{
uint8_t child = kids[s_sel[depth]];
content_page_id_t pid = menu_content_page_for(child);
if (pid < CONTENT_PAGE_COUNT) {
ui_content_page_open(pid, perm); /* 页已关,守卫可过:开目标内容页(携权限) */
}
else if (depth < MENU_PAGE_MAX - 1u) {
menu_open(child); /* 压层:建新框 + 焦点移到新框(叶子 → 空白终点框) */
}
/* 最深层无子层可压:页已关,停在菜单屏 */
}
}
@@ -114,7 +165,10 @@ static content_page_id_t menu_content_page_for(uint8_t node) {
* 返回值:无
* 限定条件:ui_menu_init() 已完成
* 函数说明: 1. UP/DOWN:移选(首尾环绕);选中越出可见区由显示层跟随滚动
* 2. ENTER/RIGHT:叶子有内容页 → 切内容屏(不压层);否则进子框(叶子 → 空白终点框)
* 2. ENTER/RIGHT:需密码叶子(含带内容页者)→ 密码页(授权按所输
* 密码:查看→只读 / 修改→可修改,menu_password_ok 携权续进入);
* 否则叶子有内容页 → 切内容屏(不压层,默认只读);
* 再否则进子框(叶子 → 空白终点框)
* 3. ESC/LEFT:关最右框(根框不响应)
* 4. 空框(终点页 0 条目)只响应返回
*/
@@ -141,14 +195,21 @@ static void menu_key_handle(uint8_t depth, lv_key_t key) {
case LV_KEY_RIGHT: {
/* 进子框:空框无条目可进;最深层(depth=MAX-1)无子层可再开 */
if (cnt > 0u) {
content_page_id_t pid = menu_content_page_for(kids[s_sel[depth]]);
uint8_t child = kids[s_sel[depth]];
content_page_id_t pid = menu_content_page_for(child);
if (pid < CONTENT_PAGE_COUNT) {
/* 叶子有内容页:切内容屏(不压层,导航状态原样保留;ESC 返回即还原) */
ui_content_page_open(pid);
if (ui_menu_tab_has_pwd(child)) {
/* 需密码叶子(含带内容页者):先经密码页;授权按所输密码
(查看→只读 / 修改→可修改),回调携权续做"进入"动作 */
ui_page_password_arm(menu_password_ok);
ui_content_page_open(CONTENT_PAGE_PASSWORD, (uint8_t)UI_PERM_VIEW);
}
else if (pid < CONTENT_PAGE_COUNT) {
/* 叶子有内容页:无密码直接进(默认只读权限) */
ui_content_page_open(pid, (uint8_t)UI_PERM_VIEW);
}
else if (depth < MENU_PAGE_MAX - 1u) {
menu_open(kids[s_sel[depth]]); /* 压层:建新框 + 焦点移到新框(叶子 → 空白终点框) */
menu_open(child); /* 压层:建新框 + 焦点移到新框(叶子 → 空白终点框) */
}
}
break;