From 4423d528b1dc6ebe8b6f7b8272ca5111032a1608 Mon Sep 17 00:00:00 2001 From: QiuSW <105186638@qq.com> Date: Sun, 16 Aug 2026 23:12:53 +0800 Subject: [PATCH 1/6] =?UTF-8?q?fix:=20=E4=BF=9D=E7=95=99=20Sense=20GoAdmin?= =?UTF-8?q?=20=E5=BA=94=E7=94=A8=E5=A4=96=E5=A3=B3=20(#101)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../version/2026081623100_sense_layout.go | 85 +++++++ .../2026081623100_sense_layout_test.go | 208 ++++++++++++++++++ 2 files changed, 293 insertions(+) create mode 100644 Sense/server/cmd/migrate/migration/version/2026081623100_sense_layout.go create mode 100644 Sense/server/cmd/migrate/migration/version/2026081623100_sense_layout_test.go diff --git a/Sense/server/cmd/migrate/migration/version/2026081623100_sense_layout.go b/Sense/server/cmd/migrate/migration/version/2026081623100_sense_layout.go new file mode 100644 index 0000000..3b48a6a --- /dev/null +++ b/Sense/server/cmd/migrate/migration/version/2026081623100_sense_layout.go @@ -0,0 +1,85 @@ +package version + +import ( + "fmt" + "runtime" + + "gorm.io/gorm" + + "git.ilapage.cn/ila/yovision/Sense/server/cmd/migrate/migration" + migrationModels "git.ilapage.cn/ila/yovision/Sense/server/cmd/migrate/migration/models" + common "git.ilapage.cn/ila/yovision/Sense/server/common/models" +) + +const senseLayoutMenuName = "SenseManage" + +var sensePageMenus = []migrationModels.SysMenu{ + {MenuName: "SenseDeviceManage", Title: "设备管理", Icon: "monitor", Path: "devices", MenuType: "C", Permission: "sense:device:list", Component: "/sense/device/index", Sort: 1, Visible: "0", IsFrame: "1"}, + {MenuName: "SenseAdmission", Title: "视频接入", Icon: "video-camera", Path: "admission", MenuType: "C", Permission: "sense:admission:list", Component: "/sense/admission/index", Sort: 2, Visible: "0", IsFrame: "1"}, + {MenuName: "SenseMedia", Title: "视频服务", Icon: "video-play", Path: "media", MenuType: "C", Permission: "sense:media:list", Component: "/sense/media/index", Sort: 3, Visible: "0", IsFrame: "1"}, + {MenuName: "SenseLiveview", Title: "实时监看", Icon: "eye-open", Path: "liveview", MenuType: "C", Permission: "sense:liveview:view", Component: "/sense/liveview/index", Sort: 4, Visible: "0", IsFrame: "1"}, + {MenuName: "SenseArea", Title: "区域与警戒线", Icon: "guide", Path: "area", MenuType: "C", Permission: "sense:area:list", Component: "/sense/area/index", Sort: 5, Visible: "0", IsFrame: "1"}, +} + +func init() { + _, fileName, _, _ := runtime.Caller(0) + migration.Migrate.SetVersion(migration.GetFilename(fileName), migrateSenseLayout) +} + +func migrateSenseLayout(db *gorm.DB, version string) error { + return db.Transaction(func(tx *gorm.DB) error { + if err := alignSenseLayout(tx); err != nil { + return err + } + return tx.Create(&common.Migration{Version: version}).Error + }) +} + +func alignSenseLayout(tx *gorm.DB) error { + root, err := ensureDeviceMenu(tx, migrationModels.SysMenu{ + MenuName: senseLayoutMenuName, + Title: "视频感知", + Icon: "video-camera", + Path: "/sense", + MenuType: "M", + ParentId: 0, + Component: "Layout", + Sort: 5, + Visible: "0", + IsFrame: "1", + }) + if err != nil { + return fmt.Errorf("ensure Sense layout menu: %w", err) + } + + for _, desired := range sensePageMenus { + desired.ParentId = root.MenuId + desired.Paths = fmt.Sprintf("/0/%d", root.MenuId) + if _, err = ensureDeviceMenu(tx, desired); err != nil { + return fmt.Errorf("align Sense page menu %s: %w", desired.MenuName, err) + } + } + + if err = rebuildSenseMenuPaths(tx, root.MenuId, "/0"); err != nil { + return err + } + return nil +} + +func rebuildSenseMenuPaths(tx *gorm.DB, menuID int, parentPath string) error { + path := fmt.Sprintf("%s/%d", parentPath, menuID) + if err := tx.Model(&migrationModels.SysMenu{}).Where("menu_id = ?", menuID).Update("paths", path).Error; err != nil { + return fmt.Errorf("update menu %d paths: %w", menuID, err) + } + + var children []migrationModels.SysMenu + if err := tx.Where("parent_id = ?", menuID).Order("sort, menu_id").Find(&children).Error; err != nil { + return fmt.Errorf("list children of menu %d: %w", menuID, err) + } + for _, child := range children { + if err := rebuildSenseMenuPaths(tx, child.MenuId, path); err != nil { + return err + } + } + return nil +} diff --git a/Sense/server/cmd/migrate/migration/version/2026081623100_sense_layout_test.go b/Sense/server/cmd/migrate/migration/version/2026081623100_sense_layout_test.go new file mode 100644 index 0000000..3779a42 --- /dev/null +++ b/Sense/server/cmd/migrate/migration/version/2026081623100_sense_layout_test.go @@ -0,0 +1,208 @@ +package version + +import ( + "fmt" + "os" + "testing" + + "gorm.io/driver/postgres" + "gorm.io/driver/sqlite" + "gorm.io/gorm" + + migrationModels "git.ilapage.cn/ila/yovision/Sense/server/cmd/migrate/migration/models" + common "git.ilapage.cn/ila/yovision/Sense/server/common/models" +) + +func TestAlignSenseLayoutPreservesShellAndExistingPages(t *testing.T) { + db := openSenseLayoutTestDB(t) + seedLegacySenseMenus(t, db) + associationsBefore := countRoleMenuAssociations(t, db) + + if err := alignSenseLayout(db); err != nil { + t.Fatal(err) + } + // The alignment helper is intentionally idempotent because partially upgraded + // deployments may rerun the repair before the migration version is recorded. + if err := alignSenseLayout(db); err != nil { + t.Fatalf("repeat alignment: %v", err) + } + + root := requireMenu(t, db, senseLayoutMenuName) + if root.ParentId != 0 || root.Component != "Layout" || root.Path != "/sense" || root.MenuType != "M" { + t.Fatalf("unexpected root menu: %#v", root) + } + if root.Paths != fmt.Sprintf("/0/%d", root.MenuId) { + t.Fatalf("root paths=%q", root.Paths) + } + + for _, desired := range sensePageMenus { + page := requireMenu(t, db, desired.MenuName) + if page.ParentId != root.MenuId || page.Path != desired.Path || page.Component != desired.Component || page.Permission != desired.Permission { + t.Errorf("unexpected page %s: %#v", desired.MenuName, page) + } + wantPagePaths := fmt.Sprintf("/0/%d/%d", root.MenuId, page.MenuId) + if page.Paths != wantPagePaths { + t.Errorf("page %s paths=%q want %q", desired.MenuName, page.Paths, wantPagePaths) + } + + var buttons []migrationModels.SysMenu + if err := db.Where("parent_id = ? AND menu_type = ?", page.MenuId, "F").Find(&buttons).Error; err != nil { + t.Fatal(err) + } + if len(buttons) != 1 { + t.Fatalf("page %s button count=%d", desired.MenuName, len(buttons)) + } + wantButtonPaths := fmt.Sprintf("%s/%d", wantPagePaths, buttons[0].MenuId) + if buttons[0].Paths != wantButtonPaths { + t.Errorf("button %s paths=%q want %q", buttons[0].MenuName, buttons[0].Paths, wantButtonPaths) + } + } + + var rootCount int64 + if err := db.Model(&migrationModels.SysMenu{}).Where("menu_name = ?", senseLayoutMenuName).Count(&rootCount).Error; err != nil { + t.Fatal(err) + } + if rootCount != 1 { + t.Fatalf("Sense layout menu count=%d", rootCount) + } + if associationsAfter := countRoleMenuAssociations(t, db); associationsAfter != associationsBefore { + t.Fatalf("role-menu associations changed from %d to %d", associationsBefore, associationsAfter) + } +} + +func TestMigrateSenseLayoutRollsBackWhenRequiredPageIsMissing(t *testing.T) { + db := openSenseLayoutTestDB(t) + seedLegacySenseMenus(t, db) + if err := db.Where("menu_name = ?", "SenseArea").Delete(&migrationModels.SysMenu{}).Error; err != nil { + t.Fatal(err) + } + + // A missing page is recreated by the repair, so force a failure when the + // migration records its version and verify the menu transaction also rolls back. + version := "2026081623100" + if err := db.Create(&common.Migration{Version: version}).Error; err != nil { + t.Fatal(err) + } + if err := migrateSenseLayout(db, version); err == nil { + t.Fatal("expected duplicate migration version error") + } + + var rootCount, areaCount int64 + db.Model(&migrationModels.SysMenu{}).Where("menu_name = ?", senseLayoutMenuName).Count(&rootCount) + db.Model(&migrationModels.SysMenu{}).Where("menu_name = ?", "SenseArea").Count(&areaCount) + if rootCount != 0 || areaCount != 0 { + t.Fatalf("transaction left partial menus: root=%d area=%d", rootCount, areaCount) + } +} + +func openSenseLayoutTestDB(t *testing.T) *gorm.DB { + t.Helper() + db, err := gorm.Open(sqlite.Open("file:"+t.Name()+"?mode=memory&cache=shared"), &gorm.Config{}) + if err != nil { + t.Fatal(err) + } + if err = db.AutoMigrate(&migrationModels.SysRole{}, &migrationModels.SysMenu{}, &common.Migration{}); err != nil { + t.Fatal(err) + } + return db +} + +func TestSenseLayoutMigrationOnPostgres(t *testing.T) { + dsn := os.Getenv("SENSE_LAYOUT_MIGRATION_TEST_DATABASE_URL") + if dsn == "" { + t.Skip("set SENSE_LAYOUT_MIGRATION_TEST_DATABASE_URL to run the PostgreSQL migration test") + } + db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{}) + if err != nil { + t.Fatal(err) + } + const schema = "sense_layout_101_test" + if err = db.Exec("DROP SCHEMA IF EXISTS " + schema + " CASCADE").Error; err != nil { + t.Fatal(err) + } + if err = db.Exec("CREATE SCHEMA " + schema).Error; err != nil { + t.Fatal(err) + } + t.Cleanup(func() { db.Exec("DROP SCHEMA IF EXISTS " + schema + " CASCADE") }) + sqlDB, err := db.DB() + if err != nil { + t.Fatal(err) + } + sqlDB.SetMaxOpenConns(1) + if err = db.Exec("SET search_path TO " + schema).Error; err != nil { + t.Fatal(err) + } + if err = db.AutoMigrate(&migrationModels.SysRole{}, &migrationModels.SysMenu{}, &common.Migration{}); err != nil { + t.Fatal(err) + } + seedLegacySenseMenus(t, db) + + const version = "2026081623100" + if err = migrateSenseLayout(db, version); err != nil { + t.Fatal(err) + } + root := requireMenu(t, db, senseLayoutMenuName) + if root.Component != "Layout" || root.Path != "/sense" { + t.Fatalf("unexpected PostgreSQL root: %#v", root) + } + var pages, versions int64 + db.Model(&migrationModels.SysMenu{}).Where("parent_id = ? AND menu_type = ?", root.MenuId, "C").Count(&pages) + db.Model(&common.Migration{}).Where("version = ?", version).Count(&versions) + if pages != int64(len(sensePageMenus)) || versions != 1 { + t.Fatalf("pages=%d versions=%d", pages, versions) + } +} + +func seedLegacySenseMenus(t *testing.T, db *gorm.DB) { + t.Helper() + role := migrationModels.SysRole{RoleName: "site_admin", RoleKey: "site_admin", Status: "2"} + if err := db.Create(&role).Error; err != nil { + t.Fatal(err) + } + assigned := make([]migrationModels.SysMenu, 0, len(sensePageMenus)*2) + for index, desired := range sensePageMenus { + legacy := desired + legacy.Path = "/sense/" + desired.Path + legacy.ParentId = 0 + legacy.Sort = index + 5 + legacy.Paths = "" + if err := db.Create(&legacy).Error; err != nil { + t.Fatal(err) + } + button := migrationModels.SysMenu{ + MenuName: desired.MenuName + "Action", + Title: "测试操作", + MenuType: "F", + Permission: desired.Permission + ":action", + ParentId: legacy.MenuId, + Paths: fmt.Sprintf("/0/%d", legacy.MenuId), + Visible: "1", + IsFrame: "1", + } + if err := db.Create(&button).Error; err != nil { + t.Fatal(err) + } + assigned = append(assigned, legacy, button) + } + if err := db.Model(&role).Association("SysMenu").Append(assigned); err != nil { + t.Fatal(err) + } +} + +func countRoleMenuAssociations(t *testing.T, db *gorm.DB) int64 { + t.Helper() + var count int64 + if err := db.Table("sys_role_menu").Count(&count).Error; err != nil { + t.Fatal(err) + } + return count +} + +func requireMenu(t *testing.T, db *gorm.DB, name string) migrationModels.SysMenu { + t.Helper() + var menu migrationModels.SysMenu + if err := db.Where("menu_name = ?", name).First(&menu).Error; err != nil { + t.Fatal(err) + } + return menu +} -- 2.34.1 From e6521097442d46868536e1b7872e8273eddc3876 Mon Sep 17 00:00:00 2001 From: QiuSW <105186638@qq.com> Date: Sun, 16 Aug 2026 23:26:55 +0800 Subject: [PATCH 2/6] =?UTF-8?q?docs:=20=E8=AE=B0=E5=BD=95=20Sense=20Layout?= =?UTF-8?q?=20=E8=8F=9C=E5=8D=95=E7=BB=93=E6=9E=84=20(#101)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/02-architecture-and-code-map.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/02-architecture-and-code-map.md b/docs/02-architecture-and-code-map.md index 5013571..d0938db 100644 --- a/docs/02-architecture-and-code-map.md +++ b/docs/02-architecture-and-code-map.md @@ -2,8 +2,8 @@ generated: true (请先修改 Gitea Wiki,禁止直接编辑本文件) wiki_page: Architecture-and-Code-Map wiki_url: https://git.ilapage.cn/ila/yovision/wiki/Architecture-and-Code-Map.- -wiki_revision: a95b7692bc0c6bf4d05f8c57088a83379e15a08f -synchronized_at: 2026-08-15T03:01:57Z +wiki_revision: 8608db441b21964aba7ba78e2c1581b4f5f910aa +synchronized_at: 2026-08-16T15:22:21Z # 架构与代码地图 @@ -85,9 +85,11 @@ Sense/Brain 生成事件 Sense 已由工单 #61 从冻结 go-admin/go-admin-ui 源码建立:后端入口为 `Sense/server/main.go`,前端入口为 `Sense/ui/src/main.js`,来源和完整 commit 记录在 `Sense/LICENSES/SOURCES.md`。后端保留 Cobra、Gin、GORM、Casbin、JWT 和迁移体系,前端保留 Router、Store、API、Layout、动态菜单与权限指令。上游作业、代码生成、监控等源码暂留用于升级追溯,但路由及用户入口不启用。 +Sense 业务菜单必须遵循冻结 GoAdmin 的路由树:顶层目录使用 `MenuType=M`、`Component=Layout`,设备管理、视频接入、视频服务、实时监看、区域与警戒线使用相对路径作为 `MenuType=C` 子页面,操作权限继续作为页面下的 `MenuType=F` 节点。这样动态路由只替换 Layout 的右侧内容区,左侧导航、顶部栏和标签页始终保留;旧数据库由 `Sense/server/cmd/migrate/migration/version/2026081623100_sense_layout.go` 新增迁移修正父子关系和完整 `paths`,页面 URL 与权限标识不变。 + 工单 #64 在该基线上重建 Sense 独立身份能力:`Sense/server/app/admin/apis/identity_bootstrap.go` 提供受外部高熵令牌保护的一次性首位管理员初始化,数据库迁移固定建立 `admin`、`implementation_operator`、`site_admin`、`viewer` 四个角色及最小 Casbin 权限;前端继续复用 go-admin-ui 动态菜单、权限按钮、请求封装与 Layout。仓库仍不提供默认账号、默认密码或可用 JWT 密钥。 -Sense JWT realm 固定为 `Sense`;浏览器令牌 Cookie 为 `Sense-Admin-Token`,后端仅接受标准 Authorization Bearer 或独立的 `sense_session` Cookie,不接受查询参数令牌,也不得与 Bell 共享 JWT 密钥、Cookie 或账户库。登录成功/失败、登出、密码变更和鉴权拒绝写入身份审计;审计内容必须剔除密码、令牌、Cookie、验证码和其他秘密。配置、接口管理等非产品必要路由不注册,即使管理员直接调用也返回 404。 +Sense JWT realm 固定为 `Sense`;浏览器令牌 Cookie 为 `Sense-Admin-Token`,后端仅接受标准 Authorization Bearer 或独立的 `sense_session` Cookie,不接受查询参数令牌,也不得与 Bell 共享 JWT 密钥、Cookie 或账户库。登录成功/失败、登出、密码变更和鉴权拒绝写入身份审计;审计内容必须剔除密码、令牌、Cookie、验证码和其他秘密。配置管理 CRUD、configKey、set-config、接口管理等非产品必要路由不注册,即使管理员直接调用也返回 404。登录外壳必需的匿名只读 `GET /api/v1/app-config` 是唯一例外:它复用 GoAdmin `SysConfig.Get2SysApp`,只投影标记为前端可见的配置,不提供写入或管理能力。 工单 #65 新增设备台账入口:后端按 `models → dto → service → api → router` 分层位于 `Sense/server/app/sense/device/`,管理路由在 `Sense/server/app/admin/router/sense_device.go`,前端页面位于 `Sense/ui/src/views/sense/device/index.vue`。设备凭据由 `Sense/server/app/sense/credential/` 独立存储和 AES-256-GCM 加密,HTTP 只返回是否已配置,不提供凭据读取接口。 -- 2.34.1 From 9ff2f6339f173b0c6cf2fa8b82f34372a5ce73c3 Mon Sep 17 00:00:00 2001 From: QiuSW <105186638@qq.com> Date: Sun, 16 Aug 2026 23:32:42 +0800 Subject: [PATCH 3/6] =?UTF-8?q?docs:=20=E5=AE=8C=E6=88=90=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=20#101=20=E5=BE=85=E9=AA=8C=E6=94=B6=E5=BD=92?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/task/101-Sense-GoAdmin-应用外壳.md | 81 +++++++++++++++++++++ wiki-docs.json | 4 + 2 files changed, 85 insertions(+) create mode 100644 docs/task/101-Sense-GoAdmin-应用外壳.md diff --git a/docs/task/101-Sense-GoAdmin-应用外壳.md b/docs/task/101-Sense-GoAdmin-应用外壳.md new file mode 100644 index 0000000..2ed2b6b --- /dev/null +++ b/docs/task/101-Sense-GoAdmin-应用外壳.md @@ -0,0 +1,81 @@ + +generated: true (请先修改 Gitea Wiki,禁止直接编辑本文件) +wiki_page: Task-101-Sense-GoAdmin-应用外壳 +wiki_url: https://git.ilapage.cn/ila/yovision/wiki/Task-101-Sense-GoAdmin-%E5%BA%94%E7%94%A8%E5%A4%96%E5%A3%B3.- +wiki_revision: 416668dca04772908eb66c5f74ef0cec7e79524c +synchronized_at: 2026-08-16T15:32:14Z + + +# 101 Sense-GoAdmin-应用外壳 + +- 类型:缺陷修复 +- 所属 Epic:#7 +- 所属 MVP / 版本:#8 / Sense 首个独立纵切 +- 状态:待验收 +- 日期:2026-08-16 +- Gitea 工单:https://git.ilapage.cn/ila/yovision/issues/101 +- Wiki 页面:Task-101-Sense-GoAdmin-应用外壳 +- Wiki revision:见本地镜像头 + +## 背景与目标 + +Sense 五个业务菜单原来都以顶层业务组件注册。go-admin-ui 只有在动态路由组件为 `Layout` 时才保留侧栏、顶部导航和标签页,因此点击设备管理等入口会用业务页面替换整个 GoAdmin 外壳。 + +本任务恢复冻结 GoAdmin 的标准父子菜单结构:应用外壳保持不变,模块切换只替换右侧内容区域。 + +## 最终方案 + +新增迁移 `2026081623100_sense_layout.go`,创建唯一的“视频感知”顶层目录: + +- 顶层目录:`MenuType=M`、`Path=/sense`、`Component=Layout`。 +- 设备管理、视频接入、视频服务、实时监看、区域与警戒线:作为相对路径的 `MenuType=C` 子页面。 +- 页面下既有 `MenuType=F` 操作权限保持不变。 +- 递归重算父目录、页面和按钮的完整 `paths`。 +- 页面 URL、组件、权限标识、角色关联和业务 API 均不改变。 +- 使用新增事务迁移兼容已经执行旧迁移的 PostgreSQL 数据库,不修改历史迁移。 + +与建单方案一致,没有修改 go-admin-ui 公共 Layout 或动态路由生成器。 + +## 修改文件 + +- `Sense/server/cmd/migrate/migration/version/2026081623100_sense_layout.go`:新增 GoAdmin Layout 菜单兼容迁移。 +- `Sense/server/cmd/migrate/migration/version/2026081623100_sense_layout_test.go`:覆盖菜单层级、相对路径、完整 paths、角色关联保持、重复对齐、事务回滚和 PostgreSQL。 +- `docs/02-architecture-and-code-map.md`:同步架构 Wiki 中的 Sense 动态菜单长期规则。 +- `wiki-docs.json`、`docs/task/101-Sense-GoAdmin-应用外壳.md`:任务归档映射与镜像。 + +## 验收结果 + +| 验收标准 | 结果 | +|---|---| +| 五个业务页位于 Layout 父路由下 | 通过 | +| 设备管理进入 `#/sense/devices`,标题与路径不串位 | 通过 | +| 切换和刷新后侧栏、顶部栏、标签页保留 | 通过 | +| 页面组件、权限标识和角色关联保持 | 通过 | +| 已有 PostgreSQL 数据库迁移无重复菜单 | 通过 | +| 重复对齐安全、失败事务回滚 | 通过 | +| 后端、前端和 Windows 包验证 | 通过 | +| Wiki、归档、PR 和证据 | 通过,等待用户验收 | + +## 测试 + +- `go test ./cmd/migrate/migration/version -run 'Test(AlignSenseLayout|MigrateSenseLayout|SenseLayout)' -count=1`:通过。 +- 真实 PostgreSQL 隔离 schema `TestSenseLayoutMigrationOnPostgres`:通过并清理测试 schema。 +- `go test ./...`:通过。 +- `go vet ./...`、后端构建:通过。 +- `pnpm lint`:0 error,32 条冻结上游/既有 warning。 +- `pnpm test:unit -- --runInBand`:17 suites、46 tests 全部通过。 +- `pnpm build:prod`:通过,4 条既有构建 warning。 +- Windows PowerShell 5.1 包测试:21 assertions 通过;包审计通过。 +- 本机生产数据库迁移及启动:通过。 +- Headless Edge:依次打开五个菜单及刷新区域页面,`.app-wrapper`、侧栏、navbar、TagsView 全程可见,URL 均正确。 +- Windows ZIP:`Sense/dist/sense-windows-amd64.zip`,SHA-256 `BAAA973F8502BB5B0BC080F11931E60419B25EFA8FF722A6B9F9B98364399642`,源码提交 `4423d528b1dc6ebe8b6f7b8272ca5111032a1608`。 +- **未验证部分**:客户全新 Windows 主机、客户目标浏览器及 implementation_operator/site_admin/viewer 三种岗位的人工视觉验收;本机使用 admin 完成真实浏览器回归。 + +## 遗留问题 + +#99 仍处于待验收并使用独立分支;本任务代码不依赖 #99,但两项长期架构说明位于同一 Wiki 页面。PR 集成时建议先验收/合入 #99,再更新本分支到最新 dev,以消除镜像元数据的并行差异。#90 的项目档案 Wiki 更新未混入本任务提交。 + +## 相关提交 + +- `4423d528b1dc6ebe8b6f7b8272ca5111032a1608` 修复 Sense GoAdmin 应用外壳。 +- `e652109` 记录 Sense Layout 菜单长期架构。 diff --git a/wiki-docs.json b/wiki-docs.json index 3fb80b4..80c032e 100644 --- a/wiki-docs.json +++ b/wiki-docs.json @@ -143,6 +143,10 @@ { "page": "Task-97-Sense免验证码登录与管理员密码重置", "path": "docs/task/97-Sense免验证码登录与管理员密码重置.md" + }, + { + "page": "Task-101-Sense-GoAdmin-应用外壳", + "path": "docs/task/101-Sense-GoAdmin-应用外壳.md" } ] } -- 2.34.1 From faa96a3bea9141e449435999072918ed6179cd87 Mon Sep 17 00:00:00 2001 From: QiuSW <105186638@qq.com> Date: Sun, 16 Aug 2026 23:51:59 +0800 Subject: [PATCH 4/6] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=E5=B7=A5?= =?UTF-8?q?=E5=8D=95=20#101=20=E7=BB=84=E5=90=88=E9=AA=8C=E6=94=B6?= =?UTF-8?q?=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/task/101-Sense-GoAdmin-应用外壳.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/docs/task/101-Sense-GoAdmin-应用外壳.md b/docs/task/101-Sense-GoAdmin-应用外壳.md index 2ed2b6b..6654805 100644 --- a/docs/task/101-Sense-GoAdmin-应用外壳.md +++ b/docs/task/101-Sense-GoAdmin-应用外壳.md @@ -2,8 +2,8 @@ generated: true (请先修改 Gitea Wiki,禁止直接编辑本文件) wiki_page: Task-101-Sense-GoAdmin-应用外壳 wiki_url: https://git.ilapage.cn/ila/yovision/wiki/Task-101-Sense-GoAdmin-%E5%BA%94%E7%94%A8%E5%A4%96%E5%A3%B3.- -wiki_revision: 416668dca04772908eb66c5f74ef0cec7e79524c -synchronized_at: 2026-08-16T15:32:14Z +wiki_revision: b64071730850396e615a40ed29006ca9f669ccaa +synchronized_at: 2026-08-16T15:52:26Z # 101 Sense-GoAdmin-应用外壳 @@ -79,3 +79,12 @@ Sense 五个业务菜单原来都以顶层业务组件注册。go-admin-ui 只 - `4423d528b1dc6ebe8b6f7b8272ca5111032a1608` 修复 Sense GoAdmin 应用外壳。 - `e652109` 记录 Sense Layout 菜单长期架构。 + +## #99 合入后的组合验收包 + +- 用户验收 #99 后,PR #100 已合入 `dev`;本任务分支通过合并提交 `42dc77b1f904032131c51b3864184c4ccaea6b8f` 更新到该基线。 +- 冲突处理保留 Wiki 事实源中 #99 的匿名只读 `app-config` 边界、#101 的 GoAdmin Layout 菜单规则,以及两张任务归档映射。 +- 重新生成 `Sense/dist/sense-windows-amd64.zip`;包内 `source_commit=42dc77b1f904032131c51b3864184c4ccaea6b8f`。 +- 新 ZIP SHA-256:`65AF5DD1CFB5D4F8339DCCC53717354495259F13630FBC0C6A4AFC1ACD794B26`。 +- 固定工具链 production build、包审计、Windows PowerShell 5.1 包测试 21 项、真实 PostgreSQL 迁移/启动及 `TestRegisterBaseRouterExposesOnlyFrontendAppConfig` 均通过。 +- 现场配置在构建前备份、ZIP 生成后恢复;ZIP 仍只包含模板配置。Sense 当前监听 `127.0.0.1:18080`。 -- 2.34.1 From 54f10d894a3823ddfbac23001f6b299c10523b4c Mon Sep 17 00:00:00 2001 From: QiuSW <105186638@qq.com> Date: Thu, 27 Aug 2026 15:34:22 +0800 Subject: [PATCH 5/6] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=E5=B7=A5?= =?UTF-8?q?=E5=8D=95=20#101=20=E7=BB=84=E5=90=88=E9=AA=8C=E6=94=B6?= =?UTF-8?q?=E8=AF=81=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/task/101-Sense-GoAdmin-应用外壳.md | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/docs/task/101-Sense-GoAdmin-应用外壳.md b/docs/task/101-Sense-GoAdmin-应用外壳.md index 6654805..28789a0 100644 --- a/docs/task/101-Sense-GoAdmin-应用外壳.md +++ b/docs/task/101-Sense-GoAdmin-应用外壳.md @@ -2,8 +2,8 @@ generated: true (请先修改 Gitea Wiki,禁止直接编辑本文件) wiki_page: Task-101-Sense-GoAdmin-应用外壳 wiki_url: https://git.ilapage.cn/ila/yovision/wiki/Task-101-Sense-GoAdmin-%E5%BA%94%E7%94%A8%E5%A4%96%E5%A3%B3.- -wiki_revision: b64071730850396e615a40ed29006ca9f669ccaa -synchronized_at: 2026-08-16T15:52:26Z +wiki_revision: f48d7f7d70cfaa00dd40ca3adcd655dd7cd105fb +synchronized_at: 2026-08-27T07:34:00Z # 101 Sense-GoAdmin-应用外壳 @@ -73,7 +73,7 @@ Sense 五个业务菜单原来都以顶层业务组件注册。go-admin-ui 只 ## 遗留问题 -#99 仍处于待验收并使用独立分支;本任务代码不依赖 #99,但两项长期架构说明位于同一 Wiki 页面。PR 集成时建议先验收/合入 #99,再更新本分支到最新 dev,以消除镜像元数据的并行差异。#90 的项目档案 Wiki 更新未混入本任务提交。 +#99 与 #104 均已验收并合入 `dev`;#101 已在最新 `dev` 上完成组合回归,仍等待用户验收。#90 的项目档案 Wiki 更新未混入本任务提交,客户全新 Windows 主机及三个非 admin 岗位的人工视觉验收仍未覆盖。 ## 相关提交 @@ -88,3 +88,14 @@ Sense 五个业务菜单原来都以顶层业务组件注册。go-admin-ui 只 - 新 ZIP SHA-256:`65AF5DD1CFB5D4F8339DCCC53717354495259F13630FBC0C6A4AFC1ACD794B26`。 - 固定工具链 production build、包审计、Windows PowerShell 5.1 包测试 21 项、真实 PostgreSQL 迁移/启动及 `TestRegisterBaseRouterExposesOnlyFrontendAppConfig` 均通过。 - 现场配置在构建前备份、ZIP 生成后恢复;ZIP 仍只包含模板配置。Sense 当前监听 `127.0.0.1:18080`。 +## #104 合入后的最终组合验收包 + +- #104 已由用户验收并经 PR #105 合入 `dev@46c3232da40528d031367225b09d4f28c85a8312`;#101 分支通过合并提交 `8cdd3f61cbd8f5bbc1a972525da91aaf49a39bb0` 更新到该基线。 +- 唯一合并冲突是 `Architecture-and-Code-Map` 镜像头;读取 Wiki revision `8df12aa3e136b1faee9c2dffb58ca39b045bc49f` 确认页面同时包含 #101 Layout 菜单规则和 #104 30 天登录规则后,以该事实源解决。业务代码无冲突。 +- `go test ./...`、`go vet ./...`、`go build ./...` 全部通过;前端 lint 0 error(32 条既有 warning),18 suites / 48 tests 通过,production build 通过(4 条既有 warning)。 +- Windows 包资源审计、包审计和 22 assertions 通过;使用现场 PostgreSQL 完成幂等迁移与生产启动,`data/runtime/settings.yml` 确认 `timeout: 2592000`。 +- Chrome 真实回归依次验证设备管理、视频接入、视频服务、实时监看、区域与警戒线五个入口;URL 分别为 `#/sense/devices`、`#/sense/admission`、`#/sense/media`、`#/sense/liveview`、`#/sense/area`,侧栏、Navbar、TagsView 全程可见。直接刷新区域页面后外壳与选中标签保持,控制台无错误。 +- 本机直连验证 `/health`、`/api/v1/app-config` 和 `/` 均返回 200;首次命令行请求受开发机 HTTP 代理影响,明确绕过代理后通过,不属于 Sense 服务错误。 +- 组合 ZIP:`Sense/dist/sense-windows-amd64-101-104.zip`,56,461,005 bytes,SHA-256 `46B2B5654EE3F61788CA4E51F5CB66C1A7C7D1088EFFD39C0281E86E84F964A2`,包内 `source_commit=8cdd3f61cbd8f5bbc1a972525da91aaf49a39bb0`。标准 ZIP 内容相同且仅含模板配置;现场配置只恢复到解压目录。 +- 当前组合服务监听 `127.0.0.1:18080`。临时现场配置备份已删除,源码目录 `node_modules` 已清理。 +- **未验证部分**:客户全新 Windows 主机、客户目标浏览器及 implementation_operator/site_admin/viewer 三种岗位的人工视觉验收。 -- 2.34.1 From 83012ad37f2ea790a2e73980cbba99fbfb8b6d1d Mon Sep 17 00:00:00 2001 From: QiuSW <105186638@qq.com> Date: Thu, 27 Aug 2026 15:53:08 +0800 Subject: [PATCH 6/6] =?UTF-8?q?docs:=20=E6=A0=87=E8=AE=B0=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=20#101=20=E9=AA=8C=E6=94=B6=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/task/101-Sense-GoAdmin-应用外壳.md | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/docs/task/101-Sense-GoAdmin-应用外壳.md b/docs/task/101-Sense-GoAdmin-应用外壳.md index 28789a0..2f0d3fe 100644 --- a/docs/task/101-Sense-GoAdmin-应用外壳.md +++ b/docs/task/101-Sense-GoAdmin-应用外壳.md @@ -2,8 +2,8 @@ generated: true (请先修改 Gitea Wiki,禁止直接编辑本文件) wiki_page: Task-101-Sense-GoAdmin-应用外壳 wiki_url: https://git.ilapage.cn/ila/yovision/wiki/Task-101-Sense-GoAdmin-%E5%BA%94%E7%94%A8%E5%A4%96%E5%A3%B3.- -wiki_revision: f48d7f7d70cfaa00dd40ca3adcd655dd7cd105fb -synchronized_at: 2026-08-27T07:34:00Z +wiki_revision: a32fd29a7b8c4fa42396e9f249bcdd99d0c09e74 +synchronized_at: 2026-08-27T07:52:48Z # 101 Sense-GoAdmin-应用外壳 @@ -11,7 +11,7 @@ synchronized_at: 2026-08-27T07:34:00Z - 类型:缺陷修复 - 所属 Epic:#7 - 所属 MVP / 版本:#8 / Sense 首个独立纵切 -- 状态:待验收 +- 状态:已完成 - 日期:2026-08-16 - Gitea 工单:https://git.ilapage.cn/ila/yovision/issues/101 - Wiki 页面:Task-101-Sense-GoAdmin-应用外壳 @@ -54,7 +54,7 @@ Sense 五个业务菜单原来都以顶层业务组件注册。go-admin-ui 只 | 已有 PostgreSQL 数据库迁移无重复菜单 | 通过 | | 重复对齐安全、失败事务回滚 | 通过 | | 后端、前端和 Windows 包验证 | 通过 | -| Wiki、归档、PR 和证据 | 通过,等待用户验收 | +| Wiki、归档、PR 和证据 | 通过,用户已验收 | ## 测试 @@ -69,11 +69,11 @@ Sense 五个业务菜单原来都以顶层业务组件注册。go-admin-ui 只 - 本机生产数据库迁移及启动:通过。 - Headless Edge:依次打开五个菜单及刷新区域页面,`.app-wrapper`、侧栏、navbar、TagsView 全程可见,URL 均正确。 - Windows ZIP:`Sense/dist/sense-windows-amd64.zip`,SHA-256 `BAAA973F8502BB5B0BC080F11931E60419B25EFA8FF722A6B9F9B98364399642`,源码提交 `4423d528b1dc6ebe8b6f7b8272ca5111032a1608`。 -- **未验证部分**:客户全新 Windows 主机、客户目标浏览器及 implementation_operator/site_admin/viewer 三种岗位的人工视觉验收;本机使用 admin 完成真实浏览器回归。 +- **未验证部分**:客户全新 Windows 主机及 implementation_operator/site_admin/viewer 三种岗位的人工视觉验收;本机使用 admin 完成真实浏览器回归,用户已确认验收通过。 ## 遗留问题 -#99 与 #104 均已验收并合入 `dev`;#101 已在最新 `dev` 上完成组合回归,仍等待用户验收。#90 的项目档案 Wiki 更新未混入本任务提交,客户全新 Windows 主机及三个非 admin 岗位的人工视觉验收仍未覆盖。 +#99、#104 与 #101 均已由用户验收;#101 经 PR #102 合入 `dev`,`main` 保持不变。#90 的项目档案 Wiki 更新未混入本任务提交;客户全新 Windows 主机及三个非 admin 岗位的人工视觉验收仍未覆盖。 ## 相关提交 @@ -98,4 +98,10 @@ Sense 五个业务菜单原来都以顶层业务组件注册。go-admin-ui 只 - 本机直连验证 `/health`、`/api/v1/app-config` 和 `/` 均返回 200;首次命令行请求受开发机 HTTP 代理影响,明确绕过代理后通过,不属于 Sense 服务错误。 - 组合 ZIP:`Sense/dist/sense-windows-amd64-101-104.zip`,56,461,005 bytes,SHA-256 `46B2B5654EE3F61788CA4E51F5CB66C1A7C7D1088EFFD39C0281E86E84F964A2`,包内 `source_commit=8cdd3f61cbd8f5bbc1a972525da91aaf49a39bb0`。标准 ZIP 内容相同且仅含模板配置;现场配置只恢复到解压目录。 - 当前组合服务监听 `127.0.0.1:18080`。临时现场配置备份已删除,源码目录 `node_modules` 已清理。 -- **未验证部分**:客户全新 Windows 主机、客户目标浏览器及 implementation_operator/site_admin/viewer 三种岗位的人工视觉验收。 +- **未验证部分**:客户全新 Windows 主机及 implementation_operator/site_admin/viewer 三种岗位的人工视觉验收;用户已确认当前交付验收通过。 + +## 验收确认 + +- 2026-08-27,用户明确确认“#101通过验收”。 +- PR #102 按规定合入 `dev`,`main` 未变更。 +- 工单 #101 状态更新为“已完成”并关闭;所属 MVP #8 的子工单索引同步勾选。 -- 2.34.1