From 6d0ec8e6ba5e9208c21f25a4d021f0f425903195 Mon Sep 17 00:00:00 2001 From: veypi Date: Thu, 5 Feb 2026 03:30:18 +0800 Subject: [PATCH] rename to vbase --- README.md | 2 +- TODO.md | 37 +-- agents.md | 22 +- api/app/access/create.go | 6 +- api/app/access/del.go | 6 +- api/app/access/get.go | 6 +- api/app/access/init.go | 2 +- api/app/access/list.go | 6 +- api/app/access/patch.go | 6 +- api/app/app.go | 10 +- api/app/app_user/create.go | 6 +- api/app/app_user/del.go | 6 +- api/app/app_user/get.go | 6 +- api/app/app_user/init.go | 2 +- api/app/app_user/list.go | 6 +- api/app/app_user/patch.go | 6 +- api/app/init.go | 12 +- api/app/resource/create.go | 6 +- api/app/resource/del.go | 6 +- api/app/resource/get.go | 6 +- api/app/resource/init.go | 2 +- api/app/resource/list.go | 6 +- api/app/resource/patch.go | 6 +- api/app/role/create.go | 6 +- api/app/role/del.go | 6 +- api/app/role/get.go | 6 +- api/app/role/init.go | 2 +- api/app/role/list.go | 6 +- api/app/role/patch.go | 6 +- api/init.go | 16 +- api/sms/init.go | 2 +- api/sms/send.go | 12 +- api/sms/utils.go | 4 +- api/sms/validate.go | 8 +- api/token/base.go | 6 +- api/token/create.go | 10 +- api/token/get.go | 6 +- api/token/init.go | 2 +- api/user/create.go | 10 +- api/user/init.go | 6 +- api/user/login.go | 16 +- api/user/role/create.go | 6 +- api/user/role/del.go | 6 +- api/user/role/get.go | 6 +- api/user/role/init.go | 2 +- api/user/role/patch.go | 6 +- api/user/user.go | 10 +- cli/main.go | 53 ++--- dev.yml | 2 +- errs/errors.go | 2 +- go.mod | 12 +- init.go | 16 +- libs/auth/jwt.go | 4 +- libs/sms_providers/aliyun.go | 6 +- libs/sms_providers/provider.go | 2 +- libs/sms_providers/tencent.go | 2 +- libs/webdav/dir_render.go | 2 +- libs/webdav/webdav.go | 2 +- libs/webdav/xml.go | 2 +- libs/webdav/xml_test.go | 2 +- models/app.go | 4 +- models/init.go | 6 +- models/sms.go | 2 +- models/token.go | 2 +- models/user.go | 2 +- oauth/OAuth_Database_Design.md | 242 -------------------- oauth/authorize.go | 127 ----------- oauth/constants.go | 159 ------------- oauth/init.go | 210 ----------------- oauth/revoke.go | 60 ----- oauth/token.go | 290 ------------------------ oauth/user.go | 397 --------------------------------- oauth/utils.go | 49 ---- ui/assets/others.css | 2 +- ui/assets/vhtml.min.js | 1 + ui/assets/vyes.min.js | 1 - ui/page/dsr1.html | 143 ++++++------ ui/page/index.html | 23 +- ui/page/latest.html | 142 +++++++----- ui/page/login.html | 86 +++++-- ui/root.html | 2 +- 81 files changed, 446 insertions(+), 1956 deletions(-) delete mode 100644 oauth/OAuth_Database_Design.md delete mode 100644 oauth/authorize.go delete mode 100644 oauth/constants.go delete mode 100644 oauth/init.go delete mode 100644 oauth/revoke.go delete mode 100644 oauth/token.go delete mode 100644 oauth/user.go delete mode 100644 oauth/utils.go create mode 100644 ui/assets/vhtml.min.js delete mode 100644 ui/assets/vyes.min.js diff --git a/README.md b/README.md index 84f9661..897dfc0 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # VBase -对标 Firebase 的后端服务,基于 vyes/vigo 框架实现,提供用户认证、数据库存储、文件存储等功能。 +对标 Firebase 的后端服务,基于 vhtml/vigo 框架实现,提供用户认证、数据库存储、文件存储等功能。 diff --git a/TODO.md b/TODO.md index 0bf10ef..f390540 100644 --- a/TODO.md +++ b/TODO.md @@ -1,33 +1,6 @@ -# UI Refactoring TODO List -任务描述:阅读agents.md指令, 我重构了common.css,现在两个任务:一个是查阅vyes-ui的文档,尽量使用vyes-ui组件去重构界面,减少代码量; 一个是修改所有界面及组件的样式,使用全局变量,颜色可以直接使用也可以用color-mix去混色增加颜色层次感和丰富度。 将界面修改任务写到TODO.md里,更改完一个界面就标记这个页面完成 +## 接口规范检查与修复任务 -## Pages -- [x] /ui/page/index.html -- [x] /ui/page/login.html -- [x] /ui/page/profile.html -- [x] /ui/page/stats.html -- [x] /ui/page/app.html -- [x] /ui/page/settings.html -- [x] /ui/page/latest.html -- [x] /ui/page/dsr1.html -- [x] /ui/page/test.html -- [x] /ui/page/404.html - -## App Pages -- [x] /ui/page/app/index.html -- [x] /ui/page/app/auth.html -- [x] /ui/page/app/user.html -- [x] /ui/page/app/settings.html - -## Layouts -- [x] /ui/layout/default.html -- [x] /ui/layout/public.html -- [x] /ui/layout/app.html - -## Components -- [x] /ui/c/app/create.html -- [x] /ui/c/app/menu.html (Deleted) -- [x] /ui/c/table.html -- [x] /ui/vselect.html -- [x] /ui/ico.html -- [x] /ui/root.html +- [ ] 检查并修复 `api/app` 及其子模块接口规范: `access`, `app_user`, `resource`, `role` +- [ ] 检查并修复 `api/sms` 接口规范 +- [ ] 检查并修复 `api/token` 接口规范 +- [ ] 检查并修复 `api/user` 及其子模块接口规范: `role` diff --git a/agents.md b/agents.md index 72376e7..c75a569 100644 --- a/agents.md +++ b/agents.md @@ -1,21 +1,23 @@ # 开发规范 ## 注意 + 如果开发中发现什么开发规则或者技巧,你可以更新在这个文档,供其他人看 -## UI界面开发指南 -- 界面采用vyes.js 框架,该框架可以将一个html文件自动加载为一个组件 -- 开始写界面前请阅读全局样式文件 /ui/assets/common.css 保证所有界面的样式一致 -- 组件内部避免重复的样式定义 如body内无需重复定义字体 -- 本项目使用vyes-ui 组件库,该组件库可以通过 curl -sS http://localhost:4000/v/README.md 查看文档 其组件代码都已经映射到了/v/目录下 +## UI 界面开发指南 + +- 界面采用 vhtml 框架,该框架可以将一个 html 文件自动加载为一个组件 +- 开始写界面前请阅读全局样式文件 /ui/assets/common.css,组件内必须使用全局中的变量去组合或者直接使用全局中的样式, 保证所有界面的样式一致, 比如只能使用颜色变量或者通过 color-mix 函数去包含至少一个颜色变量 +- 组件内部避免重复的样式定义 如 body 内无需重复定义字体 +- 本项目使用 vhtml-ui 组件库,该组件库可以通过 curl -sS 查看文档 其组件代码都已经映射到了/v/目录下 - 前端路由文件 /ui/routes.js 该文件定义了所有的路由规则 +## vhtml-ui 文档查看方法 -## vyes-ui 文档查看方法 curl 指令可以不用沙盒运行 获取文档目录 该操作可以查看所有组件的目录结构 -curl -sS http://localhost:4000/v/docs/README.md?toc=1 +curl -sS 获取文档全文(较长,一般建议查询目录再查询章节内容) -curl -sS http://localhost:4000/v/docs/README.md -获取章节内容(可以根据第一步获取的目录编号查询内容) 一般使用这个查询章节内容,查询内容时不能带toc参数 -curl -sS http://localhost:4000/v/docs/README.md?from=1.2&to=1.2 +curl -sS +获取章节内容(可以根据第一步获取的目录编号查询内容) 一般使用这个查询章节内容,查询内容时不能带 toc 参数 +curl -sS diff --git a/api/app/access/create.go b/api/app/access/create.go index b0dc995..386753d 100644 --- a/api/app/access/create.go +++ b/api/app/access/create.go @@ -7,9 +7,9 @@ package access import ( - "github.com/vyes-ai/vigo" - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" + "github.com/veypi/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" ) type createOpts struct { diff --git a/api/app/access/del.go b/api/app/access/del.go index 05d714b..d1eccfe 100644 --- a/api/app/access/del.go +++ b/api/app/access/del.go @@ -7,9 +7,9 @@ package access import ( - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" ) type deleteOpts struct { diff --git a/api/app/access/get.go b/api/app/access/get.go index 720e6e4..915c015 100644 --- a/api/app/access/get.go +++ b/api/app/access/get.go @@ -7,9 +7,9 @@ package access import ( - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" ) type getIDReq struct { diff --git a/api/app/access/init.go b/api/app/access/init.go index c6d95a6..3fae2d2 100644 --- a/api/app/access/init.go +++ b/api/app/access/init.go @@ -8,7 +8,7 @@ package access import ( - "github.com/vyes-ai/vigo" + "github.com/veypi/vigo" ) var Router = vigo.NewRouter() diff --git a/api/app/access/list.go b/api/app/access/list.go index 99dc46d..92ff1fa 100644 --- a/api/app/access/list.go +++ b/api/app/access/list.go @@ -7,9 +7,9 @@ package access import ( - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" ) type listOpts struct { diff --git a/api/app/access/patch.go b/api/app/access/patch.go index db93c76..0389771 100644 --- a/api/app/access/patch.go +++ b/api/app/access/patch.go @@ -7,9 +7,9 @@ package access import ( - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" ) type updateOpts struct { diff --git a/api/app/app.go b/api/app/app.go index 27c0160..eaf8396 100644 --- a/api/app/app.go +++ b/api/app/app.go @@ -5,11 +5,11 @@ import ( "math/rand" "time" - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/libs/auth" - "github.com/veypi/OneAuth/libs/utils" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/libs/auth" + "github.com/veypi/vbase/libs/utils" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" "gorm.io/gorm" ) diff --git a/api/app/app_user/create.go b/api/app/app_user/create.go index 7d39749..34c2c3c 100644 --- a/api/app/app_user/create.go +++ b/api/app/app_user/create.go @@ -1,9 +1,9 @@ package app_user import ( - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" ) type createOpts struct { diff --git a/api/app/app_user/del.go b/api/app/app_user/del.go index 38db3cf..91eb134 100644 --- a/api/app/app_user/del.go +++ b/api/app/app_user/del.go @@ -1,9 +1,9 @@ package app_user import ( - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" ) type deleteOpts struct { diff --git a/api/app/app_user/get.go b/api/app/app_user/get.go index fc2e476..2cbe771 100644 --- a/api/app/app_user/get.go +++ b/api/app/app_user/get.go @@ -1,9 +1,9 @@ package app_user import ( - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" ) type appUserIDReq struct { diff --git a/api/app/app_user/init.go b/api/app/app_user/init.go index d7fe814..f80573f 100644 --- a/api/app/app_user/init.go +++ b/api/app/app_user/init.go @@ -8,7 +8,7 @@ package app_user import ( - "github.com/vyes-ai/vigo" + "github.com/veypi/vigo" ) var Router = vigo.NewRouter() diff --git a/api/app/app_user/list.go b/api/app/app_user/list.go index ab68b6d..36f8c52 100644 --- a/api/app/app_user/list.go +++ b/api/app/app_user/list.go @@ -1,9 +1,9 @@ package app_user import ( - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" ) type listOpts struct { diff --git a/api/app/app_user/patch.go b/api/app/app_user/patch.go index 164ee33..cfcd804 100644 --- a/api/app/app_user/patch.go +++ b/api/app/app_user/patch.go @@ -1,9 +1,9 @@ package app_user import ( - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" ) type updateOpts struct { diff --git a/api/app/init.go b/api/app/init.go index 754878c..e09425c 100644 --- a/api/app/init.go +++ b/api/app/init.go @@ -8,12 +8,12 @@ package app import ( - "github.com/veypi/OneAuth/api/app/access" - "github.com/veypi/OneAuth/api/app/app_user" - "github.com/veypi/OneAuth/api/app/resource" - "github.com/veypi/OneAuth/api/app/role" - "github.com/veypi/OneAuth/libs/auth" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/api/app/access" + "github.com/veypi/vbase/api/app/app_user" + "github.com/veypi/vbase/api/app/resource" + "github.com/veypi/vbase/api/app/role" + "github.com/veypi/vbase/libs/auth" + "github.com/veypi/vigo" ) var Router = vigo.NewRouter() diff --git a/api/app/resource/create.go b/api/app/resource/create.go index 6223932..62b912b 100644 --- a/api/app/resource/create.go +++ b/api/app/resource/create.go @@ -1,9 +1,9 @@ package resource import ( - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" ) type createOpts struct { diff --git a/api/app/resource/del.go b/api/app/resource/del.go index 67ba8d0..25f15d9 100644 --- a/api/app/resource/del.go +++ b/api/app/resource/del.go @@ -1,9 +1,9 @@ package resource import ( - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" ) type deleteOpts struct { diff --git a/api/app/resource/get.go b/api/app/resource/get.go index 6358b5a..0da22a7 100644 --- a/api/app/resource/get.go +++ b/api/app/resource/get.go @@ -1,9 +1,9 @@ package resource import ( - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" ) type getIDReq struct { diff --git a/api/app/resource/init.go b/api/app/resource/init.go index 2dbc4a7..7e5104a 100644 --- a/api/app/resource/init.go +++ b/api/app/resource/init.go @@ -8,7 +8,7 @@ package resource import ( - "github.com/vyes-ai/vigo" + "github.com/veypi/vigo" ) var Router = vigo.NewRouter() diff --git a/api/app/resource/list.go b/api/app/resource/list.go index 380d70e..005e2ec 100644 --- a/api/app/resource/list.go +++ b/api/app/resource/list.go @@ -1,9 +1,9 @@ package resource import ( - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" ) type listOpts struct { diff --git a/api/app/resource/patch.go b/api/app/resource/patch.go index ab79103..3279e8f 100644 --- a/api/app/resource/patch.go +++ b/api/app/resource/patch.go @@ -1,9 +1,9 @@ package resource import ( - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" ) type updateOpts struct { diff --git a/api/app/role/create.go b/api/app/role/create.go index 74d6a20..1126a4c 100644 --- a/api/app/role/create.go +++ b/api/app/role/create.go @@ -1,9 +1,9 @@ package role import ( - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" ) type createOpts struct { diff --git a/api/app/role/del.go b/api/app/role/del.go index 325c38f..c155160 100644 --- a/api/app/role/del.go +++ b/api/app/role/del.go @@ -1,9 +1,9 @@ package role import ( - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" ) type deleteOpts struct { diff --git a/api/app/role/get.go b/api/app/role/get.go index df8a347..ebd5430 100644 --- a/api/app/role/get.go +++ b/api/app/role/get.go @@ -1,9 +1,9 @@ package role import ( - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" ) type getIDReq struct { diff --git a/api/app/role/init.go b/api/app/role/init.go index 4328e96..7a7baa5 100644 --- a/api/app/role/init.go +++ b/api/app/role/init.go @@ -8,7 +8,7 @@ package role import ( - "github.com/vyes-ai/vigo" + "github.com/veypi/vigo" ) var Router = vigo.NewRouter() diff --git a/api/app/role/list.go b/api/app/role/list.go index 0bec309..2074849 100644 --- a/api/app/role/list.go +++ b/api/app/role/list.go @@ -1,9 +1,9 @@ package role import ( - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" ) var _ = Router.Get("/", "获取角色列表", listRoles) diff --git a/api/app/role/patch.go b/api/app/role/patch.go index f84ac72..00275c9 100644 --- a/api/app/role/patch.go +++ b/api/app/role/patch.go @@ -1,9 +1,9 @@ package role import ( - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" ) type updateOpts struct { diff --git a/api/init.go b/api/init.go index bf235dc..03689b9 100644 --- a/api/init.go +++ b/api/init.go @@ -8,14 +8,14 @@ package api import ( - "github.com/veypi/OneAuth/api/app" - "github.com/veypi/OneAuth/api/sms" - "github.com/veypi/OneAuth/api/token" - "github.com/veypi/OneAuth/api/user" - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/libs/auth" - "github.com/vyes-ai/vigo" - "github.com/vyes-ai/vigo/contrib/common" + "github.com/veypi/vbase/api/app" + "github.com/veypi/vbase/api/sms" + "github.com/veypi/vbase/api/token" + "github.com/veypi/vbase/api/user" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/libs/auth" + "github.com/veypi/vigo" + "github.com/veypi/vigo/contrib/common" ) var Router = vigo.NewRouter() diff --git a/api/sms/init.go b/api/sms/init.go index 522e3c5..205475a 100644 --- a/api/sms/init.go +++ b/api/sms/init.go @@ -7,7 +7,7 @@ package sms -import "github.com/vyes-ai/vigo" +import "github.com/veypi/vigo" var Router = vigo.NewRouter() diff --git a/api/sms/send.go b/api/sms/send.go index 068a2de..361b37e 100644 --- a/api/sms/send.go +++ b/api/sms/send.go @@ -4,12 +4,12 @@ import ( "fmt" "time" - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/libs/sms_providers" - "github.com/veypi/OneAuth/libs/utils" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" - "github.com/vyes-ai/vigo/contrib/limiter" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/libs/sms_providers" + "github.com/veypi/vbase/libs/utils" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" + "github.com/veypi/vigo/contrib/limiter" "gorm.io/gorm" ) diff --git a/api/sms/utils.go b/api/sms/utils.go index 26d1430..ee5bd29 100644 --- a/api/sms/utils.go +++ b/api/sms/utils.go @@ -11,8 +11,8 @@ import ( "fmt" "time" - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" "gorm.io/gorm" ) diff --git a/api/sms/validate.go b/api/sms/validate.go index 8c95394..fd12053 100644 --- a/api/sms/validate.go +++ b/api/sms/validate.go @@ -11,10 +11,10 @@ import ( "fmt" "time" - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/libs/utils" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/libs/utils" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" "gorm.io/gorm" ) diff --git a/api/token/base.go b/api/token/base.go index 378f956..584ed65 100644 --- a/api/token/base.go +++ b/api/token/base.go @@ -3,9 +3,9 @@ package token import ( "time" - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" ) type patchOpts struct { diff --git a/api/token/create.go b/api/token/create.go index b3a19ba..d9ef334 100644 --- a/api/token/create.go +++ b/api/token/create.go @@ -12,11 +12,11 @@ import ( "time" "github.com/golang-jwt/jwt/v5" - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/libs/auth" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" - "github.com/vyes-ai/vigo/logv" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/libs/auth" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" + "github.com/veypi/vigo/logv" ) type postOpts struct { diff --git a/api/token/get.go b/api/token/get.go index 597c1b2..c0cd6c9 100644 --- a/api/token/get.go +++ b/api/token/get.go @@ -8,9 +8,9 @@ package token import ( - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" ) type getOpts struct { diff --git a/api/token/init.go b/api/token/init.go index 00f3de8..251d557 100644 --- a/api/token/init.go +++ b/api/token/init.go @@ -8,7 +8,7 @@ package token import ( - "github.com/vyes-ai/vigo" + "github.com/veypi/vigo" ) var Router = vigo.NewRouter() diff --git a/api/user/create.go b/api/user/create.go index e91e087..d9b7089 100644 --- a/api/user/create.go +++ b/api/user/create.go @@ -15,11 +15,11 @@ import ( "time" "github.com/google/uuid" - "github.com/veypi/OneAuth/api/sms" - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/libs/utils" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/api/sms" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/libs/utils" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" "gorm.io/gorm" ) diff --git a/api/user/init.go b/api/user/init.go index e35ecd1..290f0c0 100644 --- a/api/user/init.go +++ b/api/user/init.go @@ -8,9 +8,9 @@ package user import ( - "github.com/veypi/OneAuth/api/user/role" - "github.com/veypi/OneAuth/libs/auth" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/api/user/role" + "github.com/veypi/vbase/libs/auth" + "github.com/veypi/vigo" ) var Router = vigo.NewRouter() diff --git a/api/user/login.go b/api/user/login.go index 4173c7e..576dd6a 100644 --- a/api/user/login.go +++ b/api/user/login.go @@ -12,14 +12,14 @@ import ( "time" "github.com/golang-jwt/jwt/v5" - "github.com/veypi/OneAuth/api/sms" - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/libs/auth" - "github.com/veypi/OneAuth/libs/utils" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" - "github.com/vyes-ai/vigo/contrib/limiter" - "github.com/vyes-ai/vigo/logv" + "github.com/veypi/vbase/api/sms" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/libs/auth" + "github.com/veypi/vbase/libs/utils" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" + "github.com/veypi/vigo/contrib/limiter" + "github.com/veypi/vigo/logv" ) var publicLimits = limiter.NewAdvancedRequestLimiter(time.Minute*5, 20, time.Second*3, nil).Limit diff --git a/api/user/role/create.go b/api/user/role/create.go index b7e2bd7..96fa09e 100644 --- a/api/user/role/create.go +++ b/api/user/role/create.go @@ -8,9 +8,9 @@ package role import ( - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" ) var _ = Router.Post("/", "创建用户角色", userRolePost) diff --git a/api/user/role/del.go b/api/user/role/del.go index 49834fd..08bb8bc 100644 --- a/api/user/role/del.go +++ b/api/user/role/del.go @@ -8,9 +8,9 @@ package role import ( - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" ) type deleteIDReq struct { diff --git a/api/user/role/get.go b/api/user/role/get.go index c5d3486..4eaf2b5 100644 --- a/api/user/role/get.go +++ b/api/user/role/get.go @@ -8,10 +8,10 @@ package role import ( - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vigo" ) type getIDReq struct { diff --git a/api/user/role/init.go b/api/user/role/init.go index 0ea6594..efc1a5b 100644 --- a/api/user/role/init.go +++ b/api/user/role/init.go @@ -7,6 +7,6 @@ package role -import "github.com/vyes-ai/vigo" +import "github.com/veypi/vigo" var Router = vigo.NewRouter() diff --git a/api/user/role/patch.go b/api/user/role/patch.go index beb4b3e..46bfb8b 100644 --- a/api/user/role/patch.go +++ b/api/user/role/patch.go @@ -8,9 +8,9 @@ package role import ( - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" ) type patchOpts struct { diff --git a/api/user/user.go b/api/user/user.go index 2b35e23..031393d 100644 --- a/api/user/user.go +++ b/api/user/user.go @@ -1,11 +1,11 @@ package user import ( - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/libs/auth" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" - "github.com/vyes-ai/vigo/contrib/crud" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/libs/auth" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" + "github.com/veypi/vigo/contrib/crud" ) type userIDReq struct { diff --git a/cli/main.go b/cli/main.go index 9968991..55826ba 100644 --- a/cli/main.go +++ b/cli/main.go @@ -8,48 +8,34 @@ package main import ( - "github.com/veypi/OneAuth" - "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/models" - "github.com/vyes-ai/vigo" - "github.com/vyes-ai/vigo/flags" - "github.com/vyes-ai/vigo/logv" + "github.com/veypi/vbase" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/models" + "github.com/veypi/vigo" + "github.com/veypi/vigo/flags" + "github.com/veypi/vigo/logv" ) -var ( - cmdMain = flags.New("app", "the backend server of app") - cmdCfg = cmdMain.SubCommand("cfg", "generate cfg file") - cmdDB = cmdMain.SubCommand("db", "database operations") -) - -var configFile = cmdMain.String("f", "./dev.yaml", "the config file") - var cliOpts = &struct { - Host string `json:"host"` - Port int `json:"port"` + Host string `json:"host" short:"h` + Port int `json:"port" short:"p"` LoggerPath string `json:"logger_path,omitempty"` LoggerLevel string `json:"logger_level,omitempty"` - Core *cfg.Options + *cfg.Options }{ - Core: cfg.Config, + Host: "0.0.0.0", + Port: 4000, + LoggerLevel: "debug", + Options: cfg.Config, } -func init() { - cmdMain.StringVar(&cliOpts.Host, "host", "0.0.0.0", "host") - cmdMain.IntVar(&cliOpts.Port, "p", 4000, "port") - cmdMain.StringVar(&cliOpts.LoggerLevel, "l", "info", "log level") - cmdMain.AutoRegister(cfg.Config) +var ( + cmdMain = flags.New("app", "the backend server of app", cliOpts) + cmdDB = cmdMain.SubCommand("db", "database operations") +) - cmdMain.Before = func() error { - flags.LoadCfg(*configFile, cfg.Config) - cmdMain.Parse() - logv.SetLevel(logv.AssertFuncErr(logv.ParseLevel(cliOpts.LoggerLevel))) - return nil - } +func init() { cmdMain.Command = runWeb - cmdCfg.Command = func() error { - return flags.DumpCfg(*configFile, cfg.Config) - } cmdDB.SubCommand("migrate", "migrate database").Command = models.Migrate cmdDB.SubCommand("drop", "drop database").Command = models.Drop cmdDB.SubCommand("init", "init db data").Command = models.InitDB @@ -64,10 +50,11 @@ func main() { } func runWeb() error { + logv.SetLevel(logv.AssertFuncErr(logv.ParseLevel(cliOpts.LoggerLevel))) server, err := vigo.New(vigo.WithHost(cliOpts.Host), vigo.WithPort(cliOpts.Port)) if err != nil { return err } - server.SetRouter(OneAuth.Router) + server.SetRouter(vbase.Router) return server.Run() } diff --git a/dev.yml b/dev.yml index b344410..b34d05a 100644 --- a/dev.yml +++ b/dev.yml @@ -2,5 +2,5 @@ host: 0.0.0.0 port: 4003 level: debug dsn: root:123456@tcp(127.0.0.1:3306)/test2?charset=utf8&parseTime=True&loc=Local -repo: /home/v/workspace/OneAuth/new/ +repo: /home/v/workspace/vbase/new/ dev: true diff --git a/errs/errors.go b/errs/errors.go index 1da0238..1b44b57 100644 --- a/errs/errors.go +++ b/errs/errors.go @@ -7,7 +7,7 @@ package errs -import "github.com/vyes-ai/vigo" +import "github.com/veypi/vigo" var ( AuthNotFound = vigo.NewError("auth not found").WithCode(40100) diff --git a/go.mod b/go.mod index 6af958c..3b32270 100644 --- a/go.mod +++ b/go.mod @@ -1,10 +1,10 @@ -module github.com/veypi/OneAuth +module github.com/veypi/vbase go 1.24.1 -replace github.com/veypi/vyes-ui => ../vyes-ui/ +replace github.com/veypi/vhtml-ui => ../vhtml-ui/ -replace github.com/vyes-ai/vigo => ../vigo/ +replace github.com/veypi/vigo => ../vigo/ require ( github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.9 @@ -15,9 +15,8 @@ require ( github.com/glebarez/sqlite v1.11.0 github.com/golang-jwt/jwt/v5 v5.2.3 github.com/google/uuid v1.6.0 - github.com/veypi/vyes-ui v0.0.0-00010101000000-000000000000 - github.com/vyes-ai/vigo v0.5.2 - golang.org/x/crypto v0.40.0 + github.com/veypi/vhtml-ui v0.0.0-00010101000000-000000000000 + github.com/veypi/vigo v0.6.0 gorm.io/driver/mysql v1.6.0 gorm.io/driver/postgres v1.6.0 gorm.io/gorm v1.30.1 @@ -50,6 +49,7 @@ require ( github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/zerolog v1.34.0 // indirect github.com/tjfoc/gmsm v1.4.1 // indirect + golang.org/x/crypto v0.40.0 // indirect golang.org/x/net v0.42.0 // indirect golang.org/x/sync v0.16.0 // indirect golang.org/x/sys v0.34.0 // indirect diff --git a/init.go b/init.go index d1b0e43..fcdc92c 100644 --- a/init.go +++ b/init.go @@ -4,16 +4,16 @@ // Distributed under terms of the MIT license. // -package OneAuth +package vbase import ( "embed" - "github.com/veypi/OneAuth/api" - vyesui "github.com/veypi/vyes-ui" - "github.com/vyes-ai/vigo" - "github.com/vyes-ai/vigo/contrib/cors" - "github.com/vyes-ai/vigo/contrib/vyes" + "github.com/veypi/vbase/api" + vhtmlui "github.com/veypi/vhtml-ui" + "github.com/veypi/vigo" + "github.com/veypi/vigo/contrib/cors" + "github.com/veypi/vigo/contrib/vhtml" ) var Router = vigo.NewRouter() @@ -22,8 +22,8 @@ var Router = vigo.NewRouter() var uifs embed.FS func init() { - Router.Extend("v", vyesui.Router) + Router.Extend("v", vhtmlui.Router) Router.Extend("api", api.Router) Router.SubRouter("/**").Use(cors.AllowAny) - vyes.WrapUI(Router, uifs) + vhtml.WrapUI(Router, uifs) } diff --git a/libs/auth/jwt.go b/libs/auth/jwt.go index 684c36a..c2db2e5 100644 --- a/libs/auth/jwt.go +++ b/libs/auth/jwt.go @@ -14,8 +14,8 @@ import ( "time" "github.com/golang-jwt/jwt/v5" - "github.com/veypi/OneAuth/cfg" - "github.com/vyes-ai/vigo" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vigo" ) var ( diff --git a/libs/sms_providers/aliyun.go b/libs/sms_providers/aliyun.go index 421ce2b..6b65136 100644 --- a/libs/sms_providers/aliyun.go +++ b/libs/sms_providers/aliyun.go @@ -10,9 +10,9 @@ import ( util "github.com/alibabacloud-go/tea-utils/v2/service" "github.com/alibabacloud-go/tea/tea" credential "github.com/aliyun/credentials-go/credentials" - "github.com/veypi/OneAuth/cfg" - "github.com/vyes-ai/vigo" - "github.com/vyes-ai/vigo/logv" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vigo" + "github.com/veypi/vigo/logv" ) // AliyunProvider 阿里云短信服务 diff --git a/libs/sms_providers/provider.go b/libs/sms_providers/provider.go index d3d61cd..de5edc3 100644 --- a/libs/sms_providers/provider.go +++ b/libs/sms_providers/provider.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/veypi/OneAuth/cfg" + "github.com/veypi/vbase/cfg" ) // SMSProvider 短信服务商接口 diff --git a/libs/sms_providers/tencent.go b/libs/sms_providers/tencent.go index f4aa12b..e89f495 100644 --- a/libs/sms_providers/tencent.go +++ b/libs/sms_providers/tencent.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/veypi/OneAuth/cfg" + "github.com/veypi/vbase/cfg" ) // TencentProvider 腾讯云短信服务 diff --git a/libs/webdav/dir_render.go b/libs/webdav/dir_render.go index d799664..5908e18 100644 --- a/libs/webdav/dir_render.go +++ b/libs/webdav/dir_render.go @@ -16,7 +16,7 @@ import ( "net/url" "strings" - "github.com/vyes-ai/vigo/logv" + "github.com/veypi/vigo/logv" ) type anyDirs interface { diff --git a/libs/webdav/webdav.go b/libs/webdav/webdav.go index 294fa17..5107f75 100644 --- a/libs/webdav/webdav.go +++ b/libs/webdav/webdav.go @@ -17,7 +17,7 @@ import ( "strings" "time" - "github.com/vyes-ai/vigo/logv" + "github.com/veypi/vigo/logv" ) func NewWebdav(p string) *Handler { diff --git a/libs/webdav/xml.go b/libs/webdav/xml.go index b2922a2..b12bf26 100644 --- a/libs/webdav/xml.go +++ b/libs/webdav/xml.go @@ -32,7 +32,7 @@ import ( // In the long term, this package should use the standard library's version // only, and the internal fork deleted, once // https://github.com/golang/go/issues/13400 is resolved. - ixml "github.com/veypi/OneAuth/libs/webdav/internal/xml" + ixml "github.com/veypi/vbase/libs/webdav/internal/xml" ) // http://www.webdav.org/specs/rfc4918.html#ELEMENT_lockinfo diff --git a/libs/webdav/xml_test.go b/libs/webdav/xml_test.go index 0238a75..a082051 100644 --- a/libs/webdav/xml_test.go +++ b/libs/webdav/xml_test.go @@ -16,7 +16,7 @@ import ( "strings" "testing" - ixml "github.com/veypi/OneAuth/libs/webdav/internal/xml" + ixml "github.com/veypi/vbase/libs/webdav/internal/xml" ) func TestReadLockInfo(t *testing.T) { diff --git a/models/app.go b/models/app.go index 3aabdb6..3bc5d76 100644 --- a/models/app.go +++ b/models/app.go @@ -1,8 +1,8 @@ package models import ( - "github.com/vyes-ai/vigo" - "github.com/vyes-ai/vigo/logv" + "github.com/veypi/vigo" + "github.com/veypi/vigo/logv" "gorm.io/gorm" ) diff --git a/models/init.go b/models/init.go index 19d7883..c9e4225 100644 --- a/models/init.go +++ b/models/init.go @@ -9,11 +9,11 @@ package models import ( "strings" - "github.com/veypi/OneAuth/cfg" + "github.com/veypi/vbase/cfg" "github.com/google/uuid" - "github.com/vyes-ai/vigo" - "github.com/vyes-ai/vigo/logv" + "github.com/veypi/vigo" + "github.com/veypi/vigo/logv" ) var AllModels = &vigo.ModelList{} diff --git a/models/sms.go b/models/sms.go index 055ff0a..8b64070 100644 --- a/models/sms.go +++ b/models/sms.go @@ -3,7 +3,7 @@ package models import ( "time" - "github.com/vyes-ai/vigo" + "github.com/veypi/vigo" ) // SMSCode 短信验证码记录 diff --git a/models/token.go b/models/token.go index d3affa5..5f756f9 100644 --- a/models/token.go +++ b/models/token.go @@ -3,7 +3,7 @@ package models import ( "time" - "github.com/vyes-ai/vigo" + "github.com/veypi/vigo" ) // refresh token,由oa 秘钥签发,有效期长, 存储在token表 diff --git a/models/user.go b/models/user.go index be288cd..22f7533 100644 --- a/models/user.go +++ b/models/user.go @@ -1,7 +1,7 @@ package models import ( - "github.com/vyes-ai/vigo" + "github.com/veypi/vigo" "gorm.io/gorm" ) diff --git a/oauth/OAuth_Database_Design.md b/oauth/OAuth_Database_Design.md deleted file mode 100644 index 60371b6..0000000 --- a/oauth/OAuth_Database_Design.md +++ /dev/null @@ -1,242 +0,0 @@ -# OAuth 服务器数据库设计 - -本文档介绍了基于您现有用户管理系统的OAuth 2.0服务器数据库设计。 - -## 核心表结构 - -### 1. OAuth 客户端相关 - -#### `oauth_clients` - OAuth客户端表 -存储注册到系统的OAuth客户端应用信息。 - -| 字段 | 类型 | 说明 | -|-----|------|------| -| id | varchar(32) | 主键ID | -| client_id | varchar(255) | 客户端ID(唯一) | -| client_secret | varchar(255) | 客户端密钥(加密存储) | -| client_name | varchar(255) | 客户端应用名称 | -| client_uri | varchar(500) | 客户端主页 | -| logo_uri | varchar(500) | 客户端Logo | -| redirect_uris | text | 重定向URI列表(JSON格式) | -| response_types | varchar(255) | 支持的响应类型 | -| grant_types | varchar(255) | 支持的授权类型 | -| scope | text | 授权范围 | -| is_public | boolean | 是否为公开客户端 | -| is_active | boolean | 是否激活 | -| owner_id | varchar(32) | 客户端拥有者ID | - -#### `oauth_scopes` - OAuth授权范围表 -定义可用的授权范围。 - -| 字段 | 类型 | 说明 | -|-----|------|------| -| id | varchar(32) | 主键ID | -| name | varchar(100) | 范围名称(唯一) | -| display_name | varchar(100) | 显示名称 | -| description | text | 范围描述 | -| is_default | boolean | 是否为默认范围 | -| is_system | boolean | 是否为系统范围 | - -#### `oauth_client_scopes` - 客户端授权范围关联表 -定义客户端可以请求的授权范围。 - -| 字段 | 类型 | 说明 | -|-----|------|------| -| client_id | varchar(32) | 客户端ID | -| scope_id | varchar(32) | 范围ID | - -### 2. OAuth 授权流程相关 - -#### `oauth_authorization_codes` - 授权码表 -存储授权码流程中的临时授权码。 - -| 字段 | 类型 | 说明 | -|-----|------|------| -| id | varchar(32) | 主键ID | -| code | varchar(255) | 授权码(唯一) | -| client_id | varchar(32) | 客户端ID | -| user_id | varchar(32) | 用户ID | -| redirect_uri | varchar(500) | 重定向URI | -| scope | text | 授权范围 | -| code_challenge | varchar(255) | PKCE代码挑战 | -| code_challenge_method | varchar(50) | PKCE挑战方法 | -| expires_at | timestamp | 过期时间 | -| used | boolean | 是否已使用 | - -#### `oauth_access_tokens` - 访问令牌表 -存储颁发的访问令牌。 - -| 字段 | 类型 | 说明 | -|-----|------|------| -| id | varchar(32) | 主键ID | -| token | varchar(500) | 访问令牌(唯一) | -| client_id | varchar(32) | 客户端ID | -| user_id | varchar(32) | 用户ID | -| scope | text | 授权范围 | -| expires_at | timestamp | 过期时间 | -| revoked | boolean | 是否已撤销 | - -#### `oauth_refresh_tokens` - 刷新令牌表 -存储刷新令牌,用于获取新的访问令牌。 - -| 字段 | 类型 | 说明 | -|-----|------|------| -| id | varchar(32) | 主键ID | -| token | varchar(500) | 刷新令牌(唯一) | -| access_token_id | varchar(32) | 关联的访问令牌ID | -| client_id | varchar(32) | 客户端ID | -| user_id | varchar(32) | 用户ID | -| scope | text | 授权范围 | -| expires_at | timestamp | 过期时间 | -| revoked | boolean | 是否已撤销 | - -#### `oauth_user_consents` - 用户授权同意表 -记录用户对客户端的授权同意。 - -| 字段 | 类型 | 说明 | -|-----|------|------| -| id | varchar(32) | 主键ID | -| user_id | varchar(32) | 用户ID | -| client_id | varchar(32) | 客户端ID | -| scope | text | 授权范围 | -| consent_at | timestamp | 同意时间 | -| expires_at | timestamp | 同意过期时间 | - -### 3. 第三方OAuth登录相关 - -#### `oauth_providers` - 第三方OAuth提供商表 -配置第三方OAuth提供商(如GitHub, Google等)。 - -| 字段 | 类型 | 说明 | -|-----|------|------| -| id | varchar(32) | 主键ID | -| name | varchar(100) | 提供商名称(唯一) | -| display_name | varchar(100) | 显示名称 | -| client_id | varchar(255) | 客户端ID | -| client_secret | varchar(255) | 客户端密钥 | -| auth_url | varchar(500) | 授权URL | -| token_url | varchar(500) | 令牌URL | -| user_info_url | varchar(500) | 用户信息URL | -| scope | text | 默认授权范围 | -| is_active | boolean | 是否激活 | - -#### `oauth_accounts` - 用户OAuth账户表 -存储用户通过第三方OAuth登录的账户信息。 - -| 字段 | 类型 | 说明 | -|-----|------|------| -| id | varchar(32) | 主键ID | -| user_id | varchar(32) | 本系统用户ID | -| provider_id | varchar(32) | 提供商ID | -| provider_user_id | varchar(255) | 提供商用户ID | -| email | varchar(255) | 邮箱 | -| username | varchar(255) | 用户名 | -| nickname | varchar(255) | 昵称 | -| avatar | varchar(500) | 头像URL | -| access_token | text | 访问令牌 | -| refresh_token | text | 刷新令牌 | -| expires_at | timestamp | 令牌过期时间 | - -### 4. 用户会话和令牌管理 - -#### `user_sessions` - 用户会话表 -管理用户登录会话。 - -| 字段 | 类型 | 说明 | -|-----|------|------| -| id | varchar(32) | 主键ID | -| user_id | varchar(32) | 用户ID | -| session_id | varchar(255) | 会话ID(唯一) | -| ip_address | varchar(45) | IP地址 | -| user_agent | text | 用户代理 | -| expires_at | timestamp | 过期时间 | -| is_active | boolean | 是否激活 | -| last_activity | timestamp | 最后活动时间 | - -#### `user_tokens` - 用户令牌表 -管理用户的API令牌等。 - -| 字段 | 类型 | 说明 | -|-----|------|------| -| id | varchar(32) | 主键ID | -| user_id | varchar(32) | 用户ID | -| token_type | varchar(50) | 令牌类型 | -| token | varchar(500) | 令牌值(唯一) | -| name | varchar(100) | 令牌名称 | -| description | text | 令牌描述 | -| scope | text | 授权范围 | -| expires_at | timestamp | 过期时间 | -| last_used_at | timestamp | 最后使用时间 | -| is_active | boolean | 是否激活 | - -## 关系说明 - -### 用户与OAuth的关系 -- 一个用户可以拥有多个OAuth客户端(`users.id` -> `oauth_clients.owner_id`) -- 一个用户可以授权多个客户端(`users.id` -> `oauth_user_consents.user_id`) -- 一个用户可以关联多个第三方账户(`users.id` -> `oauth_accounts.user_id`) - -### OAuth授权流程关系 -- 授权码关联客户端和用户(`oauth_authorization_codes.client_id` -> `oauth_clients.id`) -- 访问令牌关联刷新令牌(`oauth_refresh_tokens.access_token_id` -> `oauth_access_tokens.id`) - -### 权限控制 -- 基于现有的RBAC系统,为OAuth相关操作定义权限 -- 管理员可以管理所有OAuth客户端 -- 普通用户只能管理自己的OAuth客户端 - -## 预定义数据 - -### 默认授权范围 -- `profile`: 基本资料访问 -- `email`: 邮箱地址访问 -- `phone`: 手机号码访问 -- `read`: 读取权限 -- `write`: 写入权限 -- `admin`: 管理员权限 - -### 预配置的第三方提供商 -- GitHub -- Google -- 微信 -- 钉钉 - -### OAuth相关权限 -- `oauth.client.create`: 创建OAuth客户端 -- `oauth.client.read`: 查看OAuth客户端 -- `oauth.client.update`: 更新OAuth客户端 -- `oauth.client.delete`: 删除OAuth客户端 -- `oauth.token.manage`: 管理OAuth令牌 -- `oauth.scope.manage`: 管理OAuth作用域 -- `oauth.provider.manage`: 管理OAuth提供商 - -## 安全考虑 - -1. **令牌存储**: 所有敏感令牌都应该进行哈希或加密存储 -2. **HTTPS强制**: 所有OAuth端点必须使用HTTPS -3. **PKCE支持**: 支持PKCE以增强安全性 -4. **令牌过期**: 设置合理的令牌过期时间 -5. **审计日志**: 记录所有OAuth相关操作 - -## 使用示例 - -### 初始化OAuth数据 -```go -import "vyes_cli/oauth" - -// 在数据库迁移后调用 -err := oauth.InitializeOAuthData(db) -if err != nil { - log.Fatal("Failed to initialize OAuth data:", err) -} -``` - -### 创建测试客户端 -```go -client, err := oauth.CreateDefaultOAuthClient(db, adminUserID) -if err != nil { - log.Fatal("Failed to create default OAuth client:", err) -} -``` - -这个设计基于OAuth 2.0 RFC标准,同时考虑了您现有的用户管理系统架构,可以无缝集成到您的项目中。 diff --git a/oauth/authorize.go b/oauth/authorize.go deleted file mode 100644 index e98ff01..0000000 --- a/oauth/authorize.go +++ /dev/null @@ -1,127 +0,0 @@ -// -// Copyright (C) 2024 veypi -// 2025-07-24 15:27:31 -// Distributed under terms of the MIT license. -// - -package oauth - -import ( - "time" - - "github.com/veypi/OneAuth/cfg" - "github.com/vyes-ai/vigo" - "gorm.io/gorm" -) - -// AuthorizeRequest 授权请求参数 -type AuthorizeRequest struct { - ResponseType string `json:"response_type" src:"query" desc:"响应类型"` - ClientID string `json:"client_id" src:"query" desc:"客户端ID"` - RedirectURI string `json:"redirect_uri" src:"query" desc:"重定向URI"` - Scope string `json:"scope" src:"query" desc:"授权范围"` - State string `json:"state" src:"query" desc:"状态"` - CodeChallenge string `json:"code_challenge" src:"query" desc:"代码挑战"` - CodeChallengeMethod string `json:"code_challenge_method" src:"query" desc:"代码挑战方法"` -} - -// AuthorizeResponse 授权响应 -type AuthorizeResponse struct { - Code string `json:"code,omitempty"` - State string `json:"state,omitempty"` - RedirectURI string `json:"redirect_uri"` - Error string `json:"error,omitempty"` - ErrorDesc string `json:"error_description,omitempty"` -} - -// handleAuthorize 处理OAuth授权请求 -func handleAuthorize(x *vigo.X, args *AuthorizeRequest) (*AuthorizeResponse, error) { - db := cfg.DB() - - // 1. 验证响应类型 - if args.ResponseType != ResponseTypeCode { - errorURI := BuildErrorRedirectURI(args.RedirectURI, ErrorUnsupportedResponseType, "不支持的响应类型", args.State) - return &AuthorizeResponse{ - Error: "unsupported_response_type", - ErrorDesc: "不支持的响应类型", - RedirectURI: errorURI, - }, nil - } - - // 2. 验证客户端 - var client OAuthClient - if err := db.Where("client_id = ? AND is_active = ?", args.ClientID, true).First(&client).Error; err != nil { - if err == gorm.ErrRecordNotFound { - errorURI := BuildErrorRedirectURI(args.RedirectURI, ErrorInvalidClient, "无效的客户端", args.State) - return &AuthorizeResponse{ - Error: "invalid_client", - ErrorDesc: "无效的客户端", - RedirectURI: errorURI, - }, nil - } - return nil, vigo.NewError("数据库查询失败").WithError(err).WithCode(500) - } - - // 3. 验证重定向URI - if !client.IsRedirectURIValid(args.RedirectURI) { - return nil, vigo.NewError("无效的重定向URI").WithCode(400) - } - - // 4. 验证作用域 - if args.Scope != "" && !client.HasScope(args.Scope) { - errorURI := BuildErrorRedirectURI(args.RedirectURI, ErrorInvalidScope, "无效的授权范围", args.State) - return &AuthorizeResponse{ - Error: "invalid_scope", - ErrorDesc: "无效的授权范围", - RedirectURI: errorURI, - }, nil - } - - // TODO: 在实际应用中,这里应该: - // 1. 检查用户是否已登录 - // 2. 显示授权同意页面 - // 3. 用户同意后生成授权码 - // 为了演示,这里假设用户已登录且同意授权 - - // 假设当前用户ID (实际应从session or JWT token中获取) - userID := "demo-user-id" - - // 5. 生成授权码 - code, err := generateRandomString(32) - if err != nil { - errorURI := BuildErrorRedirectURI(args.RedirectURI, ErrorServerError, "授权码生成失败", args.State) - return &AuthorizeResponse{ - Error: "server_error", - ErrorDesc: "授权码生成失败", - RedirectURI: errorURI, - }, nil - } - - // 6. 保存授权码 - authCode := &OAuthAuthorizationCode{ - Code: code, - ClientID: client.ID, - UserID: userID, - RedirectURI: args.RedirectURI, - Scope: args.Scope, - ExpiresAt: time.Now().Add(10 * time.Minute), // 授权码10分钟有效 - CodeChallenge: args.CodeChallenge, - CodeChallengeMethod: args.CodeChallengeMethod, - } - - if err := db.Create(authCode).Error; err != nil { - errorURI := BuildErrorRedirectURI(args.RedirectURI, ErrorServerError, "授权码保存失败", args.State) - return &AuthorizeResponse{ - Error: "server_error", - ErrorDesc: "授权码保存失败", - RedirectURI: errorURI, - }, nil - } - - // 7. 返回授权码重定向 - return &AuthorizeResponse{ - Code: code, - State: args.State, - RedirectURI: BuildRedirectURI(args.RedirectURI, code, args.State), - }, nil -} diff --git a/oauth/constants.go b/oauth/constants.go deleted file mode 100644 index 8d9b10d..0000000 --- a/oauth/constants.go +++ /dev/null @@ -1,159 +0,0 @@ -// -// Copyright (C) 2024 veypi -// 2025-07-24 15:27:31 -// Distributed under terms of the MIT license. -// - -package oauth - -import "time" - -// OAuth 2.0 相关常量 -const ( - // Grant Types - GrantTypeAuthorizationCode = "authorization_code" - GrantTypeRefreshToken = "refresh_token" - GrantTypeClientCredentials = "client_credentials" - GrantTypePassword = "password" - GrantTypeImplicit = "implicit" - - // Response Types - ResponseTypeCode = "code" - ResponseTypeToken = "token" - - // Token Types - TokenTypeBearer = "Bearer" - - // PKCE Challenge Methods - CodeChallengeMethodPlain = "plain" - CodeChallengeMethodS256 = "S256" - - // Default Scopes - ScopeRead = "read" - ScopeWrite = "write" - ScopeProfile = "profile" - ScopeEmail = "email" - ScopePhone = "phone" - ScopeAdmin = "admin" - - // Token 生存时间 - DefaultAuthorizationCodeExpiry = 10 * time.Minute // 授权码10分钟过期 - DefaultAccessTokenExpiry = 1 * time.Hour // 访问令牌1小时过期 - DefaultRefreshTokenExpiry = 30 * 24 * time.Hour // 刷新令牌30天过期 - DefaultSessionExpiry = 24 * time.Hour // 会话24小时过期 - - // Error Codes (RFC 6749) - ErrorInvalidRequest = "invalid_request" - ErrorInvalidClient = "invalid_client" - ErrorInvalidGrant = "invalid_grant" - ErrorUnauthorizedClient = "unauthorized_client" - ErrorUnsupportedGrantType = "unsupported_grant_type" - ErrorInvalidScope = "invalid_scope" - ErrorAccessDenied = "access_denied" - ErrorUnsupportedResponseType = "unsupported_response_type" - ErrorServerError = "server_error" - ErrorTemporarilyUnavailable = "temporarily_unavailable" - - // PKCE Error Codes (RFC 7636) - ErrorInvalidGrant2 = "invalid_grant" - - // Token 类型 - UserTokenTypeAPI = "api" // API 令牌 - UserTokenTypeSession = "session" // 会话令牌 - UserTokenTypePersonal = "personal" // 个人访问令牌 -) - -// 默认作用域定义 -var DefaultScopes = []struct { - Name string - DisplayName string - Description string - IsDefault bool - IsSystem bool -}{ - { - Name: ScopeProfile, - DisplayName: "基本资料", - Description: "访问您的基本资料信息,如用户名、昵称等", - IsDefault: true, - IsSystem: true, - }, - { - Name: ScopeEmail, - DisplayName: "邮箱地址", - Description: "访问您的邮箱地址", - IsDefault: false, - IsSystem: true, - }, - { - Name: ScopePhone, - DisplayName: "手机号码", - Description: "访问您的手机号码", - IsDefault: false, - IsSystem: true, - }, - { - Name: ScopeRead, - DisplayName: "读取权限", - Description: "读取您的数据", - IsDefault: true, - IsSystem: false, - }, - { - Name: ScopeWrite, - DisplayName: "写入权限", - Description: "修改您的数据", - IsDefault: false, - IsSystem: false, - }, - { - Name: ScopeAdmin, - DisplayName: "管理员权限", - Description: "完全的管理员权限", - IsDefault: false, - IsSystem: true, - }, -} - -// 预定义的第三方OAuth提供商 -var DefaultOAuthProviders = []struct { - Name string - DisplayName string - AuthURL string - TokenURL string - UserInfoURL string - Scope string -}{ - { - Name: "github", - DisplayName: "GitHub", - AuthURL: "https://github.com/login/oauth/authorize", - TokenURL: "https://github.com/login/oauth/access_token", - UserInfoURL: "https://api.github.com/user", - Scope: "user:email", - }, - { - Name: "google", - DisplayName: "Google", - AuthURL: "https://accounts.google.com/o/oauth2/v2/auth", - TokenURL: "https://oauth2.googleapis.com/token", - UserInfoURL: "https://www.googleapis.com/oauth2/v2/userinfo", - Scope: "openid profile email", - }, - { - Name: "wechat", - DisplayName: "微信", - AuthURL: "https://open.weixin.qq.com/connect/oauth2/authorize", - TokenURL: "https://api.weixin.qq.com/sns/oauth2/access_token", - UserInfoURL: "https://api.weixin.qq.com/sns/userinfo", - Scope: "snsapi_userinfo", - }, - { - Name: "dingtalk", - DisplayName: "钉钉", - AuthURL: "https://oapi.dingtalk.com/connect/oauth2/sns_authorize", - TokenURL: "https://oapi.dingtalk.com/sns/gettoken", - UserInfoURL: "https://oapi.dingtalk.com/sns/getuserinfo", - Scope: "snsapi_login", - }, -} diff --git a/oauth/init.go b/oauth/init.go deleted file mode 100644 index 9e2791a..0000000 --- a/oauth/init.go +++ /dev/null @@ -1,210 +0,0 @@ -// -// Copyright (C) 2024 veypi -// 2025-07-24 15:27:31 -// Distributed under terms of the MIT license. -// - -package oauth - -import ( - "github.com/vyes-ai/vigo" - "gorm.io/gorm" -) - -var Router = vigo.NewRouter() - -func init() { - // OAuth 授权端点 - var _ = Router.Get("/authorize", "OAuth授权端点 - 获取授权码", vigo.SkipBefore, handleAuthorize) - - // OAuth 令牌端点 - var _ = Router.Post("/token", "OAuth令牌端点 - 用授权码换取令牌或刷新令牌", vigo.SkipBefore, handleToken) - - // OAuth 撤销端点 - var _ = Router.Post("/revoke", "OAuth撤销端点 - 撤销访问令牌或刷新令牌", vigo.SkipBefore, handleRevoke) -} - -// InitializeOAuthData 初始化OAuth相关的基础数据 -func InitializeOAuthData(db *gorm.DB) error { - // 1. 创建默认的OAuth作用域 - if err := createDefaultScopes(db); err != nil { - return err - } - - // 2. 创建默认的第三方OAuth提供商 - if err := createDefaultProviders(db); err != nil { - return err - } - - // 3. 创建默认权限 - if err := createDefaultPermissions(db); err != nil { - return err - } - - return nil -} - -func createDefaultScopes(db *gorm.DB) error { - for _, scopeData := range DefaultScopes { - scope := &OAuthScope{ - Name: scopeData.Name, - DisplayName: scopeData.DisplayName, - Description: scopeData.Description, - IsDefault: scopeData.IsDefault, - IsSystem: scopeData.IsSystem, - } - - // 如果不存在则创建 - var existingScope OAuthScope - result := db.Where("name = ?", scope.Name).First(&existingScope) - if result.Error == gorm.ErrRecordNotFound { - if err := db.Create(scope).Error; err != nil { - return err - } - } - } - return nil -} - -func createDefaultProviders(db *gorm.DB) error { - for _, providerData := range DefaultOAuthProviders { - provider := &OAuthProvider{ - Name: providerData.Name, - DisplayName: providerData.DisplayName, - AuthURL: providerData.AuthURL, - TokenURL: providerData.TokenURL, - UserInfoURL: providerData.UserInfoURL, - Scope: providerData.Scope, - IsActive: false, // 默认不激活,需要配置ClientID和ClientSecret后激活 - } - - // 如果不存在则创建 - var existingProvider OAuthProvider - result := db.Where("name = ?", provider.Name).First(&existingProvider) - if result.Error == gorm.ErrRecordNotFound { - if err := db.Create(provider).Error; err != nil { - return err - } - } - } - return nil -} - -func createDefaultPermissions(db *gorm.DB) error { - oauthPermissions := []struct { - Name string - DisplayName string - Description string - Resource string - Action string - IsSystem bool - }{ - { - Name: "oauth.client.create", - DisplayName: "创建OAuth客户端", - Description: "允许创建新的OAuth客户端应用", - Resource: "oauth_client", - Action: "create", - IsSystem: true, - }, - { - Name: "oauth.client.read", - DisplayName: "查看OAuth客户端", - Description: "允许查看OAuth客户端信息", - Resource: "oauth_client", - Action: "read", - IsSystem: true, - }, - { - Name: "oauth.client.update", - DisplayName: "更新OAuth客户端", - Description: "允许更新OAuth客户端信息", - Resource: "oauth_client", - Action: "update", - IsSystem: true, - }, - { - Name: "oauth.client.delete", - DisplayName: "删除OAuth客户端", - Description: "允许删除OAuth客户端", - Resource: "oauth_client", - Action: "delete", - IsSystem: true, - }, - { - Name: "oauth.token.manage", - DisplayName: "管理OAuth令牌", - Description: "允许管理用户的OAuth令牌", - Resource: "oauth_token", - Action: "manage", - IsSystem: true, - }, - { - Name: "oauth.scope.manage", - DisplayName: "管理OAuth作用域", - Description: "允许管理OAuth作用域", - Resource: "oauth_scope", - Action: "manage", - IsSystem: true, - }, - { - Name: "oauth.provider.manage", - DisplayName: "管理OAuth提供商", - Description: "允许管理第三方OAuth提供商", - Resource: "oauth_provider", - Action: "manage", - IsSystem: true, - }, - } - - for _, permData := range oauthPermissions { - permission := &Permission{ - Name: permData.Name, - DisplayName: permData.DisplayName, - Description: permData.Description, - Resource: permData.Resource, - Action: permData.Action, - IsSystem: permData.IsSystem, - } - - // 如果不存在则创建 - var existingPerm Permission - result := db.Where("name = ?", permission.Name).First(&existingPerm) - if result.Error == gorm.ErrRecordNotFound { - if err := db.Create(permission).Error; err != nil { - return err - } - } - } - - return nil -} - -// CreateDefaultOAuthClient 创建默认的OAuth客户端(用于测试) -func CreateDefaultOAuthClient(db *gorm.DB, ownerID string) (*OAuthClient, error) { - client := &OAuthClient{ - ClientID: "default-client-id", - ClientSecret: "default-client-secret", // 实际使用时应该使用加密存储 - ClientName: "Default Test Client", - ClientURI: "http://localhost:3000", - RedirectURIs: `["http://localhost:3000/callback", "http://localhost:8080/callback"]`, - ResponseTypes: "code", - GrantTypes: "authorization_code,refresh_token", - Scope: "profile read write", - IsPublic: false, - IsActive: true, - OwnerID: ownerID, - } - - // 检查是否已存在 - var existingClient OAuthClient - result := db.Where("client_id = ?", client.ClientID).First(&existingClient) - if result.Error == gorm.ErrRecordNotFound { - if err := db.Create(client).Error; err != nil { - return nil, err - } - return client, nil - } - - return &existingClient, nil -} diff --git a/oauth/revoke.go b/oauth/revoke.go deleted file mode 100644 index 5f6cb16..0000000 --- a/oauth/revoke.go +++ /dev/null @@ -1,60 +0,0 @@ -// -// Copyright (C) 2024 veypi -// 2025-07-24 15:27:31 -// Distributed under terms of the MIT license. -// - -package oauth - -import ( - "github.com/veypi/OneAuth/cfg" - "github.com/vyes-ai/vigo" -) - -// RevokeRequest 撤销令牌请求参数 -type RevokeRequest struct { - Token string `src:"form" desc:"令牌" binding:"required"` - TokenTypeHint string `src:"form" desc:"令牌类型提示"` // access_token 或 refresh_token - ClientID string `src:"form" desc:"客户端ID"` - ClientSecret string `src:"form" desc:"客户端密钥"` -} - -// RevokeResponse 撤销令牌响应 -type RevokeResponse struct { - Message string `json:"message"` - Success bool `json:"success"` -} - -// handleRevoke 处理OAuth撤销请求 -func handleRevoke(x *vigo.X, args *RevokeRequest) (*RevokeResponse, error) { - if args.Token == "" { - return nil, vigo.NewError("令牌不能为空").WithCode(400) - } - - db := cfg.DB() - - // 根据OAuth 2.0规范,撤销令牌应该是幂等操作 - // 即使令牌不存在也应该返回成功,这是为了防止信息泄露 - var revoked = false - - // 尝试撤销访问令牌 - result := db.Model(&OAuthAccessToken{}).Where("token = ?", args.Token).Update("revoked", true) - if result.Error == nil && result.RowsAffected > 0 { - revoked = true - } - - // 如果没有找到访问令牌,尝试撤销刷新令牌 - if !revoked { - result = db.Model(&OAuthRefreshToken{}).Where("token = ?", args.Token).Update("revoked", true) - if result.Error == nil && result.RowsAffected > 0 { - revoked = true - } - } - - // 根据OAuth 2.0规范,即使令牌不存在也返回成功 - // 这样可以防止攻击者通过响应差异推断令牌是否存在 - return &RevokeResponse{ - Message: "令牌撤销成功", - Success: true, - }, nil -} diff --git a/oauth/token.go b/oauth/token.go deleted file mode 100644 index 2976b48..0000000 --- a/oauth/token.go +++ /dev/null @@ -1,290 +0,0 @@ -// -// Copyright (C) 2024 veypi -// 2025-07-24 15:27:31 -// Distributed under terms of the MIT license. -// - -package oauth - -import ( - "crypto/sha256" - "encoding/base64" - "fmt" - "time" - - "github.com/veypi/OneAuth/cfg" - "github.com/vyes-ai/vigo" - "golang.org/x/crypto/bcrypt" - "gorm.io/gorm" -) - -// TokenRequest 令牌请求参数 -type TokenRequest struct { - GrantType string `json:"grant_type" src:"form" desc:"授权类型"` - Code string `json:"code" src:"form" desc:"授权码"` - RedirectURI string `json:"redirect_uri" src:"form" desc:"重定向URI"` - ClientID string `json:"client_id" src:"form" desc:"客户端ID"` - ClientSecret string `json:"client_secret" src:"form" desc:"客户端密钥"` - RefreshToken string `json:"refresh_token" src:"form" desc:"刷新令牌"` - CodeVerifier string `json:"code_verifier" src:"form" desc:"PKCE验证码"` - Username string `json:"username" src:"form" desc:"用户名"` // for password grant - Password string `json:"password" src:"form" desc:"密码"` // for password grant - Scope string `json:"scope" src:"form" desc:"权限范围"` // for password grant -} - -// TokenResponse 令牌响应 -type TokenResponse struct { - AccessToken string `json:"access_token"` - TokenType string `json:"token_type"` - ExpiresIn int64 `json:"expires_in"` - RefreshToken string `json:"refresh_token,omitempty"` - Scope string `json:"scope,omitempty"` -} - -// handleToken 处理OAuth令牌请求 -func handleToken(x *vigo.X, args *TokenRequest) (*TokenResponse, error) { - db := cfg.DB() - - switch args.GrantType { - case GrantTypeAuthorizationCode: - return handleAuthorizationCodeGrant(db, x, args) - case GrantTypeRefreshToken: - return handleRefreshTokenGrant(db, x, args) - case GrantTypePassword: - return handlePasswordGrant(db, x, args) - default: - return nil, vigo.NewError("不支持的授权类型").WithCode(400) - } -} - -// handleAuthorizationCodeGrant 处理授权码授权类型 -func handleAuthorizationCodeGrant(db *gorm.DB, x *vigo.X, args *TokenRequest) (*TokenResponse, error) { - // 1. 验证授权码 - var authCode OAuthAuthorizationCode - if err := db.Where("code = ? AND used = ?", args.Code, false).First(&authCode).Error; err != nil { - return nil, vigo.NewError("无效的授权码").WithCode(400) - } - - // 2. 检查授权码是否过期 - if authCode.IsExpired() { - return nil, vigo.NewError("授权码已过期").WithCode(400) - } - - // 3. 验证客户端 - var client OAuthClient - if err := db.Where("id = ? AND client_id = ?", authCode.ClientID, args.ClientID).First(&client).Error; err != nil { - return nil, vigo.NewError("无效的客户端").WithCode(400) - } - - // 4. 验证客户端密钥(对于机密客户端) - if !client.IsPublic && client.ClientSecret != args.ClientSecret { - return nil, vigo.NewError("无效的客户端凭据").WithCode(400) - } - - // 5. 验证重定向URI - if authCode.RedirectURI != args.RedirectURI { - return nil, vigo.NewError("重定向URI不匹配").WithCode(400) - } - - // 6. 验证PKCE(如果使用) - if authCode.CodeChallenge != "" { - if err := validatePKCE(authCode.CodeChallenge, authCode.CodeChallengeMethod, args.CodeVerifier); err != nil { - return nil, vigo.NewError("PKCE验证失败").WithError(err).WithCode(400) - } - } - - // 7. 标记授权码为已使用 - if err := db.Model(&authCode).Update("used", true).Error; err != nil { - return nil, vigo.NewError("授权码更新失败").WithError(err).WithCode(500) - } - - // 8. 生成访问令牌 - accessToken, err := generateAccessToken(db, &client, authCode.UserID, authCode.Scope) - if err != nil { - return nil, vigo.NewError("访问令牌生成失败").WithError(err).WithCode(500) - } - - // 9. 生成刷新令牌 - refreshToken, err := generateRefreshToken(db, accessToken, &client, authCode.UserID, authCode.Scope) - if err != nil { - return nil, vigo.NewError("刷新令牌生成失败").WithError(err).WithCode(500) - } - - return &TokenResponse{ - AccessToken: accessToken.Token, - TokenType: TokenTypeBearer, - ExpiresIn: int64(DefaultAccessTokenExpiry.Seconds()), - RefreshToken: refreshToken.Token, - Scope: authCode.Scope, - }, nil -} - -// handleRefreshTokenGrant 处理刷新令牌授权类型 -func handleRefreshTokenGrant(db *gorm.DB, x *vigo.X, args *TokenRequest) (*TokenResponse, error) { - // 1. 验证刷新令牌 - var refreshToken OAuthRefreshToken - if err := db.Where("token = ? AND revoked = ?", args.RefreshToken, false).First(&refreshToken).Error; err != nil { - return nil, vigo.NewError("无效的刷新令牌").WithCode(400) - } - - // 2. 检查刷新令牌是否过期 - if refreshToken.IsExpired() { - return nil, vigo.NewError("刷新令牌已过期").WithCode(400) - } - - // 3. 验证客户端 - var client OAuthClient - if err := db.Where("id = ? AND client_id = ?", refreshToken.ClientID, args.ClientID).First(&client).Error; err != nil { - return nil, vigo.NewError("无效的客户端").WithCode(400) - } - - // 4. 撤销旧的访问令牌 - if err := db.Model(&OAuthAccessToken{}).Where("id = ?", refreshToken.AccessTokenID).Update("revoked", true).Error; err != nil { - return nil, vigo.NewError("旧令牌撤销失败").WithError(err).WithCode(500) - } - - // 5. 生成新的访问令牌 - accessToken, err := generateAccessToken(db, &client, refreshToken.UserID, refreshToken.Scope) - if err != nil { - return nil, vigo.NewError("访问令牌生成失败").WithError(err).WithCode(500) - } - - // 6. 更新刷新令牌关联 - if err := db.Model(&refreshToken).Update("access_token_id", accessToken.ID).Error; err != nil { - return nil, vigo.NewError("刷新令牌更新失败").WithError(err).WithCode(500) - } - - return &TokenResponse{ - AccessToken: accessToken.Token, - TokenType: TokenTypeBearer, - ExpiresIn: int64(DefaultAccessTokenExpiry.Seconds()), - RefreshToken: refreshToken.Token, - Scope: refreshToken.Scope, - }, nil -} - -// handlePasswordGrant 处理密码授权类型 -func handlePasswordGrant(db *gorm.DB, x *vigo.X, args *TokenRequest) (*TokenResponse, error) { - // 1. 验证必要参数 - if args.Username == "" || args.Password == "" { - return nil, vigo.NewError("用户名和密码不能为空").WithCode(400) - } - - // 2. 验证客户端 - var client OAuthClient - if err := db.Where("client_id = ?", args.ClientID).First(&client).Error; err != nil { - return nil, vigo.NewError("无效的客户端").WithCode(400) - } - - // 3. 验证客户端密钥(对于机密客户端) - if !client.IsPublic && client.ClientSecret != args.ClientSecret { - return nil, vigo.NewError("无效的客户端凭据").WithCode(400) - } - - // 4. 验证用户凭据 - var user User - if err := db.Where("username = ?", args.Username).First(&user).Error; err != nil { - return nil, vigo.NewError("用户名或密码错误").WithCode(400) - } - - // 5. 验证密码 - if err := bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(args.Password)); err != nil { - return nil, vigo.NewError("用户名或密码错误").WithCode(400) - } - - // 6. 处理权限范围 - scope := args.Scope - if scope == "" { - // scope = DefaultScope // 默认权限范围 - } - - // 7. 生成访问令牌 - accessToken, err := generateAccessToken(db, &client, user.ID, scope) - if err != nil { - return nil, vigo.NewError("访问令牌生成失败").WithError(err).WithCode(500) - } - - // 8. 生成刷新令牌 - refreshToken, err := generateRefreshToken(db, accessToken, &client, user.ID, scope) - if err != nil { - return nil, vigo.NewError("刷新令牌生成失败").WithError(err).WithCode(500) - } - - return &TokenResponse{ - AccessToken: accessToken.Token, - TokenType: TokenTypeBearer, - ExpiresIn: int64(DefaultAccessTokenExpiry.Seconds()), - RefreshToken: refreshToken.Token, - Scope: scope, - }, nil -} - -// 辅助函数 - -func generateAccessToken(db *gorm.DB, client *OAuthClient, userID, scope string) (*OAuthAccessToken, error) { - token, err := generateRandomString(64) - if err != nil { - return nil, err - } - - accessToken := &OAuthAccessToken{ - Token: token, - ClientID: client.ID, - UserID: userID, - Scope: scope, - ExpiresAt: time.Now().Add(DefaultAccessTokenExpiry), - Revoked: false, - } - - if err := db.Create(accessToken).Error; err != nil { - return nil, err - } - - return accessToken, nil -} - -func generateRefreshToken(db *gorm.DB, accessToken *OAuthAccessToken, client *OAuthClient, userID, scope string) (*OAuthRefreshToken, error) { - token, err := generateRandomString(64) - if err != nil { - return nil, err - } - - refreshToken := &OAuthRefreshToken{ - Token: token, - AccessTokenID: accessToken.ID, - ClientID: client.ID, - UserID: userID, - Scope: scope, - ExpiresAt: time.Now().Add(DefaultRefreshTokenExpiry), - Revoked: false, - } - - if err := db.Create(refreshToken).Error; err != nil { - return nil, err - } - - return refreshToken, nil -} - -func validatePKCE(codeChallenge, method, codeVerifier string) error { - if codeVerifier == "" { - return fmt.Errorf("code verifier required") - } - - switch method { - case CodeChallengeMethodPlain: - if codeChallenge != codeVerifier { - return fmt.Errorf("invalid code verifier") - } - case CodeChallengeMethodS256: - h := sha256.Sum256([]byte(codeVerifier)) - expected := base64.RawURLEncoding.EncodeToString(h[:]) - if codeChallenge != expected { - return fmt.Errorf("invalid code verifier") - } - default: - return fmt.Errorf("unsupported code challenge method") - } - - return nil -} diff --git a/oauth/user.go b/oauth/user.go deleted file mode 100644 index 38bbc28..0000000 --- a/oauth/user.go +++ /dev/null @@ -1,397 +0,0 @@ -// -// Copyright (C) 2024 veypi -// 2025-07-24 15:27:31 -// Distributed under terms of the MIT license. -// - -package oauth - -import ( - "time" - - "github.com/vyes-ai/vigo" - "gorm.io/gorm" -) - -// User 用户表 -type User struct { - vigo.Model - Username string `json:"username" gorm:"uniqueIndex;not null;size:50;comment:用户名""` - Email string `json:"email" gorm:"uniqueIndex;size:100;comment:邮箱地址"` - Phone string `json:"phone" gorm:"uniqueIndex;size:20;comment:手机号码"` - PasswordHash string `json:"-" gorm:"not null;size:255;comment:密码哈希"` - Nickname string `json:"nickname" gorm:"size:50;comment:昵称"` - Avatar string `json:"avatar" gorm:"size:255;comment:头像URL"` - IsActive bool `json:"is_active" gorm:"default:true;comment:是否激活"` - IsSuperuser bool `json:"is_superuser" gorm:"default:false;comment:是否为超级用户"` - LastLoginAt *time.Time `json:"last_login_at" gorm:"comment:最后登录时间"` - EmailVerified bool `json:"email_verified" gorm:"default:false;comment:邮箱是否已验证"` - PhoneVerified bool `json:"phone_verified" gorm:"default:false;comment:手机是否已验证"` - TwoFactorAuth bool `json:"two_factor_auth" gorm:"default:false;comment:是否启用双因素认证"` - Locale string `json:"locale" gorm:"size:10;default:zh-CN;comment:语言偏好"` - Timezone string `json:"timezone" gorm:"size:50;default:Asia/Shanghai;comment:时区"` - Bio string `json:"bio" gorm:"type:text;comment:个人简介"` - - // 关联关系 - Roles []Role `json:"roles" gorm:"many2many:user_roles;"` - UserRoles []UserRole `json:"-"` - OAuthAccounts []OAuthAccount `json:"oauth_accounts"` - Tokens []UserToken `json:"-"` - MetaData []byte `json:"meta_data" gorm:"type:jsonb;comment:用户元数据"` // 存储用户自定义的元数据 -} - -// Role 角色表 -type Role struct { - vigo.Model - Name string `json:"name" gorm:"uniqueIndex;not null;size:50;comment:角色名称" validate:"required"` - DisplayName string `json:"display_name" gorm:"size:100;comment:显示名称"` - Description string `json:"description" gorm:"type:text;comment:角色描述"` - IsSystem bool `json:"is_system" gorm:"default:false;comment:是否为系统角色"` - IsActive bool `json:"is_active" gorm:"default:true;comment:是否激活"` - - // 关联关系 - Users []User `json:"-" gorm:"many2many:user_roles;"` - UserRoles []UserRole `json:"-"` - Permissions []Permission `json:"permissions" gorm:"many2many:role_permissions;"` -} - -// Permission 权限表 -type Permission struct { - vigo.Model - Name string `json:"name" gorm:"uniqueIndex;not null;size:100;comment:权限名称" validate:"required"` - DisplayName string `json:"display_name" gorm:"size:100;comment:显示名称"` - Description string `json:"description" gorm:"type:text;comment:权限描述"` - Resource string `json:"resource" gorm:"not null;size:50;comment:资源名称" validate:"required"` - Action string `json:"action" gorm:"not null;size:50;comment:操作类型" validate:"required"` - IsSystem bool `json:"is_system" gorm:"default:false;comment:是否为系统权限"` - - // 关联关系 - Roles []Role `json:"-" gorm:"many2many:role_permissions;"` -} - -// UserRole 用户角色关联表 -type UserRole struct { - UserID string `json:"user_id" gorm:"primaryKey;type:varchar(32);comment:用户ID"` - RoleID string `json:"role_id" gorm:"primaryKey;type:varchar(32);comment:角色ID"` - GrantedBy string `json:"granted_by" gorm:"type:varchar(32);comment:授权人ID"` - GrantedAt time.Time `json:"granted_at" gorm:"autoCreateTime;comment:授权时间"` - ExpiresAt *time.Time `json:"expires_at" gorm:"comment:过期时间"` - - // 关联关系 - User *User `json:"user" gorm:"foreignKey:UserID"` - Role *Role `json:"role" gorm:"foreignKey:RoleID"` - GrantedByUser *User `json:"granted_by_user" gorm:"foreignKey:GrantedBy"` -} - -// RolePermission 角色权限关联表 -type RolePermission struct { - RoleID string `json:"role_id" gorm:"primaryKey;type:varchar(32);comment:角色ID"` - PermissionID string `json:"permission_id" gorm:"primaryKey;type:varchar(32);comment:权限ID"` - GrantedBy string `json:"granted_by" gorm:"type:varchar(32);comment:授权人ID"` - GrantedAt time.Time `json:"granted_at" gorm:"autoCreateTime;comment:授权时间"` - - // 关联关系 - Role *Role `json:"role" gorm:"foreignKey:RoleID"` - Permission *Permission `json:"permission" gorm:"foreignKey:PermissionID"` - GrantedByUser *User `json:"granted_by_user" gorm:"foreignKey:GrantedBy"` -} - -// UserLoginLog 用户登录日志表 -type UserLoginLog struct { - vigo.Model - UserID string `json:"user_id" gorm:"not null;type:varchar(32);index;comment:用户ID"` - IPAddress string `json:"ip_address" gorm:"size:45;comment:IP地址"` - UserAgent string `json:"user_agent" gorm:"type:text;comment:用户代理"` - LoginAt time.Time `json:"login_at" gorm:"autoCreateTime;comment:登录时间"` - Success bool `json:"success" gorm:"default:true;comment:是否成功"` - FailReason string `json:"fail_reason" gorm:"size:255;comment:失败原因"` - Location string `json:"location" gorm:"size:100;comment:地理位置"` // 地理位置 - - // 关联关系 - User User `json:"user" gorm:"foreignKey:UserID"` -} - -// GORM Hooks -func (u *User) BeforeCreate(tx *gorm.DB) error { - if u.Locale == "" { - u.Locale = "zh-CN" - } - if u.Timezone == "" { - u.Timezone = "Asia/Shanghai" - } - return nil -} - -// 用户方法 -func (u *User) HasRole(roleName string) bool { - for _, role := range u.Roles { - if role.Name == roleName { - return true - } - } - return false -} - -func (u *User) HasPermission(resource, action string) bool { - for _, role := range u.Roles { - for _, permission := range role.Permissions { - if permission.Resource == resource && permission.Action == action { - return true - } - } - } - return false -} - -func (u *User) GetPermissions() []Permission { - var permissions []Permission - permissionMap := make(map[string]bool) - - for _, role := range u.Roles { - for _, permission := range role.Permissions { - if !permissionMap[permission.ID] { - permissions = append(permissions, permission) - permissionMap[permission.ID] = true - } - } - } - return permissions -} - -// 角色方法 -func (r *Role) HasPermission(resource, action string) bool { - for _, permission := range r.Permissions { - if permission.Resource == resource && permission.Action == action { - return true - } - } - return false -} - -// ===== OAuth 服务器相关模型 ===== - -// OAuthClient OAuth客户端表 -type OAuthClient struct { - vigo.Model - ClientID string `json:"client_id" gorm:"uniqueIndex;not null;size:255;comment:客户端ID"` - ClientSecret string `json:"-" gorm:"not null;size:255;comment:客户端密钥"` - ClientName string `json:"client_name" gorm:"not null;size:255;comment:客户端名称"` - ClientURI string `json:"client_uri" gorm:"size:500;comment:客户端主页"` - LogoURI string `json:"logo_uri" gorm:"size:500;comment:客户端Logo"` - TermsOfServiceURI string `json:"tos_uri" gorm:"size:500;comment:服务条款URL"` - PolicyURI string `json:"policy_uri" gorm:"size:500;comment:隐私政策URL"` - RedirectURIs string `json:"redirect_uris" gorm:"type:text;comment:重定向URI列表,JSON格式"` - ResponseTypes string `json:"response_types" gorm:"size:255;default:'code';comment:响应类型"` - GrantTypes string `json:"grant_types" gorm:"size:255;default:'authorization_code,refresh_token';comment:授权类型"` - Scope string `json:"scope" gorm:"type:text;comment:授权范围"` - Contacts string `json:"contacts" gorm:"type:text;comment:联系人邮箱,JSON格式"` - IsPublic bool `json:"is_public" gorm:"default:false;comment:是否为公开客户端"` - IsActive bool `json:"is_active" gorm:"default:true;comment:是否激活"` - OwnerID string `json:"owner_id" gorm:"type:varchar(32);comment:客户端拥有者ID"` - - // 关联关系 - Owner *User `json:"owner" gorm:"foreignKey:OwnerID"` - AuthorizationCodes []OAuthAuthorizationCode `json:"-"` - AccessTokens []OAuthAccessToken `json:"-"` - RefreshTokens []OAuthRefreshToken `json:"-"` -} - -// OAuthAuthorizationCode 授权码表 -type OAuthAuthorizationCode struct { - vigo.Model - Code string `json:"code" gorm:"uniqueIndex;not null;size:255;comment:授权码"` - ClientID string `json:"client_id" gorm:"not null;type:varchar(32);index;comment:客户端ID"` - UserID string `json:"user_id" gorm:"not null;type:varchar(32);index;comment:用户ID"` - RedirectURI string `json:"redirect_uri" gorm:"not null;size:500;comment:重定向URI"` - Scope string `json:"scope" gorm:"type:text;comment:授权范围"` - CodeChallenge string `json:"code_challenge" gorm:"size:255;comment:PKCE代码挑战"` - CodeChallengeMethod string `json:"code_challenge_method" gorm:"size:50;comment:PKCE挑战方法"` - ExpiresAt time.Time `json:"expires_at" gorm:"not null;comment:过期时间"` - Used bool `json:"used" gorm:"default:false;comment:是否已使用"` - - // 关联关系 - Client *OAuthClient `json:"client" gorm:"foreignKey:ClientID"` - User *User `json:"user" gorm:"foreignKey:UserID"` -} - -// OAuthAccessToken 访问令牌表 -type OAuthAccessToken struct { - vigo.Model - Token string `json:"token" gorm:"uniqueIndex;not null;size:500;comment:访问令牌"` - ClientID string `json:"client_id" gorm:"not null;type:varchar(32);index;comment:客户端ID"` - UserID string `json:"user_id" gorm:"not null;type:varchar(32);index;comment:用户ID"` - Scope string `json:"scope" gorm:"type:text;comment:授权范围"` - ExpiresAt time.Time `json:"expires_at" gorm:"not null;comment:过期时间"` - Revoked bool `json:"revoked" gorm:"default:false;comment:是否已撤销"` - - // 关联关系 - Client *OAuthClient `json:"client" gorm:"foreignKey:ClientID"` - User *User `json:"user" gorm:"foreignKey:UserID"` - RefreshToken *OAuthRefreshToken `json:"refresh_token"` -} - -// OAuthRefreshToken 刷新令牌表 -type OAuthRefreshToken struct { - vigo.Model - Token string `json:"token" gorm:"uniqueIndex;not null;size:500;comment:刷新令牌"` - AccessTokenID string `json:"access_token_id" gorm:"type:varchar(32);uniqueIndex;comment:访问令牌ID"` - ClientID string `json:"client_id" gorm:"not null;type:varchar(32);index;comment:客户端ID"` - UserID string `json:"user_id" gorm:"not null;type:varchar(32);index;comment:用户ID"` - Scope string `json:"scope" gorm:"type:text;comment:授权范围"` - ExpiresAt time.Time `json:"expires_at" gorm:"not null;comment:过期时间"` - Revoked bool `json:"revoked" gorm:"default:false;comment:是否已撤销"` - - // 关联关系 - Client *OAuthClient `json:"client" gorm:"foreignKey:ClientID"` - User *User `json:"user" gorm:"foreignKey:UserID"` - AccessToken *OAuthAccessToken `json:"access_token" gorm:"foreignKey:AccessTokenID"` -} - -// OAuthScope OAuth授权范围表 -type OAuthScope struct { - vigo.Model - Name string `json:"name" gorm:"uniqueIndex;not null;size:100;comment:范围名称"` - DisplayName string `json:"display_name" gorm:"size:100;comment:显示名称"` - Description string `json:"description" gorm:"type:text;comment:范围描述"` - IsDefault bool `json:"is_default" gorm:"default:false;comment:是否为默认范围"` - IsSystem bool `json:"is_system" gorm:"default:false;comment:是否为系统范围"` -} - -// OAuthClientScope 客户端授权范围关联表 -type OAuthClientScope struct { - ClientID string `json:"client_id" gorm:"primaryKey;type:varchar(32);comment:客户端ID"` - ScopeID string `json:"scope_id" gorm:"primaryKey;type:varchar(32);comment:范围ID"` - - // 关联关系 - Client *OAuthClient `json:"client" gorm:"foreignKey:ClientID"` - Scope *OAuthScope `json:"scope" gorm:"foreignKey:ScopeID"` -} - -// OAuthProvider 第三方OAuth提供商表(用于OAuth客户端模式) -type OAuthProvider struct { - vigo.Model - Name string `json:"name" gorm:"uniqueIndex;not null;size:100;comment:提供商名称"` - DisplayName string `json:"display_name" gorm:"size:100;comment:显示名称"` - ClientID string `json:"client_id" gorm:"not null;size:255;comment:客户端ID"` - ClientSecret string `json:"-" gorm:"not null;size:255;comment:客户端密钥"` - AuthURL string `json:"auth_url" gorm:"not null;size:500;comment:授权URL"` - TokenURL string `json:"token_url" gorm:"not null;size:500;comment:令牌URL"` - UserInfoURL string `json:"user_info_url" gorm:"size:500;comment:用户信息URL"` - Scope string `json:"scope" gorm:"type:text;comment:默认授权范围"` - IsActive bool `json:"is_active" gorm:"default:true;comment:是否激活"` - - // 关联关系 - OAuthAccounts []OAuthAccount `json:"oauth_accounts"` -} - -// OAuthAccount 用户OAuth账户表(第三方登录) -type OAuthAccount struct { - vigo.Model - UserID string `json:"user_id" gorm:"not null;type:varchar(32);index;comment:用户ID"` - ProviderID string `json:"provider_id" gorm:"not null;type:varchar(32);index;comment:提供商ID"` - ProviderUserID string `json:"provider_user_id" gorm:"not null;size:255;comment:提供商用户ID"` - Email string `json:"email" gorm:"size:255;comment:邮箱"` - Username string `json:"username" gorm:"size:255;comment:用户名"` - Nickname string `json:"nickname" gorm:"size:255;comment:昵称"` - Avatar string `json:"avatar" gorm:"size:500;comment:头像URL"` - AccessToken string `json:"-" gorm:"type:text;comment:访问令牌"` - RefreshToken string `json:"-" gorm:"type:text;comment:刷新令牌"` - ExpiresAt *time.Time `json:"expires_at" gorm:"comment:令牌过期时间"` - - // 关联关系 - User *User `json:"user" gorm:"foreignKey:UserID"` - Provider *OAuthProvider `json:"provider" gorm:"foreignKey:ProviderID"` -} - -// UserToken 用户令牌表(API令牌等) -type UserToken struct { - vigo.Model - UserID string `json:"user_id" gorm:"not null;type:varchar(32);index;comment:用户ID"` - TokenType string `json:"token_type" gorm:"not null;size:50;comment:令牌类型"` // api, session, etc. - Token string `json:"token" gorm:"uniqueIndex;not null;size:500;comment:令牌值"` - Name string `json:"name" gorm:"size:100;comment:令牌名称"` - Description string `json:"description" gorm:"type:text;comment:令牌描述"` - Scope string `json:"scope" gorm:"type:text;comment:授权范围"` - ExpiresAt *time.Time `json:"expires_at" gorm:"comment:过期时间"` - LastUsedAt *time.Time `json:"last_used_at" gorm:"comment:最后使用时间"` - IsActive bool `json:"is_active" gorm:"default:true;comment:是否激活"` - - // 关联关系 - User *User `json:"user" gorm:"foreignKey:UserID"` -} - -// UserSession 用户会话表 -type UserSession struct { - vigo.Model - UserID string `json:"user_id" gorm:"not null;type:varchar(32);index;comment:用户ID"` - SessionID string `json:"session_id" gorm:"uniqueIndex;not null;size:255;comment:会话ID"` - IPAddress string `json:"ip_address" gorm:"size:45;comment:IP地址"` - UserAgent string `json:"user_agent" gorm:"type:text;comment:用户代理"` - ExpiresAt time.Time `json:"expires_at" gorm:"not null;comment:过期时间"` - IsActive bool `json:"is_active" gorm:"default:true;comment:是否激活"` - LastActivity time.Time `json:"last_activity" gorm:"comment:最后活动时间"` - - // 关联关系 - User *User `json:"user" gorm:"foreignKey:UserID"` -} - -// OAuthUserConsent 用户授权同意表 -type OAuthUserConsent struct { - vigo.Model - UserID string `json:"user_id" gorm:"not null;type:varchar(32);index;comment:用户ID"` - ClientID string `json:"client_id" gorm:"not null;type:varchar(32);index;comment:客户端ID"` - Scope string `json:"scope" gorm:"type:text;comment:授权范围"` - ConsentAt time.Time `json:"consent_at" gorm:"autoCreateTime;comment:同意时间"` - ExpiresAt *time.Time `json:"expires_at" gorm:"comment:同意过期时间"` - - // 关联关系 - User *User `json:"user" gorm:"foreignKey:UserID"` - Client *OAuthClient `json:"client" gorm:"foreignKey:ClientID"` -} - -// ===== OAuth 模型方法 ===== - -// OAuthClient 方法 -func (c *OAuthClient) IsRedirectURIValid(uri string) bool { - // 这里应该解析 RedirectURIs JSON 并验证 - // 简化实现,实际使用时需要完善 - return true -} - -func (c *OAuthClient) HasScope(scope string) bool { - // 这里应该解析 Scope 并检查 - // 简化实现,实际使用时需要完善 - return true -} - -// OAuthAuthorizationCode 方法 -func (code *OAuthAuthorizationCode) IsExpired() bool { - return time.Now().After(code.ExpiresAt) -} - -// OAuthAccessToken 方法 -func (token *OAuthAccessToken) IsExpired() bool { - return time.Now().After(token.ExpiresAt) -} - -func (token *OAuthAccessToken) IsValid() bool { - return !token.Revoked && !token.IsExpired() -} - -// OAuthRefreshToken 方法 -func (token *OAuthRefreshToken) IsExpired() bool { - return time.Now().After(token.ExpiresAt) -} - -func (token *OAuthRefreshToken) IsValid() bool { - return !token.Revoked && !token.IsExpired() -} - -// UserSession 方法 -func (s *UserSession) IsExpired() bool { - return time.Now().After(s.ExpiresAt) -} - -func (s *UserSession) IsValid() bool { - return s.IsActive && !s.IsExpired() -} diff --git a/oauth/utils.go b/oauth/utils.go deleted file mode 100644 index 619f08f..0000000 --- a/oauth/utils.go +++ /dev/null @@ -1,49 +0,0 @@ -// -// Copyright (C) 2024 veypi -// 2025-07-24 15:27:31 -// Distributed under terms of the MIT license. -// - -package oauth - -import ( - "crypto/rand" - "encoding/hex" - "net/url" -) - -// generateRandomString 生成指定长度的随机字符串 -func generateRandomString(length int) (string, error) { - bytes := make([]byte, length) - if _, err := rand.Read(bytes); err != nil { - return "", err - } - return hex.EncodeToString(bytes)[:length], nil -} - -// BuildRedirectURI 构建成功重定向URI -func BuildRedirectURI(baseURI, code, state string) string { - u, _ := url.Parse(baseURI) - q := u.Query() - q.Set("code", code) - if state != "" { - q.Set("state", state) - } - u.RawQuery = q.Encode() - return u.String() -} - -// BuildErrorRedirectURI 构建错误重定向URI -func BuildErrorRedirectURI(baseURI, errorCode, errorDesc, state string) string { - u, _ := url.Parse(baseURI) - q := u.Query() - q.Set("error", errorCode) - if errorDesc != "" { - q.Set("error_description", errorDesc) - } - if state != "" { - q.Set("state", state) - } - u.RawQuery = q.Encode() - return u.String() -} diff --git a/ui/assets/others.css b/ui/assets/others.css index 3390e29..7dd0f73 100644 --- a/ui/assets/others.css +++ b/ui/assets/others.css @@ -1,4 +1,4 @@ -/* 用于定义vyes-ui库的样式变量 */ +/* 用于定义vhtml-ui库的样式变量 */ body { --v-color-primary: var(--color-primary); diff --git a/ui/assets/vhtml.min.js b/ui/assets/vhtml.min.js new file mode 100644 index 0000000..dc8d416 --- /dev/null +++ b/ui/assets/vhtml.min.js @@ -0,0 +1 @@ +var t;t=function(){const t=[],e=[];function n(){return`${performance.now().toString(36)}-${Math.random().toString(36).substring(2,5)}`}function o(t,e=new Set){if(t&&"object"==typeof t&&!e.has(t)){e.add(t);for(let n in t)o(t[n],e)}return t}setInterval((()=>{let n=new Set(e.splice(0)),o=0;for(let e of n)t[e]&&(t[e](),o++);return o}),25),window.$vupdate=e=>{t[e]()};var r=[];const i=Symbol("isProxy"),s=Symbol("DataID"),a=Symbol("bind"),c=Symbol("root"),l=Symbol("root arg");function u(t,e){t[c]=e,Object.keys(e).forEach((e=>{e in t||(t[e]=l)}))}function f(t){return!(!t||"object"!=typeof t||t instanceof Node||t instanceof Date||t instanceof RegExp||t instanceof Event||t.t||t.constructor!==Object&&t.constructor!==Array)}function h(t,e){if(!t||!t[i]||!f(e))return e;let n=t[a];if(!e[i]){if(Array.isArray(e)&&Array.isArray(t)){t.length=0;for(let n=0;n{e.hasOwnProperty(n)||delete t[n]})),Object.keys(e).forEach((n=>{t[n]?.[i]?t[n]=h(t[n],e[n]):t[n]=e[n]})),t}if(e[s]===t[s])return e;for(let o in n)if(e[a][o]?.indexOf){const t=e[a][o],r=new Set(t);for(let e of n[o])r.has(e)||(t.push(e),r.add(e))}else e[a][o]=n[o];for(let o in e)o in t&&t[o]?.[i]&&(e[o]=h(t[o],e[o]));return e}let d=!1;const p={console,window,prompt:prompt.bind(window),alert:alert.bind(window),confirm:confirm.bind(window),RegExp,document,Array,Object,Math,Date,JSON,Symbol,Number,eval,isNaN,parseInt,parseFloat,setTimeout:setTimeout.bind(window),setInterval:setInterval.bind(window),clearTimeout:clearTimeout.bind(window),clearInterval:clearInterval.bind(window),encodeURIComponent,btoa:btoa.bind(window),fetch:fetch.bind(window),TextDecoder,history,requestAnimationFrame:requestAnimationFrame.bind(window)};function m(t,e,n){const o=new Proxy(t,{has:(t,e)=>!0,get(o,r,i){let s;return"$data"===r?s=t:"$env"===r?s=e:r in o?s=Reflect.get(o,r,i):r in e?s=e[r]:n&&r in n?s=n[r]:r in p?s=p[r]:r in window&&(s=window[r]),s},set:(t,e,n,o)=>Reflect.set(t,e,n,o)});return o}const w=Object.getPrototypeOf((async function(){})).constructor;function b(t,e){if(t.startsWith("/"))return t;const n=e.substring(0,e.lastIndexOf("/")).split("/").filter((t=>""!==t)),o=t.split("/").filter((t=>""!==t));for(const r of o)if(".."===r)n.length>0&&n.pop();else{if("."===r)continue;n.push(r)}return"/"+n.join("/")}const y={Wrap:function o(p,m=void 0){const w=n();let b=!1;"[object Array]"==={}.toString.call(p)&&(b=!0),m&&u(p,m);const y={},v={get(t,e,n){if(e===s)return w;if(e===i)return!0;if(e===a)return y;const u=Reflect.get(t,e,n);if(u===l)return t[c][e];if("symbol"==typeof e&&d)return u;if("function"==typeof u)return u;let h=-1;if(r.length>0){let t=e;h=r[r.length-1],b&&(t=""),y.hasOwnProperty(t)?-1==y[t].indexOf(h)&&y[t].push(h):y[t]=[h]}if(window.vdev,f(u)&&!u[i]){let r=o(u,void 0);return Reflect.set(t,e,r,n),r}return u},set(n,o,s,a){const u=Reflect.get(n,o,a);if(u===l)return n[c][o]=s,!0;if(u===s)return!0;if(d)return Reflect.set(n,o,s,a);let p=!0;if(Array.isArray(s)&&Array.isArray(u)){d=!0,u.length=0;for(let t=0;t{n(e())})):t.push(e);try{s=e(),i&&i.deep&&o(s)}catch(g){}finally{r.pop()}return"function"==typeof n&&n(s),a},Cancel:function(e){e>=0&&et.trim()))}const i=await import(t);"string"==typeof o?i.default?e[o]=i.default:e[o]=i:o.forEach((t=>{t in i?e[t]=i[t]:t in i.default&&(e[t]=i.default[t])}))}catch(l){}}return s.trim()}};class v{constructor(){this.events={}}on(t,e,n=null){if("function"!=typeof e)throw Error("\u56de\u8c03\u51fd\u6570\u5fc5\u987b\u662f\u4e00\u4e2a\u51fd\u6570");this.events[t]||(this.events[t]=[]);const o={callback:e,context:n};return this.events[t].push(o),()=>this.off(t,e,n)}once(t,e,n=null){const o=(...r)=>{this.off(t,o,n),e.apply(n,r)};return this.on(t,o,n)}off(t,e=null,n=null){this.events[t]&&(e?(this.events[t]=this.events[t].filter((t=>!(t.callback===e&&t.context===n))),0===this.events[t].length&&delete this.events[t]):delete this.events[t])}emit(t,...e){this.events[t]&&[...this.events[t]].forEach((t=>{try{t.callback.apply(t.context,e)}catch(n){}}))}listenerCount(t){return this.events[t]?this.events[t].length:0}eventNames(){return Object.keys(this.events)}removeAllListeners(){this.events={}}hasListeners(t){return this.listenerCount(t)>0}}function g(t,e){return function(){return t.apply(e,arguments)}}const{toString:x}=Object.prototype,{getPrototypeOf:R}=Object,{iterator:k,toStringTag:O}=Symbol,T=(E=Object.create(null),t=>{const e=x.call(t);return E[e]||(E[e]=e.slice(8,-1).toLowerCase())});var E;const S=t=>(t=t.toLowerCase(),e=>T(e)===t),A=t=>e=>typeof e===t,{isArray:j}=Array,$=A("undefined"),N=S("ArrayBuffer"),P=A("string"),C=A("function"),U=A("number"),F=t=>null!==t&&"object"==typeof t,D=t=>{if("object"!==T(t))return!1;const e=R(t);return!(null!==e&&e!==Object.prototype&&null!==Object.getPrototypeOf(e)||O in t||k in t)},L=S("Date"),I=S("File"),z=S("Blob"),M=S("FileList"),q=S("URLSearchParams"),[B,_,H,V]=["ReadableStream","Request","Response","Headers"].map(S);function X(t,e,{allOwnKeys:n=!1}={}){if(null==t)return;let o,r;if("object"!=typeof t&&(t=[t]),j(t))for(o=0,r=t.length;r>o;o++)e.call(null,t[o],o,t);else{const r=n?Object.getOwnPropertyNames(t):Object.keys(t),i=r.length;let s;for(o=0;i>o;o++)s=r[o],e.call(null,t[s],s,t)}}function J(t,e){e=e.toLowerCase();const n=Object.keys(t);let o,r=n.length;for(;r-- >0;)if(o=n[r],e===o.toLowerCase())return o;return null}const W="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:global,K=t=>!$(t)&&t!==W,G=(Z="undefined"!=typeof Uint8Array&&R(Uint8Array),t=>Z&&t instanceof Z);var Z;const Y=S("HTMLFormElement"),Q=(({hasOwnProperty:t})=>(e,n)=>t.call(e,n))(Object.prototype),tt=S("RegExp"),et=(t,e)=>{const n=Object.getOwnPropertyDescriptors(t),o={};X(n,((n,r)=>{let i;!1!==(i=e(n,r,t))&&(o[r]=i||n)})),Object.defineProperties(t,o)},nt=S("AsyncFunction"),ot=(rt="function"==typeof setImmediate,it=C(W.postMessage),rt?setImmediate:it?(st="axios@"+Math.random(),at=[],W.addEventListener("message",(({source:t,data:e})=>{t===W&&e===st&&at.length&&at.shift()()}),!1),t=>{at.push(t),W.postMessage(st,"*")}):t=>setTimeout(t));var rt,it,st,at;const ct="undefined"!=typeof queueMicrotask?queueMicrotask.bind(W):"undefined"!=typeof process&&process.nextTick||ot,lt={isArray:j,isArrayBuffer:N,isBuffer:function(t){return null!==t&&!$(t)&&null!==t.constructor&&!$(t.constructor)&&C(t.constructor.isBuffer)&&t.constructor.isBuffer(t)},isFormData:t=>{let e;return t&&("function"==typeof FormData&&t instanceof FormData||C(t.append)&&("formdata"===(e=T(t))||"object"===e&&C(t.toString)&&"[object FormData]"===t.toString()))},isArrayBufferView:function(t){let e;return e="undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(t):t&&t.buffer&&N(t.buffer),e},isString:P,isNumber:U,isBoolean:t=>!0===t||!1===t,isObject:F,isPlainObject:D,isReadableStream:B,isRequest:_,isResponse:H,isHeaders:V,isUndefined:$,isDate:L,isFile:I,isBlob:z,isRegExp:tt,isFunction:C,isStream:t=>F(t)&&C(t.pipe),isURLSearchParams:q,isTypedArray:G,isFileList:M,forEach:X,merge:function t(){const{caseless:e}=K(this)&&this||{},n={},o=(o,r)=>{const i=e&&J(n,r)||r;D(n[i])&&D(o)?n[i]=t(n[i],o):D(o)?n[i]=t({},o):j(o)?n[i]=o.slice():n[i]=o};for(let r=0,i=arguments.length;i>r;r++)arguments[r]&&X(arguments[r],o);return n},extend:(t,e,n,{allOwnKeys:o}={})=>(X(e,((e,o)=>{n&&C(e)?t[o]=g(e,n):t[o]=e}),{allOwnKeys:o}),t),trim:t=>t.trim?t.trim():t.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,""),stripBOM:t=>(65279===t.charCodeAt(0)&&(t=t.slice(1)),t),inherits:(t,e,n,o)=>{t.prototype=Object.create(e.prototype,o),t.prototype.constructor=t,Object.defineProperty(t,"super",{value:e.prototype}),n&&Object.assign(t.prototype,n)},toFlatObject:(t,e,n,o)=>{let r,i,s;const a={};if(e=e||{},null==t)return e;do{for(r=Object.getOwnPropertyNames(t),i=r.length;i-- >0;)s=r[i],o&&!o(s,t,e)||a[s]||(e[s]=t[s],a[s]=!0);t=!1!==n&&R(t)}while(t&&(!n||n(t,e))&&t!==Object.prototype);return e},kindOf:T,kindOfTest:S,endsWith:(t,e,n)=>{t+="",(void 0===n||n>t.length)&&(n=t.length),n-=e.length;const o=t.indexOf(e,n);return-1!==o&&o===n},toArray:t=>{if(!t)return null;if(j(t))return t;let e=t.length;if(!U(e))return null;const n=Array(e);for(;e-- >0;)n[e]=t[e];return n},forEachEntry:(t,e)=>{const n=(t&&t[k]).call(t);let o;for(;(o=n.next())&&!o.done;){const n=o.value;e.call(t,n[0],n[1])}},matchAll:(t,e)=>{let n;const o=[];for(;null!==(n=t.exec(e));)o.push(n);return o},isHTMLForm:Y,hasOwnProperty:Q,hasOwnProp:Q,reduceDescriptors:et,freezeMethods:t=>{et(t,((e,n)=>{if(C(t)&&-1!==["arguments","caller","callee"].indexOf(n))return!1;const o=t[n];C(o)&&(e.enumerable=!1,"writable"in e?e.writable=!1:e.set||(e.set=()=>{throw Error("Can not rewrite read-only method '"+n+"'")}))}))},toObjectSet:(t,e)=>{const n={},o=t=>{t.forEach((t=>{n[t]=!0}))};return j(t)?o(t):o((t+"").split(e)),n},toCamelCase:t=>t.toLowerCase().replace(/[-_\s]([a-z\d])(\w*)/g,(function(t,e,n){return e.toUpperCase()+n})),noop:()=>{},toFiniteNumber:(t,e)=>null!=t&&Number.isFinite(t=+t)?t:e,findKey:J,global:W,isContextDefined:K,isSpecCompliantForm:function(t){return!!(t&&C(t.append)&&"FormData"===t[O]&&t[k])},toJSONObject:t=>{const e=[,,,,,,,,,,],n=(t,o)=>{if(F(t)){if(e.indexOf(t)>=0)return;if(!("toJSON"in t)){e[o]=t;const r=j(t)?[]:{};return X(t,((t,e)=>{const i=n(t,o+1);!$(i)&&(r[e]=i)})),e[o]=void 0,r}}return t};return n(t,0)},isAsyncFn:nt,isThenable:t=>t&&(F(t)||C(t))&&C(t.then)&&C(t.catch),setImmediate:ot,asap:ct,isIterable:t=>null!=t&&C(t[k])};function ut(t,e,n,o,r){Error.call(this),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=Error().stack,this.message=t,this.name="AxiosError",e&&(this.code=e),n&&(this.config=n),o&&(this.request=o),r&&(this.response=r,this.status=r.status?r.status:null)}lt.inherits(ut,Error,{toJSON:function(){return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:lt.toJSONObject(this.config),code:this.code,status:this.status}}});const ft=ut.prototype,ht={};function dt(t){return lt.isPlainObject(t)||lt.isArray(t)}function pt(t){return lt.endsWith(t,"[]")?t.slice(0,-2):t}function mt(t,e,n){return t?t.concat(e).map((function(t,e){return t=pt(t),!n&&e?"["+t+"]":t})).join(n?".":""):e}["ERR_BAD_OPTION_VALUE","ERR_BAD_OPTION","ECONNABORTED","ETIMEDOUT","ERR_NETWORK","ERR_FR_TOO_MANY_REDIRECTS","ERR_DEPRECATED","ERR_BAD_RESPONSE","ERR_BAD_REQUEST","ERR_CANCELED","ERR_NOT_SUPPORT","ERR_INVALID_URL"].forEach((t=>{ht[t]={value:t}})),Object.defineProperties(ut,ht),Object.defineProperty(ft,"isAxiosError",{value:!0}),ut.from=(t,e,n,o,r,i)=>{const s=Object.create(ft);return lt.toFlatObject(t,s,(function(t){return t!==Error.prototype}),(t=>"isAxiosError"!==t)),ut.call(s,t.message,e,n,o,r),s.cause=t,s.name=t.name,i&&Object.assign(s,i),s};const wt=lt.toFlatObject(lt,{},null,(function(t){return/^is[A-Z]/.test(t)}));function bt(t,e,n){if(!lt.isObject(t))throw new TypeError("target must be an object");e=e||new FormData;const o=(n=lt.toFlatObject(n,{metaTokens:!0,dots:!1,indexes:!1},!1,(function(t,e){return!lt.isUndefined(e[t])}))).metaTokens,r=n.visitor||l,i=n.dots,s=n.indexes,a=(n.Blob||"undefined"!=typeof Blob&&Blob)&<.isSpecCompliantForm(e);if(!lt.isFunction(r))throw new TypeError("visitor must be a function");function c(t){if(null===t)return"";if(lt.isDate(t))return t.toISOString();if(lt.isBoolean(t))return t.toString();if(!a&<.isBlob(t))throw new ut("Blob is not supported. Use a Buffer instead.");return lt.isArrayBuffer(t)||lt.isTypedArray(t)?a&&"function"==typeof Blob?new Blob([t]):Buffer.from(t):t}function l(t,n,r){let a=t;if(t&&!r&&"object"==typeof t)if(lt.endsWith(n,"{}"))n=o?n:n.slice(0,-2),t=JSON.stringify(t);else if(lt.isArray(t)&&function(t){return lt.isArray(t)&&!t.some(dt)}(t)||(lt.isFileList(t)||lt.endsWith(n,"[]"))&&(a=lt.toArray(t)))return n=pt(n),a.forEach((function(t,o){!lt.isUndefined(t)&&null!==t&&e.append(!0===s?mt([n],o,i):null===s?n:n+"[]",c(t))})),!1;return!!dt(t)||(e.append(mt(r,n,i),c(t)),!1)}const u=[],f=Object.assign(wt,{defaultVisitor:l,convertValue:c,isVisitable:dt});if(!lt.isObject(t))throw new TypeError("data must be an object");return function t(n,o){if(!lt.isUndefined(n)){if(-1!==u.indexOf(n))throw Error("Circular reference detected in "+o.join("."));u.push(n),lt.forEach(n,(function(n,i){!0===(!(lt.isUndefined(n)||null===n)&&r.call(e,n,lt.isString(i)?i.trim():i,o,f))&&t(n,o?o.concat(i):[i])})),u.pop()}}(t),e}function yt(t){const e={"!":"%21","'":"%27","(":"%28",")":"%29","~":"%7E","%20":"+","%00":"\0"};return encodeURIComponent(t).replace(/[!'()~]|%20|%00/g,(function(t){return e[t]}))}function vt(t,e){this.o=[],t&&bt(t,this,e)}const gt=vt.prototype;function xt(t){return encodeURIComponent(t).replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}function Rt(t,e,n){if(!e)return t;const o=n&&n.encode||xt;lt.isFunction(n)&&(n={serialize:n});const r=n&&n.serialize;let i;if(i=r?r(e,n):lt.isURLSearchParams(e)?e.toString():new vt(e,n).toString(o),i){const e=t.indexOf("#");-1!==e&&(t=t.slice(0,e)),t+=(-1===t.indexOf("?")?"?":"&")+i}return t}gt.append=function(t,e){this.o.push([t,e])},gt.toString=function(t){const e=t?function(e){return t.call(this,e,yt)}:yt;return this.o.map((function(t){return e(t[0])+"="+e(t[1])}),"").join("&")};const kt=class{constructor(){this.handlers=[]}use(t,e,n){return this.handlers.push({fulfilled:t,rejected:e,synchronous:!!n&&n.synchronous,runWhen:n?n.runWhen:null}),this.handlers.length-1}eject(t){this.handlers[t]&&(this.handlers[t]=null)}clear(){this.handlers&&(this.handlers=[])}forEach(t){lt.forEach(this.handlers,(function(e){null!==e&&t(e)}))}},Ot={silentJSONParsing:!0,forcedJSONParsing:!0,clarifyTimeoutError:!1},Tt={isBrowser:!0,classes:{URLSearchParams:"undefined"!=typeof URLSearchParams?URLSearchParams:vt,FormData:"undefined"!=typeof FormData?FormData:null,Blob:"undefined"!=typeof Blob?Blob:null},protocols:["http","https","file","blob","url","data"]},Et="undefined"!=typeof window&&"undefined"!=typeof document,St="object"==typeof navigator&&navigator||void 0,At=Et&&(!St||0>["ReactNative","NativeScript","NS"].indexOf(St.product)),jt="undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope&&"function"==typeof self.importScripts,$t=Et&&window.location.href||"http://localhost",Nt={...Object.freeze({__proto__:null,hasBrowserEnv:Et,hasStandardBrowserWebWorkerEnv:jt,hasStandardBrowserEnv:At,navigator:St,origin:$t}),...Tt};function Pt(t){function e(t,n,o,r){let i=t[r++];if("__proto__"===i)return!0;const s=Number.isFinite(+i),a=r>=t.length;return i=!i&<.isArray(o)?o.length:i,a?(lt.hasOwnProp(o,i)?o[i]=[o[i],n]:o[i]=n,!s):(o[i]&<.isObject(o[i])||(o[i]=[]),e(t,n,o[i],r)&<.isArray(o[i])&&(o[i]=function(t){const e={},n=Object.keys(t);let o;const r=n.length;let i;for(o=0;r>o;o++)i=n[o],e[i]=t[i];return e}(o[i])),!s)}if(lt.isFormData(t)&<.isFunction(t.entries)){const n={};return lt.forEachEntry(t,((t,o)=>{e(function(t){return lt.matchAll(/\w+|\[(\w*)]/g,t).map((t=>"[]"===t[0]?"":t[1]||t[0]))}(t),o,n,0)})),n}return null}const Ct={transitional:Ot,adapter:["xhr","http","fetch"],transformRequest:[function(t,e){const n=e.getContentType()||"",o=n.indexOf("application/json")>-1,r=lt.isObject(t);if(r&<.isHTMLForm(t)&&(t=new FormData(t)),lt.isFormData(t))return o?JSON.stringify(Pt(t)):t;if(lt.isArrayBuffer(t)||lt.isBuffer(t)||lt.isStream(t)||lt.isFile(t)||lt.isBlob(t)||lt.isReadableStream(t))return t;if(lt.isArrayBufferView(t))return t.buffer;if(lt.isURLSearchParams(t))return e.setContentType("application/x-www-form-urlencoded;charset=utf-8",!1),t.toString();let i;if(r){if(n.indexOf("application/x-www-form-urlencoded")>-1)return function(t,e){return bt(t,new Nt.classes.URLSearchParams,Object.assign({visitor:function(t,e,n,o){return Nt.isNode&<.isBuffer(t)?(this.append(e,t.toString("base64")),!1):o.defaultVisitor.apply(this,arguments)}},e))}(t,this.formSerializer).toString();if((i=lt.isFileList(t))||n.indexOf("multipart/form-data")>-1){const e=this.env&&this.env.FormData;return bt(i?{"files[]":t}:t,e&&new e,this.formSerializer)}}return r||o?(e.setContentType("application/json",!1),function(t){if(lt.isString(t))try{return(0,JSON.parse)(t),lt.trim(t)}catch(t){if("SyntaxError"!==t.name)throw t}return(0,JSON.stringify)(t)}(t)):t}],transformResponse:[function(t){const e=this.transitional||Ct.transitional,n=e&&e.forcedJSONParsing,o="json"===this.responseType;if(lt.isResponse(t)||lt.isReadableStream(t))return t;if(t&<.isString(t)&&(n&&!this.responseType||o)){const n=!(e&&e.silentJSONParsing)&&o;try{return JSON.parse(t)}catch(t){if(n){if("SyntaxError"===t.name)throw ut.from(t,ut.ERR_BAD_RESPONSE,this,null,this.response);throw t}}}return t}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,maxBodyLength:-1,env:{FormData:Nt.classes.FormData,Blob:Nt.classes.Blob},validateStatus:function(t){return t>=200&&300>t},headers:{common:{Accept:"application/json, text/plain, */*","Content-Type":void 0}}};lt.forEach(["delete","get","head","post","put","patch"],(t=>{Ct.headers[t]={}}));const Ut=Ct,Ft=lt.toObjectSet(["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"]),Dt=Symbol("internals");function Lt(t){return t&&(t+"").trim().toLowerCase()}function It(t){return!1===t||null==t?t:lt.isArray(t)?t.map(It):t+""}function zt(t,e,n,o,r){return lt.isFunction(o)?o.call(this,e,n):(r&&(e=n),lt.isString(e)?lt.isString(o)?-1!==e.indexOf(o):lt.isRegExp(o)?o.test(e):void 0:void 0)}class Mt{constructor(t){t&&this.set(t)}set(t,e,n){const o=this;function r(t,e,n){const r=Lt(e);if(!r)throw Error("header name must be a non-empty string");const i=lt.findKey(o,r);(!i||void 0===o[i]||!0===n||void 0===n&&!1!==o[i])&&(o[i||e]=It(t))}const i=(t,e)=>lt.forEach(t,((t,n)=>r(t,n,e)));if(lt.isPlainObject(t)||t instanceof this.constructor)i(t,e);else if(lt.isString(t)&&(t=t.trim())&&!/^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(t.trim()))i((t=>{const e={};let n,o,r;return t&&t.split("\n").forEach((function(t){r=t.indexOf(":"),n=t.substring(0,r).trim().toLowerCase(),o=t.substring(r+1).trim(),!n||e[n]&&Ft[n]||("set-cookie"===n?e[n]?e[n].push(o):e[n]=[o]:e[n]=e[n]?e[n]+", "+o:o)})),e})(t),e);else if(lt.isObject(t)&<.isIterable(t)){let n,o,r={};for(const e of t){if(!lt.isArray(e))throw TypeError("Object iterator must return a key-value pair");r[o=e[0]]=(n=r[o])?lt.isArray(n)?[...n,e[1]]:[n,e[1]]:e[1]}i(r,e)}else null!=t&&r(e,t,n);return this}get(t,e){if(t=Lt(t)){const n=lt.findKey(this,t);if(n){const t=this[n];if(!e)return t;if(!0===e)return function(t){const e=Object.create(null),n=/([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g;let o;for(;o=n.exec(t);)e[o[1]]=o[2];return e}(t);if(lt.isFunction(e))return e.call(this,t,n);if(lt.isRegExp(e))return e.exec(t);throw new TypeError("parser must be boolean|regexp|function")}}}has(t,e){if(t=Lt(t)){const n=lt.findKey(this,t);return!(!n||void 0===this[n]||e&&!zt(0,this[n],n,e))}return!1}delete(t,e){const n=this;let o=!1;function r(t){if(t=Lt(t)){const r=lt.findKey(n,t);!r||e&&!zt(0,n[r],r,e)||(delete n[r],o=!0)}}return lt.isArray(t)?t.forEach(r):r(t),o}clear(t){const e=Object.keys(this);let n=e.length,o=!1;for(;n--;){const r=e[n];t&&!zt(0,this[r],r,t,!0)||(delete this[r],o=!0)}return o}normalize(t){const e=this,n={};return lt.forEach(this,((o,r)=>{const i=lt.findKey(n,r);if(i)return e[i]=It(o),void delete e[r];const s=t?function(t){return t.trim().toLowerCase().replace(/([a-z\d])(\w*)/g,((t,e,n)=>e.toUpperCase()+n))}(r):(r+"").trim();s!==r&&delete e[r],e[s]=It(o),n[s]=!0})),this}concat(...t){return this.constructor.concat(this,...t)}toJSON(t){const e=Object.create(null);return lt.forEach(this,((n,o)=>{null!=n&&!1!==n&&(e[o]=t&<.isArray(n)?n.join(", "):n)})),e}[Symbol.iterator](){return Object.entries(this.toJSON())[Symbol.iterator]()}toString(){return Object.entries(this.toJSON()).map((([t,e])=>t+": "+e)).join("\n")}getSetCookie(){return this.get("set-cookie")||[]}get[Symbol.toStringTag](){return"AxiosHeaders"}static from(t){return t instanceof this?t:new this(t)}static concat(t,...e){const n=new this(t);return e.forEach((t=>n.set(t))),n}static accessor(t){const e=(this[Dt]=this[Dt]={accessors:{}}).accessors,n=this.prototype;function o(t){const o=Lt(t);e[o]||(function(t,e){const n=lt.toCamelCase(" "+e);["get","set","has"].forEach((o=>{Object.defineProperty(t,o+n,{value:function(t,n,r){return this[o].call(this,e,t,n,r)},configurable:!0})}))}(n,t),e[o]=!0)}return lt.isArray(t)?t.forEach(o):o(t),this}}Mt.accessor(["Content-Type","Content-Length","Accept","Accept-Encoding","User-Agent","Authorization"]),lt.reduceDescriptors(Mt.prototype,(({value:t},e)=>{let n=e[0].toUpperCase()+e.slice(1);return{get:()=>t,set(t){this[n]=t}}})),lt.freezeMethods(Mt);const qt=Mt;function Bt(t,e){const n=this||Ut,o=e||n,r=qt.from(o.headers);let i=o.data;return lt.forEach(t,(function(t){i=t.call(n,i,r.normalize(),e?e.status:void 0)})),r.normalize(),i}function _t(t){return!(!t||!t.i)}function Ht(t,e,n){ut.call(this,t??"canceled",ut.ERR_CANCELED,e,n),this.name="CanceledError"}function Vt(t,e,n){const o=n.config.validateStatus;n.status&&o&&!o(n.status)?e(new ut("Request failed with status code "+n.status,[ut.ERR_BAD_REQUEST,ut.ERR_BAD_RESPONSE][Math.floor(n.status/100)-4],n.config,n.request,n)):t(n)}lt.inherits(Ht,ut,{i:!0});const Xt=(t,e,n=3)=>{let o=0;const r=function(t,e){const n=Array(t=t||10),o=Array(t);let r,i=0,s=0;return e=void 0!==e?e:1e3,function(a){const c=Date.now(),l=o[s];r||(r=c),n[i]=a,o[i]=c;let u=s,f=0;for(;u!==i;)f+=n[u++],u%=t;if(i=(i+1)%t,i===s&&(s=(s+1)%t),e>c-r)return;const h=l&&c-l;return h?Math.round(1e3*f/h):void 0}}(50,250);return function(t,e){let n,o,r=0,i=1e3/e;const s=(e,i=Date.now())=>{r=i,n=null,o&&(clearTimeout(o),o=null),t.apply(null,e)};return[(...t)=>{const e=Date.now(),a=e-r;i>a?(n=t,o||(o=setTimeout((()=>{o=null,s(n)}),i-a))):s(t,e)},()=>n&&s(n)]}((n=>{const i=n.loaded,s=n.lengthComputable?n.total:void 0,a=i-o,c=r(a);o=i,t({loaded:i,total:s,progress:s?i/s:void 0,bytes:a,rate:c||void 0,estimated:c&&s&&s>=i?(s-i)/c:void 0,event:n,lengthComputable:null!=s,[e?"download":"upload"]:!0})}),n)},Jt=(t,e)=>{const n=null!=t;return[o=>e[0]({lengthComputable:n,total:t,loaded:o}),e[1]]},Wt=t=>(...e)=>lt.asap((()=>t(...e))),Kt=Nt.hasStandardBrowserEnv?((t,e)=>n=>(n=new URL(n,Nt.origin),t.protocol===n.protocol&&t.host===n.host&&(e||t.port===n.port)))(new URL(Nt.origin),Nt.navigator&&/(msie|trident)/i.test(Nt.navigator.userAgent)):()=>!0,Gt=Nt.hasStandardBrowserEnv?{write(t,e,n,o,r,i){const s=[t+"="+encodeURIComponent(e)];lt.isNumber(n)&&s.push("expires="+new Date(n).toGMTString()),lt.isString(o)&&s.push("path="+o),lt.isString(r)&&s.push("domain="+r),!0===i&&s.push("secure"),document.cookie=s.join("; ")},read(t){const e=document.cookie.match(RegExp("(^|;\\s*)("+t+")=([^;]*)"));return e?decodeURIComponent(e[3]):null},remove(t){this.write(t,"",Date.now()-864e5)}}:{write(){},read:()=>null,remove(){}};function Zt(t,e,n){return!t||/^([a-z][a-z\d+\-.]*:)?\/\//i.test(e)&&0!=n?e:function(t,e){return e?t.replace(/\/?\/$/,"")+"/"+e.replace(/^\/+/,""):t}(t,e)}const Yt=t=>t instanceof qt?{...t}:t;function Qt(t,e){e=e||{};const n={};function o(t,e,n,o){return lt.isPlainObject(t)&<.isPlainObject(e)?lt.merge.call({caseless:o},t,e):lt.isPlainObject(e)?lt.merge({},e):lt.isArray(e)?e.slice():e}function r(t,e,n,r){return lt.isUndefined(e)?lt.isUndefined(t)?void 0:o(void 0,t,0,r):o(t,e,0,r)}function i(t,e){if(!lt.isUndefined(e))return o(void 0,e)}function s(t,e){return lt.isUndefined(e)?lt.isUndefined(t)?void 0:o(void 0,t):o(void 0,e)}function a(n,r,i){return i in e?o(n,r):i in t?o(void 0,n):void 0}const c={url:i,method:i,data:i,baseURL:s,transformRequest:s,transformResponse:s,paramsSerializer:s,timeout:s,timeoutMessage:s,withCredentials:s,withXSRFToken:s,adapter:s,responseType:s,xsrfCookieName:s,xsrfHeaderName:s,onUploadProgress:s,onDownloadProgress:s,decompress:s,maxContentLength:s,maxBodyLength:s,beforeRedirect:s,transport:s,httpAgent:s,httpsAgent:s,cancelToken:s,socketPath:s,responseEncoding:s,validateStatus:a,headers:(t,e,n)=>r(Yt(t),Yt(e),0,!0)};return lt.forEach(Object.keys(Object.assign({},t,e)),(function(o){const i=c[o]||r,s=i(t[o],e[o],o);lt.isUndefined(s)&&i!==a||(n[o]=s)})),n}const te=t=>{const e=Qt({},t);let n,{data:o,withXSRFToken:r,xsrfHeaderName:i,xsrfCookieName:s,headers:a,auth:c}=e;if(e.headers=a=qt.from(a),e.url=Rt(Zt(e.baseURL,e.url,e.allowAbsoluteUrls),t.params,t.paramsSerializer),c&&a.set("Authorization","Basic "+btoa((c.username||"")+":"+(c.password?unescape(encodeURIComponent(c.password)):""))),lt.isFormData(o))if(Nt.hasStandardBrowserEnv||Nt.hasStandardBrowserWebWorkerEnv)a.setContentType(void 0);else if(!1!==(n=a.getContentType())){const[t,...e]=n?n.split(";").map((t=>t.trim())).filter(Boolean):[];a.setContentType([t||"multipart/form-data",...e].join("; "))}if(Nt.hasStandardBrowserEnv&&(r&<.isFunction(r)&&(r=r(e)),r||!1!==r&&Kt(e.url))){const t=i&&s&&Gt.read(s);t&&a.set(i,t)}return e},ee="undefined"!=typeof XMLHttpRequest&&function(t){return new Promise((function(e,n){const o=te(t);let r=o.data;const i=qt.from(o.headers).normalize();let s,a,c,l,u,{responseType:f,onUploadProgress:h,onDownloadProgress:d}=o;function p(){l&&l(),u&&u(),o.cancelToken&&o.cancelToken.unsubscribe(s),o.signal&&o.signal.removeEventListener("abort",s)}let m=new XMLHttpRequest;function w(){if(!m)return;const o=qt.from("getAllResponseHeaders"in m&&m.getAllResponseHeaders());Vt((function(t){e(t),p()}),(function(t){n(t),p()}),{data:f&&"text"!==f&&"json"!==f?m.response:m.responseText,status:m.status,statusText:m.statusText,headers:o,config:t,request:m}),m=null}m.open(o.method.toUpperCase(),o.url,!0),m.timeout=o.timeout,"onloadend"in m?m.onloadend=w:m.onreadystatechange=function(){m&&4===m.readyState&&(0!==m.status||m.responseURL&&0===m.responseURL.indexOf("file:"))&&setTimeout(w)},m.onabort=function(){m&&(n(new ut("Request aborted",ut.ECONNABORTED,t,m)),m=null)},m.onerror=function(){n(new ut("Network Error",ut.ERR_NETWORK,t,m)),m=null},m.ontimeout=function(){let e=o.timeout?"timeout of "+o.timeout+"ms exceeded":"timeout exceeded";const r=o.transitional||Ot;o.timeoutErrorMessage&&(e=o.timeoutErrorMessage),n(new ut(e,r.clarifyTimeoutError?ut.ETIMEDOUT:ut.ECONNABORTED,t,m)),m=null},void 0===r&&i.setContentType(null),"setRequestHeader"in m&<.forEach(i.toJSON(),(function(t,e){m.setRequestHeader(e,t)})),lt.isUndefined(o.withCredentials)||(m.withCredentials=!!o.withCredentials),f&&"json"!==f&&(m.responseType=o.responseType),d&&([c,u]=Xt(d,!0),m.addEventListener("progress",c)),h&&m.upload&&([a,l]=Xt(h),m.upload.addEventListener("progress",a),m.upload.addEventListener("loadend",l)),(o.cancelToken||o.signal)&&(s=e=>{m&&(n(!e||e.type?new Ht(null,t,m):e),m.abort(),m=null)},o.cancelToken&&o.cancelToken.subscribe(s),o.signal&&(o.signal.aborted?s():o.signal.addEventListener("abort",s)));const b=function(t){const e=/^([-+\w]{1,25})(:?\/\/|:)/.exec(t);return e&&e[1]||""}(o.url);b&&-1===Nt.protocols.indexOf(b)?n(new ut("Unsupported protocol "+b+":",ut.ERR_BAD_REQUEST,t)):m.send(r||null)}))},ne=(t,e)=>{const{length:n}=t=t?t.filter(Boolean):[];if(e||n){let n,o=new AbortController;const r=function(t){if(!n){n=!0,s();const e=t instanceof Error?t:this.reason;o.abort(e instanceof ut?e:new Ht(e instanceof Error?e.message:e))}};let i=e&&setTimeout((()=>{i=null,r(new ut(`timeout ${e} of ms exceeded`,ut.ETIMEDOUT))}),e);const s=()=>{t&&(i&&clearTimeout(i),i=null,t.forEach((t=>{t.unsubscribe?t.unsubscribe(r):t.removeEventListener("abort",r)})),t=null)};t.forEach((t=>t.addEventListener("abort",r)));const{signal:a}=o;return a.unsubscribe=()=>lt.asap(s),a}},oe=function*(t,e){let n=t.byteLength;if(e>n)return void(yield t);let o,r=0;for(;n>r;)o=r+e,yield t.slice(r,o),r=o},re=(t,e,n,o)=>{const r=async function*(t,e){for await(const n of async function*(t){if(t[Symbol.asyncIterator])return void(yield*t);const e=t.getReader();try{for(;;){const{done:t,value:n}=await e.read();if(t)break;yield n}}finally{await e.cancel()}}(t))yield*oe(n,e)}(t,e);let i,s=0,a=t=>{i||(i=!0,o&&o(t))};return new ReadableStream({async pull(t){try{const{done:e,value:o}=await r.next();if(e)return a(),void t.close();let i=o.byteLength;if(n){let t=s+=i;n(t)}t.enqueue(new Uint8Array(o))}catch(t){throw a(t),t}},cancel:t=>(a(t),r.return())},{highWaterMark:2})},ie="function"==typeof fetch&&"function"==typeof Request&&"function"==typeof Response,se=ie&&"function"==typeof ReadableStream,ae=ie&&("function"==typeof TextEncoder?(ce=new TextEncoder,t=>ce.encode(t)):async t=>new Uint8Array(await new Response(t).arrayBuffer()));var ce;const le=(t,...e)=>{try{return!!t(...e)}catch(t){return!1}},ue=se&&le((()=>{let t=!1;const e=new Request(Nt.origin,{body:new ReadableStream,method:"POST",get duplex(){return t=!0,"half"}}).headers.has("Content-Type");return t&&!e})),fe=se&&le((()=>lt.isReadableStream(new Response("").body))),he={stream:fe&&(t=>t.body)};var de;ie&&(de=new Response,["text","arrayBuffer","blob","formData","stream"].forEach((t=>{!he[t]&&(he[t]=lt.isFunction(de[t])?e=>e[t]():(e,n)=>{throw new ut(`Response type '${t}' is not supported`,ut.ERR_NOT_SUPPORT,n)})})));const pe={http:null,xhr:ee,fetch:ie&&(async t=>{let{url:e,method:n,data:o,signal:r,cancelToken:i,timeout:s,onDownloadProgress:a,onUploadProgress:c,responseType:l,headers:u,withCredentials:f="same-origin",fetchOptions:h}=te(t);l=l?(l+"").toLowerCase():"text";let d,p=ne([r,i&&i.toAbortSignal()],s);const m=p&&p.unsubscribe&&(()=>{p.unsubscribe()});let w;try{if(c&&ue&&"get"!==n&&"head"!==n&&0!==(w=await(async(t,e)=>lt.toFiniteNumber(t.getContentLength())??(async t=>{if(null==t)return 0;if(lt.isBlob(t))return t.size;if(lt.isSpecCompliantForm(t)){const e=new Request(Nt.origin,{method:"POST",body:t});return(await e.arrayBuffer()).byteLength}return lt.isArrayBufferView(t)||lt.isArrayBuffer(t)?t.byteLength:(lt.isURLSearchParams(t)&&(t+=""),lt.isString(t)?(await ae(t)).byteLength:void 0)})(e))(u,o))){let t,n=new Request(e,{method:"POST",body:o,duplex:"half"});if(lt.isFormData(o)&&(t=n.headers.get("content-type"))&&u.setContentType(t),n.body){const[t,e]=Jt(w,Xt(Wt(c)));o=re(n.body,65536,t,e)}}lt.isString(f)||(f=f?"include":"omit");const r="credentials"in Request.prototype;d=new Request(e,{...h,signal:p,method:n.toUpperCase(),headers:u.normalize().toJSON(),body:o,duplex:"half",credentials:r?f:void 0});let i=await fetch(d,h);const s=fe&&("stream"===l||"response"===l);if(fe&&(a||s&&m)){const t={};["status","statusText","headers"].forEach((e=>{t[e]=i[e]}));const e=lt.toFiniteNumber(i.headers.get("content-length")),[n,o]=a&&Jt(e,Xt(Wt(a),!0))||[];i=new Response(re(i.body,65536,n,(()=>{o&&o(),m&&m()})),t)}l=l||"text";let b=await he[lt.findKey(he,l)||"text"](i,t);return!s&&m&&m(),await new Promise(((e,n)=>{Vt(e,n,{data:b,headers:qt.from(i.headers),status:i.status,statusText:i.statusText,config:t,request:d})}))}catch(e){if(m&&m(),e&&"TypeError"===e.name&&/Load failed|fetch/i.test(e.message))throw Object.assign(new ut("Network Error",ut.ERR_NETWORK,t,d),{cause:e.cause||e});throw ut.from(e,e&&e.code,t,d)}})};lt.forEach(pe,((t,e)=>{if(t){try{Object.defineProperty(t,"name",{value:e})}catch(t){}Object.defineProperty(t,"adapterName",{value:e})}}));const me=t=>"- "+t,we=t=>lt.isFunction(t)||null===t||!1===t,be=t=>{t=lt.isArray(t)?t:[t];const{length:e}=t;let n,o;const r={};for(let i=0;e>i;i++){let e;if(n=t[i],o=n,!we(n)&&(o=pe[(e=n+"").toLowerCase()],void 0===o))throw new ut(`Unknown adapter '${e}'`);if(o)break;r[e||"#"+i]=o}if(!o){const t=Object.entries(r).map((([t,e])=>`adapter ${t} `+(!1===e?"is not supported by the environment":"is not available in the build")));throw new ut("There is no suitable adapter to dispatch the request "+(e?t.length>1?"since :\n"+t.map(me).join("\n"):" "+me(t[0]):"as no adapter specified"),"ERR_NOT_SUPPORT")}return o};function ye(t){if(t.cancelToken&&t.cancelToken.throwIfRequested(),t.signal&&t.signal.aborted)throw new Ht(null,t)}function ve(t){return ye(t),t.headers=qt.from(t.headers),t.data=Bt.call(t,t.transformRequest),-1!==["post","put","patch"].indexOf(t.method)&&t.headers.setContentType("application/x-www-form-urlencoded",!1),be(t.adapter||Ut.adapter)(t).then((function(e){return ye(t),e.data=Bt.call(t,t.transformResponse,e),e.headers=qt.from(e.headers),e}),(function(e){return _t(e)||(ye(t),e&&e.response&&(e.response.data=Bt.call(t,t.transformResponse,e.response),e.response.headers=qt.from(e.response.headers))),Promise.reject(e)}))}const ge={};["object","boolean","number","function","string","symbol"].forEach(((t,e)=>{ge[t]=function(n){return typeof n===t||"a"+(1>e?"n ":" ")+t}}));const xe={};ge.transitional=function(t,e,n){function o(t,e){return"[Axios v1.10.0] Transitional option '"+t+"'"+e+(n?". "+n:"")}return(n,r,i)=>{if(!1===t)throw new ut(o(r," has been removed"+(e?" in "+e:"")),ut.ERR_DEPRECATED);return e&&!xe[r]&&(xe[r]=!0),!t||t(n,r,i)}},ge.spelling=function(t){return(t,e)=>!0};const Re={assertOptions:function(t,e,n){if("object"!=typeof t)throw new ut("options must be an object",ut.ERR_BAD_OPTION_VALUE);const o=Object.keys(t);let r=o.length;for(;r-- >0;){const i=o[r],s=e[i];if(s){const e=t[i],n=void 0===e||s(e,i,t);if(!0!==n)throw new ut("option "+i+" must be "+n,ut.ERR_BAD_OPTION_VALUE)}else if(!0!==n)throw new ut("Unknown option "+i,ut.ERR_BAD_OPTION)}},validators:ge},ke=Re.validators;class Oe{constructor(t){this.defaults=t||{},this.interceptors={request:new kt,response:new kt}}async request(t,e){try{return await this.l(t,e)}catch(t){if(t instanceof Error){let e={};Error.captureStackTrace?Error.captureStackTrace(e):e=Error();const n=e.stack?e.stack.replace(/^.+\n/,""):"";try{t.stack?n&&!(t.stack+"").endsWith(n.replace(/^.+\n.+\n/,""))&&(t.stack+="\n"+n):t.stack=n}catch(t){}}throw t}}l(t,e){"string"==typeof t?(e=e||{}).url=t:e=t||{},e=Qt(this.defaults,e);const{transitional:n,paramsSerializer:o,headers:r}=e;void 0!==n&&Re.assertOptions(n,{silentJSONParsing:ke.transitional(ke.boolean),forcedJSONParsing:ke.transitional(ke.boolean),clarifyTimeoutError:ke.transitional(ke.boolean)},!1),null!=o&&(lt.isFunction(o)?e.paramsSerializer={serialize:o}:Re.assertOptions(o,{encode:ke.function,serialize:ke.function},!0)),void 0!==e.allowAbsoluteUrls||(void 0!==this.defaults.allowAbsoluteUrls?e.allowAbsoluteUrls=this.defaults.allowAbsoluteUrls:e.allowAbsoluteUrls=!0),Re.assertOptions(e,{baseUrl:ke.spelling("baseURL"),withXsrfToken:ke.spelling("withXSRFToken")},!0),e.method=(e.method||this.defaults.method||"get").toLowerCase();let i=r&<.merge(r.common,r[e.method]);r&<.forEach(["delete","get","head","post","put","patch","common"],(t=>{delete r[t]})),e.headers=qt.concat(i,r);const s=[];let a=!0;this.interceptors.request.forEach((function(t){"function"==typeof t.runWhen&&!1===t.runWhen(e)||(a=a&&t.synchronous,s.unshift(t.fulfilled,t.rejected))}));const c=[];let l;this.interceptors.response.forEach((function(t){c.push(t.fulfilled,t.rejected)}));let u,f=0;if(!a){const t=[ve.bind(this),void 0];for(t.unshift.apply(t,s),t.push.apply(t,c),u=t.length,l=Promise.resolve(e);u>f;)l=l.then(t[f++],t[f++]);return l}u=s.length;let h=e;for(f=0;u>f;){const e=s[f++],n=s[f++];try{h=e(h)}catch(t){n.call(this,t);break}}try{l=ve(h)}catch(t){return Promise.reject(t)}for(f=0,u=c.length;u>f;)l=l.then(c[f++],c[f++]);return l}getUri(t){return Rt(Zt((t=Qt(this.defaults,t)).baseURL,t.url,t.allowAbsoluteUrls),t.params,t.paramsSerializer)}}lt.forEach(["delete","get","head","options"],(function(t){Oe.prototype[t]=function(e,n){return this.request(Qt(n||{},{method:t,url:e,data:(n||{}).data}))}})),lt.forEach(["post","put","patch"],(function(t){function e(e){return function(n,o,r){return this.request(Qt(r||{},{method:t,headers:e?{"Content-Type":"multipart/form-data"}:{},url:n,data:o}))}}Oe.prototype[t]=e(),Oe.prototype[t+"Form"]=e(!0)}));const Te=Oe;class Ee{constructor(t){if("function"!=typeof t)throw new TypeError("executor must be a function.");let e;this.promise=new Promise((function(t){e=t}));const n=this;this.promise.then((t=>{if(!n.u)return;let e=n.u.length;for(;e-- >0;)n.u[e](t);n.u=null})),this.promise.then=t=>{let e;const o=new Promise((t=>{n.subscribe(t),e=t})).then(t);return o.cancel=function(){n.unsubscribe(e)},o},t((function(t,o,r){n.reason||(n.reason=new Ht(t,o,r),e(n.reason))}))}throwIfRequested(){if(this.reason)throw this.reason}subscribe(t){this.reason?t(this.reason):this.u?this.u.push(t):this.u=[t]}unsubscribe(t){if(!this.u)return;const e=this.u.indexOf(t);-1!==e&&this.u.splice(e,1)}toAbortSignal(){const t=new AbortController,e=e=>{t.abort(e)};return this.subscribe(e),t.signal.unsubscribe=()=>this.unsubscribe(e),t.signal}static source(){let t;return{token:new Ee((function(e){t=e})),cancel:t}}}const Se=Ee,Ae={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511};Object.entries(Ae).forEach((([t,e])=>{Ae[e]=t}));const je=Ae,$e=function t(e){const n=new Te(e),o=g(Te.prototype.request,n);return lt.extend(o,Te.prototype,n,{allOwnKeys:!0}),lt.extend(o,n,null,{allOwnKeys:!0}),o.create=function(n){return t(Qt(e,n))},o}(Ut);$e.Axios=Te,$e.CanceledError=Ht,$e.CancelToken=Se,$e.isCancel=_t,$e.VERSION="1.10.0",$e.toFormData=bt,$e.AxiosError=ut,$e.Cancel=$e.CanceledError,$e.all=function(t){return Promise.all(t)},$e.spread=function(t){return function(e){return t.apply(null,e)}},$e.isAxiosError=function(t){return lt.isObject(t)&&!0===t.isAxiosError},$e.mergeConfig=Qt,$e.AxiosHeaders=qt,$e.formToJSON=t=>Pt(lt.isHTMLForm(t)?new FormData(t):t),$e.getAdapter=be,$e.HttpStatusCode=je,$e.default=$e;const Ne=$e,{Axios:Pe,AxiosError:Ce,CanceledError:Ue,isCancel:Fe,CancelToken:De,VERSION:Le,all:Ie,Cancel:ze,isAxiosError:Me,spread:qe,toFormData:Be,AxiosHeaders:_e,HttpStatusCode:He,formToJSON:Ve,getAdapter:Xe,mergeConfig:Je}=Ne,We=new class{constructor(){this.scopeAttribute="",this.scopeBody="",this.scopedKeyframes=new Map}parse(t,e){return this.scopeAttribute=`[vrefof="${e}"]`,this.scopeBody=`[vref="${e}"]`,this.scopedKeyframes.clear(),this.scopeSuffix=e.replace(/[^a-zA-Z0-9]/g,""),t=this.removeComments(t),this.collectKeyframes(t),this.parseRules(t)}collectKeyframes(t){const e=/@keyframes\s+([^\s{]+)/gi;let n;for(;null!==(n=e.exec(t));){const t=n[1],e=t+"-"+this.scopeSuffix;this.scopedKeyframes.set(t,e)}}removeComments(t){return t.replace(/\/\*[\s\S]*?\*\//g,"")}parseRules(t){let e="",n=0;for(;n=t.length)break;if("@"===t[n]){const o=this.parseAtRule(t,n);e+=o.content,n=o.endIndex}else{const o=this.parseNormalRule(t,n);e+=o.content,n=o.endIndex}}return e}parseAtRule(t,e){let n=e,o="";for(;n=t.length)return{content:o,endIndex:n};const r=o.toLowerCase().trim();if(r.startsWith("@keyframes"))return this.parseKeyframes(t,e);if(r.startsWith("@media"))return this.parseMedia(t,e);if(r.startsWith("@supports"))return this.parseSupports(t,e);{const e=this.findMatchingBrace(t,n);return{content:o+e.content,endIndex:e.endIndex}}}parseKeyframes(t,e){let n=e,o="";for(;n=t.length)return{content:o,endIndex:n};const r=this.findMatchingBrace(t,n),i=r.content,s=this.extractKeyframeName(o),a=this.scopedKeyframes.get(s);return a&&(o=o.replace(s,a)),o+=i,{content:o,endIndex:r.endIndex}}extractKeyframeName(t){const e=t.match(/@keyframes\s+([^\s{]+)/i);return e?e[1]:""}parseMedia(t,e){let n=e,o="";for(;n=t.length)return{content:o,endIndex:n};o+="{",n++;let r=1,i="";for(;n0;){if("{"===t[n])r++;else if("}"===t[n]&&(r--,0===r))break;i+=t[n],n++}return o+=this.parseRules(i),n=t.length)return{content:o,endIndex:n};const r=this.addScopeToSelector(o.trim()),i=this.findMatchingBrace(t,n);return{content:r+this.processRuleContent(i.content),endIndex:i.endIndex}}processRuleContent(t){let e=t;return e=e.replace(/animation\s*:\s*([^;]+);/gi,((t,e)=>`animation: ${this.processAnimationValue(e)};`)),e=e.replace(/animation-name\s*:\s*([^;]+);/gi,((t,e)=>`animation-name: ${this.processAnimationNames(e)};`)),e}processAnimationValue(t){return t.split(",").map((t=>t.trim())).map((t=>{const e=t.split(/\s+/);for(let n=0;n{const e=t.trim();return this.scopedKeyframes.get(e)||e})).join(", ")}addScopeToSelector(t){return t.trim()?t.split(",").map((t=>t.trim())).map((t=>this.addScopeToSingleSelector(t))).join(", "):t}addScopeToSingleSelector(t){if(!t.trim())return t;if(t.includes("::")){const e=t.split("::"),n=e[0],o="::"+e.slice(1).join("::");return this.addScopeToSelectorPart(n)+o}if(t.includes(":")&&!t.includes("::")){const e=t.match(/^([^:]+)(:.+)$/);if(e){const t=e[1],n=e[2];return this.addScopeToSelectorPart(t)+n}}return"*"===t||t.startsWith("@")?t:this.addScopeToSelectorPart(t)}addScopeToSelectorPart(t){const e=/(\s*[>+~]\s*|\s+)/;if(e.test(t)){const n=t.split(e);if(/^body(?:$|[:\[ ])/.test(n[0]))return n[0]=this.scopeBody+n[0].slice(4),n.join("");if(/^:root(?:$|[:\[ ])/.test(n[0]))return n[0]=this.scopeBody+n[0].slice(5),n.join("");for(let t=n.length-1;t>=0;t--)if(n[t].trim()&&!e.test(n[t])){let e=n[t].trim();n[t]=/^body(?:$|[:\[ ])/.test(e)?this.scopeBody+e.slice(4):/^:root(?:$:[$:\[ ])/.test(e)?this.scopeBody+e.slice(5):n[t].trim()+this.scopeAttribute;break}return n.join("")}let n=(t=t.trim()).trim();return/^body(?:$|[:\[ ])/.test(n)?this.scopeBody+n.slice(4):/^:root(?:$:[$:\[ ])/.test(n)?this.scopeBody+n.slice(5):n+this.scopeAttribute}findMatchingBrace(t,e){let n=e,o="",r=0;for(;n{this.removeMessage(s),i&&i()},s.appendChild(t)}return this.container.appendChild(s),setTimeout((()=>{s.classList.add("show")}),10),o>0&&setTimeout((()=>{this.removeMessage(s),i&&i()}),o),s}removeMessage(t){t&&t.parentNode&&(t.classList.remove("show"),setTimeout((()=>{t.parentNode&&t.parentNode.removeChild(t)}),300))}success(t,e={}){return this.createMessage("success",t,e)}warning(t,e={}){return this.createMessage("warning",t,e)}error(t,e={}){return this.createMessage("error",t,e)}info(t,e={}){return this.createMessage("info",t,e)}h(t,e={}){return new Promise(((n,o)=>{const{title:r="\u63d0\u793a",type:i="confirm",inputValue:s="",confirmText:a="\u786e\u5b9a",cancelText:c="\u53d6\u6d88",onConfirm:l=null,onCancel:u=()=>{n("")}}=e,f=document.createElement("div");f.className="prompt-overlay";const h=document.createElement("div");h.className="prompt-dialog";const d=document.createElement("div");d.className="prompt-header";const p=document.createElement("h3");p.className="prompt-title",p.textContent=r;const m=document.createElement("button");m.className="prompt-close",m.innerHTML="×",d.appendChild(p),d.appendChild(m);const w=document.createElement("div");w.className="prompt-body";const b=document.createElement("div");b.className="prompt-content",b.textContent=t,w.appendChild(b);let y=null;"input"===i&&(y=document.createElement("input"),y.className="prompt-input",y.type="text",y.value=s,w.appendChild(y));const v=document.createElement("div");v.className="prompt-footer";const g=document.createElement("button");g.className="prompt-btn prompt-btn-cancel",g.textContent=c;const x=document.createElement("button");x.className="prompt-btn prompt-btn-confirm",x.textContent=a,v.appendChild(g),v.appendChild(x),h.appendChild(d),h.appendChild(w),h.appendChild(v),f.appendChild(h),document.body.appendChild(f),setTimeout((()=>{f.classList.add("show")}),10),y&&setTimeout((()=>{y.focus()}),300);const R=(t=null)=>(f.classList.remove("show"),setTimeout((()=>{f.parentNode&&f.parentNode.removeChild(f)}),300),t);m.onclick=()=>{R(),u?u():o(Error("cancelled"))},g.onclick=()=>{R(),u?u():o(Error("cancelled"))},x.onclick=()=>{const t=!y||y.value;R(),n(t),l&&l(t)};const k=t=>{"Escape"===t.key&&(R(),u?u():o(Error("cancelled")),document.removeEventListener("keydown",k))};document.addEventListener("keydown",k),f.onclick=t=>{t.target===f&&(R(),u?u():o(Error("cancelled")))}}))}confirm(t,e={}){return this.h(t,{...e,type:"confirm"})}prompt(t,e,n={}){return this.h(t,{...n,type:"input",inputValue:e})}};var Ge={},Ze={};const Ye={};function Qe(t,e){Array.from(t.childNodes).forEach((t=>{1===t.nodeType&&(t.setAttribute("vrefof",e),Qe(t,e))}))}async function tn(t,e,n,o){void 0===n&&(n="#"+function(){let t=(new Date).getTime().toString(36);t.length>4&&(t=t.substring(t.length-4));let e="";for(let n=0;4>n;n++)e+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".charAt(Math.floor(52*Math.random()));return e+t.padStart(4,"0")}()),n.endsWith(".html")&&(n=n.slice(0,-5));let r=(new DOMParser).parseFromString(t,"text/html");if(r.body.hasAttribute("root")&&!o)throw Error("HTTP error! status: 404");let i={url:n,heads:[],body:document.createElement("div"),setup:void 0,scripts:[],styles:"",txt:t,env:e,tmp:r,customAttrs:{}};if(i.heads=Array.from(r.querySelector("head")?.children),n&&(r.querySelectorAll("style").forEach((t=>{null===t.getAttribute("unscoped")?i.styles+=We.parse(t.innerHTML,n):i.styles+=t.innerHTML})),i.styles)){const t=document.createElement("style");t.innerHTML=i.styles,t.setAttribute("vref",n),document.head.appendChild(t)}return i.body.append(...r.querySelector("body").childNodes),i.body.querySelectorAll("script").forEach((t=>{""!=t.innerHTML.trim()?(t.hasAttribute("setup")?i.setup=t:t.hasAttribute("no-vhtml")||i.scripts.push(t),t.remove()):t.remove()})),Array.from(r.body.attributes).forEach((t=>{/^[a-zA-Z]/.test(t.name)?i.body.setAttribute(t.name,t.value):i.customAttrs[t.name]=t.value})),i.body.setAttribute("vref",n),Qe(i.body,n),o||await async function(t,e){for(let n of t.heads){let o=n.nodeName.toLowerCase();"link"===o?nn(n,e):"script"===o?await en(n,e):"title"===o&&(t.title=n.innerText)}}(i,e),i}function en(t,e){let n=t.getAttribute("src"),o=t.getAttribute("key"),r=e?.root;if(r&&n.startsWith("/")&&(n=r+n),n.startsWith("@")&&(n=n.slice(1)),n&&document.querySelector(`script[src="${n}"]`))return;if(o&&document.querySelector(`script[key="${o}"]`))return;let i=document.createElement("script");return i.src=n,i.key=o,i.type=t.getAttribute("type")||"text/javascript",new Promise(((t,e)=>{i.onload=()=>{t(i)},i.onerror=()=>e(Error("Failed to load script "+n)),document.head.appendChild(i)}))}async function nn(t,e){let n=t.getAttribute("href"),o=t.getAttribute("key"),r=e?.root;r&&n.startsWith("/")&&(n=r+n),n.startsWith("@")&&(n=n.slice(1)),n&&document.querySelector(`link[href="${n}"]`)||o&&document.querySelector(`link[key="${o}"]`)||(t.setAttribute("href",n),document.head.append(t))}const on={FetchUI:async function(t,e,n){t&&"/"!==t||(t="/root.html"),t.startsWith("http")||t.startsWith("@")||t.startsWith("/")||(t="/"+t);let o=e?.root;if(o&&t.startsWith("/")&&(t=o+t),t.startsWith("@")&&(t=t.slice(1)),Ge[t])return Promise.resolve(Ge[t]);if(Ze[t])return Ze[t];let r={};const i=fetch(t+"?random="+Math.random()).then((async e=>{if(!e.ok)throw Error("HTTP error! status: "+e.status);for(const[t,i]of e.headers.entries())t.startsWith("vhtml-")&&(r[t.slice(5)]=i);let n=r.root||"";t.startsWith("http")&&(n=new URL(t).origin+n,r.root=n);let o=await async function(t,e){if(!Ye[t=t||""]){let n=t.startsWith("http")?t:window.location.origin+t;Ye[t]=Object.assign({},e,{root:t,$G:y.Wrap({}),$bus:new v,$axios:Ne.create({baseURL:n}),$message:Ke,$router:null,$emit:null}),t===$vhtml.root||null===$vhtml.root?Ye[t].$router=$vhtml.$router:Ye[t].$router={addRoutes:()=>{},beforeEnter:()=>{}};try{await(await import(n+"/env.js")).default(Ye[t])}catch(g){}}return Ye[t]}(n,r);return Object.assign(r,o),e.text()})).then((e=>tn(e,r,t,n))).then((e=>(Ge[t]=e,e))).catch((e=>{e.message;let n=document.createElement("div");n.style.cssText="\n backgound:#aaa;\n height:100%;\n width: 100%;\n display:grid;\n place-items: center;\n",n.innerHTML=`\n
\n
404
\n

${t}

\n
\n`;let o={heads:[],body:n,setup:"",scripts:[],styles:"",txt:"",tmp:"",env:r,err:e};return Ge[t]=o,o})).finally((()=>{delete Ze[t]}));return Ze[t]=i,i},FetchFile:async function(t){return fetch(t).then((t=>{if(!t.ok)throw Error("HTTP error! status: "+t.status);return t.text()}))},LoadScript:en,LoadLink:nn,ParseUI:tn};function rn(t,e){let n,o;if(t.startsWith("http://")||t.startsWith("https://")){if(n=new URL(t),n.origin!==window.location.origin)return null;n.pathname.startsWith(e)&&(o=n.pathname.slice(e.length))}else n=new URL(t,window.location.href),o=n.pathname;const r={};return n.searchParams.forEach(((t,e)=>{r[e]=t})),{path:o,query:r,hash:n.hash}}class sn{constructor(t,e){this.originalPath=t,this.name=e,this.keys=[],this.regexp=this.pathToRegexp(t)}pathToRegexp(t){let e=t.replace(/:([^(/]+)/g,((t,e)=>(this.keys.push(e),`(?<${e}>[^/]+)`)));return e=e.replace(/\*(\w+)/g,((t,e)=>(this.keys.push(e),`(?<${e}>.*)`))),e=e.replace(/\*/g,".*"),RegExp(`^${e}$`)}match(t){let e;if("string"==typeof t)e=t;else{if(!t||"object"!=typeof t)return null;if(!t.path)return t.name&&t.name===this.name?{path:this.originalPath,params:t.params||{},matched:this.originalPath}:null;e=t.path}const n=this.regexp.exec(e);if(!n)return null;const o={};return this.keys.forEach((t=>{n.groups?.[t]&&(o[t]=n.groups[t])})),{path:this.originalPath,params:o,matched:n[0]}}}const an=new Map;class cn{constructor(t,e,n){this.vhtml=t,this.node=e,this.layoutDom=void 0,this.matchedRoute=n,this.htmlPath=this.resolveHtmlPath(n)}resolveHtmlPath(t){let e=t.route.component||t.route.path;return"function"==typeof e&&(e=e(t.path)),Object.entries(t.params).forEach((([t,n])=>{e=e.replace(":"+t,n)})),e.startsWith("/")||(e="/"+e),e.endsWith("/")&&(e=e.slice(0,-1)),e.endsWith(".html")||(e+=".html"),e}async mount(t,e,n){const o=await on.FetchUI(this.htmlPath,t);if(o.err){let n=document.createElement("div");return Object.assign(n.style,{width:"100%",height:"100%"}),n.append(...e),this.node.innerHTML="",this.node.append(n),void this.vhtml.parseRef(this.htmlPath,n,{},t,null,!0)}this.title=o.title||"";const r={},i=document.createElement("div");if(i.setAttribute("vsrc",this.htmlPath),r[""]=[i],this.slots=r,!n)return this.node.innerHTML="",this.node.append(i),void this.vhtml.parseRef(this.htmlPath,i,{},t,null);let s=an.get(n);if(s)this.layoutDom=s,this.activate();else{let e=n;e.startsWith("/")||(e="/"+n),e.endsWith(".html")||(e+=".html"),e.startsWith("/layout")||(e="/layout"+e);const o=await on.FetchUI(e,t);if(o.err)return this.node.innerHTML="",this.node.append(i),void this.vhtml.parseRef(this.htmlPath,i,{},t,null);s=o.body.cloneNode(!0),an.set(n,s),i.$refData=y.Wrap({}),s.$refSlots=y.Wrap({...r}),this.node.innerHTML="",this.node.append(s),this.layoutDom=s,this.vhtml.parseRef("/layout/"+n,s,{},t,null,!0)}}activate(){this.title&&(document.title=this.title);const t=this.layoutDom;if(t)t.querySelectorAll("vslot").forEach((e=>{e.closest("[vref]")===t&&this.slots[e.getAttribute("name")||""]&&(e.innerHTML="")})),Object.keys(t.$refSlots).forEach((e=>{delete t.$refSlots[e]})),Object.assign(t.$refSlots,this.slots),t.isConnected||(this.node.innerHTML=""),this.node.append(t);else{this.node.innerHTML="";const t=this.slots[""];t instanceof Array?this.node.append(...t):this.node.append(t)}}}const ln=new class{#t=[];#e=[];#n=null;#o="";#r=[];#i=new Map;#s=null;#a=null;#c=[];#l=!1;#u=null;#f=new Map;constructor(){this.init()}get routes(){return this.#t.slice()}get history(){return this.#e.slice()}get current(){return this.#n}get query(){return this.#n?.query||{}}get params(){return this.#n?.params||{}}get root(){return this.#o}onChange(t){this.#r.push(t)}addRoute(t){if(!t.path)throw Error("Route must have a path");"/"!=t.path&&t.path.endsWith("/")&&(t.path=t.path.slice(0,-1));const e={path:t.path,component:t.component,name:t.name,meta:t.meta||{},children:t.children||[],matcher:new sn(t.path,t.name),description:t.description||"",layout:t.layout||""};this.#t.push(e),t.name&&this.#f.set(t.name,e),t.children?.length>0&&t.children.forEach((n=>{const o=t.path+(n.path.startsWith("/")?n.path:"/"+n.path),r=n.layout||t.layout||"",i={...t.meta,...n.meta};this.addRoute({...n,path:o,parent:e,layout:r,meta:i})}))}addRoutes(t){t.forEach((t=>this.addRoute(t)))}#h(t,e){this.#r.forEach((n=>{if("function"==typeof n)try{n(t,e)}catch(o){}}))}#d(t){const e=this.#n;this.#n={path:t.path,fullPath:t.fullPath,params:t.params||{},query:t.query||{},hash:new URL(t.fullPath,window.location.origin).hash,meta:t.route?.meta||{},description:t.route?.description||"",layout:t.route?.layout||"",name:t.route?.name,matched:t.route?[t.route]:[]},this.#e.push(this.#n),this.#o&&!t.fullPath.startsWith("http")?history.pushState({},"",this.#o+t.fullPath):history.pushState({},"",t.fullPath),this.#h(this.#n,e)}matchRoute(t){const e=this.normalizeRouteTarget(t);if(!e)return null;const{path:n,query:o,params:r,name:i}=e;if(i){const t=this.#f.get(i);if(!t)return null;let e=t.path;Object.entries(r).forEach((([t,n])=>{e=e.replace(":"+t,n)}));const n=t.matcher.match(e);return n?{route:t,params:{...n.params,...r},matched:n.matched,path:e,query:o,name:i}:null}for(const s of this.#t){const t=s.matcher.match(n);if(t&&s.component)return{route:s,params:{...t.params,...r},matched:t.matched,description:s.description,layout:s.layout,path:n,query:o,name:s.name}}return null}normalizeRouteTarget(t){let e,n,o={},r={},i="";if("string"==typeof t){const n=rn(t,this.#o);if(!n)return null;e=n.path,o={...n.query},i=n.hash}else{if(!t||"object"!=typeof t)return null;if(t.path){const n=rn(t.path,this.#o);if(!n)return null;e=n.path,o={...n.query,...t.query||{}},i=t.hash||n.hash,r=t.params||{}}else{if(!t.name)return null;n=t.name,o=t.query||{},r=t.params||{},i=t.hash||""}}return e&&!e.startsWith("/")&&(e="/"+e),this.#o&&(e=e.startsWith(this.#o)?e.slice(this.#o.length):e),e.startsWith("/")||(e="/"+e),"/"!=e&&e.endsWith("/")&&(e=e.slice(0,-1)),{path:e,query:o,params:r,hash:i,name:n}}matchTo(t){const e=this.matchRoute(t);if(!e)return null;const{route:n,params:o,query:r,path:i,name:s}=e;let a="";r&&Object.keys(r).length>0&&(a="?"+Object.entries(r).map((([t,e])=>`${encodeURIComponent(t)}=${encodeURIComponent(e)}`)).join("&"));const c=(i||e.path)+a;return{route:n,params:o,query:r,name:s||n.name,path:i||e.path,fullPath:c,matched:[n]}}buildUrl(t,e={}){const n=new URL(t,window.location.origin);return Object.entries(e).forEach((([t,e])=>{n.searchParams.append(t,e)})),n}resolveRoutePath(t,e={}){let n=t.component||t.path;return Object.entries(e).forEach((([t,e])=>{n=n.replace(":"+t,e)})),"/"!==n&&""!==n||(n="/index"),n.startsWith("/")||(n="/"+n),n.endsWith(".html")&&(n=n.slice(0,-5)),n.endsWith("/")&&(n=n.slice(0,-1)),n}async#p(t){if(!t)return;const{route:e,params:n,query:o}=t,r={path:t.path,fullPath:t.fullPath,params:n,query:o,hash:new URL(t.fullPath,window.location.origin).hash,meta:e.meta,description:e.description,layout:e.layout,name:e.name,matched:[e]};if(this.beforeEnter)try{let t=!0;if(!1===await this.beforeEnter(r,this.#n,(e=>{e&&(t=!1,this.push(e))}))||!t)return}catch(a){return}const i=t.fullPath;let s=this.#i.get(i);this.#d(t),s?s.activate():(s=new cn(this.#u,this.#s,t),await s.mount(this.#a,this.#c,r.layout),this.#i.set(i,s))}async push(t){const e=this.matchTo(t);e?await this.#p(e):"string"==typeof t||t.path||t.name}replace(t){this.push(t),this.#e.length>1&&this.#e.splice(-2,1)}go(t){history.go(t)}back(){history.back()}forward(){history.forward()}init(){this.#l||(this.#l=!0,document.body.addEventListener("click",(t=>{const e=t.target.closest("a");if(!e)return;const n=e.getAttribute("href");!n||n.startsWith("http")||n.startsWith("#")||(t.preventDefault(),e.hasAttribute("reload")?window.location.href=n:this.push(n))}),!0),window.addEventListener("popstate",(()=>{this.push(window.location.href)})))}ParseVrouter(t,e,n){this.#s=e,this.#a=n,this.#o=n.root||"",this.#c=Array.from(e.childNodes),this.#u=t,this.push(window.location.href)}},un={$router:ln},fn=[];document.addEventListener("click",(t=>{fn.forEach((e=>{e?.dom instanceof Element&&"function"==typeof e?.callback&&(e.dom.contains(t.target)||e.callback(t))}))}));const hn={CamelToKebabCase:function(t){return 0===t.length?"":t.charAt(0).toLowerCase()+t.slice(1).replace(/([A-Z])/g,(function(t,e){return"-"+e.toLowerCase()}))},EventsList:["load","unload","beforeunload","resize","scroll","submit","reset","input","change","focus","blur","keydown","keypress","keyup","click","dblclick","contextmenu","mousedown","mouseup","mousemove","mouseover","mouseout","mouseenter","mouseleave","touchstart","touchmove","touchend","touchcancel","drag","dragstart","dragend","dragover","dragenter","dragleave","drop","copy","cut","paste","animationstart","animationend","animationiteration","transitionend","abort","error","loadstart","progress","play","pause","ended","volumechange","timeupdate","loadeddata","waiting","playing","online","offline","storage","visibilitychange"],BindInputDomValue:function(t,e,n,o){const r="string"==typeof t?document.querySelector(t):t;if(r){switch(r.type||r.tagName.toLowerCase()){case"text":case"password":case"email":case"tel":case"url":case"search":case"number":case"range":case"color":case"date":case"time":case"datetime-local":case"month":case"week":case"hidden":case"textarea":o((()=>e[n]),(t=>{r.value=void 0===t?"":t})),r.addEventListener("input",(function(){e[n]=this.value}));break;case"checkbox":o((function(){r.checked=!!e[n]})),r.addEventListener("change",(function(){e[n]=this.checked}));break;case"radio":o((()=>{r.checked=r.value===e[n]})),r.addEventListener("change",(function(){this.checked&&(e[n]=this.value)}));break;case"select-one":case"select-multiple":o((()=>{let t=e[n];if(r.multiple){const e=Array.isArray(t)?t:[];for(let t=0;t{if("outer"===e){let e=fn.length;return fn.push({dom:t,callback:n}),()=>{fn[e]=null}}}},dn=async t=>navigator.clipboard&&navigator.clipboard.writeText?navigator.clipboard.writeText(t):(prompt("http\u73af\u5883\u65e0\u6cd5\u81ea\u52a8\u590d\u5236\uff0c\u8bf7\u624b\u52a8\u590d\u5236\u5185\u5bb9\u5230\u526a\u8d34\u677f:",t),new Promise((t=>{})));class pn{postMessage=(t,e)=>{};constructor(t={}){this.options={highlightColor:"#007bff",overlayColor:"rgba(0, 123, 255, 0.1)",borderWidth:"2px",zIndex:1e4,showTagName:!0,...t},this.isActive=!1,this.selectedElement=null,this.currentHoverElement=null,this.overlay=null,this.selectedOverlay=null,this.tooltip=null,this.selectedTooltip=null,this.actionPanel=null,this.originalCursor="",this.init()}init(){this.createStyles(),this.bindEvents()}createStyles(){const t=document.createElement("style");t.textContent=`\n .div-selector-overlay {\n position: fixed;\n pointer-events: none;\n border: ${this.options.borderWidth} solid ${this.options.highlightColor};\n background: ${this.options.overlayColor};\n z-index: ${this.options.zIndex};\n transition: all 0.2s ease;\n box-sizing: border-box;\n }\n \n .div-selector-selected {\n position: fixed;\n pointer-events: none;\n border: ${this.options.borderWidth} solid #28a745;\n background: rgba(40, 167, 69, 0.1);\n z-index: ${this.options.zIndex-1};\n box-sizing: border-box;\n }\n \n .div-selector-tooltip {\n position: fixed;\n background: rgba(51, 51, 51, 0.95);\n cursor:pointer;\n color: white;\n padding: 8px 12px;\n border-radius: 6px;\n font-size: 12px;\n font-family: 'Consolas', 'Monaco', 'Courier New', monospace;\n z-index: ${this.options.zIndex+1};\n user-select: none;\n box-shadow: 0 2px 8px rgba(0,0,0,0.3);\n border: 1px solid rgba(255,255,255,0.1);\n backdrop-filter: blur(4px);\n }\n \n .div-selector-tooltip.hover {\n background: rgba(0, 123, 255, 0.9);\n }\n \n .div-selector-tooltip.selected {\n background: rgba(40, 167, 69, 0.9);\n border-color: rgba(40, 167, 69, 0.3);\n }\n \n .div-selector-actions {\n position: fixed;\n background: white;\n border: 1px solid #ddd;\n border-radius: 8px;\n padding: 8px;\n z-index: ${this.options.zIndex+2};\n box-shadow: 0 4px 16px rgba(0,0,0,0.15);\n display: flex;\n gap: 6px;\n min-width: 30px;\n backdrop-filter: blur(8px);\n }\n \n .div-selector-btn {\n padding: 4px 6px;\n border: 1px solid #ddd;\n background: white;\n border-radius: 6px;\n cursor: pointer;\n font-size: 12px;\n transition: all 0.2s ease;\n text-align: left;\n white-space: nowrap;\n }\n \n .div-selector-btn:hover {\n background: #f8f9fa;\n transform: translateX(2px);\n }\n \n .div-selector-btn.danger {\n color: #dc3545;\n border-color: #dc3545;\n }\n \n .div-selector-btn.danger:hover {\n background: #dc3545;\n color: white;\n }\n \n .div-selector-btn.primary {\n background: #007bff;\n color: white;\n border-color: #007bff;\n }\n \n .div-selector-btn.primary:hover {\n background: #0056b3;\n }\n \n .div-selector-active {\n cursor: crosshair !important;\n }\n `,document.head.appendChild(t)}bindEvents(){this.handleMouseMove=this.handleMouseMove.bind(this),this.handleClick=this.handleClick.bind(this),this.handleScroll=this.handleScroll.bind(this),this.handleResize=this.handleResize.bind(this)}activate(){this.isActive||(this.isActive=!0,this.originalCursor=document.body.style.cursor,document.body.classList.add("div-selector-active"),document.addEventListener("mousemove",this.handleMouseMove),document.addEventListener("click",this.handleClick),window.addEventListener("scroll",this.handleScroll),window.addEventListener("resize",this.handleResize),this.createOverlay(),this.createTooltip())}deactivate(){this.isActive&&(this.isActive=!1,document.body.style.cursor=this.originalCursor,document.body.classList.remove("div-selector-active"),document.removeEventListener("mousemove",this.handleMouseMove),document.removeEventListener("click",this.handleClick),window.removeEventListener("scroll",this.handleScroll),window.removeEventListener("resize",this.handleResize),this.removeOverlay(),this.removeTooltip())}handleMouseMove(t){if(!this.isActive)return;const e=document.elementFromPoint(t.clientX,t.clientY);if(!e)return;if(this.isPluginElement(e))return;const n="DIV"===e.tagName?e:e.closest("div,[vref]");n&&!this.isPluginElement(n)&&this.selectedElement!==n&&(this.currentHoverElement=n,this.highlightElement(n),this.updateHoverTooltip(n))}handleClick(t){if(!this.isActive)return;const e=document.elementFromPoint(t.clientX,t.clientY);if(!e)return;if(this.isPluginElement(e))return;t.preventDefault(),t.stopPropagation();const n="DIV"===e.tagName?e:e.closest("div");n&&!this.isPluginElement(n)&&(this.selectElement(n),this.deactivate())}handleScroll(){this.selectedElement&&(this.updateSelectedOverlay(),this.updateSelectedTooltip(),this.updateActionPanelPosition()),this.currentHoverElement&&!this.selectedElement&&(this.highlightElement(this.currentHoverElement),this.updateHoverTooltip(this.currentHoverElement))}handleResize(){this.selectedElement&&(this.updateSelectedOverlay(),this.updateSelectedTooltip(),this.updateActionPanelPosition())}isPluginElement(t){return t.closest(".div-selector-overlay, .div-selector-selected, .div-selector-tooltip, .div-selector-actions")}createOverlay(){this.overlay=document.createElement("div"),this.overlay.className="div-selector-overlay",this.overlay.style.display="none",document.body.appendChild(this.overlay)}createSelectedOverlay(){this.selectedOverlay=document.createElement("div"),this.selectedOverlay.className="div-selector-selected",document.body.appendChild(this.selectedOverlay)}createTooltip(){this.tooltip=document.createElement("div"),this.tooltip.className="div-selector-tooltip hover",this.tooltip.style.display="none",document.body.appendChild(this.tooltip)}createSelectedTooltip(){this.selectedTooltip=document.createElement("div"),this.selectedTooltip.className="div-selector-tooltip selected",document.body.appendChild(this.selectedTooltip)}highlightElement(t){if(!this.overlay)return;const e=t.getBoundingClientRect();this.overlay.style.display="block",this.overlay.style.left=e.left+"px",this.overlay.style.top=e.top+"px",this.overlay.style.width=e.width+"px",this.overlay.style.height=e.height+"px"}updateHoverTooltip(t){if(!this.tooltip)return;const e=this.getElementInfo(t),n=t.getBoundingClientRect();this.tooltip.textContent=e,this.tooltip.style.display="block";let o=n.left-8,r=n.top-this.tooltip.offsetHeight-8;0>o&&(o=8),0>r&&(r=n.top+8),this.tooltip.style.left=o+"px",this.tooltip.style.top=r+"px"}selectElement(t){this.clearSelection(),this.selectedElement=t,this.createSelectedOverlay(),this.createSelectedTooltip(),this.updateSelectedOverlay(),this.updateSelectedTooltip(),this.overlay&&(this.overlay.style.display="none"),this.tooltip&&(this.tooltip.style.display="none"),this.showActionPanel()}updateSelectedOverlay(){if(!this.selectedOverlay||!this.selectedElement)return;const t=this.selectedElement.getBoundingClientRect();this.selectedOverlay.style.left=t.left+"px",this.selectedOverlay.style.top=t.top+"px",this.selectedOverlay.style.width=t.width+"px",this.selectedOverlay.style.height=t.height+"px"}updateSelectedTooltip(){if(!this.selectedTooltip||!this.selectedElement)return;const t=this.getElementInfo(this.selectedElement);let e=this.getFilePath(this.selectedElement);const n=this.selectedElement.getBoundingClientRect();this.selectedTooltip.addEventListener("click",(t=>{e&&this.postMessage("fs-open",e),t.preventDefault(),t.stopPropagation()})),this.selectedTooltip.textContent="\u2713 "+t;let o=n.left-8,r=n.top-this.selectedTooltip.offsetHeight-8;0>o&&(o=8),0>r&&(r=n.top+8),this.selectedTooltip.style.left=o+"px",this.selectedTooltip.style.top=r+"px"}showActionPanel(){this.removeActionPanel();const t=this.selectedElement.getBoundingClientRect();this.actionPanel=document.createElement("div"),this.actionPanel.className="div-selector-actions";let e=t.right-180,n=t.top+6;e+180>window.innerWidth&&(e=t.left-180-8),0>e&&(e=8),n+40>window.innerHeight&&(n=window.innerHeight-40-8),0>n&&(n=8),this.actionPanel.style.left=e+"px",this.actionPanel.style.top=n+"px",[{text:"\ud83d\udccb",action:()=>this.copySelector(this.selectedElement)},{text:"x",action:()=>this.clearSelection()}].forEach((t=>{const e=document.createElement("button");e.className="div-selector-btn "+(t.class||""),e.textContent=t.text,e.onclick=t.action,this.actionPanel.appendChild(e)})),document.body.appendChild(this.actionPanel)}updateActionPanelPosition(){if(!this.actionPanel||!this.selectedElement)return;const t=this.selectedElement.getBoundingClientRect(),e=this.actionPanel.offsetWidth,n=this.actionPanel.offsetHeight;let o=t.right-e+8,r=t.top-8;o+e>window.innerWidth&&(o=t.left-e-8),0>o&&(o=8),r+n>window.innerHeight&&(r=window.innerHeight-n-8),0>r&&(r=8),this.actionPanel.style.left=o+"px",this.actionPanel.style.top=r+"px"}clearSelection(){this.selectedElement=null,this.selectedOverlay&&(this.selectedOverlay.remove(),this.selectedOverlay=null),this.selectedTooltip&&(this.selectedTooltip.remove(),this.selectedTooltip=null),this.removeActionPanel()}getElementInfo(t){const e=t.getBoundingClientRect();let n=t.getAttribute("vref");return n||(n=t.closest("[vref]").getAttribute("vref"),n+="."+t.tagName.toLowerCase()),`${n} (${Math.round(e.width)}\xd7${Math.round(e.height)})`}getFilePath(t){let e=t.getAttribute("vref");return e||(e=t.closest("[vref]").getAttribute("vref")),e&&(e="/ui"+e+".html"),e}copySelector(t){let e=this.getFilePath(t);dn(e).then((()=>{this.showNotification("\ud83d\udccb CSS\u9009\u62e9\u5668\u5df2\u590d\u5236\u5230\u526a\u8d34\u677f")}))}copyXPath(t){const e=this.generateXPath(t);dn(e).then((()=>{this.showNotification("\ud83d\udd0d XPath\u5df2\u590d\u5236\u5230\u526a\u8d34\u677f")}))}viewStyles(t){const e=window.getComputedStyle(t);let n="\ud83d\udcca \u91cd\u8981\u6837\u5f0f\u5c5e\u6027:\n\n";["display","position","width","height","margin","padding","background-color","color","font-size","border","z-index","opacity"].forEach((t=>{n+=`${t}: ${e.getPropertyValue(t)}\n`})),alert(n)}showNotification(t){const e=document.createElement("div");e.style.cssText=`\n position: fixed;\n top: 20px;\n right: 20px;\n background: linear-gradient(135deg, #28a745, #20c997);\n color: white;\n padding: 12px 18px;\n border-radius: 8px;\n z-index: ${this.options.zIndex+10};\n font-size: 14px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.2);\n transform: translateX(100%);\n transition: transform 0.3s ease;\n `,e.textContent=t,document.body.appendChild(e),setTimeout((()=>{e.style.transform="translateX(0)"}),100),setTimeout((()=>{e.style.transform="translateX(100%)",setTimeout((()=>{e.remove()}),300)}),2500)}generateXPath(t){if(t.id)return`//*[@id="${t.id}"]`;const e=[];for(;t&&t.nodeType===Node.ELEMENT_NODE;){let n=0,o=!1,r=!1;for(let e=t.previousSibling;e;e=e.previousSibling)e.nodeType===Node.ELEMENT_NODE&&e.nodeName===t.nodeName&&(r=!0,n++);for(let e=t.nextSibling;e&&!o;e=e.nextSibling)e.nodeType===Node.ELEMENT_NODE&&e.nodeName===t.nodeName&&(o=!0);const i=t.nodeName.toLowerCase(),s=r||o?`[${n+1}]`:"";if(e.unshift(i+s),(t=t.parentNode)===document.body)break}return e.length?"/"+e.join("/"):null}removeOverlay(){this.overlay&&(this.overlay.remove(),this.overlay=null)}removeTooltip(){this.tooltip&&(this.tooltip.remove(),this.tooltip=null)}removeActionPanel(){this.actionPanel&&(this.actionPanel.remove(),this.actionPanel=null)}}let mn=!1,wn=null;const bn=(t,e)=>{mn&&("string"!=typeof e&&"number"!=typeof e||(e={value:e}),window.parent.postMessage(Object.assign({type:t,from:"vdev"},e),"*"))};!async function(){const t=document.createElement("style");t.innerHTML="\n [vref] {\n display: block;\n }\n [vparsing] {\n display: none;\n -webkit-text-fill-color: transparent;\n }\n vslot, vrouter {\n display: block;\n }\n",document.head.firstChild?document.head.insertBefore(t,document.head.firstChild):document.head.appendChild(t);const e=[],n=t=>{if(!t.isConnected)return;let n=t.getAttribute("vdelay");if(n){let o=e[n];o&&o(t)}};function o(t,e){const n=Function("sandbox",t=`with (sandbox) { ${t} }`);let o={data:null,key:null};const r=t=>new Proxy(t,{has:(t,e)=>!0,get(t,e,n){if(e===Symbol.unscopables)return;let i=Reflect.get(t,e,n);return o.data=t,o.key=e,"object"==typeof i&&i?r(i):i},set:(t,e,n,o)=>!1});return n(r(e)),o}new MutationObserver((function(t,e){t.forEach((function(t){for(let e of t.addedNodes)1===e.nodeType&&(n(e),e.querySelectorAll("*[vdelay]").forEach(n))}))})).observe(document.body,{attributes:!1,childList:!0,subtree:!0,characterData:!1});const r=/{{|}}/g,i=/^(\s*(\w+)\s+in\s+|\((\w+),\s*(\w+)\)\s+in\s+)([\w\?\$\.\[\]\(\)'"]+)$/;window.$vhtml||(window.$vhtml=new class{app=null;root=null;vget=on;vproxy=y;t=!0;$router=un.$router;constructor(t){"string"==typeof t?this.app=document.getElementById(t):t instanceof HTMLElement?this.app=t:this.app=document.body,this.app&&(async()=>{let t=await on.FetchUI(window.location.pathname,{},!0);this.root=t.env?.root||"",t.env?.vdev&&window.self!==window.top&&(mn||(mn=!0,wn=new pn,bn("iframe-loaded"),wn.postMessage=bn,window.addEventListener("keyup",(t=>{"Escape"===t.key&&bn("key-esc")})),setTimeout((()=>{window.$vhtml&&window.$vhtml.$router&&$vhtml.$router.onChange((t=>{bn("url-change",t.fullPath)}))}),100),window.addEventListener("message",(t=>{const e=t.data;if("vhtml"==e.from)switch(e.type){case"reload":window.location.reload();break;case"magic":wn&&wn.isActive?wn.deactivate():wn&&wn.activate()}})))),this.parseRef("root",this.app,{},t.env||{},t,!0)})()}async parseDom(t,e={},n){if(n instanceof HTMLElement)throw Error("env error");let o=t.nodeName.toLowerCase();if(3===t.nodeType)return void this.parseTextNode(t,e,n);if(8===t.nodeType)return;if(1!==t.nodeType)return;if(t.hasAttribute("no-vhtml")||t.vparsed)return;let r=t.getAttribute("v-for");if(null!==r)return void this.parseVfor(r,t,e,n);if(-1!==o.indexOf("-")){let r="/"+o.split("-").join("/"),i=t.hasAttribute("single");return this.parseRef(r,t,e,n,null,i),void(t.vparsed=!0)}if(t.getAttribute(":vsrc")){let o=t.getAttribute(":vsrc");t.removeAttribute(":vsrc");let r=Array.from(t.attributes).map((t=>({name:t.name,value:t.value}))),i=Array.from(t.childNodes);return void y.Watch((()=>{delete t.vparsed,t.setAttribute("vparsing","");let s=y.Run(o,e,n);s&&(Array.from(t.attributes).forEach((e=>{t.removeAttribute(e.name)})),t.innerHTML="",r.forEach((e=>{t.setAttribute(e.name,e.value)})),i.forEach((e=>{t.appendChild(e.cloneNode(!0))})),this.parseRef(s,t,e,n,null,!1),t.vparsed=!0)}))}if(t.getAttribute("vsrc")){let o=t.hasAttribute("single");return this.parseRef(t.getAttribute("vsrc"),t,e,n,null,o),void(t.vparsed=!0)}if("div"===o&&t.getAttribute("v-html")){let o=t.getAttribute("v-html");return t.removeAttribute("v-html"),t.innerHTML="",this.parseAttrs(t,e,n),t.vparsed=!0,void y.Watch((()=>{let r=y.Run(o,e,n);t.innerHTML=r;let i=this.parseVif(Array.from(t.childNodes),e,n);for(let t of i)this.parseDom(t,e,n)}))}if("vslot"===o)return this.parseSlots(t,e,n),void(t.vparsed=!0);if("vrouter"===o)return this.parseAttrs(t,e,n),void un.$router.ParseVrouter(this,t,n);this.parseAttrs(t,e,n);let i=this.parseVif(Array.from(t.childNodes),e,n);for(let s of i)this.parseDom(s,e,n);t.vparsed=!0}onMountedRun(t,n,o=!0){if(o){if(t.isConnected)return void n(t);let o=e.push((t=>{t.removeAttribute("vdelay"),n(t)}));return void t.setAttribute("vdelay",o-1)}t.isConnected&&n(t);let r=e.push(n);t.setAttribute("vdelay",r-1)}AllENVs={};async parseRef(t,e,n,o,r,i=!1){e.setAttribute("vparsing","");let s=o,a=e.getAttribute("vrefof"),c=e.closest(`*[vref='${a}']`);c&&(o=c.$env),!r&&t&&(t.endsWith(".html")||(t+=".html"),r=await on.FetchUI(t,o,e.hasAttribute("root"))),o=Object.assign({},o,r?.env||{}),e.$env=o,e.$vsrc=t,o.$router=un.$router,o.$emit=(t,...n)=>{if(t=t.toLowerCase(),!e.$vevent)return;let o=e.$vevent[t];o&&"function"==typeof o&&o(...n)};let l=await this.setupRef(e,n,s,r,i);i?this.parseAttrs(e,l,o,r?.customAttrs):this.parseAttrs(e,n,s,r?.customAttrs);let u=this.parseVif(Array.from(e.childNodes),l,o);for(let f of u)this.parseDom(f,l,o);e.removeAttribute("vparsing"),this.mountRef(e,l,o,r)}async setupRef(t,e,n,r,i=!1){let s=y.Wrap({});if(r.setup){let e=r.setup.innerHTML;e=await y.ParseImport(e,s,t.$env,t.$vsrc),await y.AsyncRun(e,s,t.$env,{$node:t})}if(t.$refScope=e,t.$refData=s,i)return s;if(!t.$refSlots){let e=y.Wrap({});t.childNodes.forEach((t=>{let n=t.getAttribute?t.getAttribute("vslot"):"";n=n||"",e[n]||(e[n]=[]),e[n].push(t)})),t.$refSlots=e}t.innerHTML="";let a=r.body.cloneNode(!0);t.append(...a.childNodes),Object.keys(s).forEach((r=>{const i=hn.CamelToKebabCase(r);if("boolean"==typeof s[r]?(t.hasAttribute(r)||t.hasAttribute(i))&&(s[r]=!0):t.hasAttribute(r)?(s[r]=t.getAttribute(r),t.removeAttribute(r)):t.hasAttribute(i)&&(s[r]=t.getAttribute(i),t.removeAttribute(i)),t.hasAttribute(":"+r)||t.hasAttribute(":"+i)){let o=t.getAttribute(":"+r)||t.getAttribute(":"+i);t.removeAttribute(":"+r),t.removeAttribute(":"+i),delete s[r],o?y.Watch((()=>y.Run(o,e,n)),(()=>{s[r]=y.Run(o,e,n)}),{deep:!0}):y.Watch((()=>e[r]),(()=>{s[r]=e[r]}),{deep:!0})}if(t.hasAttribute("v:"+r)||t.hasAttribute("v:"+i)){let n=t.getAttribute("v:"+r)||t.getAttribute("v:"+i);t.removeAttribute("v:"+r),t.removeAttribute("v:"+i),n||(n=r),delete s[r],y.Watch((()=>o(n,e)),(t=>{t&&t.data&&t.key&&(s[r]=t.data[t.key])})),y.Watch((()=>s[r]),(()=>{let t=o(n,e);t&&t.data&&t.key&&(t.data[t.key]=s[r])}))}}));let c=Array.from(a.attributes);return c=c.filter((e=>!this.parseAttr(t,e.name,e.value,s,n)||(a.removeAttribute(e.name),!1))),c.forEach((e=>{if("class"===e.name)t.classList.add(...e.value.trim().split(/\s+/));else if("style"===e.name){let n=e.value.split(";");for(let e of n){let n=e.split(":");if(2===n.length&&!t.style[n[0]]){let e=n[0].trim();e.startsWith("--")?t.style.setProperty(e,n[1].trim()):t.style[e]=n[1].trim()}}}else t.getAttribute(e.name)||t.setAttribute(e.name,e.value)})),s}async mountRef(t,e,n,o){for(let r of o.scripts)r.hasAttribute("active")?this.onMountedRun(t,(()=>{y.AsyncRun(r.innerHTML,e,n,{$node:t,$watch:y.Watch})}),!1):y.AsyncRun(r.innerHTML,e,n,{$node:t,$watch:y.Watch})}parseAttrs(t,e,n,o){if("A"===t.nodeName&&this.parseAHref(t,e,n),Array.from(t.attributes).forEach((o=>{this.parseAttr(t,o.name,o.value,e,n)&&t.removeAttribute(o.name)})),o&&Object.keys(o).forEach((e=>{this.parseAttr(t,e,o[e],t.$refData,n)})),t.hasAttribute("v-show")){let o=t.getAttribute("v-show"),r=t.style.display;y.Watch((()=>{let i=y.Run(o,e,n);t.style.display=i?r:"none"}))}}parseAHref(t,e,n){if(!t.hasAttribute("href")&&!t.hasAttribute(":href"))return;y.Watch((()=>{let o=t.getAttribute("href");if(t.hasAttribute(":href")){let r=t.getAttribute(":href");t.removeAttribute(":href"),o=y.Run(r,e,n)}if(o&&!o.startsWith("#")&&!o.startsWith("http"))if(o.startsWith("@"))o=o.replaceAll("//","/"),t.setAttribute("href",o.slice(1));else if(o){let e=n?.root;e&&(o=e+o),t.setAttribute("href",o)}}));const o=e=>{let n=e?.fullPath;t.getAttribute("href")===n?t.setAttribute("active",""):t.removeAttribute("active")};o(un.$router.current),un.$router.onChange(o)}parseAttr(t,e,n,r,i){if(e.startsWith(":")){let o=e.slice(1);return"class"===o||"style"===o?this.handleStyle(t,o,n,r,i):y.Watch((()=>{let e;e=n?y.Run(n,r,i):r[o],hn.SetAttr(t,o,e)})),!0}if(e.startsWith("@"))return this.handleEvent(t,e,n,r,i),!0;if(e.indexOf("!")>-1);else if(e.startsWith("v:")){let e=o(n,r);if(e&&e.data&&e.key){let n=e.key,o=e.data;return hn.BindInputDomValue(t,o,n,y.Watch)}}else if("vdom"===e){let e=o(n,r);return e&&e.data&&e.key&&(e.data[e.key]=t),!0}return!1}handleStyle(t,e,n,o,r){let i="";y.Watch((()=>{let s=y.Run(n,o,r);if("function"==typeof s&&(s=s()),"class"===e){if(i&&(t.classList.remove(...i.split(/\s+/)),i=""),s instanceof Array)i="",s.forEach((t=>{if("string"==typeof t&&t.length)i+=" "+t;else if("object"==typeof t)for(let e in t)t[e]&&(i+=" "+e)}));else if("string"==typeof s&&s.length)i=s.trim();else if("object"==typeof s){i="";for(let t in s)s[t]&&(i+=" "+t)}i=i.trim(),i&&t.classList.add(...i.split(/\s+/))}else if("style"===e){if(i)if("object"==typeof i)for(let e in i)e.startsWith("--")?t.style.removeProperty(e):t.style[e]="";else if("string"==typeof i){let e=i.split(";");for(let n of e){let e=n.split(":");2===e.length&&(e[0].trim().startsWith("--")?t.style.removeProperty(e[0].trim()):t.style[e[0].trim()]="")}}if("object"==typeof s)for(let e in s)e.startsWith("--")?t.style.setProperty(e,s[e]):t.style[e]=s[e];else if("string"==typeof s){let e=s.split(";");for(let n of e){let e=n.split(":");2===e.length&&(e[0].trim().startsWith("--")?t.style.setProperty(e[0].trim(),e[1].trim()):t.style[e[0].trim()]=e[1].trim())}}i=s}}))}handleEvent(t,e,n,o,r){let i=e.slice(1).split("."),s={self:!1,prevent:!1,stop:!1},a=i[0];if("mounted"===a)this.onMountedRun(t,(t=>{let e=y.Run(n,o,r);"function"==typeof e&&e(t)}),!1);else if("outerclick"===a){let e=t=>{let e=y.Run(n,o,r,{$event:t});"function"==typeof e&&e(t)};hn.AddClicker(t,"outer",e)}else if(-1!==hn.EventsList.indexOf(a)){"keydown"!==a&&"keyup"!==a&&"keypress"!==a||"INPUT"!==t.tagName&&"TEXTAREA"!==t.tagName&&t.setAttribute("tabindex","0");let e=t=>{let e=y.Run(n,o,r,{$event:t});"function"==typeof e&&e(t)};i.slice(1).forEach((i=>{if(i.startsWith("delay")){let s=i.slice(5);s=s?s.endsWith("ms")?+s.slice(0,-2):s.endsWith("s")?1e3*+s.slice(0,-1):+s:1e3,isNaN(s)&&(s=1e3),e=e=>{let i=t["_"+a];i&&"number"==typeof i&&clearTimeout(i),t["_"+a]=setTimeout((()=>{let t=y.Run(n,o,r,{$event:e});"function"==typeof t&&t(e)}),s)}}s[i]=!0})),t.addEventListener(a,(t=>{(1>=i.length||"keydown"!==a&&"keyup"!=a&&"keypress"!=a||i[1]===t.key?.toLowerCase())&&(s.self&&t.currentTarget!==t.target||(s.prevent&&t.preventDefault(),s.stop&&t.stopPropagation(),e(t)))}))}else t.$vevent=t.$vevent||{},t.$vevent[a]=(...t)=>{let e=y.Run(n,o,r,{});"function"==typeof e&&e(...t)}}parseTextNode(t,e,n){let o,i=t.nodeValue.trim();if(!i)return;let s=0,a=-1,c=[];for(;null!==(o=r.exec(i));)if("{{"===o[0])a=o.index;else if("}}"===o[0]&&a>=0){s!==a&&c.push(i.slice(s,a)),c.push("");let r=i.slice(a+2,o.index),l=c.length;a=-1,s=o.index+2,y.Watch((()=>{c[l-1]=y.Run(r,e,n),"object"==typeof c[l-1]&&(c[l-1]=JSON.stringify(c[l-1])),t.nodeValue=c.join("")}))}c.push(i.slice(s)),t.nodeValue=c.join("")}vforDomCache={};parseVfor(t,e,n,o){e.removeAttribute("v-for");let r=i.exec(t);if(6===r?.length){let t=document.createElement("div");t.style.display="none";let i=y.GenUniqueID();this.vforDomCache[i]={},e.parentNode.replaceChild(t,e),y.Watch((()=>{let s=r[3]||r[2],a=r[4],c=y.Run(r[5],n,o),l=this.vforDomCache[i],u=new Set;if("function"==typeof c?c=c():"number"==typeof c&&(c=Array.from({length:c},((t,e)=>e))),null==c&&(c=[]),c.length,"object"==typeof c){let r=Object.keys(c),f=[];for(let t in r){let e=r[t],n="";n=c[e]&&c[e][y.DataID]?c[e][y.DataID]:e+"."+c[e],n=i+"."+n,u.add(n),f.push({k:e,vfk:n,val:c[e]})}for(let t of Object.keys(l))u.has(t)||(l[t]instanceof Array?l[t].forEach((t=>t.remove())):l[t].remove(),delete l[t]);let h=t;for(let i=f.length-1;i>=0;i--){let{k:r,vfk:c,val:u}=f[i],d=l[c];if(d){a&&(d.$vforData[a]="0"===r?0:+r||r),d.isConnected&&(d.nextSibling!==h&&t.parentNode.insertBefore(d,h),h=d);continue}let p=e.cloneNode(!0);l[c]=p;let m={[s]:u};a&&(m[a]="0"===r?0:+r||r),m=y.Wrap(m,n),p.$vforData=m,t.parentNode.insertBefore(p,h);let w=e.getAttribute("v-if");if(!w){this.parseDom(p,m,o),h=p;continue}p.removeAttribute("v-if");let b=-1;b=y.Watch((()=>{let e=l[c];if(e)if(y.Run(w,m,o)){if(e.vparsed||this.parseDom(e,m,o),!e.isConnected){let n=!1,o=t;for(let t in l)if(t!==c){if(n&&l[t].isConnected){o=l[t];break}}else n=!0;t.parentNode.insertBefore(e,o)}}else e.isConnected?e.remove():this.onMountedRun(e,(t=>{e.remove()}));else y.Cancel(b)})),p.isConnected&&(h=p)}}}))}}parseVif(t,e,n){let o={now:document.createElement("div"),conds:[],doms:[]};const r=t=>{let o={now:t.now,conds:t.conds,doms:t.doms},r=[];for(let e in o.conds){let t=o.conds[e];t=""===t?"true":"Boolean("+t+")",r.push(t)}let i=`let res = [${r.join(",")}]\n return res.indexOf(true)`;y.Watch((()=>{let t=y.Run(i,e,n),r=o.doms[t];return r||(r=document.createElement("div"),r.style.display="none"),r}),(t=>{t&&(this.onMountedRun(o.now,(e=>{e.replaceWith(t),o.now=t})),t?.vparsed||this.parseDom(t,e,n))}))};let i=t.filter((t=>!(t.getAttribute&&!t.getAttribute("v-for")&&(null!==t.getAttribute("v-if")?(o.conds.length>0&&(r(o),o={now:document.createElement("div"),conds:[],doms:[]}),t.replaceWith(o.now),o.conds.push(t.getAttribute("v-if")),t.removeAttribute("v-if"),o.doms.push(t),1):null!==t.getAttribute("v-else-if")?(o.conds.push(t.getAttribute("v-else-if")),t.removeAttribute("v-else-if"),o.doms.push(t),t.remove(),1):null!==t.getAttribute("v-else")&&(o.conds.push(""),t.removeAttribute("v-else"),o.doms.push(t),t.remove(),1)))));return o.conds.length>0&&r(o),i}parseSlots(t,e,n){let o=t.getAttribute("vrefof"),r=t.closest(`*[vref='${o}']`);if(!r)return void this.onMountedRun(t,(t=>{this.parseSlots(t,e,n)}));for(;;){let t=r?.parentNode.closest("*[vref]");if(!t)break;if(t.getAttribute("vref")!==o)break;r=t}let i=t.getAttribute("name")||"";if(t.getAttribute(":name")){let o=t.getAttribute(":name");t.removeAttribute(":name"),i=y.Run(o,e,n)}return t.originContent||(t.$originContent=Array.from(t.childNodes),t.innerHTML=""),t.$slotCache={},y.Watch((()=>{let o=r.$refSlots||{},s=r.$refScope||{},a=o[i];if(a&&a.length>0){let o=a[0].hashID;if(o){if(t.$slotCache[o])return t.innerHTML="",void t.append(...t.$slotCache[o])}else o=y.GenUniqueID(),a[0].hashID=o;t.innerHTML="",a=a.map((t=>t.cloneNode(!0))),t.append(...a);let r=s;if(null!==t.getAttribute("vbind")){let n=t.getAttribute("vbind").split(",").map((t=>t.trim()));r=y.Wrap({}),n.forEach((t=>{e.hasOwnProperty(t)&&(r[t]=e[t])})),y.SetDataRoot(r,s)}let i="";a.find((t=>!(!t.getAttribute||!t.getAttribute("vrefof")||(i=t.getAttribute("vrefof"),0))));let c=n;if(i){let e=t.closest(`*[vref='${i}']`);c=e?.$env||n}a=this.parseVif(a,r,c),a.forEach((t=>this.parseDom(t,r,c))),t.$slotCache[o]=a}else{t.innerHTML="",t.append(...t.$originContent);let o=!1;t.$originContent.forEach((t=>{t.hasAttribute&&t.vparsed&&(o=!0)})),o||(t.$originContent=this.parseVif(t.$originContent,e,n),t.$originContent.forEach((t=>this.parseDom(t,e,n))))}})),this.parseAttrs(t,e,n),t}}(document.body))}()},"function"==typeof define&&define.amd?define(t):t(); \ No newline at end of file diff --git a/ui/assets/vyes.min.js b/ui/assets/vyes.min.js deleted file mode 100644 index e037a3b..0000000 --- a/ui/assets/vyes.min.js +++ /dev/null @@ -1 +0,0 @@ -var t;t=function(){const t=[],e=[];function n(){return`${performance.now().toString(36)}-${Math.random().toString(36).substring(2,5)}`}setInterval((()=>{let n=new Set(e.splice(0)),o=0;for(let e of n)t[e]&&(window.vdev||t[e](),o++);return o}),25),window.$vupdate=e=>{t[e]()};var o=[];const r=Symbol("isProxy"),i=Symbol("DataID"),s=Symbol("bind"),a=Symbol("root"),c=Symbol("root arg");function l(t,e){t[a]=e,Object.keys(e).forEach((e=>{e in t||(t[e]=c)}))}function u(t){return!(!t||"object"!=typeof t||t instanceof Node||t instanceof Date||t instanceof RegExp||t instanceof Event||t.t||t.constructor!==Object&&t.constructor!==Array)}function f(t,e){if(!t||!t[r]||!u(e))return e;let n=t[s];if(!e[r]){if(Array.isArray(e)&&Array.isArray(t)){t.length=0;for(let n=0;n{e.hasOwnProperty(n)||delete t[n]})),Object.keys(e).forEach((n=>{t[n]?.[r]?t[n]=f(t[n],e[n]):t[n]=e[n]})),t}if(e[i]===t[i])return e;for(let o in n)if(e[s][o]?.indexOf){const t=e[s][o],r=new Set(t);for(let e of n[o])r.has(e)||(t.push(e),r.add(e))}else e[s][o]=n[o];for(let o in e)o in t&&t[o]?.[r]&&(e[o]=f(t[o],e[o]));return e}const h={console,window,prompt:prompt.bind(window),alert:alert.bind(window),confirm:confirm.bind(window),RegExp,document,Array,Object,Math,Date,JSON,Symbol,Number,eval,isNaN,parseInt,parseFloat,setTimeout:setTimeout.bind(window),setInterval:setInterval.bind(window),clearTimeout:clearTimeout.bind(window),clearInterval:clearInterval.bind(window),encodeURIComponent,btoa:btoa.bind(window),fetch:fetch.bind(window),TextDecoder,history,requestAnimationFrame:requestAnimationFrame.bind(window)};function d(t,e,n){const o=new Proxy(t,{has:(t,e)=>!0,get(o,r,i){let s;return"$data"===r?s=t:"$env"===r?s=e:r in o?s=Reflect.get(o,r,i):r in e?s=e[r]:n&&r in n?s=n[r]:r in h?s=h[r]:r in window&&(s=window[r]),s},set:(t,e,n,o)=>Reflect.set(t,e,n,o)});return o}const p=Object.getPrototypeOf((async function(){})).constructor;function m(t,e){if(t.startsWith("/"))return t;const n=e.substring(0,e.lastIndexOf("/")).split("/").filter((t=>""!==t)),o=t.split("/").filter((t=>""!==t));for(const r of o)if(".."===r)n.length>0&&n.pop();else{if("."===r)continue;n.push(r)}return"/"+n.join("/")}const w={Wrap:function h(d,p=void 0){const m=n();let w=!1;"[object Array]"==={}.toString.call(d)&&(w=!0),p&&l(d,p);const y={},b={get(t,e,n){if(e===i)return m;if(e===r)return!0;if(e===s)return y;if("hasOwnProperty"===e)return t.hasOwnProperty.bind(t);const l=Reflect.get(t,e,n);if(l===c)return t[a][e];if("symbol"==typeof e)return l;let f=-1;if(o.length>0){let t=e;f=o[o.length-1],w&&(t=""),y.hasOwnProperty(t)?-1==y[t].indexOf(f)&&y[t].push(f):y[t]=[f]}if(window.vdev,u(l)&&!l[r]){let o=h(l,void 0);return Reflect.set(t,e,o,n),o}return l},set(n,i,s,l){const h=Reflect.get(n,i,l);if(h===c)return n[a][i]=s,!0;if(h===s)return!0;let d=!0;if(Array.isArray(s)&&Array.isArray(h)?(h.length=0,h.push(...s)):h&&h[r]&&u(s)?(s=f(h,s),d=Reflect.set(n,i,s,l)):d=Reflect.set(n,i,s,l),d&&0===o.length){let n=i;if(w&&(n=""),y[n]){let o=0;for(;o{n(e())})):t.push(e);try{r=e()}catch(b){}finally{o.pop()}return"function"==typeof n&&n(r),i},Cancel:function(e){e>=0&&et.trim()))}const i=await import(t);"string"==typeof o?i.default?e[o]=i.default:e[o]=i:o.forEach((t=>{t in i?e[t]=i[t]:t in i.default&&(e[t]=i.default[t])}))}catch(l){}}return s.trim()}};class y{constructor(){this.events={}}on(t,e,n=null){if("function"!=typeof e)throw Error("\u56de\u8c03\u51fd\u6570\u5fc5\u987b\u662f\u4e00\u4e2a\u51fd\u6570");this.events[t]||(this.events[t]=[]);const o={callback:e,context:n};return this.events[t].push(o),()=>this.off(t,e,n)}once(t,e,n=null){const o=(...r)=>{this.off(t,o,n),e.apply(n,r)};return this.on(t,o,n)}off(t,e=null,n=null){this.events[t]&&(e?(this.events[t]=this.events[t].filter((t=>!(t.callback===e&&t.context===n))),0===this.events[t].length&&delete this.events[t]):delete this.events[t])}emit(t,...e){this.events[t]&&[...this.events[t]].forEach((t=>{try{t.callback.apply(t.context,e)}catch(n){}}))}listenerCount(t){return this.events[t]?this.events[t].length:0}eventNames(){return Object.keys(this.events)}removeAllListeners(){this.events={}}hasListeners(t){return this.listenerCount(t)>0}}function b(t,e){return function(){return t.apply(e,arguments)}}const{toString:v}=Object.prototype,{getPrototypeOf:g}=Object,{iterator:x,toStringTag:R}=Symbol,O=(k=Object.create(null),t=>{const e=v.call(t);return k[e]||(k[e]=e.slice(8,-1).toLowerCase())});var k;const T=t=>(t=t.toLowerCase(),e=>O(e)===t),E=t=>e=>typeof e===t,{isArray:S}=Array,A=E("undefined"),j=T("ArrayBuffer"),$=E("string"),N=E("function"),P=E("number"),C=t=>null!==t&&"object"==typeof t,U=t=>{if("object"!==O(t))return!1;const e=g(t);return!(null!==e&&e!==Object.prototype&&null!==Object.getPrototypeOf(e)||R in t||x in t)},F=T("Date"),D=T("File"),L=T("Blob"),I=T("FileList"),z=T("URLSearchParams"),[M,q,B,_]=["ReadableStream","Request","Response","Headers"].map(T);function H(t,e,{allOwnKeys:n=!1}={}){if(null==t)return;let o,r;if("object"!=typeof t&&(t=[t]),S(t))for(o=0,r=t.length;r>o;o++)e.call(null,t[o],o,t);else{const r=n?Object.getOwnPropertyNames(t):Object.keys(t),i=r.length;let s;for(o=0;i>o;o++)s=r[o],e.call(null,t[s],s,t)}}function V(t,e){e=e.toLowerCase();const n=Object.keys(t);let o,r=n.length;for(;r-- >0;)if(o=n[r],e===o.toLowerCase())return o;return null}const X="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:global,J=t=>!A(t)&&t!==X,W=(K="undefined"!=typeof Uint8Array&&g(Uint8Array),t=>K&&t instanceof K);var K;const G=T("HTMLFormElement"),Z=(({hasOwnProperty:t})=>(e,n)=>t.call(e,n))(Object.prototype),Y=T("RegExp"),Q=(t,e)=>{const n=Object.getOwnPropertyDescriptors(t),o={};H(n,((n,r)=>{let i;!1!==(i=e(n,r,t))&&(o[r]=i||n)})),Object.defineProperties(t,o)},tt=T("AsyncFunction"),et=(nt="function"==typeof setImmediate,ot=N(X.postMessage),nt?setImmediate:ot?(rt="axios@"+Math.random(),it=[],X.addEventListener("message",(({source:t,data:e})=>{t===X&&e===rt&&it.length&&it.shift()()}),!1),t=>{it.push(t),X.postMessage(rt,"*")}):t=>setTimeout(t));var nt,ot,rt,it;const st="undefined"!=typeof queueMicrotask?queueMicrotask.bind(X):"undefined"!=typeof process&&process.nextTick||et,at={isArray:S,isArrayBuffer:j,isBuffer:function(t){return null!==t&&!A(t)&&null!==t.constructor&&!A(t.constructor)&&N(t.constructor.isBuffer)&&t.constructor.isBuffer(t)},isFormData:t=>{let e;return t&&("function"==typeof FormData&&t instanceof FormData||N(t.append)&&("formdata"===(e=O(t))||"object"===e&&N(t.toString)&&"[object FormData]"===t.toString()))},isArrayBufferView:function(t){let e;return e="undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(t):t&&t.buffer&&j(t.buffer),e},isString:$,isNumber:P,isBoolean:t=>!0===t||!1===t,isObject:C,isPlainObject:U,isReadableStream:M,isRequest:q,isResponse:B,isHeaders:_,isUndefined:A,isDate:F,isFile:D,isBlob:L,isRegExp:Y,isFunction:N,isStream:t=>C(t)&&N(t.pipe),isURLSearchParams:z,isTypedArray:W,isFileList:I,forEach:H,merge:function t(){const{caseless:e}=J(this)&&this||{},n={},o=(o,r)=>{const i=e&&V(n,r)||r;U(n[i])&&U(o)?n[i]=t(n[i],o):U(o)?n[i]=t({},o):S(o)?n[i]=o.slice():n[i]=o};for(let r=0,i=arguments.length;i>r;r++)arguments[r]&&H(arguments[r],o);return n},extend:(t,e,n,{allOwnKeys:o}={})=>(H(e,((e,o)=>{n&&N(e)?t[o]=b(e,n):t[o]=e}),{allOwnKeys:o}),t),trim:t=>t.trim?t.trim():t.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,""),stripBOM:t=>(65279===t.charCodeAt(0)&&(t=t.slice(1)),t),inherits:(t,e,n,o)=>{t.prototype=Object.create(e.prototype,o),t.prototype.constructor=t,Object.defineProperty(t,"super",{value:e.prototype}),n&&Object.assign(t.prototype,n)},toFlatObject:(t,e,n,o)=>{let r,i,s;const a={};if(e=e||{},null==t)return e;do{for(r=Object.getOwnPropertyNames(t),i=r.length;i-- >0;)s=r[i],o&&!o(s,t,e)||a[s]||(e[s]=t[s],a[s]=!0);t=!1!==n&&g(t)}while(t&&(!n||n(t,e))&&t!==Object.prototype);return e},kindOf:O,kindOfTest:T,endsWith:(t,e,n)=>{t+="",(void 0===n||n>t.length)&&(n=t.length),n-=e.length;const o=t.indexOf(e,n);return-1!==o&&o===n},toArray:t=>{if(!t)return null;if(S(t))return t;let e=t.length;if(!P(e))return null;const n=Array(e);for(;e-- >0;)n[e]=t[e];return n},forEachEntry:(t,e)=>{const n=(t&&t[x]).call(t);let o;for(;(o=n.next())&&!o.done;){const n=o.value;e.call(t,n[0],n[1])}},matchAll:(t,e)=>{let n;const o=[];for(;null!==(n=t.exec(e));)o.push(n);return o},isHTMLForm:G,hasOwnProperty:Z,hasOwnProp:Z,reduceDescriptors:Q,freezeMethods:t=>{Q(t,((e,n)=>{if(N(t)&&-1!==["arguments","caller","callee"].indexOf(n))return!1;const o=t[n];N(o)&&(e.enumerable=!1,"writable"in e?e.writable=!1:e.set||(e.set=()=>{throw Error("Can not rewrite read-only method '"+n+"'")}))}))},toObjectSet:(t,e)=>{const n={},o=t=>{t.forEach((t=>{n[t]=!0}))};return S(t)?o(t):o((t+"").split(e)),n},toCamelCase:t=>t.toLowerCase().replace(/[-_\s]([a-z\d])(\w*)/g,(function(t,e,n){return e.toUpperCase()+n})),noop:()=>{},toFiniteNumber:(t,e)=>null!=t&&Number.isFinite(t=+t)?t:e,findKey:V,global:X,isContextDefined:J,isSpecCompliantForm:function(t){return!!(t&&N(t.append)&&"FormData"===t[R]&&t[x])},toJSONObject:t=>{const e=[,,,,,,,,,,],n=(t,o)=>{if(C(t)){if(e.indexOf(t)>=0)return;if(!("toJSON"in t)){e[o]=t;const r=S(t)?[]:{};return H(t,((t,e)=>{const i=n(t,o+1);!A(i)&&(r[e]=i)})),e[o]=void 0,r}}return t};return n(t,0)},isAsyncFn:tt,isThenable:t=>t&&(C(t)||N(t))&&N(t.then)&&N(t.catch),setImmediate:et,asap:st,isIterable:t=>null!=t&&N(t[x])};function ct(t,e,n,o,r){Error.call(this),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=Error().stack,this.message=t,this.name="AxiosError",e&&(this.code=e),n&&(this.config=n),o&&(this.request=o),r&&(this.response=r,this.status=r.status?r.status:null)}at.inherits(ct,Error,{toJSON:function(){return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:at.toJSONObject(this.config),code:this.code,status:this.status}}});const lt=ct.prototype,ut={};function ft(t){return at.isPlainObject(t)||at.isArray(t)}function ht(t){return at.endsWith(t,"[]")?t.slice(0,-2):t}function dt(t,e,n){return t?t.concat(e).map((function(t,e){return t=ht(t),!n&&e?"["+t+"]":t})).join(n?".":""):e}["ERR_BAD_OPTION_VALUE","ERR_BAD_OPTION","ECONNABORTED","ETIMEDOUT","ERR_NETWORK","ERR_FR_TOO_MANY_REDIRECTS","ERR_DEPRECATED","ERR_BAD_RESPONSE","ERR_BAD_REQUEST","ERR_CANCELED","ERR_NOT_SUPPORT","ERR_INVALID_URL"].forEach((t=>{ut[t]={value:t}})),Object.defineProperties(ct,ut),Object.defineProperty(lt,"isAxiosError",{value:!0}),ct.from=(t,e,n,o,r,i)=>{const s=Object.create(lt);return at.toFlatObject(t,s,(function(t){return t!==Error.prototype}),(t=>"isAxiosError"!==t)),ct.call(s,t.message,e,n,o,r),s.cause=t,s.name=t.name,i&&Object.assign(s,i),s};const pt=at.toFlatObject(at,{},null,(function(t){return/^is[A-Z]/.test(t)}));function mt(t,e,n){if(!at.isObject(t))throw new TypeError("target must be an object");e=e||new FormData;const o=(n=at.toFlatObject(n,{metaTokens:!0,dots:!1,indexes:!1},!1,(function(t,e){return!at.isUndefined(e[t])}))).metaTokens,r=n.visitor||l,i=n.dots,s=n.indexes,a=(n.Blob||"undefined"!=typeof Blob&&Blob)&&at.isSpecCompliantForm(e);if(!at.isFunction(r))throw new TypeError("visitor must be a function");function c(t){if(null===t)return"";if(at.isDate(t))return t.toISOString();if(at.isBoolean(t))return t.toString();if(!a&&at.isBlob(t))throw new ct("Blob is not supported. Use a Buffer instead.");return at.isArrayBuffer(t)||at.isTypedArray(t)?a&&"function"==typeof Blob?new Blob([t]):Buffer.from(t):t}function l(t,n,r){let a=t;if(t&&!r&&"object"==typeof t)if(at.endsWith(n,"{}"))n=o?n:n.slice(0,-2),t=JSON.stringify(t);else if(at.isArray(t)&&function(t){return at.isArray(t)&&!t.some(ft)}(t)||(at.isFileList(t)||at.endsWith(n,"[]"))&&(a=at.toArray(t)))return n=ht(n),a.forEach((function(t,o){!at.isUndefined(t)&&null!==t&&e.append(!0===s?dt([n],o,i):null===s?n:n+"[]",c(t))})),!1;return!!ft(t)||(e.append(dt(r,n,i),c(t)),!1)}const u=[],f=Object.assign(pt,{defaultVisitor:l,convertValue:c,isVisitable:ft});if(!at.isObject(t))throw new TypeError("data must be an object");return function t(n,o){if(!at.isUndefined(n)){if(-1!==u.indexOf(n))throw Error("Circular reference detected in "+o.join("."));u.push(n),at.forEach(n,(function(n,i){!0===(!(at.isUndefined(n)||null===n)&&r.call(e,n,at.isString(i)?i.trim():i,o,f))&&t(n,o?o.concat(i):[i])})),u.pop()}}(t),e}function wt(t){const e={"!":"%21","'":"%27","(":"%28",")":"%29","~":"%7E","%20":"+","%00":"\0"};return encodeURIComponent(t).replace(/[!'()~]|%20|%00/g,(function(t){return e[t]}))}function yt(t,e){this.o=[],t&&mt(t,this,e)}const bt=yt.prototype;function vt(t){return encodeURIComponent(t).replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}function gt(t,e,n){if(!e)return t;const o=n&&n.encode||vt;at.isFunction(n)&&(n={serialize:n});const r=n&&n.serialize;let i;if(i=r?r(e,n):at.isURLSearchParams(e)?e.toString():new yt(e,n).toString(o),i){const e=t.indexOf("#");-1!==e&&(t=t.slice(0,e)),t+=(-1===t.indexOf("?")?"?":"&")+i}return t}bt.append=function(t,e){this.o.push([t,e])},bt.toString=function(t){const e=t?function(e){return t.call(this,e,wt)}:wt;return this.o.map((function(t){return e(t[0])+"="+e(t[1])}),"").join("&")};const xt=class{constructor(){this.handlers=[]}use(t,e,n){return this.handlers.push({fulfilled:t,rejected:e,synchronous:!!n&&n.synchronous,runWhen:n?n.runWhen:null}),this.handlers.length-1}eject(t){this.handlers[t]&&(this.handlers[t]=null)}clear(){this.handlers&&(this.handlers=[])}forEach(t){at.forEach(this.handlers,(function(e){null!==e&&t(e)}))}},Rt={silentJSONParsing:!0,forcedJSONParsing:!0,clarifyTimeoutError:!1},Ot={isBrowser:!0,classes:{URLSearchParams:"undefined"!=typeof URLSearchParams?URLSearchParams:yt,FormData:"undefined"!=typeof FormData?FormData:null,Blob:"undefined"!=typeof Blob?Blob:null},protocols:["http","https","file","blob","url","data"]},kt="undefined"!=typeof window&&"undefined"!=typeof document,Tt="object"==typeof navigator&&navigator||void 0,Et=kt&&(!Tt||0>["ReactNative","NativeScript","NS"].indexOf(Tt.product)),St="undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope&&"function"==typeof self.importScripts,At=kt&&window.location.href||"http://localhost",jt={...Object.freeze({__proto__:null,hasBrowserEnv:kt,hasStandardBrowserWebWorkerEnv:St,hasStandardBrowserEnv:Et,navigator:Tt,origin:At}),...Ot};function $t(t){function e(t,n,o,r){let i=t[r++];if("__proto__"===i)return!0;const s=Number.isFinite(+i),a=r>=t.length;return i=!i&&at.isArray(o)?o.length:i,a?(at.hasOwnProp(o,i)?o[i]=[o[i],n]:o[i]=n,!s):(o[i]&&at.isObject(o[i])||(o[i]=[]),e(t,n,o[i],r)&&at.isArray(o[i])&&(o[i]=function(t){const e={},n=Object.keys(t);let o;const r=n.length;let i;for(o=0;r>o;o++)i=n[o],e[i]=t[i];return e}(o[i])),!s)}if(at.isFormData(t)&&at.isFunction(t.entries)){const n={};return at.forEachEntry(t,((t,o)=>{e(function(t){return at.matchAll(/\w+|\[(\w*)]/g,t).map((t=>"[]"===t[0]?"":t[1]||t[0]))}(t),o,n,0)})),n}return null}const Nt={transitional:Rt,adapter:["xhr","http","fetch"],transformRequest:[function(t,e){const n=e.getContentType()||"",o=n.indexOf("application/json")>-1,r=at.isObject(t);if(r&&at.isHTMLForm(t)&&(t=new FormData(t)),at.isFormData(t))return o?JSON.stringify($t(t)):t;if(at.isArrayBuffer(t)||at.isBuffer(t)||at.isStream(t)||at.isFile(t)||at.isBlob(t)||at.isReadableStream(t))return t;if(at.isArrayBufferView(t))return t.buffer;if(at.isURLSearchParams(t))return e.setContentType("application/x-www-form-urlencoded;charset=utf-8",!1),t.toString();let i;if(r){if(n.indexOf("application/x-www-form-urlencoded")>-1)return function(t,e){return mt(t,new jt.classes.URLSearchParams,Object.assign({visitor:function(t,e,n,o){return jt.isNode&&at.isBuffer(t)?(this.append(e,t.toString("base64")),!1):o.defaultVisitor.apply(this,arguments)}},e))}(t,this.formSerializer).toString();if((i=at.isFileList(t))||n.indexOf("multipart/form-data")>-1){const e=this.env&&this.env.FormData;return mt(i?{"files[]":t}:t,e&&new e,this.formSerializer)}}return r||o?(e.setContentType("application/json",!1),function(t){if(at.isString(t))try{return(0,JSON.parse)(t),at.trim(t)}catch(t){if("SyntaxError"!==t.name)throw t}return(0,JSON.stringify)(t)}(t)):t}],transformResponse:[function(t){const e=this.transitional||Nt.transitional,n=e&&e.forcedJSONParsing,o="json"===this.responseType;if(at.isResponse(t)||at.isReadableStream(t))return t;if(t&&at.isString(t)&&(n&&!this.responseType||o)){const n=!(e&&e.silentJSONParsing)&&o;try{return JSON.parse(t)}catch(t){if(n){if("SyntaxError"===t.name)throw ct.from(t,ct.ERR_BAD_RESPONSE,this,null,this.response);throw t}}}return t}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,maxBodyLength:-1,env:{FormData:jt.classes.FormData,Blob:jt.classes.Blob},validateStatus:function(t){return t>=200&&300>t},headers:{common:{Accept:"application/json, text/plain, */*","Content-Type":void 0}}};at.forEach(["delete","get","head","post","put","patch"],(t=>{Nt.headers[t]={}}));const Pt=Nt,Ct=at.toObjectSet(["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"]),Ut=Symbol("internals");function Ft(t){return t&&(t+"").trim().toLowerCase()}function Dt(t){return!1===t||null==t?t:at.isArray(t)?t.map(Dt):t+""}function Lt(t,e,n,o,r){return at.isFunction(o)?o.call(this,e,n):(r&&(e=n),at.isString(e)?at.isString(o)?-1!==e.indexOf(o):at.isRegExp(o)?o.test(e):void 0:void 0)}class It{constructor(t){t&&this.set(t)}set(t,e,n){const o=this;function r(t,e,n){const r=Ft(e);if(!r)throw Error("header name must be a non-empty string");const i=at.findKey(o,r);(!i||void 0===o[i]||!0===n||void 0===n&&!1!==o[i])&&(o[i||e]=Dt(t))}const i=(t,e)=>at.forEach(t,((t,n)=>r(t,n,e)));if(at.isPlainObject(t)||t instanceof this.constructor)i(t,e);else if(at.isString(t)&&(t=t.trim())&&!/^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(t.trim()))i((t=>{const e={};let n,o,r;return t&&t.split("\n").forEach((function(t){r=t.indexOf(":"),n=t.substring(0,r).trim().toLowerCase(),o=t.substring(r+1).trim(),!n||e[n]&&Ct[n]||("set-cookie"===n?e[n]?e[n].push(o):e[n]=[o]:e[n]=e[n]?e[n]+", "+o:o)})),e})(t),e);else if(at.isObject(t)&&at.isIterable(t)){let n,o,r={};for(const e of t){if(!at.isArray(e))throw TypeError("Object iterator must return a key-value pair");r[o=e[0]]=(n=r[o])?at.isArray(n)?[...n,e[1]]:[n,e[1]]:e[1]}i(r,e)}else null!=t&&r(e,t,n);return this}get(t,e){if(t=Ft(t)){const n=at.findKey(this,t);if(n){const t=this[n];if(!e)return t;if(!0===e)return function(t){const e=Object.create(null),n=/([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g;let o;for(;o=n.exec(t);)e[o[1]]=o[2];return e}(t);if(at.isFunction(e))return e.call(this,t,n);if(at.isRegExp(e))return e.exec(t);throw new TypeError("parser must be boolean|regexp|function")}}}has(t,e){if(t=Ft(t)){const n=at.findKey(this,t);return!(!n||void 0===this[n]||e&&!Lt(0,this[n],n,e))}return!1}delete(t,e){const n=this;let o=!1;function r(t){if(t=Ft(t)){const r=at.findKey(n,t);!r||e&&!Lt(0,n[r],r,e)||(delete n[r],o=!0)}}return at.isArray(t)?t.forEach(r):r(t),o}clear(t){const e=Object.keys(this);let n=e.length,o=!1;for(;n--;){const r=e[n];t&&!Lt(0,this[r],r,t,!0)||(delete this[r],o=!0)}return o}normalize(t){const e=this,n={};return at.forEach(this,((o,r)=>{const i=at.findKey(n,r);if(i)return e[i]=Dt(o),void delete e[r];const s=t?function(t){return t.trim().toLowerCase().replace(/([a-z\d])(\w*)/g,((t,e,n)=>e.toUpperCase()+n))}(r):(r+"").trim();s!==r&&delete e[r],e[s]=Dt(o),n[s]=!0})),this}concat(...t){return this.constructor.concat(this,...t)}toJSON(t){const e=Object.create(null);return at.forEach(this,((n,o)=>{null!=n&&!1!==n&&(e[o]=t&&at.isArray(n)?n.join(", "):n)})),e}[Symbol.iterator](){return Object.entries(this.toJSON())[Symbol.iterator]()}toString(){return Object.entries(this.toJSON()).map((([t,e])=>t+": "+e)).join("\n")}getSetCookie(){return this.get("set-cookie")||[]}get[Symbol.toStringTag](){return"AxiosHeaders"}static from(t){return t instanceof this?t:new this(t)}static concat(t,...e){const n=new this(t);return e.forEach((t=>n.set(t))),n}static accessor(t){const e=(this[Ut]=this[Ut]={accessors:{}}).accessors,n=this.prototype;function o(t){const o=Ft(t);e[o]||(function(t,e){const n=at.toCamelCase(" "+e);["get","set","has"].forEach((o=>{Object.defineProperty(t,o+n,{value:function(t,n,r){return this[o].call(this,e,t,n,r)},configurable:!0})}))}(n,t),e[o]=!0)}return at.isArray(t)?t.forEach(o):o(t),this}}It.accessor(["Content-Type","Content-Length","Accept","Accept-Encoding","User-Agent","Authorization"]),at.reduceDescriptors(It.prototype,(({value:t},e)=>{let n=e[0].toUpperCase()+e.slice(1);return{get:()=>t,set(t){this[n]=t}}})),at.freezeMethods(It);const zt=It;function Mt(t,e){const n=this||Pt,o=e||n,r=zt.from(o.headers);let i=o.data;return at.forEach(t,(function(t){i=t.call(n,i,r.normalize(),e?e.status:void 0)})),r.normalize(),i}function qt(t){return!(!t||!t.i)}function Bt(t,e,n){ct.call(this,t??"canceled",ct.ERR_CANCELED,e,n),this.name="CanceledError"}function _t(t,e,n){const o=n.config.validateStatus;n.status&&o&&!o(n.status)?e(new ct("Request failed with status code "+n.status,[ct.ERR_BAD_REQUEST,ct.ERR_BAD_RESPONSE][Math.floor(n.status/100)-4],n.config,n.request,n)):t(n)}at.inherits(Bt,ct,{i:!0});const Ht=(t,e,n=3)=>{let o=0;const r=function(t,e){const n=Array(t=t||10),o=Array(t);let r,i=0,s=0;return e=void 0!==e?e:1e3,function(a){const c=Date.now(),l=o[s];r||(r=c),n[i]=a,o[i]=c;let u=s,f=0;for(;u!==i;)f+=n[u++],u%=t;if(i=(i+1)%t,i===s&&(s=(s+1)%t),e>c-r)return;const h=l&&c-l;return h?Math.round(1e3*f/h):void 0}}(50,250);return function(t,e){let n,o,r=0,i=1e3/e;const s=(e,i=Date.now())=>{r=i,n=null,o&&(clearTimeout(o),o=null),t.apply(null,e)};return[(...t)=>{const e=Date.now(),a=e-r;i>a?(n=t,o||(o=setTimeout((()=>{o=null,s(n)}),i-a))):s(t,e)},()=>n&&s(n)]}((n=>{const i=n.loaded,s=n.lengthComputable?n.total:void 0,a=i-o,c=r(a);o=i,t({loaded:i,total:s,progress:s?i/s:void 0,bytes:a,rate:c||void 0,estimated:c&&s&&s>=i?(s-i)/c:void 0,event:n,lengthComputable:null!=s,[e?"download":"upload"]:!0})}),n)},Vt=(t,e)=>{const n=null!=t;return[o=>e[0]({lengthComputable:n,total:t,loaded:o}),e[1]]},Xt=t=>(...e)=>at.asap((()=>t(...e))),Jt=jt.hasStandardBrowserEnv?((t,e)=>n=>(n=new URL(n,jt.origin),t.protocol===n.protocol&&t.host===n.host&&(e||t.port===n.port)))(new URL(jt.origin),jt.navigator&&/(msie|trident)/i.test(jt.navigator.userAgent)):()=>!0,Wt=jt.hasStandardBrowserEnv?{write(t,e,n,o,r,i){const s=[t+"="+encodeURIComponent(e)];at.isNumber(n)&&s.push("expires="+new Date(n).toGMTString()),at.isString(o)&&s.push("path="+o),at.isString(r)&&s.push("domain="+r),!0===i&&s.push("secure"),document.cookie=s.join("; ")},read(t){const e=document.cookie.match(RegExp("(^|;\\s*)("+t+")=([^;]*)"));return e?decodeURIComponent(e[3]):null},remove(t){this.write(t,"",Date.now()-864e5)}}:{write(){},read:()=>null,remove(){}};function Kt(t,e,n){return!t||/^([a-z][a-z\d+\-.]*:)?\/\//i.test(e)&&0!=n?e:function(t,e){return e?t.replace(/\/?\/$/,"")+"/"+e.replace(/^\/+/,""):t}(t,e)}const Gt=t=>t instanceof zt?{...t}:t;function Zt(t,e){e=e||{};const n={};function o(t,e,n,o){return at.isPlainObject(t)&&at.isPlainObject(e)?at.merge.call({caseless:o},t,e):at.isPlainObject(e)?at.merge({},e):at.isArray(e)?e.slice():e}function r(t,e,n,r){return at.isUndefined(e)?at.isUndefined(t)?void 0:o(void 0,t,0,r):o(t,e,0,r)}function i(t,e){if(!at.isUndefined(e))return o(void 0,e)}function s(t,e){return at.isUndefined(e)?at.isUndefined(t)?void 0:o(void 0,t):o(void 0,e)}function a(n,r,i){return i in e?o(n,r):i in t?o(void 0,n):void 0}const c={url:i,method:i,data:i,baseURL:s,transformRequest:s,transformResponse:s,paramsSerializer:s,timeout:s,timeoutMessage:s,withCredentials:s,withXSRFToken:s,adapter:s,responseType:s,xsrfCookieName:s,xsrfHeaderName:s,onUploadProgress:s,onDownloadProgress:s,decompress:s,maxContentLength:s,maxBodyLength:s,beforeRedirect:s,transport:s,httpAgent:s,httpsAgent:s,cancelToken:s,socketPath:s,responseEncoding:s,validateStatus:a,headers:(t,e,n)=>r(Gt(t),Gt(e),0,!0)};return at.forEach(Object.keys(Object.assign({},t,e)),(function(o){const i=c[o]||r,s=i(t[o],e[o],o);at.isUndefined(s)&&i!==a||(n[o]=s)})),n}const Yt=t=>{const e=Zt({},t);let n,{data:o,withXSRFToken:r,xsrfHeaderName:i,xsrfCookieName:s,headers:a,auth:c}=e;if(e.headers=a=zt.from(a),e.url=gt(Kt(e.baseURL,e.url,e.allowAbsoluteUrls),t.params,t.paramsSerializer),c&&a.set("Authorization","Basic "+btoa((c.username||"")+":"+(c.password?unescape(encodeURIComponent(c.password)):""))),at.isFormData(o))if(jt.hasStandardBrowserEnv||jt.hasStandardBrowserWebWorkerEnv)a.setContentType(void 0);else if(!1!==(n=a.getContentType())){const[t,...e]=n?n.split(";").map((t=>t.trim())).filter(Boolean):[];a.setContentType([t||"multipart/form-data",...e].join("; "))}if(jt.hasStandardBrowserEnv&&(r&&at.isFunction(r)&&(r=r(e)),r||!1!==r&&Jt(e.url))){const t=i&&s&&Wt.read(s);t&&a.set(i,t)}return e},Qt="undefined"!=typeof XMLHttpRequest&&function(t){return new Promise((function(e,n){const o=Yt(t);let r=o.data;const i=zt.from(o.headers).normalize();let s,a,c,l,u,{responseType:f,onUploadProgress:h,onDownloadProgress:d}=o;function p(){l&&l(),u&&u(),o.cancelToken&&o.cancelToken.unsubscribe(s),o.signal&&o.signal.removeEventListener("abort",s)}let m=new XMLHttpRequest;function w(){if(!m)return;const o=zt.from("getAllResponseHeaders"in m&&m.getAllResponseHeaders());_t((function(t){e(t),p()}),(function(t){n(t),p()}),{data:f&&"text"!==f&&"json"!==f?m.response:m.responseText,status:m.status,statusText:m.statusText,headers:o,config:t,request:m}),m=null}m.open(o.method.toUpperCase(),o.url,!0),m.timeout=o.timeout,"onloadend"in m?m.onloadend=w:m.onreadystatechange=function(){m&&4===m.readyState&&(0!==m.status||m.responseURL&&0===m.responseURL.indexOf("file:"))&&setTimeout(w)},m.onabort=function(){m&&(n(new ct("Request aborted",ct.ECONNABORTED,t,m)),m=null)},m.onerror=function(){n(new ct("Network Error",ct.ERR_NETWORK,t,m)),m=null},m.ontimeout=function(){let e=o.timeout?"timeout of "+o.timeout+"ms exceeded":"timeout exceeded";const r=o.transitional||Rt;o.timeoutErrorMessage&&(e=o.timeoutErrorMessage),n(new ct(e,r.clarifyTimeoutError?ct.ETIMEDOUT:ct.ECONNABORTED,t,m)),m=null},void 0===r&&i.setContentType(null),"setRequestHeader"in m&&at.forEach(i.toJSON(),(function(t,e){m.setRequestHeader(e,t)})),at.isUndefined(o.withCredentials)||(m.withCredentials=!!o.withCredentials),f&&"json"!==f&&(m.responseType=o.responseType),d&&([c,u]=Ht(d,!0),m.addEventListener("progress",c)),h&&m.upload&&([a,l]=Ht(h),m.upload.addEventListener("progress",a),m.upload.addEventListener("loadend",l)),(o.cancelToken||o.signal)&&(s=e=>{m&&(n(!e||e.type?new Bt(null,t,m):e),m.abort(),m=null)},o.cancelToken&&o.cancelToken.subscribe(s),o.signal&&(o.signal.aborted?s():o.signal.addEventListener("abort",s)));const y=function(t){const e=/^([-+\w]{1,25})(:?\/\/|:)/.exec(t);return e&&e[1]||""}(o.url);y&&-1===jt.protocols.indexOf(y)?n(new ct("Unsupported protocol "+y+":",ct.ERR_BAD_REQUEST,t)):m.send(r||null)}))},te=(t,e)=>{const{length:n}=t=t?t.filter(Boolean):[];if(e||n){let n,o=new AbortController;const r=function(t){if(!n){n=!0,s();const e=t instanceof Error?t:this.reason;o.abort(e instanceof ct?e:new Bt(e instanceof Error?e.message:e))}};let i=e&&setTimeout((()=>{i=null,r(new ct(`timeout ${e} of ms exceeded`,ct.ETIMEDOUT))}),e);const s=()=>{t&&(i&&clearTimeout(i),i=null,t.forEach((t=>{t.unsubscribe?t.unsubscribe(r):t.removeEventListener("abort",r)})),t=null)};t.forEach((t=>t.addEventListener("abort",r)));const{signal:a}=o;return a.unsubscribe=()=>at.asap(s),a}},ee=function*(t,e){let n=t.byteLength;if(e>n)return void(yield t);let o,r=0;for(;n>r;)o=r+e,yield t.slice(r,o),r=o},ne=(t,e,n,o)=>{const r=async function*(t,e){for await(const n of async function*(t){if(t[Symbol.asyncIterator])return void(yield*t);const e=t.getReader();try{for(;;){const{done:t,value:n}=await e.read();if(t)break;yield n}}finally{await e.cancel()}}(t))yield*ee(n,e)}(t,e);let i,s=0,a=t=>{i||(i=!0,o&&o(t))};return new ReadableStream({async pull(t){try{const{done:e,value:o}=await r.next();if(e)return a(),void t.close();let i=o.byteLength;if(n){let t=s+=i;n(t)}t.enqueue(new Uint8Array(o))}catch(t){throw a(t),t}},cancel:t=>(a(t),r.return())},{highWaterMark:2})},oe="function"==typeof fetch&&"function"==typeof Request&&"function"==typeof Response,re=oe&&"function"==typeof ReadableStream,ie=oe&&("function"==typeof TextEncoder?(se=new TextEncoder,t=>se.encode(t)):async t=>new Uint8Array(await new Response(t).arrayBuffer()));var se;const ae=(t,...e)=>{try{return!!t(...e)}catch(t){return!1}},ce=re&&ae((()=>{let t=!1;const e=new Request(jt.origin,{body:new ReadableStream,method:"POST",get duplex(){return t=!0,"half"}}).headers.has("Content-Type");return t&&!e})),le=re&&ae((()=>at.isReadableStream(new Response("").body))),ue={stream:le&&(t=>t.body)};var fe;oe&&(fe=new Response,["text","arrayBuffer","blob","formData","stream"].forEach((t=>{!ue[t]&&(ue[t]=at.isFunction(fe[t])?e=>e[t]():(e,n)=>{throw new ct(`Response type '${t}' is not supported`,ct.ERR_NOT_SUPPORT,n)})})));const he={http:null,xhr:Qt,fetch:oe&&(async t=>{let{url:e,method:n,data:o,signal:r,cancelToken:i,timeout:s,onDownloadProgress:a,onUploadProgress:c,responseType:l,headers:u,withCredentials:f="same-origin",fetchOptions:h}=Yt(t);l=l?(l+"").toLowerCase():"text";let d,p=te([r,i&&i.toAbortSignal()],s);const m=p&&p.unsubscribe&&(()=>{p.unsubscribe()});let w;try{if(c&&ce&&"get"!==n&&"head"!==n&&0!==(w=await(async(t,e)=>at.toFiniteNumber(t.getContentLength())??(async t=>{if(null==t)return 0;if(at.isBlob(t))return t.size;if(at.isSpecCompliantForm(t)){const e=new Request(jt.origin,{method:"POST",body:t});return(await e.arrayBuffer()).byteLength}return at.isArrayBufferView(t)||at.isArrayBuffer(t)?t.byteLength:(at.isURLSearchParams(t)&&(t+=""),at.isString(t)?(await ie(t)).byteLength:void 0)})(e))(u,o))){let t,n=new Request(e,{method:"POST",body:o,duplex:"half"});if(at.isFormData(o)&&(t=n.headers.get("content-type"))&&u.setContentType(t),n.body){const[t,e]=Vt(w,Ht(Xt(c)));o=ne(n.body,65536,t,e)}}at.isString(f)||(f=f?"include":"omit");const r="credentials"in Request.prototype;d=new Request(e,{...h,signal:p,method:n.toUpperCase(),headers:u.normalize().toJSON(),body:o,duplex:"half",credentials:r?f:void 0});let i=await fetch(d,h);const s=le&&("stream"===l||"response"===l);if(le&&(a||s&&m)){const t={};["status","statusText","headers"].forEach((e=>{t[e]=i[e]}));const e=at.toFiniteNumber(i.headers.get("content-length")),[n,o]=a&&Vt(e,Ht(Xt(a),!0))||[];i=new Response(ne(i.body,65536,n,(()=>{o&&o(),m&&m()})),t)}l=l||"text";let y=await ue[at.findKey(ue,l)||"text"](i,t);return!s&&m&&m(),await new Promise(((e,n)=>{_t(e,n,{data:y,headers:zt.from(i.headers),status:i.status,statusText:i.statusText,config:t,request:d})}))}catch(e){if(m&&m(),e&&"TypeError"===e.name&&/Load failed|fetch/i.test(e.message))throw Object.assign(new ct("Network Error",ct.ERR_NETWORK,t,d),{cause:e.cause||e});throw ct.from(e,e&&e.code,t,d)}})};at.forEach(he,((t,e)=>{if(t){try{Object.defineProperty(t,"name",{value:e})}catch(t){}Object.defineProperty(t,"adapterName",{value:e})}}));const de=t=>"- "+t,pe=t=>at.isFunction(t)||null===t||!1===t,me=t=>{t=at.isArray(t)?t:[t];const{length:e}=t;let n,o;const r={};for(let i=0;e>i;i++){let e;if(n=t[i],o=n,!pe(n)&&(o=he[(e=n+"").toLowerCase()],void 0===o))throw new ct(`Unknown adapter '${e}'`);if(o)break;r[e||"#"+i]=o}if(!o){const t=Object.entries(r).map((([t,e])=>`adapter ${t} `+(!1===e?"is not supported by the environment":"is not available in the build")));throw new ct("There is no suitable adapter to dispatch the request "+(e?t.length>1?"since :\n"+t.map(de).join("\n"):" "+de(t[0]):"as no adapter specified"),"ERR_NOT_SUPPORT")}return o};function we(t){if(t.cancelToken&&t.cancelToken.throwIfRequested(),t.signal&&t.signal.aborted)throw new Bt(null,t)}function ye(t){return we(t),t.headers=zt.from(t.headers),t.data=Mt.call(t,t.transformRequest),-1!==["post","put","patch"].indexOf(t.method)&&t.headers.setContentType("application/x-www-form-urlencoded",!1),me(t.adapter||Pt.adapter)(t).then((function(e){return we(t),e.data=Mt.call(t,t.transformResponse,e),e.headers=zt.from(e.headers),e}),(function(e){return qt(e)||(we(t),e&&e.response&&(e.response.data=Mt.call(t,t.transformResponse,e.response),e.response.headers=zt.from(e.response.headers))),Promise.reject(e)}))}const be={};["object","boolean","number","function","string","symbol"].forEach(((t,e)=>{be[t]=function(n){return typeof n===t||"a"+(1>e?"n ":" ")+t}}));const ve={};be.transitional=function(t,e,n){function o(t,e){return"[Axios v1.10.0] Transitional option '"+t+"'"+e+(n?". "+n:"")}return(n,r,i)=>{if(!1===t)throw new ct(o(r," has been removed"+(e?" in "+e:"")),ct.ERR_DEPRECATED);return e&&!ve[r]&&(ve[r]=!0),!t||t(n,r,i)}},be.spelling=function(t){return(t,e)=>!0};const ge={assertOptions:function(t,e,n){if("object"!=typeof t)throw new ct("options must be an object",ct.ERR_BAD_OPTION_VALUE);const o=Object.keys(t);let r=o.length;for(;r-- >0;){const i=o[r],s=e[i];if(s){const e=t[i],n=void 0===e||s(e,i,t);if(!0!==n)throw new ct("option "+i+" must be "+n,ct.ERR_BAD_OPTION_VALUE)}else if(!0!==n)throw new ct("Unknown option "+i,ct.ERR_BAD_OPTION)}},validators:be},xe=ge.validators;class Re{constructor(t){this.defaults=t||{},this.interceptors={request:new xt,response:new xt}}async request(t,e){try{return await this.l(t,e)}catch(t){if(t instanceof Error){let e={};Error.captureStackTrace?Error.captureStackTrace(e):e=Error();const n=e.stack?e.stack.replace(/^.+\n/,""):"";try{t.stack?n&&!(t.stack+"").endsWith(n.replace(/^.+\n.+\n/,""))&&(t.stack+="\n"+n):t.stack=n}catch(t){}}throw t}}l(t,e){"string"==typeof t?(e=e||{}).url=t:e=t||{},e=Zt(this.defaults,e);const{transitional:n,paramsSerializer:o,headers:r}=e;void 0!==n&&ge.assertOptions(n,{silentJSONParsing:xe.transitional(xe.boolean),forcedJSONParsing:xe.transitional(xe.boolean),clarifyTimeoutError:xe.transitional(xe.boolean)},!1),null!=o&&(at.isFunction(o)?e.paramsSerializer={serialize:o}:ge.assertOptions(o,{encode:xe.function,serialize:xe.function},!0)),void 0!==e.allowAbsoluteUrls||(void 0!==this.defaults.allowAbsoluteUrls?e.allowAbsoluteUrls=this.defaults.allowAbsoluteUrls:e.allowAbsoluteUrls=!0),ge.assertOptions(e,{baseUrl:xe.spelling("baseURL"),withXsrfToken:xe.spelling("withXSRFToken")},!0),e.method=(e.method||this.defaults.method||"get").toLowerCase();let i=r&&at.merge(r.common,r[e.method]);r&&at.forEach(["delete","get","head","post","put","patch","common"],(t=>{delete r[t]})),e.headers=zt.concat(i,r);const s=[];let a=!0;this.interceptors.request.forEach((function(t){"function"==typeof t.runWhen&&!1===t.runWhen(e)||(a=a&&t.synchronous,s.unshift(t.fulfilled,t.rejected))}));const c=[];let l;this.interceptors.response.forEach((function(t){c.push(t.fulfilled,t.rejected)}));let u,f=0;if(!a){const t=[ye.bind(this),void 0];for(t.unshift.apply(t,s),t.push.apply(t,c),u=t.length,l=Promise.resolve(e);u>f;)l=l.then(t[f++],t[f++]);return l}u=s.length;let h=e;for(f=0;u>f;){const e=s[f++],n=s[f++];try{h=e(h)}catch(t){n.call(this,t);break}}try{l=ye(h)}catch(t){return Promise.reject(t)}for(f=0,u=c.length;u>f;)l=l.then(c[f++],c[f++]);return l}getUri(t){return gt(Kt((t=Zt(this.defaults,t)).baseURL,t.url,t.allowAbsoluteUrls),t.params,t.paramsSerializer)}}at.forEach(["delete","get","head","options"],(function(t){Re.prototype[t]=function(e,n){return this.request(Zt(n||{},{method:t,url:e,data:(n||{}).data}))}})),at.forEach(["post","put","patch"],(function(t){function e(e){return function(n,o,r){return this.request(Zt(r||{},{method:t,headers:e?{"Content-Type":"multipart/form-data"}:{},url:n,data:o}))}}Re.prototype[t]=e(),Re.prototype[t+"Form"]=e(!0)}));const Oe=Re;class ke{constructor(t){if("function"!=typeof t)throw new TypeError("executor must be a function.");let e;this.promise=new Promise((function(t){e=t}));const n=this;this.promise.then((t=>{if(!n.u)return;let e=n.u.length;for(;e-- >0;)n.u[e](t);n.u=null})),this.promise.then=t=>{let e;const o=new Promise((t=>{n.subscribe(t),e=t})).then(t);return o.cancel=function(){n.unsubscribe(e)},o},t((function(t,o,r){n.reason||(n.reason=new Bt(t,o,r),e(n.reason))}))}throwIfRequested(){if(this.reason)throw this.reason}subscribe(t){this.reason?t(this.reason):this.u?this.u.push(t):this.u=[t]}unsubscribe(t){if(!this.u)return;const e=this.u.indexOf(t);-1!==e&&this.u.splice(e,1)}toAbortSignal(){const t=new AbortController,e=e=>{t.abort(e)};return this.subscribe(e),t.signal.unsubscribe=()=>this.unsubscribe(e),t.signal}static source(){let t;return{token:new ke((function(e){t=e})),cancel:t}}}const Te=ke,Ee={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511};Object.entries(Ee).forEach((([t,e])=>{Ee[e]=t}));const Se=Ee,Ae=function t(e){const n=new Oe(e),o=b(Oe.prototype.request,n);return at.extend(o,Oe.prototype,n,{allOwnKeys:!0}),at.extend(o,n,null,{allOwnKeys:!0}),o.create=function(n){return t(Zt(e,n))},o}(Pt);Ae.Axios=Oe,Ae.CanceledError=Bt,Ae.CancelToken=Te,Ae.isCancel=qt,Ae.VERSION="1.10.0",Ae.toFormData=mt,Ae.AxiosError=ct,Ae.Cancel=Ae.CanceledError,Ae.all=function(t){return Promise.all(t)},Ae.spread=function(t){return function(e){return t.apply(null,e)}},Ae.isAxiosError=function(t){return at.isObject(t)&&!0===t.isAxiosError},Ae.mergeConfig=Zt,Ae.AxiosHeaders=zt,Ae.formToJSON=t=>$t(at.isHTMLForm(t)?new FormData(t):t),Ae.getAdapter=me,Ae.HttpStatusCode=Se,Ae.default=Ae;const je=Ae,{Axios:$e,AxiosError:Ne,CanceledError:Pe,isCancel:Ce,CancelToken:Ue,VERSION:Fe,all:De,Cancel:Le,isAxiosError:Ie,spread:ze,toFormData:Me,AxiosHeaders:qe,HttpStatusCode:Be,formToJSON:_e,getAdapter:He,mergeConfig:Ve}=je,Xe=new class{constructor(){this.scopeAttribute="",this.scopeBody="",this.scopedKeyframes=new Map}parse(t,e){return this.scopeAttribute=`[vrefof="${e}"]`,this.scopeBody=`[vref="${e}"]`,this.scopedKeyframes.clear(),this.scopeSuffix=e.replace(/[^a-zA-Z0-9]/g,""),t=this.removeComments(t),this.collectKeyframes(t),this.parseRules(t)}collectKeyframes(t){const e=/@keyframes\s+([^\s{]+)/gi;let n;for(;null!==(n=e.exec(t));){const t=n[1],e=t+"-"+this.scopeSuffix;this.scopedKeyframes.set(t,e)}}removeComments(t){return t.replace(/\/\*[\s\S]*?\*\//g,"")}parseRules(t){let e="",n=0;for(;n=t.length)break;if("@"===t[n]){const o=this.parseAtRule(t,n);e+=o.content,n=o.endIndex}else{const o=this.parseNormalRule(t,n);e+=o.content,n=o.endIndex}}return e}parseAtRule(t,e){let n=e,o="";for(;n=t.length)return{content:o,endIndex:n};const r=o.toLowerCase().trim();if(r.startsWith("@keyframes"))return this.parseKeyframes(t,e);if(r.startsWith("@media"))return this.parseMedia(t,e);if(r.startsWith("@supports"))return this.parseSupports(t,e);{const e=this.findMatchingBrace(t,n);return{content:o+e.content,endIndex:e.endIndex}}}parseKeyframes(t,e){let n=e,o="";for(;n=t.length)return{content:o,endIndex:n};const r=this.findMatchingBrace(t,n),i=r.content,s=this.extractKeyframeName(o),a=this.scopedKeyframes.get(s);return a&&(o=o.replace(s,a)),o+=i,{content:o,endIndex:r.endIndex}}extractKeyframeName(t){const e=t.match(/@keyframes\s+([^\s{]+)/i);return e?e[1]:""}parseMedia(t,e){let n=e,o="";for(;n=t.length)return{content:o,endIndex:n};o+="{",n++;let r=1,i="";for(;n0;){if("{"===t[n])r++;else if("}"===t[n]&&(r--,0===r))break;i+=t[n],n++}return o+=this.parseRules(i),n=t.length)return{content:o,endIndex:n};const r=this.addScopeToSelector(o.trim()),i=this.findMatchingBrace(t,n);return{content:r+this.processRuleContent(i.content),endIndex:i.endIndex}}processRuleContent(t){let e=t;return e=e.replace(/animation\s*:\s*([^;]+);/gi,((t,e)=>`animation: ${this.processAnimationValue(e)};`)),e=e.replace(/animation-name\s*:\s*([^;]+);/gi,((t,e)=>`animation-name: ${this.processAnimationNames(e)};`)),e}processAnimationValue(t){return t.split(",").map((t=>t.trim())).map((t=>{const e=t.split(/\s+/);for(let n=0;n{const e=t.trim();return this.scopedKeyframes.get(e)||e})).join(", ")}addScopeToSelector(t){return t.trim()?t.split(",").map((t=>t.trim())).map((t=>this.addScopeToSingleSelector(t))).join(", "):t}addScopeToSingleSelector(t){if(!t.trim())return t;if(t.includes("::")){const e=t.split("::"),n=e[0],o="::"+e.slice(1).join("::");return this.addScopeToSelectorPart(n)+o}if(t.includes(":")&&!t.includes("::")){const e=t.match(/^([^:]+)(:.+)$/);if(e){const t=e[1],n=e[2];return this.addScopeToSelectorPart(t)+n}}return"*"===t||t.startsWith("@")?t:this.addScopeToSelectorPart(t)}addScopeToSelectorPart(t){const e=/(\s*[>+~]\s*|\s+)/;if(e.test(t)){const n=t.split(e);if(/^body(?:$|[:\[ ])/.test(n[0]))return n[0]=this.scopeBody+n[0].slice(4),n.join("");if(/^:root(?:$|[:\[ ])/.test(n[0]))return n[0]=this.scopeBody+n[0].slice(5),n.join("");for(let t=n.length-1;t>=0;t--)if(n[t].trim()&&!e.test(n[t])){let e=n[t].trim();n[t]=/^body(?:$|[:\[ ])/.test(e)?this.scopeBody+e.slice(4):/^:root(?:$:[$:\[ ])/.test(e)?this.scopeBody+e.slice(5):n[t].trim()+this.scopeAttribute;break}return n.join("")}let n=(t=t.trim()).trim();return/^body(?:$|[:\[ ])/.test(n)?this.scopeBody+n.slice(4):/^:root(?:$:[$:\[ ])/.test(n)?this.scopeBody+n.slice(5):n+this.scopeAttribute}findMatchingBrace(t,e){let n=e,o="",r=0;for(;n{this.removeMessage(s),i&&i()},s.appendChild(t)}return this.container.appendChild(s),setTimeout((()=>{s.classList.add("show")}),10),o>0&&setTimeout((()=>{this.removeMessage(s),i&&i()}),o),s}removeMessage(t){t&&t.parentNode&&(t.classList.remove("show"),setTimeout((()=>{t.parentNode&&t.parentNode.removeChild(t)}),300))}success(t,e={}){return this.createMessage("success",t,e)}warning(t,e={}){return this.createMessage("warning",t,e)}error(t,e={}){return this.createMessage("error",t,e)}info(t,e={}){return this.createMessage("info",t,e)}h(t,e={}){return new Promise(((n,o)=>{const{title:r="\u63d0\u793a",type:i="confirm",inputValue:s="",confirmText:a="\u786e\u5b9a",cancelText:c="\u53d6\u6d88",onConfirm:l=null,onCancel:u=()=>{n("")}}=e,f=document.createElement("div");f.className="prompt-overlay";const h=document.createElement("div");h.className="prompt-dialog";const d=document.createElement("div");d.className="prompt-header";const p=document.createElement("h3");p.className="prompt-title",p.textContent=r;const m=document.createElement("button");m.className="prompt-close",m.innerHTML="×",d.appendChild(p),d.appendChild(m);const w=document.createElement("div");w.className="prompt-body";const y=document.createElement("div");y.className="prompt-content",y.textContent=t,w.appendChild(y);let b=null;"input"===i&&(b=document.createElement("input"),b.className="prompt-input",b.type="text",b.value=s,w.appendChild(b));const v=document.createElement("div");v.className="prompt-footer";const g=document.createElement("button");g.className="prompt-btn prompt-btn-cancel",g.textContent=c;const x=document.createElement("button");x.className="prompt-btn prompt-btn-confirm",x.textContent=a,v.appendChild(g),v.appendChild(x),h.appendChild(d),h.appendChild(w),h.appendChild(v),f.appendChild(h),document.body.appendChild(f),setTimeout((()=>{f.classList.add("show")}),10),b&&setTimeout((()=>{b.focus()}),300);const R=(t=null)=>(f.classList.remove("show"),setTimeout((()=>{f.parentNode&&f.parentNode.removeChild(f)}),300),t);m.onclick=()=>{R(),u?u():o(Error("cancelled"))},g.onclick=()=>{R(),u?u():o(Error("cancelled"))},x.onclick=()=>{const t=!b||b.value;R(),n(t),l&&l(t)};const O=t=>{"Escape"===t.key&&(R(),u?u():o(Error("cancelled")),document.removeEventListener("keydown",O))};document.addEventListener("keydown",O),f.onclick=t=>{t.target===f&&(R(),u?u():o(Error("cancelled")))}}))}confirm(t,e={}){return this.h(t,{...e,type:"confirm"})}prompt(t,e,n={}){return this.h(t,{...n,type:"input",inputValue:e})}};var We={},Ke={};const Ge={};function Ze(t,e){Array.from(t.childNodes).forEach((t=>{1===t.nodeType&&(t.setAttribute("vrefof",e),Ze(t,e))}))}async function Ye(t,e,n,o){void 0===n&&(n="#"+function(){let t=(new Date).getTime().toString(36);t.length>4&&(t=t.substring(t.length-4));let e="";for(let n=0;4>n;n++)e+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".charAt(Math.floor(52*Math.random()));return e+t.padStart(4,"0")}()),n.endsWith(".html")&&(n=n.slice(0,-5));let r=(new DOMParser).parseFromString(t,"text/html");if(r.body.hasAttribute("root")&&!o)throw Error("HTTP error! status: 404");let i={url:n,heads:[],body:document.createElement("div"),setup:void 0,scripts:[],styles:"",txt:t,env:e,tmp:r,customAttrs:{}};if(i.heads=Array.from(r.querySelector("head")?.children),n&&(r.querySelectorAll("style").forEach((t=>{null===t.getAttribute("unscoped")?i.styles+=Xe.parse(t.innerHTML,n):i.styles+=t.innerHTML})),i.styles)){const t=document.createElement("style");t.innerHTML=i.styles,t.setAttribute("vref",n),document.head.appendChild(t)}return i.body.append(...r.querySelector("body").childNodes),i.body.querySelectorAll("script").forEach((t=>{""!=t.innerHTML.trim()?(t.hasAttribute("setup")?i.setup=t:t.hasAttribute("novyes")||i.scripts.push(t),t.remove()):t.remove()})),Array.from(r.body.attributes).forEach((t=>{/^[a-zA-Z]/.test(t.name)?i.body.setAttribute(t.name,t.value):i.customAttrs[t.name]=t.value})),i.body.setAttribute("vref",n),Ze(i.body,n),o||await async function(t,e){for(let n of t.heads){let o=n.nodeName.toLowerCase();"link"===o?tn(n,e):"script"===o?await Qe(n,e):"title"===o&&(t.title=n.innerText)}}(i,e),i}function Qe(t,e){let n=t.getAttribute("src"),o=t.getAttribute("key"),r=e?.root;if(r&&n.startsWith("/")&&(n=r+n),n.startsWith("@")&&(n=n.slice(1)),n&&document.querySelector(`script[src="${n}"]`))return;if(o&&document.querySelector(`script[key="${o}"]`))return;let i=document.createElement("script");return i.src=n,i.key=o,i.type=t.getAttribute("type")||"text/javascript",new Promise(((t,e)=>{i.onload=()=>{t(i)},i.onerror=()=>e(Error("Failed to load script "+n)),document.head.appendChild(i)}))}async function tn(t,e){let n=t.getAttribute("href"),o=t.getAttribute("key"),r=e?.root;r&&n.startsWith("/")&&(n=r+n),n.startsWith("@")&&(n=n.slice(1)),n&&document.querySelector(`link[href="${n}"]`)||o&&document.querySelector(`link[key="${o}"]`)||(t.setAttribute("href",n),document.head.append(t))}const en={FetchUI:async function(t,e,n){t&&"/"!==t||(t="/root.html"),t.startsWith("http")||t.startsWith("@")||t.startsWith("/")||(t="/"+t);let o=e?.root;if(o&&t.startsWith("/")&&(t=o+t),t.startsWith("@")&&(t=t.slice(1)),We[t])return Promise.resolve(We[t]);if(Ke[t])return Ke[t];let r={};const i=fetch(t+"?random="+Math.random()).then((async e=>{if(!e.ok)throw Error("HTTP error! status: "+e.status);for(const[t,i]of e.headers.entries())t.startsWith("vyes-")&&(r[t.slice(5)]=i);let n=r.root||"";t.startsWith("http")&&(n=new URL(t).origin+n,r.root=n);let o=await async function(t,e){if(!Ge[t=t||""]){let n=t.startsWith("http")?t:window.location.origin+t;Ge[t]=Object.assign({},e,{root:t,$G:w.Wrap({}),$bus:new y,$axios:je.create({baseURL:n}),$message:Je,$router:null,$emit:null}),t===$vyes.root||null===$vyes.root?Ge[t].$router=$vyes.$router:Ge[t].$router={addRoutes:()=>{},beforeEnter:()=>{}};try{await(await import(n+"/env.js")).default(Ge[t])}catch(b){}}return Ge[t]}(n,r);return Object.assign(r,o),e.text()})).then((e=>Ye(e,r,t,n))).then((e=>(We[t]=e,e))).catch((e=>{e.message;let n=document.createElement("div");n.style.cssText="\n backgound:#aaa;\n height:100%;\n width: 100%;\n display:grid;\n place-items: center;\n",n.innerHTML=`\n
\n
404
\n

${t}

\n
\n`;let o={heads:[],body:n,setup:"",scripts:[],styles:"",txt:"",tmp:"",env:r,err:e};return We[t]=o,o})).finally((()=>{delete Ke[t]}));return Ke[t]=i,i},FetchFile:async function(t){return fetch(t).then((t=>{if(!t.ok)throw Error("HTTP error! status: "+t.status);return t.text()}))},LoadScript:Qe,LoadLink:tn,ParseUI:Ye};function nn(t,e){let n,o;if(t.startsWith("http://")||t.startsWith("https://")){if(n=new URL(t),n.origin!==window.location.origin)return null;n.pathname.startsWith(e)&&(o=n.pathname.slice(e.length))}else n=new URL(t,window.location.href),o=n.pathname;const r={};return n.searchParams.forEach(((t,e)=>{r[e]=t})),{path:o,query:r,hash:n.hash}}class on{constructor(t,e){this.originalPath=t,this.name=e,this.keys=[],this.regexp=this.pathToRegexp(t)}pathToRegexp(t){let e=t.replace(/:([^(/]+)/g,((t,e)=>(this.keys.push(e),`(?<${e}>[^/]+)`)));return e=e.replace(/\*(\w+)/g,((t,e)=>(this.keys.push(e),`(?<${e}>.*)`))),e=e.replace(/\*/g,".*"),RegExp(`^${e}$`)}match(t){let e;if("string"==typeof t)e=t;else{if(!t||"object"!=typeof t)return null;if(!t.path)return t.name&&t.name===this.name?{path:this.originalPath,params:t.params||{},matched:this.originalPath}:null;e=t.path}const n=this.regexp.exec(e);if(!n)return null;const o={};return this.keys.forEach((t=>{n.groups?.[t]&&(o[t]=n.groups[t])})),{path:this.originalPath,params:o,matched:n[0]}}}const rn=new Map;class sn{constructor(t,e,n){this.vyes=t,this.node=e,this.layoutDom=void 0,this.matchedRoute=n,this.htmlPath=this.resolveHtmlPath(n)}resolveHtmlPath(t){let e=t.route.component||t.route.path;return"function"==typeof e&&(e=e(t.path)),Object.entries(t.params).forEach((([t,n])=>{e=e.replace(":"+t,n)})),e.startsWith("/")||(e="/"+e),e.endsWith("/")&&(e=e.slice(0,-1)),e.endsWith(".html")||(e+=".html"),e}async mount(t,e,n){const o=await en.FetchUI(this.htmlPath,t);if(o.err){let n=document.createElement("div");return Object.assign(n.style,{width:"100%",height:"100%"}),n.append(...e),this.node.innerHTML="",this.node.append(n),void this.vyes.parseRef(this.htmlPath,n,{},t,null,!0)}this.title=o.title||"";const r={},i=document.createElement("div");if(i.setAttribute("vsrc",this.htmlPath),r[""]=[i],this.slots=r,!n)return this.node.innerHTML="",this.node.append(i),void this.vyes.parseRef(this.htmlPath,i,{},t,null);let s=rn.get(n);if(s)this.layoutDom=s,this.activate();else{let e=n;e.startsWith("/")||(e="/"+n),e.endsWith(".html")||(e+=".html"),e.startsWith("/layout")||(e="/layout"+e);const o=await en.FetchUI(e,t);if(o.err)return this.node.innerHTML="",this.node.append(i),void this.vyes.parseRef(this.htmlPath,i,{},t,null);s=o.body.cloneNode(!0),rn.set(n,s),i.$refData=w.Wrap({}),s.$refSlots=w.Wrap({...r}),this.node.innerHTML="",this.node.append(s),this.layoutDom=s,this.vyes.parseRef("/layout/"+n,s,{},t,null,!0)}}activate(){this.title&&(document.title=this.title);const t=this.layoutDom;if(t)t.querySelectorAll("vslot").forEach((e=>{e.closest("[vref]")===t&&this.slots[e.getAttribute("name")||""]&&(e.innerHTML="")})),Object.keys(t.$refSlots).forEach((e=>{delete t.$refSlots[e]})),Object.assign(t.$refSlots,this.slots),t.isConnected||(this.node.innerHTML=""),this.node.append(t);else{this.node.innerHTML="";const t=this.slots[""];t instanceof Array?this.node.append(...t):this.node.append(t)}}}const an=new class{#t=[];#e=[];#n=null;#o="";#r=[];#i=new Map;#s=null;#a=null;#c=[];#l=!1;#u=null;#f=new Map;constructor(){this.init()}get routes(){return this.#t.slice()}get history(){return this.#e.slice()}get current(){return this.#n}get query(){return this.#n?.query||{}}get params(){return this.#n?.params||{}}get root(){return this.#o}onChange(t){this.#r.push(t)}addRoute(t){if(!t.path)throw Error("Route must have a path");"/"!=t.path&&t.path.endsWith("/")&&(t.path=t.path.slice(0,-1));const e={path:t.path,component:t.component,name:t.name,meta:t.meta||{},children:t.children||[],matcher:new on(t.path,t.name),description:t.description||"",layout:t.layout||""};this.#t.push(e),t.name&&this.#f.set(t.name,e),t.children?.length>0&&t.children.forEach((n=>{const o=t.path+(n.path.startsWith("/")?n.path:"/"+n.path),r=n.layout||t.layout||"",i={...t.meta,...n.meta};this.addRoute({...n,path:o,parent:e,layout:r,meta:i})}))}addRoutes(t){t.forEach((t=>this.addRoute(t)))}#h(t,e){this.#r.forEach((n=>{if("function"==typeof n)try{n(t,e)}catch(o){}}))}#d(t){const e=this.#n;this.#n={path:t.path,fullPath:t.fullPath,params:t.params||{},query:t.query||{},hash:new URL(t.fullPath,window.location.origin).hash,meta:t.route?.meta||{},description:t.route?.description||"",layout:t.route?.layout||"",name:t.route?.name,matched:t.route?[t.route]:[]},this.#e.push(this.#n),this.#o&&!t.fullPath.startsWith("http")?history.pushState({},"",this.#o+t.fullPath):history.pushState({},"",t.fullPath),this.#h(this.#n,e)}matchRoute(t){const e=this.normalizeRouteTarget(t);if(!e)return null;const{path:n,query:o,params:r,name:i}=e;if(i){const t=this.#f.get(i);if(!t)return null;let e=t.path;Object.entries(r).forEach((([t,n])=>{e=e.replace(":"+t,n)}));const n=t.matcher.match(e);return n?{route:t,params:{...n.params,...r},matched:n.matched,path:e,query:o,name:i}:null}for(const s of this.#t){const t=s.matcher.match(n);if(t&&s.component)return{route:s,params:{...t.params,...r},matched:t.matched,description:s.description,layout:s.layout,path:n,query:o,name:s.name}}return null}normalizeRouteTarget(t){let e,n,o={},r={},i="";if("string"==typeof t){const n=nn(t,this.#o);if(!n)return null;e=n.path,o={...n.query},i=n.hash}else{if(!t||"object"!=typeof t)return null;if(t.path){const n=nn(t.path,this.#o);if(!n)return null;e=n.path,o={...n.query,...t.query||{}},i=t.hash||n.hash,r=t.params||{}}else{if(!t.name)return null;n=t.name,o=t.query||{},r=t.params||{},i=t.hash||""}}return e&&!e.startsWith("/")&&(e="/"+e),this.#o&&(e=e.startsWith(this.#o)?e.slice(this.#o.length):e),e.startsWith("/")||(e="/"+e),"/"!=e&&e.endsWith("/")&&(e=e.slice(0,-1)),{path:e,query:o,params:r,hash:i,name:n}}matchTo(t){const e=this.matchRoute(t);if(!e)return null;const{route:n,params:o,query:r,path:i,name:s}=e;let a="";r&&Object.keys(r).length>0&&(a="?"+Object.entries(r).map((([t,e])=>`${encodeURIComponent(t)}=${encodeURIComponent(e)}`)).join("&"));const c=(i||e.path)+a;return{route:n,params:o,query:r,name:s||n.name,path:i||e.path,fullPath:c,matched:[n]}}buildUrl(t,e={}){const n=new URL(t,window.location.origin);return Object.entries(e).forEach((([t,e])=>{n.searchParams.append(t,e)})),n}resolveRoutePath(t,e={}){let n=t.component||t.path;return Object.entries(e).forEach((([t,e])=>{n=n.replace(":"+t,e)})),"/"!==n&&""!==n||(n="/index"),n.startsWith("/")||(n="/"+n),n.endsWith(".html")&&(n=n.slice(0,-5)),n.endsWith("/")&&(n=n.slice(0,-1)),n}async#p(t){if(!t)return;const{route:e,params:n,query:o}=t,r={path:t.path,fullPath:t.fullPath,params:n,query:o,hash:new URL(t.fullPath,window.location.origin).hash,meta:e.meta,description:e.description,layout:e.layout,name:e.name,matched:[e]};if(this.beforeEnter)try{let t=!0;if(!1===await this.beforeEnter(r,this.#n,(e=>{e&&(t=!1,this.push(e))}))||!t)return}catch(a){return}const i=t.fullPath;let s=this.#i.get(i);this.#d(t),s?s.activate():(s=new sn(this.#u,this.#s,t),await s.mount(this.#a,this.#c,r.layout),this.#i.set(i,s))}async push(t){const e=this.matchTo(t);e?await this.#p(e):"string"==typeof t||t.path||t.name}replace(t){this.push(t),this.#e.length>1&&this.#e.splice(-2,1)}go(t){history.go(t)}back(){history.back()}forward(){history.forward()}init(){this.#l||(this.#l=!0,document.body.addEventListener("click",(t=>{const e=t.target.closest("a");if(!e)return;const n=e.getAttribute("href");!n||n.startsWith("http")||n.startsWith("#")||(t.preventDefault(),e.hasAttribute("reload")?window.location.href=n:this.push(n))}),!0),window.addEventListener("popstate",(()=>{this.push(window.location.href)})))}ParseVrouter(t,e,n){this.#s=e,this.#a=n,this.#o=n.root||"",this.#c=Array.from(e.childNodes),this.#u=t,this.push(window.location.href)}},cn={$router:an},ln=[];document.addEventListener("click",(t=>{ln.forEach((e=>{e?.dom instanceof Element&&"function"==typeof e?.callback&&(e.dom.contains(t.target)||e.callback(t))}))}));const un={CamelToKebabCase:function(t){return 0===t.length?"":t.charAt(0).toLowerCase()+t.slice(1).replace(/([A-Z])/g,(function(t,e){return"-"+e.toLowerCase()}))},EventsList:["load","unload","beforeunload","resize","scroll","submit","reset","input","change","focus","blur","keydown","keypress","keyup","click","dblclick","contextmenu","mousedown","mouseup","mousemove","mouseover","mouseout","mouseenter","mouseleave","touchstart","touchmove","touchend","touchcancel","drag","dragstart","dragend","dragover","dragenter","dragleave","drop","copy","cut","paste","animationstart","animationend","animationiteration","transitionend","abort","error","loadstart","progress","play","pause","ended","volumechange","timeupdate","loadeddata","waiting","playing","online","offline","storage","visibilitychange"],BindInputDomValue:function(t,e,n,o){const r="string"==typeof t?document.querySelector(t):t;if(r){switch(r.type||r.tagName.toLowerCase()){case"text":case"password":case"email":case"tel":case"url":case"search":case"number":case"range":case"color":case"date":case"time":case"datetime-local":case"month":case"week":case"hidden":case"textarea":o((()=>{r.value=e[n]})),r.addEventListener("input",(function(){e[n]=this.value}));break;case"checkbox":o((function(){r.checked=!!e[n]})),r.addEventListener("change",(function(){e[n]=this.checked}));break;case"radio":o((()=>{r.checked=r.value===e[n]})),r.addEventListener("change",(function(){this.checked&&(e[n]=this.value)}));break;case"select-one":case"select-multiple":o((()=>{let t=e[n];if(r.multiple){const e=Array.isArray(t)?t:[];for(let t=0;t{if("outer"===e){let e=ln.length;return ln.push({dom:t,callback:n}),()=>{ln[e]=null}}}},fn=async t=>navigator.clipboard&&navigator.clipboard.writeText?navigator.clipboard.writeText(t):(prompt("http\u73af\u5883\u65e0\u6cd5\u81ea\u52a8\u590d\u5236\uff0c\u8bf7\u624b\u52a8\u590d\u5236\u5185\u5bb9\u5230\u526a\u8d34\u677f:",t),new Promise((t=>{})));class hn{postMessage=(t,e)=>{};constructor(t={}){this.options={highlightColor:"#007bff",overlayColor:"rgba(0, 123, 255, 0.1)",borderWidth:"2px",zIndex:1e4,showTagName:!0,...t},this.isActive=!1,this.selectedElement=null,this.currentHoverElement=null,this.overlay=null,this.selectedOverlay=null,this.tooltip=null,this.selectedTooltip=null,this.actionPanel=null,this.originalCursor="",this.init()}init(){this.createStyles(),this.bindEvents()}createStyles(){const t=document.createElement("style");t.textContent=`\n .div-selector-overlay {\n position: fixed;\n pointer-events: none;\n border: ${this.options.borderWidth} solid ${this.options.highlightColor};\n background: ${this.options.overlayColor};\n z-index: ${this.options.zIndex};\n transition: all 0.2s ease;\n box-sizing: border-box;\n }\n \n .div-selector-selected {\n position: fixed;\n pointer-events: none;\n border: ${this.options.borderWidth} solid #28a745;\n background: rgba(40, 167, 69, 0.1);\n z-index: ${this.options.zIndex-1};\n box-sizing: border-box;\n }\n \n .div-selector-tooltip {\n position: fixed;\n background: rgba(51, 51, 51, 0.95);\n cursor:pointer;\n color: white;\n padding: 8px 12px;\n border-radius: 6px;\n font-size: 12px;\n font-family: 'Consolas', 'Monaco', 'Courier New', monospace;\n z-index: ${this.options.zIndex+1};\n user-select: none;\n box-shadow: 0 2px 8px rgba(0,0,0,0.3);\n border: 1px solid rgba(255,255,255,0.1);\n backdrop-filter: blur(4px);\n }\n \n .div-selector-tooltip.hover {\n background: rgba(0, 123, 255, 0.9);\n }\n \n .div-selector-tooltip.selected {\n background: rgba(40, 167, 69, 0.9);\n border-color: rgba(40, 167, 69, 0.3);\n }\n \n .div-selector-actions {\n position: fixed;\n background: white;\n border: 1px solid #ddd;\n border-radius: 8px;\n padding: 8px;\n z-index: ${this.options.zIndex+2};\n box-shadow: 0 4px 16px rgba(0,0,0,0.15);\n display: flex;\n gap: 6px;\n min-width: 30px;\n backdrop-filter: blur(8px);\n }\n \n .div-selector-btn {\n padding: 4px 6px;\n border: 1px solid #ddd;\n background: white;\n border-radius: 6px;\n cursor: pointer;\n font-size: 12px;\n transition: all 0.2s ease;\n text-align: left;\n white-space: nowrap;\n }\n \n .div-selector-btn:hover {\n background: #f8f9fa;\n transform: translateX(2px);\n }\n \n .div-selector-btn.danger {\n color: #dc3545;\n border-color: #dc3545;\n }\n \n .div-selector-btn.danger:hover {\n background: #dc3545;\n color: white;\n }\n \n .div-selector-btn.primary {\n background: #007bff;\n color: white;\n border-color: #007bff;\n }\n \n .div-selector-btn.primary:hover {\n background: #0056b3;\n }\n \n .div-selector-active {\n cursor: crosshair !important;\n }\n `,document.head.appendChild(t)}bindEvents(){this.handleMouseMove=this.handleMouseMove.bind(this),this.handleClick=this.handleClick.bind(this),this.handleScroll=this.handleScroll.bind(this),this.handleResize=this.handleResize.bind(this)}activate(){this.isActive||(this.isActive=!0,this.originalCursor=document.body.style.cursor,document.body.classList.add("div-selector-active"),document.addEventListener("mousemove",this.handleMouseMove),document.addEventListener("click",this.handleClick),window.addEventListener("scroll",this.handleScroll),window.addEventListener("resize",this.handleResize),this.createOverlay(),this.createTooltip())}deactivate(){this.isActive&&(this.isActive=!1,document.body.style.cursor=this.originalCursor,document.body.classList.remove("div-selector-active"),document.removeEventListener("mousemove",this.handleMouseMove),document.removeEventListener("click",this.handleClick),window.removeEventListener("scroll",this.handleScroll),window.removeEventListener("resize",this.handleResize),this.removeOverlay(),this.removeTooltip())}handleMouseMove(t){if(!this.isActive)return;const e=document.elementFromPoint(t.clientX,t.clientY);if(!e)return;if(this.isPluginElement(e))return;const n="DIV"===e.tagName?e:e.closest("div,[vref]");n&&!this.isPluginElement(n)&&this.selectedElement!==n&&(this.currentHoverElement=n,this.highlightElement(n),this.updateHoverTooltip(n))}handleClick(t){if(!this.isActive)return;const e=document.elementFromPoint(t.clientX,t.clientY);if(!e)return;if(this.isPluginElement(e))return;t.preventDefault(),t.stopPropagation();const n="DIV"===e.tagName?e:e.closest("div");n&&!this.isPluginElement(n)&&(this.selectElement(n),this.deactivate())}handleScroll(){this.selectedElement&&(this.updateSelectedOverlay(),this.updateSelectedTooltip(),this.updateActionPanelPosition()),this.currentHoverElement&&!this.selectedElement&&(this.highlightElement(this.currentHoverElement),this.updateHoverTooltip(this.currentHoverElement))}handleResize(){this.selectedElement&&(this.updateSelectedOverlay(),this.updateSelectedTooltip(),this.updateActionPanelPosition())}isPluginElement(t){return t.closest(".div-selector-overlay, .div-selector-selected, .div-selector-tooltip, .div-selector-actions")}createOverlay(){this.overlay=document.createElement("div"),this.overlay.className="div-selector-overlay",this.overlay.style.display="none",document.body.appendChild(this.overlay)}createSelectedOverlay(){this.selectedOverlay=document.createElement("div"),this.selectedOverlay.className="div-selector-selected",document.body.appendChild(this.selectedOverlay)}createTooltip(){this.tooltip=document.createElement("div"),this.tooltip.className="div-selector-tooltip hover",this.tooltip.style.display="none",document.body.appendChild(this.tooltip)}createSelectedTooltip(){this.selectedTooltip=document.createElement("div"),this.selectedTooltip.className="div-selector-tooltip selected",document.body.appendChild(this.selectedTooltip)}highlightElement(t){if(!this.overlay)return;const e=t.getBoundingClientRect();this.overlay.style.display="block",this.overlay.style.left=e.left+"px",this.overlay.style.top=e.top+"px",this.overlay.style.width=e.width+"px",this.overlay.style.height=e.height+"px"}updateHoverTooltip(t){if(!this.tooltip)return;const e=this.getElementInfo(t),n=t.getBoundingClientRect();this.tooltip.textContent=e,this.tooltip.style.display="block";let o=n.left-8,r=n.top-this.tooltip.offsetHeight-8;0>o&&(o=8),0>r&&(r=n.top+8),this.tooltip.style.left=o+"px",this.tooltip.style.top=r+"px"}selectElement(t){this.clearSelection(),this.selectedElement=t,this.createSelectedOverlay(),this.createSelectedTooltip(),this.updateSelectedOverlay(),this.updateSelectedTooltip(),this.overlay&&(this.overlay.style.display="none"),this.tooltip&&(this.tooltip.style.display="none"),this.showActionPanel()}updateSelectedOverlay(){if(!this.selectedOverlay||!this.selectedElement)return;const t=this.selectedElement.getBoundingClientRect();this.selectedOverlay.style.left=t.left+"px",this.selectedOverlay.style.top=t.top+"px",this.selectedOverlay.style.width=t.width+"px",this.selectedOverlay.style.height=t.height+"px"}updateSelectedTooltip(){if(!this.selectedTooltip||!this.selectedElement)return;const t=this.getElementInfo(this.selectedElement);let e=this.getFilePath(this.selectedElement);const n=this.selectedElement.getBoundingClientRect();this.selectedTooltip.addEventListener("click",(t=>{e&&this.postMessage("fs-open",e),t.preventDefault(),t.stopPropagation()})),this.selectedTooltip.textContent="\u2713 "+t;let o=n.left-8,r=n.top-this.selectedTooltip.offsetHeight-8;0>o&&(o=8),0>r&&(r=n.top+8),this.selectedTooltip.style.left=o+"px",this.selectedTooltip.style.top=r+"px"}showActionPanel(){this.removeActionPanel();const t=this.selectedElement.getBoundingClientRect();this.actionPanel=document.createElement("div"),this.actionPanel.className="div-selector-actions";let e=t.right-180,n=t.top+6;e+180>window.innerWidth&&(e=t.left-180-8),0>e&&(e=8),n+40>window.innerHeight&&(n=window.innerHeight-40-8),0>n&&(n=8),this.actionPanel.style.left=e+"px",this.actionPanel.style.top=n+"px",[{text:"\ud83d\udccb",action:()=>this.copySelector(this.selectedElement)},{text:"x",action:()=>this.clearSelection()}].forEach((t=>{const e=document.createElement("button");e.className="div-selector-btn "+(t.class||""),e.textContent=t.text,e.onclick=t.action,this.actionPanel.appendChild(e)})),document.body.appendChild(this.actionPanel)}updateActionPanelPosition(){if(!this.actionPanel||!this.selectedElement)return;const t=this.selectedElement.getBoundingClientRect(),e=this.actionPanel.offsetWidth,n=this.actionPanel.offsetHeight;let o=t.right-e+8,r=t.top-8;o+e>window.innerWidth&&(o=t.left-e-8),0>o&&(o=8),r+n>window.innerHeight&&(r=window.innerHeight-n-8),0>r&&(r=8),this.actionPanel.style.left=o+"px",this.actionPanel.style.top=r+"px"}clearSelection(){this.selectedElement=null,this.selectedOverlay&&(this.selectedOverlay.remove(),this.selectedOverlay=null),this.selectedTooltip&&(this.selectedTooltip.remove(),this.selectedTooltip=null),this.removeActionPanel()}getElementInfo(t){const e=t.getBoundingClientRect();let n=t.getAttribute("vref");return n||(n=t.closest("[vref]").getAttribute("vref"),n+="."+t.tagName.toLowerCase()),`${n} (${Math.round(e.width)}\xd7${Math.round(e.height)})`}getFilePath(t){let e=t.getAttribute("vref");return e||(e=t.closest("[vref]").getAttribute("vref")),e&&(e="/ui"+e+".html"),e}copySelector(t){let e=this.getFilePath(t);fn(e).then((()=>{this.showNotification("\ud83d\udccb CSS\u9009\u62e9\u5668\u5df2\u590d\u5236\u5230\u526a\u8d34\u677f")}))}copyXPath(t){const e=this.generateXPath(t);fn(e).then((()=>{this.showNotification("\ud83d\udd0d XPath\u5df2\u590d\u5236\u5230\u526a\u8d34\u677f")}))}viewStyles(t){const e=window.getComputedStyle(t);let n="\ud83d\udcca \u91cd\u8981\u6837\u5f0f\u5c5e\u6027:\n\n";["display","position","width","height","margin","padding","background-color","color","font-size","border","z-index","opacity"].forEach((t=>{n+=`${t}: ${e.getPropertyValue(t)}\n`})),alert(n)}showNotification(t){const e=document.createElement("div");e.style.cssText=`\n position: fixed;\n top: 20px;\n right: 20px;\n background: linear-gradient(135deg, #28a745, #20c997);\n color: white;\n padding: 12px 18px;\n border-radius: 8px;\n z-index: ${this.options.zIndex+10};\n font-size: 14px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.2);\n transform: translateX(100%);\n transition: transform 0.3s ease;\n `,e.textContent=t,document.body.appendChild(e),setTimeout((()=>{e.style.transform="translateX(0)"}),100),setTimeout((()=>{e.style.transform="translateX(100%)",setTimeout((()=>{e.remove()}),300)}),2500)}generateXPath(t){if(t.id)return`//*[@id="${t.id}"]`;const e=[];for(;t&&t.nodeType===Node.ELEMENT_NODE;){let n=0,o=!1,r=!1;for(let e=t.previousSibling;e;e=e.previousSibling)e.nodeType===Node.ELEMENT_NODE&&e.nodeName===t.nodeName&&(r=!0,n++);for(let e=t.nextSibling;e&&!o;e=e.nextSibling)e.nodeType===Node.ELEMENT_NODE&&e.nodeName===t.nodeName&&(o=!0);const i=t.nodeName.toLowerCase(),s=r||o?`[${n+1}]`:"";if(e.unshift(i+s),(t=t.parentNode)===document.body)break}return e.length?"/"+e.join("/"):null}removeOverlay(){this.overlay&&(this.overlay.remove(),this.overlay=null)}removeTooltip(){this.tooltip&&(this.tooltip.remove(),this.tooltip=null)}removeActionPanel(){this.actionPanel&&(this.actionPanel.remove(),this.actionPanel=null)}}let dn=!1,pn=null;const mn=(t,e)=>{dn&&("string"!=typeof e&&"number"!=typeof e||(e={value:e}),window.parent.postMessage(Object.assign({type:t,from:"vdev"},e),"*"))};!async function(){const t=document.createElement("style");t.innerHTML="\n [vref] {\n display: block;\n }\n [vparsing] {\n display: none;\n -webkit-text-fill-color: transparent;\n }\n vslot, vrouter {\n display: block;\n }\n",document.head.firstChild?document.head.insertBefore(t,document.head.firstChild):document.head.appendChild(t);const e=[],n=t=>{if(!t.isConnected)return;let n=t.getAttribute("vdelay");if(n){let o=e[n];o&&o(t)}};function o(t,e){const n=Function("sandbox",t=`with (sandbox) { ${t} }`);let o={data:null,key:null};const r=t=>new Proxy(t,{has:(t,e)=>!0,get(t,e,n){if(e===Symbol.unscopables)return;let i=Reflect.get(t,e,n);return o.data=t,o.key=e,"object"==typeof i&&i&&i[w.DataID]?r(i):i},set:(t,e,n,o)=>!1});return n(r(e)),o}new MutationObserver((function(t,e){t.forEach((function(t){for(let e of t.addedNodes)1===e.nodeType&&(n(e),e.querySelectorAll("*[vdelay]").forEach(n))}))})).observe(document.body,{attributes:!1,childList:!0,subtree:!0,characterData:!1});const r=/{{|}}/g,i=/^(\s*(\w+)\s+in\s+|\((\w+),\s*(\w+)\)\s+in\s+)([\w\?\$\.\[\]\(\)'"]+)$/;window.$vyes||(window.$vyes=new class{app=null;root=null;vget=en;vproxy=w;t=!0;$router=cn.$router;constructor(t){"string"==typeof t?this.app=document.getElementById(t):t instanceof HTMLElement?this.app=t:this.app=document.body,this.app&&(async()=>{let t=await en.FetchUI(window.location.pathname,{},!0);this.root=t.env?.root||"",t.env?.vdev&&window.self!==window.top&&(dn||(dn=!0,pn=new hn,mn("iframe-loaded"),pn.postMessage=mn,window.addEventListener("keyup",(t=>{"Escape"===t.key&&mn("key-esc")})),setTimeout((()=>{window.$vyes&&window.$vyes.$router&&$vyes.$router.onChange((t=>{mn("url-change",t.fullPath)}))}),100),window.addEventListener("message",(t=>{const e=t.data;if("vyes"==e.from)switch(e.type){case"reload":window.location.reload();break;case"magic":pn&&pn.isActive?pn.deactivate():pn&&pn.activate()}})))),this.parseRef("root",this.app,{},t.env||{},t,!0)})()}async parseDom(t,e={},n){if(n instanceof HTMLElement)throw Error("env error");let o=t.nodeName.toLowerCase();if(3===t.nodeType)return void this.parseTextNode(t,e,n);if(8===t.nodeType)return;if(1!==t.nodeType)return;if(t.hasAttribute("novyes")||t.vparsed)return;let r=t.getAttribute("v-for");if(null!==r)return void this.parseVfor(r,t,e,n);if(-1!==o.indexOf("-")){let r="/"+o.split("-").join("/"),i=t.hasAttribute("single");return this.parseRef(r,t,e,n,null,i),void(t.vparsed=!0)}if(t.getAttribute(":vsrc")){let o=t.getAttribute(":vsrc");t.removeAttribute(":vsrc");let r=Array.from(t.attributes).map((t=>({name:t.name,value:t.value}))),i=Array.from(t.childNodes);return void w.Watch((()=>{delete t.vparsed,t.setAttribute("vparsing","");let s=w.Run(o,e,n);s&&(Array.from(t.attributes).forEach((e=>{t.removeAttribute(e.name)})),t.innerHTML="",r.forEach((e=>{t.setAttribute(e.name,e.value)})),i.forEach((e=>{t.appendChild(e.cloneNode(!0))})),this.parseRef(s,t,e,n,null,!1),t.vparsed=!0)}))}if(t.getAttribute("vsrc")){let o=t.hasAttribute("single");return this.parseRef(t.getAttribute("vsrc"),t,e,n,null,o),void(t.vparsed=!0)}if("div"===o&&t.getAttribute("v-html")){let o=t.getAttribute("v-html");return t.removeAttribute("v-html"),t.innerHTML="",this.parseAttrs(t,e,n),t.vparsed=!0,void w.Watch((()=>{let r=w.Run(o,e,n);t.innerHTML=r;let i=this.parseVif(Array.from(t.childNodes),e,n);for(let t of i)this.parseDom(t,e,n)}))}if("vslot"===o)return this.parseSlots(t,e,n),void(t.vparsed=!0);if("vrouter"===o)return this.parseAttrs(t,e,n),void cn.$router.ParseVrouter(this,t,n);this.parseAttrs(t,e,n);let i=this.parseVif(Array.from(t.childNodes),e,n);for(let s of i)this.parseDom(s,e,n);t.vparsed=!0}onMountedRun(t,n,o=!0){if(o){if(t.isConnected)return void n(t);let o=e.push((t=>{t.removeAttribute("vdelay"),n(t)}));return void t.setAttribute("vdelay",o-1)}t.isConnected&&n(t);let r=e.push(n);t.setAttribute("vdelay",r-1)}AllENVs={};async parseRef(t,e,n,o,r,i=!1){e.setAttribute("vparsing","");let s=o,a=e.getAttribute("vrefof"),c=e.closest(`*[vref='${a}']`);c&&(o=c.$env),!r&&t&&(t.endsWith(".html")||(t+=".html"),r=await en.FetchUI(t,o,e.hasAttribute("root"))),o=Object.assign({},o,r?.env||{}),e.$env=o,e.$vsrc=t,o.$router=cn.$router,o.$emit=(t,...n)=>{if(t=t.toLowerCase(),!e.$vevent)return;let o=e.$vevent[t];o&&"function"==typeof o&&o(...n)};let l=await this.setupRef(e,n,s,r,i);i?this.parseAttrs(e,l,o,r?.customAttrs):this.parseAttrs(e,n,s,r?.customAttrs);let u=this.parseVif(Array.from(e.childNodes),l,o);for(let f of u)this.parseDom(f,l,o);e.removeAttribute("vparsing"),this.mountRef(e,l,o,r)}async setupRef(t,e,n,r,i=!1){let s=w.Wrap({});if(r.setup){let e=r.setup.innerHTML;e=await w.ParseImport(e,s,t.$env,t.$vsrc),await w.AsyncRun(e,s,t.$env,{$node:t,$watch:t=>{setTimeout((()=>{w.Watch(t)}),50)}})}if(t.$refScope=e,t.$refData=s,i)return s;if(!t.$refSlots){let e=w.Wrap({});t.childNodes.forEach((t=>{let n=t.getAttribute?t.getAttribute("vslot"):"";n=n||"",e[n]||(e[n]=[]),e[n].push(t)})),t.$refSlots=e}t.innerHTML="";let a=r.body.cloneNode(!0);t.append(...a.childNodes),Object.keys(s).forEach((r=>{const i=un.CamelToKebabCase(r);if("boolean"==typeof s[r]?(t.hasAttribute(r)||t.hasAttribute(i))&&(s[r]=!0):t.hasAttribute(r)?s[r]=t.getAttribute(r):t.hasAttribute(i)&&(s[r]=t.getAttribute(i)),t.hasAttribute(":"+r)||t.hasAttribute(":"+i)){let o=t.getAttribute(":"+r)||t.getAttribute(":"+i);t.removeAttribute(":"+r),t.removeAttribute(":"+i),w.Watch((()=>{s[r]=o?w.Run(o,e,n):e[r]}))}if(t.hasAttribute("v:"+r)||t.hasAttribute("v:"+i)){let n=t.getAttribute("v:"+r)||t.getAttribute("v:"+i);t.removeAttribute("v:"+r),t.removeAttribute("v:"+i),n||(n=r);let a=o(n,e);if(a.data&&a.key){let t=a.key,e=a.data;void 0!==e[t]&&null!==e[t]||(e[t]=s[r]),w.Watch((()=>{s[r]=e[t]})),w.Watch((()=>{e[t]=s[r]}))}}}));let c=Array.from(a.attributes);return c=c.filter((e=>!this.parseAttr(t,e.name,e.value,s,n)||(a.removeAttribute(e.name),!1))),c.forEach((e=>{if("class"===e.name)t.classList.add(...e.value.trim().split(/\s+/));else if("style"===e.name){let n=e.value.split(";");for(let e of n){let n=e.split(":");if(2===n.length&&!t.style[n[0]]){let e=n[0].trim();e.startsWith("--")?t.style.setProperty(e,n[1].trim()):t.style[e]=n[1].trim()}}}else t.getAttribute(e.name)||t.setAttribute(e.name,e.value)})),s}async mountRef(t,e,n,o){for(let r of o.scripts)r.hasAttribute("active")?this.onMountedRun(t,(()=>{w.AsyncRun(r.innerHTML,e,n,{$node:t,$watch:w.Watch})}),!1):w.AsyncRun(r.innerHTML,e,n,{$node:t,$watch:w.Watch})}parseAttrs(t,e,n,o){if("A"===t.nodeName&&this.parseAHref(t,e,n),Array.from(t.attributes).forEach((o=>{this.parseAttr(t,o.name,o.value,e,n)&&t.removeAttribute(o.name)})),o&&Object.keys(o).forEach((e=>{this.parseAttr(t,e,o[e],t.$refData,n)})),t.hasAttribute("v-show")){let o=t.getAttribute("v-show"),r=t.style.display;w.Watch((()=>{let i=w.Run(o,e,n);t.style.display=i?r:"none"}))}}parseAHref(t,e,n){if(!t.hasAttribute("href")&&!t.hasAttribute(":href"))return;w.Watch((()=>{let o=t.getAttribute("href");if(t.hasAttribute(":href")){let r=t.getAttribute(":href");t.removeAttribute(":href"),o=w.Run(r,e,n)}if(o&&!o.startsWith("#")&&!o.startsWith("http"))if(o.startsWith("@"))o=o.replaceAll("//","/"),t.setAttribute("href",o.slice(1));else if(o){let e=n?.root;e&&(o=e+o),t.setAttribute("href",o)}}));const o=e=>{let n=e?.fullPath;t.getAttribute("href")===n?t.setAttribute("active",""):t.removeAttribute("active")};o(cn.$router.current),cn.$router.onChange(o)}parseAttr(t,e,n,r,i){if(e.startsWith(":")){let o=e.slice(1);return"class"===o||"style"===o?this.handleStyle(t,o,n,r,i):w.Watch((()=>{let e;e=n?w.Run(n,r,i):r[o],un.SetAttr(t,o,e)})),!0}if(e.startsWith("@"))return this.handleEvent(t,e,n,r,i),!0;if(e.indexOf("!")>-1);else if(e.startsWith("v:")){let e=o(n,r);if(e.data&&e.key){let n=e.key,o=e.data;return un.BindInputDomValue(t,o,n,w.Watch)}}else if("vdom"===e){let e=o(n,r);return e.data&&e.key&&(e.data[e.key]=t),!0}return!1}handleStyle(t,e,n,o,r){let i="";w.Watch((()=>{let s=w.Run(n,o,r);if("function"==typeof s&&(s=s()),"class"===e){if(i&&(t.classList.remove(...i.split(/\s+/)),i=""),s instanceof Array)i="",s.forEach((t=>{if("string"==typeof t&&t.length)i+=" "+t;else if("object"==typeof t)for(let e in t)t[e]&&(i+=" "+e)}));else if("string"==typeof s&&s.length)i=s.trim();else if("object"==typeof s){i="";for(let t in s)s[t]&&(i+=" "+t)}i=i.trim(),i&&t.classList.add(...i.split(/\s+/))}else if("style"===e){if(i)if("object"==typeof i)for(let e in i)e.startsWith("--")?t.style.removeProperty(e):t.style[e]="";else if("string"==typeof i){let e=i.split(";");for(let n of e){let e=n.split(":");2===e.length&&(e[0].trim().startsWith("--")?t.style.removeProperty(e[0].trim()):t.style[e[0].trim()]="")}}if("object"==typeof s)for(let e in s)e.startsWith("--")?t.style.setProperty(e,s[e]):t.style[e]=s[e];else if("string"==typeof s){let e=s.split(";");for(let n of e){let e=n.split(":");2===e.length&&(e[0].trim().startsWith("--")?t.style.setProperty(e[0].trim(),e[1].trim()):t.style[e[0].trim()]=e[1].trim())}}i=s}}))}handleEvent(t,e,n,o,r){let i=e.slice(1).split("."),s={self:!1,prevent:!1,stop:!1},a=i[0];if("mounted"===a)this.onMountedRun(t,(t=>{let e=w.Run(n,o,r);"function"==typeof e&&e(t)}),!1);else if("outerclick"===a){let e=t=>{let e=w.Run(n,o,r,{$event:t});"function"==typeof e&&e(t)};un.AddClicker(t,"outer",e)}else if(-1!==un.EventsList.indexOf(a)){"keydown"!==a&&"keyup"!==a&&"keypress"!==a||"INPUT"!==t.tagName&&"TEXTAREA"!==t.tagName&&t.setAttribute("tabindex","0");let e=t=>{let e=w.Run(n,o,r,{$event:t});"function"==typeof e&&e(t)};i.slice(1).forEach((i=>{if(i.startsWith("delay")){let s=i.slice(5);s=s?s.endsWith("ms")?+s.slice(0,-2):s.endsWith("s")?1e3*+s.slice(0,-1):+s:1e3,isNaN(s)&&(s=1e3),e=e=>{let i=t["_"+a];i&&"number"==typeof i&&clearTimeout(i),t["_"+a]=setTimeout((()=>{let t=w.Run(n,o,r,{$event:e});"function"==typeof t&&t(e)}),s)}}s[i]=!0})),t.addEventListener(a,(t=>{(1>=i.length||"keydown"!==a&&"keyup"!=a&&"keypress"!=a||i[1]===t.key.toLowerCase())&&(s.self&&t.currentTarget!==t.target||(s.prevent&&t.preventDefault(),s.stop&&t.stopPropagation(),e(t)))}))}else t.$vevent=t.$vevent||{},t.$vevent[a]=(...t)=>{let e=w.Run(n,o,r,{});"function"==typeof e&&e(...t)}}parseTextNode(t,e,n){let o,i=t.nodeValue.trim();if(!i)return;let s=0,a=-1,c=[];for(;null!==(o=r.exec(i));)if("{{"===o[0])a=o.index;else if("}}"===o[0]&&a>=0){s!==a&&c.push(i.slice(s,a)),c.push("");let r=i.slice(a+2,o.index),l=c.length;a=-1,s=o.index+2,w.Watch((()=>{c[l-1]=w.Run(r,e,n),"object"==typeof c[l-1]&&(c[l-1]=JSON.stringify(c[l-1])),t.nodeValue=c.join("")}))}c.push(i.slice(s)),t.nodeValue=c.join("")}vforDomCache={};parseVfor(t,e,n,o){e.removeAttribute("v-for");let r=i.exec(t);if(6===r?.length){let t=document.createElement("div");t.style.display="none";let i=w.GenUniqueID();this.vforDomCache[i]={},e.parentNode.replaceChild(t,e),w.Watch((()=>{let s=r[3]||r[2],a=r[4],c=w.Run(r[5],n,o),l=this.vforDomCache[i],u=new Set;if("function"==typeof c?c=c():"number"==typeof c&&(c=Array.from({length:c},((t,e)=>e))),null==c&&(c=[]),c.length,"object"==typeof c){let r=Object.keys(c),f=[];for(let t in r){let e=r[t],n="";n=c[e]&&c[e][w.DataID]?c[e][w.DataID]:e+"."+c[e],n=i+"."+n,u.add(n),f.push({k:e,vfk:n,val:c[e]})}for(let t of Object.keys(l))u.has(t)||(l[t]instanceof Array?l[t].forEach((t=>t.remove())):l[t].remove(),delete l[t]);let h=t;for(let i=f.length-1;i>=0;i--){let{k:r,vfk:c,val:u}=f[i],d=l[c];if(d){a&&(d.$vforData[a]="0"===r?0:+r||r),d.isConnected&&(d.nextSibling!==h&&t.parentNode.insertBefore(d,h),h=d);continue}let p=e.cloneNode(!0);l[c]=p;let m={[s]:u};a&&(m[a]="0"===r?0:+r||r),m=w.Wrap(m,n),p.$vforData=m,t.parentNode.insertBefore(p,h);let y=e.getAttribute("v-if");if(!y){this.parseDom(p,m,o),h=p;continue}p.removeAttribute("v-if");let b=-1;b=w.Watch((()=>{let e=l[c];if(e)if(w.Run(y,m,o)){if(e.vparsed||this.parseDom(e,m,o),!e.isConnected){let n=!1,o=t;for(let t in l)if(t!==c){if(n&&l[t].isConnected){o=l[t];break}}else n=!0;t.parentNode.insertBefore(e,o)}}else e.isConnected?e.remove():this.onMountedRun(e,(t=>{e.remove()}));else w.Cancel(b)})),p.isConnected&&(h=p)}}}))}}parseVif(t,e,n){let o={now:document.createElement("div"),conds:[],doms:[]};const r=t=>{let o={now:t.now,conds:t.conds,doms:t.doms},r=[];for(let e in o.conds){let t=o.conds[e];t=""===t?"true":"Boolean("+t+")",r.push(t)}let i=`let res = [${r.join(",")}]\n return res.indexOf(true)`;w.Watch((()=>{let t=w.Run(i,e,n),r=o.doms[t];return r||(r=document.createElement("div"),r.style.display="none"),r}),(t=>{t&&(this.onMountedRun(o.now,(e=>{e.replaceWith(t),o.now=t})),t?.vparsed||this.parseDom(t,e,n))}))};let i=t.filter((t=>!(t.getAttribute&&!t.getAttribute("v-for")&&(null!==t.getAttribute("v-if")?(o.conds.length>0&&(r(o),o={now:document.createElement("div"),conds:[],doms:[]}),t.replaceWith(o.now),o.conds.push(t.getAttribute("v-if")),t.removeAttribute("v-if"),o.doms.push(t),1):null!==t.getAttribute("v-else-if")?(o.conds.push(t.getAttribute("v-else-if")),t.removeAttribute("v-else-if"),o.doms.push(t),t.remove(),1):null!==t.getAttribute("v-else")&&(o.conds.push(""),t.removeAttribute("v-else"),o.doms.push(t),t.remove(),1)))));return o.conds.length>0&&r(o),i}parseSlots(t,e,n){let o=t.getAttribute("vrefof"),r=t.closest(`*[vref='${o}']`);if(!r)return void this.onMountedRun(t,(t=>{this.parseSlots(t,e,n)}));for(;;){let t=r?.parentNode.closest("*[vref]");if(!t)break;if(t.getAttribute("vref")!==o)break;r=t}let i=t.getAttribute("name")||"";if(t.getAttribute(":name")){let o=t.getAttribute(":name");t.removeAttribute(":name"),i=w.Run(o,e,n)}return t.originContent||(t.$originContent=Array.from(t.childNodes),t.innerHTML=""),t.$slotCache={},w.Watch((()=>{let o=r.$refSlots||{},s=r.$refScope||{},a=o[i];if(a&&a.length>0){let o=a[0].hashID;if(o){if(t.$slotCache[o])return t.innerHTML="",void t.append(...t.$slotCache[o])}else o=w.GenUniqueID(),a[0].hashID=o;t.innerHTML="",a=a.map((t=>t.cloneNode(!0))),t.append(...a);let r=s;if(null!==t.getAttribute("vbind")){let n=t.getAttribute("vbind").split(",").map((t=>t.trim()));r=w.Wrap({}),n.forEach((t=>{e.hasOwnProperty(t)&&(r[t]=e[t])})),w.SetDataRoot(r,s)}let i="";a.find((t=>!(!t.getAttribute||!t.getAttribute("vrefof")||(i=t.getAttribute("vrefof"),0))));let c=n;if(i){let e=t.closest(`*[vref='${i}']`);c=e?.$env||n}a=this.parseVif(a,r,c),a.forEach((t=>this.parseDom(t,r,c))),t.$slotCache[o]=a}else{t.innerHTML="",t.append(...t.$originContent);let o=!1;t.$originContent.forEach((t=>{t.hasAttribute&&t.vparsed&&(o=!0)})),o||(t.$originContent=this.parseVif(t.$originContent,e,n),t.$originContent.forEach((t=>this.parseDom(t,e,n))))}})),this.parseAttrs(t,e,n),t}}(document.body))}()},"function"==typeof define&&define.amd?define(t):t(); \ No newline at end of file diff --git a/ui/page/dsr1.html b/ui/page/dsr1.html index f569610..3c56065 100644 --- a/ui/page/dsr1.html +++ b/ui/page/dsr1.html @@ -1,61 +1,62 @@ + - - - - VyesJS - 现代Web组件框架 - + + + + vhtmlJS - 现代Web组件框架 + + - - -
-
-

- 下一代Web组件框架 -

-

- 用熟悉的HTML语法,构建现代Web应用。无需构建工具,开箱即用。 -

-
- - -
-
-
+ + +
+
+

+ 下一代Web组件框架 +

+

+ 用熟悉的HTML语法,构建现代Web应用。无需构建工具,开箱即用。 +

+
+ + +
+
+
- \ No newline at end of file + + diff --git a/ui/page/index.html b/ui/page/index.html index ae6bd40..8bd13af 100644 --- a/ui/page/index.html +++ b/ui/page/index.html @@ -2,10 +2,10 @@ - OneAuth + vbase - + -

OneAuth

+

vbase

Secure, Simple, Scalable Authentication Service for your applications.

- +
@@ -82,8 +82,9 @@
Developer Friendly
- - Get Started + + Get Started - \ No newline at end of file + diff --git a/ui/page/latest.html b/ui/page/latest.html index b065f0f..ec7b810 100644 --- a/ui/page/latest.html +++ b/ui/page/latest.html @@ -1,47 +1,54 @@ + - - - - Vyes.js - 现代前端框架 + + + + vhtml - 现代前端框架 + -
-

Vyes.js

-

现代化、轻量级的前端框架

- 立即开始 -
-
-
-
-

{{ feature.title }}

-

{{ feature.desc }}

-
-
+
+

vhtml.js

+

现代化、轻量级的前端框架

+ 立即开始 +
+
+
+
+

{{ feature.title }}

+

{{ feature.desc }}

+
-
-

© 2024 Vyes.js Team. All rights reserved.

-
+
+
+

© 2024 vhtml Team. All rights reserved.

+
- \ No newline at end of file + + diff --git a/ui/page/login.html b/ui/page/login.html index 641a922..8d84962 100644 --- a/ui/page/login.html +++ b/ui/page/login.html @@ -359,26 +359,27 @@
或使用手机/邮箱注册
- +
- +
- + {{ smsCountdown > 0 ? `${smsCountdown}s` : '获取验证码' }}
- +
-
{{ signUpError }}
+
{{ signUpError }}
立即注册
@@ -408,32 +409,34 @@ - -
- - -
+ + +
+ 忘记密码? +
{{ signInError }}
+ 登 录 +
+
- +
- +
- + {{ smsCountdown > 0 ? `${smsCountdown}s` : '获取验证码' }}
-
- 忘记密码? -
{{ signInError }}
- - 登 录 +
{{ signInError }}
+ 登 录 + @@ -471,6 +474,39 @@ signUpLoading = false; // 注册按钮加载状态 signInLoading = false; // 登录按钮加载状态 + // 验证规则函数 + validateUsername = (val) => { + if (!val || val.length < 5) return '用户名必须大于5位'; + return true; + }; + + validatePassword = (val) => { + const regex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[_]).{9,}$/; + if (!regex.test(val)) return '密码必须大于8位,且包含大小写字母、下划线和数字'; + return true; + }; + + validatePhone = (val) => { + const region = isSignUp ? signUpForm.region : signInForm.region; + let regex = /^\d{7,15}$/; + if (region === '+86') regex = /^1[3-9]\d{9}$/; + else if (region === '+1') regex = /^\d{10}$/; + + if (!regex.test(val)) return '手机号格式不正确'; + return true; + }; + + validateCode = (val) => { + if (!val || val.length < 4) return '请输入正确的验证码'; + return true; + }; + + // v-form 配置项 (用户名登录) + signInUsernameItems = [ + {name: 'username', placeholder: '用户名', required: true, validate: validateUsername}, + {name: 'password', placeholder: '密码', type: 'password', required: true, validate: validatePassword} + ]; + // 常用国家/地区代码 - 转换为 v-select 格式 regions = [ {value: '+86', label: '+86 中国'}, @@ -496,7 +532,8 @@ ]; // 验证手机号格式(根据不同地区调整) - validatePhone = (phone, region) => { + // 已迁移至 validatePhone 函数,保留此函数供 sendVerifyCode 使用 + checkPhone = (phone, region) => { if (region === '+86') { const regex = /^1[3-9]\d{9}$/; return regex.test(phone); @@ -554,7 +591,7 @@ return; } - if (!validatePhone(phone, region)) { + if (!checkPhone(phone, region)) { const errorMsg = '请输入正确的手机号格式'; type === 'signup' ? signUpError = errorMsg : signInError = errorMsg; return; @@ -639,12 +676,13 @@ try { let loginData = {}; if (loginType === 'username') { - if (!signInForm.username) {signInError = '请输入用户名'; return;} - if (!signInForm.password) {signInError = '请输入密码'; return;} + // v-form 提交时已经通过了基本验证,但 double check 也没坏处 + if (validateUsername(signInForm.username) !== true) return; + if (validatePassword(signInForm.password) !== true) return; loginData = {username: signInForm.username, code: btoa(signInForm.password), type: 'username'}; } else { - if (!signInForm.phone) {signInError = '请输入手机号'; return;} - if (!signInForm.verifyCode) {signInError = '请输入验证码'; return;} + if (validatePhone(signInForm.phone) !== true) return; + if (validateCode(signInForm.verifyCode) !== true) return; loginData = {phone: signInForm.phone, region: signInForm.region, verify_code: signInForm.verifyCode, type: 'phone'}; } diff --git a/ui/root.html b/ui/root.html index 677cfc3..4120b43 100644 --- a/ui/root.html +++ b/ui/root.html @@ -4,7 +4,7 @@ oa - +