diff --git a/backend/README.md b/backend/README.md index 95da4d3..b0723b2 100644 --- a/backend/README.md +++ b/backend/README.md @@ -7,6 +7,5 @@ | `api` | Gin HTTP API / BFF、同步事务、JWT 鉴权与统一响应 | | `worker` | Redis Streams 消费、Outbox 投递、超时扫描与 Mock 外部适配 | | `iot` | MQTT 协议适配边界、遥测/命令契约校验与 Mock 设备接入 | -| `migrations` | PostgreSQL 迁移、中文注释、回滚说明和初始化数据 | `sample/server` 的工程机制被直接沿用;但由于项目规范强制要求 `identity` 为 UUID V7 主键,领域模型使用自定义 `models.Entity`,不使用样例中含自增 `ID` 的 `types.Std_IICUDS`。 diff --git a/backend/api/Makefile b/backend/api/Makefile index 16465bf..1889684 100644 --- a/backend/api/Makefile +++ b/backend/api/Makefile @@ -1,4 +1,4 @@ -.PHONY: build run cli migrate lint tidy +.PHONY: build run cli lint tidy build: go build -o build/platform-api ./cmd/main/main.go @@ -10,9 +10,6 @@ run: cli: go run ./cmd/cli/main.go $(ARGS) -migrate: - go run ./cmd/cli/main.go migrate - lint: go vet ./... go fmt ./... diff --git a/backend/api/README.md b/backend/api/README.md index ffa0db5..54a7b0d 100644 --- a/backend/api/README.md +++ b/backend/api/README.md @@ -12,8 +12,8 @@ $env:HEQI_PLATFORM_ROOT_PASSWORD="请设置不少于12位的root初始密码" go run ./cmd/main/main.go ``` -应用启动和 `go run ./cmd/cli/main.go migrate` 都会在事务内幂等创建平台 `root` 账号。账号名固定为 `root`;优先使用 `HEQI_PLATFORM_ROOT_PASSWORD`,未设置时仅使用开发环境默认值。root 首次登录后必须通过 `PUT /heqi/v1/auth/password` 修改密码。 +应用启动时会在事务内幂等创建平台 `root` 账号。账号名固定为 `root`;优先使用 `HEQI_PLATFORM_ROOT_PASSWORD`,未设置时仅使用开发环境默认值。已登录账户可通过 `PUT /heqi/v1/auth/password` 修改密码。 匿名接口为 `POST /heqi/v1/auth/login`;其余平台接口经 `middleware.JwtAuth(true)` 保护。请求头 `Authorization` 直接传递 JWT 原始值,不使用 `Bearer` 前缀。 -UUID V7 主键、模型中文注释和 PostgreSQL 变更记录以 `../migrations` 为准。 +UUID V7 主键、模型中文注释与表结构以 `internal/models` 为准;应用启动时由 GORM 自动同步模型结构。 diff --git a/backend/api/cmd/cli/main.go b/backend/api/cmd/cli/main.go index 631ad0a..15cab45 100644 --- a/backend/api/cmd/cli/main.go +++ b/backend/api/cmd/cli/main.go @@ -1,35 +1,19 @@ -// 平台 API 的数据库迁移与版本命令行工具。 +// 平台 API 的版本命令行工具。 package main import ( "fmt" "os" - - "git.apinb.com/heqiapp/platforms/backend/api/internal/config" - "git.apinb.com/heqiapp/platforms/backend/api/internal/impl" - "git.apinb.com/heqiapp/platforms/backend/api/internal/initdb" - _ "git.apinb.com/heqiapp/platforms/backend/api/internal/models" ) -const serviceKey = "heqi" - func main() { if len(os.Args) < 2 { - fmt.Println("usage: platform-cli ") + fmt.Println("usage: platform-cli ") return } - switch os.Args[1] { - case "version": - fmt.Println("platform-cli 0.1.0") - case "migrate": - config.New(serviceKey) - impl.NewImpl() - if err := initdb.New(impl.DBService); err != nil { - panic(err) - } - fmt.Println("platform database auto migrate completed") - default: + if os.Args[1] != "version" { fmt.Fprintf(os.Stderr, "unknown command: %s\n", os.Args[1]) os.Exit(1) } + fmt.Println("platform-cli 0.1.0") } diff --git a/backend/api/internal/initdb/new.go b/backend/api/internal/initdb/new.go index 3795c19..6820a39 100644 --- a/backend/api/internal/initdb/new.go +++ b/backend/api/internal/initdb/new.go @@ -6,6 +6,9 @@ import "gorm.io/gorm" // New 在同一事务中初始化平台基础数据。 func New(database *gorm.DB) error { return database.Transaction(func(tx *gorm.DB) error { + if err := InitPlatformAccess(tx); err != nil { + return err + } return InitPlatformRoot(tx) }) } diff --git a/backend/api/internal/initdb/platform.go b/backend/api/internal/initdb/platform.go index 3942e24..d987e8e 100644 --- a/backend/api/internal/initdb/platform.go +++ b/backend/api/internal/initdb/platform.go @@ -15,12 +15,50 @@ const ( // PlatformRootPassword 是仅用于首次启动的初始密码,首次登录后必须修改。 PlatformRootPassword = "Heqi@Root2026" // PlatformRootRoleCode 表示根账号的平台角色。 - PlatformRootRoleCode = "platform_root" + PlatformRootRoleCode = "root" ) +// InitPlatformAccess 幂等初始化 root 角色、菜单和 root 的全菜单授权。 +func InitPlatformAccess(database *gorm.DB) error { + rootRole := models.PlatformRole{ + Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled", Version: 1}, + RoleCode: PlatformRootRoleCode, + Name: "系统管理员", + DataScope: "global", + IsSystem: true, + } + if err := database.Where("role_code = ?", rootRole.RoleCode).FirstOrCreate(&rootRole).Error; err != nil { + return err + } + + menus := []models.PlatformMenu{ + {Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled", Version: 1}, MenuCode: "dashboard", Name: "工作台", Icon: "icon-dashboard", Path: "/dashboard", SortNo: 10}, + {Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled", Version: 1}, MenuCode: "gas", Name: "可燃气体站管理", Icon: "icon-fire", Path: "/gas/basic", SortNo: 20}, + {Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled", Version: 1}, MenuCode: "delivery", Name: "配送管理", Icon: "icon-car", Path: "/delivery/basic", SortNo: 30}, + {Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled", Version: 1}, MenuCode: "staff", Name: "服务人员", Icon: "icon-user", Path: "/staff/list", SortNo: 40}, + {Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled", Version: 1}, MenuCode: "user", Name: "业主客户", Icon: "icon-user-group", Path: "/user/list", SortNo: 50}, + {Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled", Version: 1}, MenuCode: "ec", Name: "电商管理", Icon: "icon-shopping", Path: "/ec/product", SortNo: 60}, + {Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled", Version: 1}, MenuCode: "finance", Name: "财务管理", Icon: "icon-safe", Path: "/finance/payment", SortNo: 70}, + {Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled", Version: 1}, MenuCode: "wallet", Name: "钱包中心", Icon: "icon-wallet", Path: "/wallet/list", SortNo: 80}, + {Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled", Version: 1}, MenuCode: "report", Name: "统计报表", Icon: "icon-bar-chart", Path: "/report/list", SortNo: 90}, + {Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled", Version: 1}, MenuCode: "platform", Name: "平台配置", Icon: "icon-settings", Path: "/platform/account", SortNo: 100}, + } + for index := range menus { + menu := menus[index] + if err := database.Where("menu_code = ?", menu.MenuCode).FirstOrCreate(&menu).Error; err != nil { + return err + } + relation := models.PlatformRoleMenuRelation{PlatformRoleID: rootRole.ID, PlatformMenuID: menu.ID} + if err := database.Where("platform_role_id = ? AND platform_menu_id = ?", rootRole.ID, menu.ID).FirstOrCreate(&relation).Error; err != nil { + return err + } + } + return nil +} + // InitPlatformRoot 幂等创建平台总后台 root 账号。 func InitPlatformRoot(database *gorm.DB) error { - var account models.IdnAccount + var account models.PlatfromAccount err := database.Where("username = ?", PlatformRootUsername).First(&account).Error if err == nil { return nil @@ -34,16 +72,13 @@ func InitPlatformRoot(database *gorm.DB) error { return err } - account = models.IdnAccount{ - Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled"}, - Username: PlatformRootUsername, - DisplayName: "平台根管理员", - PasswordHash: string(passwordHash), - RoleCode: PlatformRootRoleCode, - MustChangePassword: true, - Phone: "", - AccountType: "operator", - ServiceArea: "全国", + account = models.PlatfromAccount{ + Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled"}, + Username: PlatformRootUsername, + DisplayName: "平台根管理员", + PasswordHash: string(passwordHash), + PlatformRoleCode: PlatformRootRoleCode, + Phone: "", } return database.Create(&account).Error } diff --git a/backend/api/internal/logic/platform/auth.go b/backend/api/internal/logic/platform/auth.go index d1eb839..3932c2f 100644 --- a/backend/api/internal/logic/platform/auth.go +++ b/backend/api/internal/logic/platform/auth.go @@ -23,12 +23,11 @@ type LoginRequest struct { // LoginReply 是后台登录成功后的访问凭证与账号状态。 type LoginReply struct { - AccessToken string `json:"access_token"` - TokenType string `json:"token_type"` - Identity string `json:"identity"` - DisplayName string `json:"display_name"` - RoleCode string `json:"role_code"` - MustChangePassword bool `json:"must_change_password"` + AccessToken string `json:"access_token"` + TokenType string `json:"token_type"` + Identity string `json:"identity"` + DisplayName string `json:"display_name"` + RoleCode string `json:"role_code"` } // Login 校验平台账号密码并签发 BSM JWT。 @@ -39,7 +38,7 @@ func Login(ctx *gin.Context) { return } - var account models.IdnAccount + var account models.PlatfromAccount err := impl.DBService.Where("username = ?", strings.TrimSpace(request.Username)).First(&account).Error if err != nil { if err == gorm.ErrRecordNotFound { @@ -60,23 +59,22 @@ func Login(ctx *gin.Context) { accessToken, err := token.New(env.Runtime.JwtSecretKey).GenerateJwt( 0, - account.Identity.String(), + account.Identity, "platform_admin", - account.RoleCode, + account.PlatformRoleCode, map[string]string{"username": account.Username, "display_name": account.DisplayName}, - map[string]string{"must_change_password": boolText(account.MustChangePassword)}, + nil, ) if err != nil { infra.Response.Error(ctx, err) return } infra.Response.Success(ctx, LoginReply{ - AccessToken: accessToken, - TokenType: "JWT", - Identity: account.Identity.String(), - DisplayName: account.DisplayName, - RoleCode: account.RoleCode, - MustChangePassword: account.MustChangePassword, + AccessToken: accessToken, + TokenType: "JWT", + Identity: account.Identity, + DisplayName: account.DisplayName, + RoleCode: account.PlatformRoleCode, }) } @@ -87,14 +85,14 @@ func CurrentProfile(ctx *gin.Context) { infra.Response.Error(ctx, err) return } - var account models.IdnAccount + var account models.PlatfromAccount if err := impl.DBService.Where("identity = ?", claims.Identity).First(&account).Error; err != nil { infra.Response.Error(ctx, errcode.ErrRecordNotFound) return } infra.Response.Success(ctx, gin.H{ - "identity": account.Identity.String(), "username": account.Username, "display_name": account.DisplayName, - "role_code": account.RoleCode, "must_change_password": account.MustChangePassword, "mfa_enabled": account.MFAEnabled, + "identity": account.Identity, "username": account.Username, "display_name": account.DisplayName, + "avatar": account.Avatar, "role_code": account.PlatformRoleCode, }) } @@ -116,7 +114,7 @@ func ChangePassword(ctx *gin.Context) { infra.Response.Error(ctx, errcode.ErrInvalidArgument) return } - var account models.IdnAccount + var account models.PlatfromAccount if err := impl.DBService.Where("identity = ?", claims.Identity).First(&account).Error; err != nil { infra.Response.Error(ctx, errcode.ErrRecordNotFound) return @@ -130,17 +128,9 @@ func ChangePassword(ctx *gin.Context) { infra.Response.Error(ctx, err) return } - if err := impl.DBService.Model(&account).Updates(map[string]any{"password_hash": string(passwordHash), "must_change_password": false}).Error; err != nil { + if err := impl.DBService.Model(&account).Update("password_hash", string(passwordHash)).Error; err != nil { infra.Response.Error(ctx, err) return } infra.Response.Success(ctx, gin.H{"changed": true}) } - -// boolText 将布尔值转换为 JWT 扩展字段约定的字符串。 -func boolText(value bool) string { - if value { - return "true" - } - return "false" -} diff --git a/backend/api/internal/logic/platform/platform.go b/backend/api/internal/logic/platform/platform.go index 3e723b9..c2f4977 100644 --- a/backend/api/internal/logic/platform/platform.go +++ b/backend/api/internal/logic/platform/platform.go @@ -2,11 +2,15 @@ package platform import ( + "errors" + "git.apinb.com/bsm-sdk/core/errcode" "git.apinb.com/bsm-sdk/core/infra" "git.apinb.com/bsm-sdk/core/utils" + "git.apinb.com/heqiapp/platforms/backend/api/internal/impl" "git.apinb.com/heqiapp/platforms/backend/api/internal/models" "github.com/gin-gonic/gin" + "gorm.io/gorm" ) // PingHello 返回匿名健康状态。 @@ -14,7 +18,7 @@ func PingHello(ctx *gin.Context) { infra.Response.Success(ctx, gin.H{"service": "platform-api", "status": "ok"}) } -// DashboardOverview 返回组织与安全运营的首期概览数据。 +// DashboardOverview 返回平台总后台的运营概览数据。 func DashboardOverview(ctx *gin.Context) { overview, err := models.GetDashboardOverview() if err != nil { @@ -24,131 +28,344 @@ func DashboardOverview(ctx *gin.Context) { infra.Response.Success(ctx, overview) } -// CreateOrgGasStationRequest 是创建 org_gas_station 的请求体。 -type CreateOrgGasStationRequest struct { - StationCode string `json:"station_code" binding:"required,max=32"` - Name string `json:"name" binding:"required,max=128"` - Principal string `json:"principal" binding:"required,max=64"` - ServiceArea string `json:"service_area" binding:"required,max=128"` +// ListGasBasic 查询可燃气体站分页列表。 +func ListGasBasic(ctx *gin.Context) { listPage[models.GasBasic](ctx) } + +// GetGasBasic 查询一个可燃气体站。 +func GetGasBasic(ctx *gin.Context) { getByIdentity[models.GasBasic](ctx) } + +// CreateGasBasic 创建可燃气体站档案。 +func CreateGasBasic(ctx *gin.Context) { + var request models.GasBasic + if err := ctx.ShouldBindJSON(&request); err != nil || request.Code == "" || request.Name == "" { + infra.Response.Error(ctx, errcode.ErrInvalidArgument) + return + } + request.Entity = newEntity("draft") + if err := impl.DBService.Create(&request).Error; err != nil { + infra.Response.Error(ctx, err) + return + } + infra.Response.Success(ctx, request) } -// OrgGasStationListReply 是 org_gas_station 的标准分页响应。 -type OrgGasStationListReply struct { - Total int64 `json:"total"` - List []models.OrgGasStation `json:"list"` -} - -// CreateOrgGasStation 创建待审核气站并由数据库层保证唯一编码。 -func CreateOrgGasStation(ctx *gin.Context) { - var request CreateOrgGasStationRequest +// UpdateGasBasic 更新可燃气体站基础资料。 +func UpdateGasBasic(ctx *gin.Context) { + var request struct { + Name string `json:"name" binding:"required,max=128"` + CreditCode string `json:"credit_code" binding:"max=64"` + Principal string `json:"principal" binding:"max=64"` + Address string `json:"address" binding:"max=255"` + Longitude string `json:"longitude" binding:"max=32"` + Latitude string `json:"latitude" binding:"max=32"` + } if err := ctx.ShouldBindJSON(&request); err != nil { infra.Response.Error(ctx, errcode.ErrInvalidArgument) return } - data := models.OrgGasStation{StationCode: request.StationCode, Name: request.Name, Principal: request.Principal, ServiceArea: request.ServiceArea} - data.Identity = models.NewIdentity() - data.Status = "draft" - data.Version = 1 - if err := models.CreateOrgGasStation(&data); err != nil { + updateByIdentity(ctx, &models.GasBasic{}, gin.H{"name": request.Name, "credit_code": request.CreditCode, "principal": request.Principal, "address": request.Address, "longitude": request.Longitude, "latitude": request.Latitude}) +} + +// ListDeliveryBasic 查询配送点分页列表。 +func ListDeliveryBasic(ctx *gin.Context) { listPage[models.DeliveryBasic](ctx) } + +// GetDeliveryBasic 查询一个配送点。 +func GetDeliveryBasic(ctx *gin.Context) { getByIdentity[models.DeliveryBasic](ctx) } + +// CreateDeliveryBasic 创建配送点档案。 +func CreateDeliveryBasic(ctx *gin.Context) { + var request models.DeliveryBasic + if err := ctx.ShouldBindJSON(&request); err != nil || request.DeliveryCode == "" || request.Name == "" { + infra.Response.Error(ctx, errcode.ErrInvalidArgument) + return + } + request.Entity = newEntity("draft") + if err := impl.DBService.Create(&request).Error; err != nil { infra.Response.Error(ctx, err) return } + infra.Response.Success(ctx, request) +} + +// UpdateDeliveryBasic 更新配送点基础资料。 +func UpdateDeliveryBasic(ctx *gin.Context) { + var request struct { + GasBasicID uint64 `json:"gas_basic_id"` + Name string `json:"name" binding:"required,max=128"` + Principal string `json:"principal" binding:"max=64"` + Address string `json:"address" binding:"max=255"` + } + if err := ctx.ShouldBindJSON(&request); err != nil { + infra.Response.Error(ctx, errcode.ErrInvalidArgument) + return + } + updateByIdentity(ctx, &models.DeliveryBasic{}, gin.H{"gas_basic_id": request.GasBasicID, "name": request.Name, "principal": request.Principal, "address": request.Address}) +} + +// ListStaff 查询服务人员分页列表。 +func ListStaff(ctx *gin.Context) { listPage[models.StaffAccount](ctx) } + +// GetStaff 查询一个服务人员档案。 +func GetStaff(ctx *gin.Context) { getByIdentity[models.StaffAccount](ctx) } + +// CreateStaff 创建服务人员档案。 +func CreateStaff(ctx *gin.Context) { + var request models.StaffAccount + if err := ctx.ShouldBindJSON(&request); err != nil || request.Name == "" { + infra.Response.Error(ctx, errcode.ErrInvalidArgument) + return + } + request.Entity = newEntity("draft") + if request.WorkStatus == "" { + request.WorkStatus = "off_duty" + } + if err := impl.DBService.Create(&request).Error; err != nil { + infra.Response.Error(ctx, err) + return + } + infra.Response.Success(ctx, request) +} + +// UpdateStaff 更新服务人员档案。 +func UpdateStaff(ctx *gin.Context) { + var request struct { + Name string `json:"name" binding:"required,max=64"` + Phone string `json:"phone" binding:"max=32"` + Avatar string `json:"avatar" binding:"max=512"` + RoleCode string `json:"role_code" binding:"max=64"` + GasBasicID uint64 `json:"gas_basic_id"` + DeliveryBasicID uint64 `json:"delivery_basic_id"` + WorkStatus string `json:"work_status" binding:"max=32"` + } + if err := ctx.ShouldBindJSON(&request); err != nil { + infra.Response.Error(ctx, errcode.ErrInvalidArgument) + return + } + updateByIdentity(ctx, &models.StaffAccount{}, gin.H{"name": request.Name, "phone": request.Phone, "avatar": request.Avatar, "role_code": request.RoleCode, "gas_basic_id": request.GasBasicID, "delivery_basic_id": request.DeliveryBasicID, "work_status": request.WorkStatus}) +} + +// ListUser 查询业主客户分页列表。 +func ListUser(ctx *gin.Context) { listPage[models.UserAccount](ctx) } + +// GetUser 查询一个业主客户档案。 +func GetUser(ctx *gin.Context) { getByIdentity[models.UserAccount](ctx) } + +// CreateUser 创建业主客户档案。 +func CreateUser(ctx *gin.Context) { + var request models.UserAccount + if err := ctx.ShouldBindJSON(&request); err != nil || request.Name == "" { + infra.Response.Error(ctx, errcode.ErrInvalidArgument) + return + } + request.Entity = newEntity("enabled") + if err := impl.DBService.Create(&request).Error; err != nil { + infra.Response.Error(ctx, err) + return + } + infra.Response.Success(ctx, request) +} + +// UpdateUser 更新业主客户档案。 +func UpdateUser(ctx *gin.Context) { + var request struct { + Name string `json:"name" binding:"required,max=64"` + Phone string `json:"phone" binding:"max=32"` + Avatar string `json:"avatar" binding:"max=512"` + RealName string `json:"real_name" binding:"max=64"` + } + if err := ctx.ShouldBindJSON(&request); err != nil { + infra.Response.Error(ctx, errcode.ErrInvalidArgument) + return + } + updateByIdentity(ctx, &models.UserAccount{}, gin.H{"name": request.Name, "phone": request.Phone, "avatar": request.Avatar, "real_name": request.RealName}) +} + +// ListPlatformRole 查询平台角色分页列表。 +func ListPlatformRole(ctx *gin.Context) { listPage[models.PlatformRole](ctx) } + +// GetPlatformRole 查询一个平台角色。 +func GetPlatformRole(ctx *gin.Context) { getByIdentity[models.PlatformRole](ctx) } + +// CreatePlatformRole 创建非内置平台角色。 +func CreatePlatformRole(ctx *gin.Context) { + var request models.PlatformRole + if err := ctx.ShouldBindJSON(&request); err != nil || request.RoleCode == "" || request.Name == "" || request.RoleCode == "root" { + infra.Response.Error(ctx, errcode.ErrInvalidArgument) + return + } + request.Entity = newEntity("enabled") + request.IsSystem = false + if request.DataScope == "" { + request.DataScope = "global" + } + if err := impl.DBService.Create(&request).Error; err != nil { + infra.Response.Error(ctx, err) + return + } + infra.Response.Success(ctx, request) +} + +// UpdatePlatformRole 更新非内置平台角色。 +func UpdatePlatformRole(ctx *gin.Context) { + var request struct { + Name string `json:"name" binding:"required,max=64"` + DataScope string `json:"data_scope" binding:"required,max=32"` + } + if err := ctx.ShouldBindJSON(&request); err != nil { + infra.Response.Error(ctx, errcode.ErrInvalidArgument) + return + } + var role models.PlatformRole + if err := impl.DBService.Where("identity = ?", ctx.Param("identity")).First(&role).Error; err != nil { + respondRecordError(ctx, err) + return + } + if role.IsSystem { + infra.Response.Error(ctx, errcode.ErrInvalidArgument) + return + } + if err := impl.DBService.Model(&role).Updates(gin.H{"name": request.Name, "data_scope": request.DataScope}).Error; err != nil { + infra.Response.Error(ctx, err) + return + } + infra.Response.Success(ctx, role) +} + +// UpdatePlatformRoleStatus 更新非内置平台角色状态,root 等系统角色始终受保护。 +func UpdatePlatformRoleStatus(ctx *gin.Context) { + var request struct { + Status string `json:"status" binding:"required,max=32"` + } + if err := ctx.ShouldBindJSON(&request); err != nil { + infra.Response.Error(ctx, errcode.ErrInvalidArgument) + return + } + var role models.PlatformRole + if err := impl.DBService.Where("identity = ?", ctx.Param("identity")).First(&role).Error; err != nil { + respondRecordError(ctx, err) + return + } + if role.IsSystem { + infra.Response.Error(ctx, errcode.ErrInvalidArgument) + return + } + if err := impl.DBService.Model(&role).Update("status", request.Status).Error; err != nil { + infra.Response.Error(ctx, err) + return + } + infra.Response.Success(ctx, gin.H{"updated": true}) +} + +// ArchivePlatformRole 归档非内置平台角色,root 等系统角色始终受保护。 +func ArchivePlatformRole(ctx *gin.Context) { + var role models.PlatformRole + if err := impl.DBService.Where("identity = ?", ctx.Param("identity")).First(&role).Error; err != nil { + respondRecordError(ctx, err) + return + } + if role.IsSystem { + infra.Response.Error(ctx, errcode.ErrInvalidArgument) + return + } + if err := impl.DBService.Model(&role).Update("status", "archived").Error; err != nil { + infra.Response.Error(ctx, err) + return + } + infra.Response.Success(ctx, gin.H{"updated": true}) +} + +// ListPlatformMenu 返回菜单树构建所需的有序菜单列表。 +func ListPlatformMenu(ctx *gin.Context) { + var list []models.PlatformMenu + if err := impl.DBService.Order("sort_no asc, id asc").Find(&list).Error; err != nil { + infra.Response.Error(ctx, err) + return + } + infra.Response.Success(ctx, gin.H{"total": len(list), "list": list}) +} + +// UpdateRecordStatus 更新主表状态,停用和归档均保留历史记录。 +func UpdateRecordStatus(ctx *gin.Context, model any) { + var request struct { + Status string `json:"status" binding:"required,max=32"` + } + if err := ctx.ShouldBindJSON(&request); err != nil { + infra.Response.Error(ctx, errcode.ErrInvalidArgument) + return + } + updateByIdentity(ctx, model, gin.H{"status": request.Status}) +} + +// ArchiveRecord 通过 archived 状态实现逻辑删除,不物理删除主数据。 +func ArchiveRecord(ctx *gin.Context, model any) { + updateByIdentity(ctx, model, gin.H{"status": "archived"}) +} + +// ListPlatfromAccount 查询平台账号列表,手机号在展示层脱敏。 +func ListPlatfromAccount(ctx *gin.Context) { + page, size := pageSize(ctx) + list, total, err := models.ListPlatfromAccount(page, size) + if err != nil { + infra.Response.Error(ctx, err) + return + } + views := make([]gin.H, 0, len(list)) + for _, item := range list { + views = append(views, gin.H{"identity": item.Identity, "username": item.Username, "display_name": item.DisplayName, "avatar": item.Avatar, "phone_masked": maskPhone(item.Phone), "platform_role_code": item.PlatformRoleCode, "status": item.Status}) + } + infra.Response.Success(ctx, gin.H{"total": total, "list": views}) +} + +func newEntity(status string) models.Entity { + return models.Entity{Identity: models.NewIdentity(), Status: status, Version: 1} +} + +func listPage[T any](ctx *gin.Context) { + page, size := pageSize(ctx) + var list []T + var total int64 + databaseQuery := impl.DBService.Model(new(T)) + if err := databaseQuery.Count(&total).Error; err != nil { + infra.Response.Error(ctx, err) + return + } + if err := databaseQuery.Order("created_at desc").Offset((page - 1) * size).Limit(size).Find(&list).Error; err != nil { + infra.Response.Error(ctx, err) + return + } + infra.Response.Success(ctx, gin.H{"total": total, "list": list}) +} + +func getByIdentity[T any](ctx *gin.Context) { + var data T + if err := impl.DBService.Where("identity = ?", ctx.Param("identity")).First(&data).Error; err != nil { + respondRecordError(ctx, err) + return + } infra.Response.Success(ctx, data) } -// ListOrgGasStation 查询气站分页列表。 -func ListOrgGasStation(ctx *gin.Context) { - page, size := pageSize(ctx) - list, total, err := models.ListOrgGasStation(page, size) - if err != nil { - infra.Response.Error(ctx, err) +func updateByIdentity(ctx *gin.Context, model any, values map[string]any) { + result := impl.DBService.Model(model).Where("identity = ?", ctx.Param("identity")).Updates(values) + if result.Error != nil { + infra.Response.Error(ctx, result.Error) return } - infra.Response.Success(ctx, OrgGasStationListReply{Total: total, List: list}) -} - -// OrgDeliveryPointListReply 是 org_delivery_point 的标准分页响应。 -type OrgDeliveryPointListReply struct { - Total int64 `json:"total"` - List []models.OrgDeliveryPoint `json:"list"` -} - -// ListOrgDeliveryPoint 查询配送点分页列表。 -func ListOrgDeliveryPoint(ctx *gin.Context) { - page, size := pageSize(ctx) - list, total, err := models.ListOrgDeliveryPoint(page, size) - if err != nil { - infra.Response.Error(ctx, err) + if result.RowsAffected == 0 { + infra.Response.Error(ctx, errcode.ErrRecordNotFound) return } - infra.Response.Success(ctx, OrgDeliveryPointListReply{Total: total, List: list}) + infra.Response.Success(ctx, gin.H{"updated": true}) } -// OrgServicePersonListReply 是 org_service_person 的标准分页响应。 -type OrgServicePersonListReply struct { - Total int64 `json:"total"` - List []models.OrgServicePerson `json:"list"` -} - -// ListOrgServicePerson 查询服务人员分页列表。 -func ListOrgServicePerson(ctx *gin.Context) { - page, size := pageSize(ctx) - list, total, err := models.ListOrgServicePerson(page, size) - if err != nil { - infra.Response.Error(ctx, err) +func respondRecordError(ctx *gin.Context, err error) { + if errors.Is(err, gorm.ErrRecordNotFound) { + infra.Response.Error(ctx, errcode.ErrRecordNotFound) return } - infra.Response.Success(ctx, OrgServicePersonListReply{Total: total, List: list}) + infra.Response.Error(ctx, err) } -// IdnAccountView 是 idn_account 的最小必要输出,手机号始终脱敏。 -type IdnAccountView struct { - Identity string `json:"identity"` - PhoneMasked string `json:"phone_masked"` - AccountType string `json:"account_type"` - Status string `json:"status"` - ServiceArea string `json:"service_area"` -} - -// IdnAccountListReply 是 idn_account 的标准分页响应。 -type IdnAccountListReply struct { - Total int64 `json:"total"` - List []IdnAccountView `json:"list"` -} - -// ListIdnAccount 查询普通用户账户列表。 -func ListIdnAccount(ctx *gin.Context) { - page, size := pageSize(ctx) - list, total, err := models.ListIdnAccount(page, size) - if err != nil { - infra.Response.Error(ctx, err) - return - } - views := make([]IdnAccountView, 0, len(list)) - for _, item := range list { - views = append(views, IdnAccountView{Identity: item.Identity.String(), PhoneMasked: maskPhone(item.Phone), AccountType: item.AccountType, Status: item.Status, ServiceArea: item.ServiceArea}) - } - infra.Response.Success(ctx, IdnAccountListReply{Total: total, List: views}) -} - -// SafEventListReply 是 saf_event 的标准分页响应。 -type SafEventListReply struct { - Total int64 `json:"total"` - List []models.SafEvent `json:"list"` -} - -// ListSafEvent 查询安全事件列表。 -func ListSafEvent(ctx *gin.Context) { - page, size := pageSize(ctx) - list, total, err := models.ListSafEvent(page, size) - if err != nil { - infra.Response.Error(ctx, err) - return - } - infra.Response.Success(ctx, SafEventListReply{Total: total, List: list}) -} - -// pageSize 统一约束分页参数,避免各接口出现不同边界。 func pageSize(ctx *gin.Context) (int, int) { page := utils.String2Int(ctx.DefaultQuery("page", "1")) size := utils.String2Int(ctx.DefaultQuery("size", "20")) @@ -161,7 +378,6 @@ func pageSize(ctx *gin.Context) (int, int) { return page, size } -// maskPhone 遵循敏感数据最小展示原则。 func maskPhone(phone string) string { if len(phone) < 7 { return "***" diff --git a/backend/api/internal/logic/upload/upload.go b/backend/api/internal/logic/upload/upload.go new file mode 100644 index 0000000..d713eb8 --- /dev/null +++ b/backend/api/internal/logic/upload/upload.go @@ -0,0 +1,87 @@ +// Package upload 提供平台总后台的受控文件上传服务。 +package upload + +import ( + "io" + "net/http" + "os" + "path/filepath" + "strings" + "time" + + "git.apinb.com/bsm-sdk/core/errcode" + "git.apinb.com/bsm-sdk/core/infra" + "git.apinb.com/heqiapp/platforms/backend/api/internal/models" + "github.com/gin-gonic/gin" +) + +const maxUploadSize int64 = 10 << 20 + +var allowedExtensions = map[string]struct{}{ + ".jpg": {}, ".jpeg": {}, ".png": {}, ".webp": {}, ".pdf": {}, +} + +// UploadFileReply 是文件上传完成后返回的受控资源标识。 +type UploadFileReply struct { + URI string `json:"uri"` // 资源访问标识,后续可由对象存储适配层解析 + OriginalName string `json:"original_name"` // 原始文件名,仅用于展示 + ContentType string `json:"content_type"` // 客户端声明的媒体类型 + Size int64 `json:"size"` // 文件字节数 +} + +// UploadFile 将允许类型的文件保存至本地 Mock 存储,不直接暴露绝对磁盘路径。 +func UploadFile(ctx *gin.Context) { + ctx.Request.Body = http.MaxBytesReader(ctx.Writer, ctx.Request.Body, maxUploadSize) + fileHeader, err := ctx.FormFile("file") + if err != nil || fileHeader == nil || fileHeader.Size <= 0 || fileHeader.Size > maxUploadSize { + infra.Response.Error(ctx, errcode.ErrInvalidArgument) + return + } + + extension := strings.ToLower(filepath.Ext(fileHeader.Filename)) + if _, allowed := allowedExtensions[extension]; !allowed { + infra.Response.Error(ctx, errcode.ErrInvalidArgument) + return + } + + file, err := fileHeader.Open() + if err != nil { + infra.Response.Error(ctx, err) + return + } + defer file.Close() + + datePath := time.Now().Format("2006/01/02") + filename := models.NewIdentity() + extension + directory := filepath.Join(uploadRoot(), filepath.FromSlash(datePath)) + if err := os.MkdirAll(directory, 0o750); err != nil { + infra.Response.Error(ctx, err) + return + } + + target, err := os.OpenFile(filepath.Join(directory, filename), os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o640) + if err != nil { + infra.Response.Error(ctx, err) + return + } + defer target.Close() + if _, err := io.Copy(target, file); err != nil { + infra.Response.Error(ctx, err) + return + } + + infra.Response.Success(ctx, UploadFileReply{ + URI: "/uploads/" + datePath + "/" + filename, + OriginalName: fileHeader.Filename, + ContentType: fileHeader.Header.Get("Content-Type"), + Size: fileHeader.Size, + }) +} + +// uploadRoot 返回本地 Mock 存储根目录;生产环境可通过环境变量映射到受控挂载目录。 +func uploadRoot() string { + if directory := strings.TrimSpace(os.Getenv("HEQI_UPLOAD_DIR")); directory != "" { + return directory + } + return filepath.Join("runtime", "uploads") +} diff --git a/backend/api/internal/models/aud_approval.go b/backend/api/internal/models/aud_approval.go new file mode 100644 index 0000000..a028fc3 --- /dev/null +++ b/backend/api/internal/models/aud_approval.go @@ -0,0 +1,15 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// AudApproval 对应 aud_approval,保存审批流与复核意见。 +type AudApproval struct { + Entity + BusinessType string `gorm:"column:business_type;type:varchar(64);not null" json:"business_type"` + BusinessIdentity string `gorm:"column:business_identity;type:varchar(36);not null;index" json:"business_identity"` + ApplicantIdentity string `gorm:"column:applicant_identity;type:varchar(36);not null;index" json:"applicant_identity"` + Opinion string `gorm:"column:opinion;type:text;not null;default:''" json:"opinion"` +} + +func init() { database.AppendMigrate(&AudApproval{}) } +func (table *AudApproval) TableName() string { return "aud_approval" } diff --git a/backend/api/internal/models/aud_export_log.go b/backend/api/internal/models/aud_export_log.go new file mode 100644 index 0000000..6374886 --- /dev/null +++ b/backend/api/internal/models/aud_export_log.go @@ -0,0 +1,19 @@ +package models + +import ( + "git.apinb.com/bsm-sdk/core/database" + "time" +) + +// AudExportLog 对应 aud_export_log,保存敏感导出审计。 +type AudExportLog struct { + Entity + ApplicantIdentity string `gorm:"column:applicant_identity;type:varchar(36);not null;index" json:"applicant_identity"` + Purpose string `gorm:"column:purpose;type:varchar(255);not null" json:"purpose"` + FieldScope string `gorm:"column:field_scope;type:jsonb;not null;default:'{}'" json:"field_scope"` + ApprovedAt *time.Time `gorm:"column:approved_at;type:timestamptz" json:"approved_at"` + FileURI string `gorm:"column:file_uri;type:varchar(512);not null;default:''" json:"file_uri"` +} + +func init() { database.AppendMigrate(&AudExportLog{}) } +func (table *AudExportLog) TableName() string { return "aud_export_log" } diff --git a/backend/api/internal/models/aud_operation_log.go b/backend/api/internal/models/aud_operation_log.go new file mode 100644 index 0000000..2aaca45 --- /dev/null +++ b/backend/api/internal/models/aud_operation_log.go @@ -0,0 +1,17 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// AudOperationLog 对应 aud_operation_log,保存不可变操作审计。 +type AudOperationLog struct { + Entity + OperatorIdentity string `gorm:"column:operator_identity;type:varchar(36);not null;index" json:"operator_identity"` + Action string `gorm:"column:action;type:varchar(64);not null" json:"action"` + ObjectType string `gorm:"column:object_type;type:varchar(64);not null" json:"object_type"` + ObjectIdentity string `gorm:"column:object_identity;type:varchar(36);not null;index" json:"object_identity"` + BeforeData string `gorm:"column:before_data;type:jsonb;not null;default:'{}'" json:"before_data"` + AfterData string `gorm:"column:after_data;type:jsonb;not null;default:'{}'" json:"after_data"` +} + +func init() { database.AppendMigrate(&AudOperationLog{}) } +func (table *AudOperationLog) TableName() string { return "aud_operation_log" } diff --git a/backend/api/internal/models/cnt_content.go b/backend/api/internal/models/cnt_content.go new file mode 100644 index 0000000..ccaefc6 --- /dev/null +++ b/backend/api/internal/models/cnt_content.go @@ -0,0 +1,16 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// CntContent 对应 cnt_content,保存公告与协议内容。 +type CntContent struct { + Entity + ContentType string `gorm:"column:content_type;type:varchar(32);not null" json:"content_type"` + Title string `gorm:"column:title;type:varchar(256);not null" json:"title"` + Body string `gorm:"column:body;type:text;not null;default:''" json:"body"` + VersionNo int `gorm:"column:version_no;not null;default:1" json:"version_no"` + PublishStatus string `gorm:"column:publish_status;type:varchar(32);not null;default:'draft'" json:"publish_status"` +} + +func init() { database.AppendMigrate(&CntContent{}) } +func (table *CntContent) TableName() string { return "cnt_content" } diff --git a/backend/api/internal/models/cs_ticket.go b/backend/api/internal/models/cs_ticket.go new file mode 100644 index 0000000..e8a1f51 --- /dev/null +++ b/backend/api/internal/models/cs_ticket.go @@ -0,0 +1,15 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// CsTicket 对应 cs_ticket,保存客服工单。 +type CsTicket struct { + Entity + TicketNo string `gorm:"column:ticket_no;type:varchar(64);not null;uniqueIndex" json:"ticket_no"` + UserAccountID uint64 `gorm:"column:user_account_id;not null;index" json:"user_account_id"` + Category string `gorm:"column:category;type:varchar(64);not null" json:"category"` + Priority string `gorm:"column:priority;type:varchar(16);not null;default:'normal'" json:"priority"` +} + +func init() { database.AppendMigrate(&CsTicket{}) } +func (table *CsTicket) TableName() string { return "cs_ticket" } diff --git a/backend/api/internal/models/delivery_account.go b/backend/api/internal/models/delivery_account.go new file mode 100644 index 0000000..e093c0c --- /dev/null +++ b/backend/api/internal/models/delivery_account.go @@ -0,0 +1,16 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// DeliveryAccount 对应 delivery_account,保存配送点登录账户。 +type DeliveryAccount struct { + Entity + DeliveryBasicID uint64 `gorm:"column:delivery_basic_id;not null;index" json:"delivery_basic_id"` + Username string `gorm:"column:username;type:varchar(64);not null;uniqueIndex" json:"username"` + DisplayName string `gorm:"column:display_name;type:varchar(64);not null;default:''" json:"display_name"` + PasswordHash string `gorm:"column:password_hash;type:varchar(255);not null" json:"-"` + RoleCode string `gorm:"column:role_code;type:varchar(64);not null" json:"role_code"` +} + +func init() { database.AppendMigrate(&DeliveryAccount{}) } +func (table *DeliveryAccount) TableName() string { return "delivery_account" } diff --git a/backend/api/internal/models/delivery_basic.go b/backend/api/internal/models/delivery_basic.go new file mode 100644 index 0000000..4746829 --- /dev/null +++ b/backend/api/internal/models/delivery_basic.go @@ -0,0 +1,18 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// DeliveryBasic 对应 delivery_basic,保存配送点主档案。 +type DeliveryBasic struct { + Entity + DeliveryCode string `gorm:"column:delivery_code;type:varchar(32);not null;uniqueIndex" json:"delivery_code"` // 配送点编码 + GasBasicID uint64 `gorm:"column:gas_basic_id;not null;default:0;index" json:"gas_basic_id"` // 所属可燃气体站自增主键,0 表示平台直属 + Name string `gorm:"column:name;type:varchar(128);not null" json:"name"` // 配送点名称 + Principal string `gorm:"column:principal;type:varchar(64);not null;default:''" json:"principal"` // 负责人 + Address string `gorm:"column:address;type:varchar(255);not null;default:''" json:"address"` // 配送点地址 +} + +func init() { database.AppendMigrate(&DeliveryBasic{}) } + +// TableName 返回与模型、文件名一致的单数数据表名。 +func (table *DeliveryBasic) TableName() string { return "delivery_basic" } diff --git a/backend/api/internal/models/delivery_task.go b/backend/api/internal/models/delivery_task.go new file mode 100644 index 0000000..1479178 --- /dev/null +++ b/backend/api/internal/models/delivery_task.go @@ -0,0 +1,14 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// DeliveryTask 对应 delivery_task,保存配送履约任务。 +type DeliveryTask struct { + Entity + EcOrderID uint64 `gorm:"column:ec_order_id;not null;index" json:"ec_order_id"` + StaffAccountID uint64 `gorm:"column:staff_account_id;not null;default:0;index" json:"staff_account_id"` + DeliveryPointID uint64 `gorm:"column:delivery_point_id;not null;index" json:"delivery_point_id"` +} + +func init() { database.AppendMigrate(&DeliveryTask{}) } +func (table *DeliveryTask) TableName() string { return "delivery_task" } diff --git a/backend/api/internal/models/delivery_track.go b/backend/api/internal/models/delivery_track.go new file mode 100644 index 0000000..bddf6aa --- /dev/null +++ b/backend/api/internal/models/delivery_track.go @@ -0,0 +1,17 @@ +package models + +import ( + "git.apinb.com/bsm-sdk/core/database" + "time" +) + +// DeliveryTrack 对应 delivery_track,保存配送轨迹摘要。 +type DeliveryTrack struct { + Entity + DeliveryTaskID uint64 `gorm:"column:delivery_task_id;not null;index" json:"delivery_task_id"` + StartedAt *time.Time `gorm:"column:started_at;type:timestamptz" json:"started_at"` + CompletedAt *time.Time `gorm:"column:completed_at;type:timestamptz" json:"completed_at"` +} + +func init() { database.AppendMigrate(&DeliveryTrack{}) } +func (table *DeliveryTrack) TableName() string { return "delivery_track" } diff --git a/backend/api/internal/models/delivery_track_point.go b/backend/api/internal/models/delivery_track_point.go new file mode 100644 index 0000000..3ad0282 --- /dev/null +++ b/backend/api/internal/models/delivery_track_point.go @@ -0,0 +1,19 @@ +package models + +import ( + "git.apinb.com/bsm-sdk/core/database" + "time" +) + +// DeliveryTrackPoint 对应 delivery_track_point,保存配送节点和位置。 +type DeliveryTrackPoint struct { + Entity + DeliveryTrackID uint64 `gorm:"column:delivery_track_id;not null;index" json:"delivery_track_id"` + PointType string `gorm:"column:point_type;type:varchar(32);not null" json:"point_type"` + OccurredAt time.Time `gorm:"column:occurred_at;type:timestamptz;not null" json:"occurred_at"` + Longitude string `gorm:"column:longitude;type:varchar(32);not null;default:''" json:"longitude"` + Latitude string `gorm:"column:latitude;type:varchar(32);not null;default:''" json:"latitude"` +} + +func init() { database.AppendMigrate(&DeliveryTrackPoint{}) } +func (table *DeliveryTrackPoint) TableName() string { return "delivery_track_point" } diff --git a/backend/api/internal/models/dev_device_binding.go b/backend/api/internal/models/dev_device_binding.go new file mode 100644 index 0000000..4b2afb6 --- /dev/null +++ b/backend/api/internal/models/dev_device_binding.go @@ -0,0 +1,18 @@ +package models + +import ( + "git.apinb.com/bsm-sdk/core/database" + "time" +) + +// DevDeviceBinding 对应 dev_device_binding,保存设备授权绑定。 +type DevDeviceBinding struct { + Entity + SmartCylinderValveID uint64 `gorm:"column:smart_cylinder_valve_id;not null;index" json:"smart_cylinder_valve_id"` + UserAccountID uint64 `gorm:"column:user_account_id;not null;index" json:"user_account_id"` + EffectiveAt time.Time `gorm:"column:effective_at;type:timestamptz;not null" json:"effective_at"` + ExpiredAt *time.Time `gorm:"column:expired_at;type:timestamptz" json:"expired_at"` +} + +func init() { database.AppendMigrate(&DevDeviceBinding{}) } +func (table *DevDeviceBinding) TableName() string { return "dev_device_binding" } diff --git a/backend/api/internal/models/dev_smart_cylinder_valve.go b/backend/api/internal/models/dev_smart_cylinder_valve.go new file mode 100644 index 0000000..ad89771 --- /dev/null +++ b/backend/api/internal/models/dev_smart_cylinder_valve.go @@ -0,0 +1,15 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// DevSmartCylinderValve 对应 dev_smart_cylinder_valve,保存智能瓶阀档案。 +type DevSmartCylinderValve struct { + Entity + DeviceNo string `gorm:"column:device_no;type:varchar(64);not null;uniqueIndex" json:"device_no"` + Model string `gorm:"column:model;type:varchar(64);not null;default:''" json:"model"` + OnlineStatus string `gorm:"column:online_status;type:varchar(32);not null;default:'offline'" json:"online_status"` + OwnerIdentity string `gorm:"column:owner_identity;type:varchar(36);not null;default:'';index" json:"owner_identity"` +} + +func init() { database.AppendMigrate(&DevSmartCylinderValve{}) } +func (table *DevSmartCylinderValve) TableName() string { return "dev_smart_cylinder_valve" } diff --git a/backend/api/internal/models/dev_telemetry.go b/backend/api/internal/models/dev_telemetry.go new file mode 100644 index 0000000..1aea5fa --- /dev/null +++ b/backend/api/internal/models/dev_telemetry.go @@ -0,0 +1,18 @@ +package models + +import ( + "git.apinb.com/bsm-sdk/core/database" + "time" +) + +// DevTelemetry 对应 dev_telemetry,保存设备遥测摘要。 +type DevTelemetry struct { + Entity + SmartCylinderValveIdentity string `gorm:"column:smart_cylinder_valve_identity;type:varchar(36);not null;index" json:"smart_cylinder_valve_identity"` + ReportedAt time.Time `gorm:"column:reported_at;type:timestamptz;not null;index" json:"reported_at"` + Payload string `gorm:"column:payload;type:jsonb;not null;default:'{}'" json:"payload"` + QualityFlag string `gorm:"column:quality_flag;type:varchar(32);not null;default:'normal'" json:"quality_flag"` +} + +func init() { database.AppendMigrate(&DevTelemetry{}) } +func (table *DevTelemetry) TableName() string { return "dev_telemetry" } diff --git a/backend/api/internal/models/ec_cart.go b/backend/api/internal/models/ec_cart.go new file mode 100644 index 0000000..46623e4 --- /dev/null +++ b/backend/api/internal/models/ec_cart.go @@ -0,0 +1,15 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// EcCart 对应 ec_cart,保存用户购物车明细。 +type EcCart struct { + Entity + UserAccountID uint64 `gorm:"column:user_account_id;not null;index" json:"user_account_id"` + EcProductID uint64 `gorm:"column:ec_product_id;not null;index" json:"ec_product_id"` + Quantity int `gorm:"column:quantity;not null;default:1" json:"quantity"` + Selected bool `gorm:"column:selected;not null;default:true" json:"selected"` +} + +func init() { database.AppendMigrate(&EcCart{}) } +func (table *EcCart) TableName() string { return "ec_cart" } diff --git a/backend/api/internal/models/ec_category.go b/backend/api/internal/models/ec_category.go new file mode 100644 index 0000000..1b48ad1 --- /dev/null +++ b/backend/api/internal/models/ec_category.go @@ -0,0 +1,14 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// EcCategory 对应 ec_category,保存商品分类树。 +type EcCategory struct { + Entity + ParentID uint64 `gorm:"column:parent_id;not null;default:0;index" json:"parent_id"` + Name string `gorm:"column:name;type:varchar(128);not null" json:"name"` + SortNo int `gorm:"column:sort_no;not null;default:0" json:"sort_no"` +} + +func init() { database.AppendMigrate(&EcCategory{}) } +func (table *EcCategory) TableName() string { return "ec_category" } diff --git a/backend/api/internal/models/ec_order.go b/backend/api/internal/models/ec_order.go new file mode 100644 index 0000000..bb21b82 --- /dev/null +++ b/backend/api/internal/models/ec_order.go @@ -0,0 +1,16 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// EcOrder 对应 ec_order,保存电商订单与组织快照。 +type EcOrder struct { + Entity + OrderNo string `gorm:"column:order_no;type:varchar(64);not null;uniqueIndex" json:"order_no"` + UserAccountID uint64 `gorm:"column:user_account_id;not null;index" json:"user_account_id"` + GasStationID uint64 `gorm:"column:gas_station_id;not null;default:0;index" json:"gas_station_id"` + DeliveryPointID uint64 `gorm:"column:delivery_point_id;not null;default:0;index" json:"delivery_point_id"` + TotalAmount int64 `gorm:"column:total_amount;not null;default:0" json:"total_amount"` +} + +func init() { database.AppendMigrate(&EcOrder{}) } +func (table *EcOrder) TableName() string { return "ec_order" } diff --git a/backend/api/internal/models/ec_order_item.go b/backend/api/internal/models/ec_order_item.go new file mode 100644 index 0000000..7d60a9d --- /dev/null +++ b/backend/api/internal/models/ec_order_item.go @@ -0,0 +1,16 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// EcOrderItem 对应 ec_order_item,保存订单商品快照。 +type EcOrderItem struct { + Entity + EcOrderID uint64 `gorm:"column:ec_order_id;not null;index" json:"ec_order_id"` + EcProductID uint64 `gorm:"column:ec_product_id;not null;index" json:"ec_product_id"` + ProductSnapshot string `gorm:"column:product_snapshot;type:jsonb;not null;default:'{}'" json:"product_snapshot"` + Quantity int `gorm:"column:quantity;not null;default:1" json:"quantity"` + SaleAmount int64 `gorm:"column:sale_amount;not null;default:0" json:"sale_amount"` +} + +func init() { database.AppendMigrate(&EcOrderItem{}) } +func (table *EcOrderItem) TableName() string { return "ec_order_item" } diff --git a/backend/api/internal/models/ec_product.go b/backend/api/internal/models/ec_product.go new file mode 100644 index 0000000..9f6b40e --- /dev/null +++ b/backend/api/internal/models/ec_product.go @@ -0,0 +1,16 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// EcProduct 对应 ec_product,保存可燃气体商品与服务。 +type EcProduct struct { + Entity + EcCategoryID uint64 `gorm:"column:ec_category_id;not null;index" json:"ec_category_id"` + ProductCode string `gorm:"column:product_code;type:varchar(64);not null;uniqueIndex" json:"product_code"` + Name string `gorm:"column:name;type:varchar(128);not null" json:"name"` + PriceAmount int64 `gorm:"column:price_amount;not null;default:0" json:"price_amount"` + StockQuantity int `gorm:"column:stock_quantity;not null;default:0" json:"stock_quantity"` +} + +func init() { database.AppendMigrate(&EcProduct{}) } +func (table *EcProduct) TableName() string { return "ec_product" } diff --git a/backend/api/internal/models/ec_product_attribute.go b/backend/api/internal/models/ec_product_attribute.go new file mode 100644 index 0000000..56e3abb --- /dev/null +++ b/backend/api/internal/models/ec_product_attribute.go @@ -0,0 +1,15 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// EcProductAttribute 对应 ec_product_attribute,保存商品属性。 +type EcProductAttribute struct { + Entity + EcProductID uint64 `gorm:"column:ec_product_id;not null;index" json:"ec_product_id"` + Name string `gorm:"column:name;type:varchar(64);not null" json:"name"` + Value string `gorm:"column:value;type:varchar(255);not null" json:"value"` + SortNo int `gorm:"column:sort_no;not null;default:0" json:"sort_no"` +} + +func init() { database.AppendMigrate(&EcProductAttribute{}) } +func (table *EcProductAttribute) TableName() string { return "ec_product_attribute" } diff --git a/backend/api/internal/models/ec_product_image.go b/backend/api/internal/models/ec_product_image.go new file mode 100644 index 0000000..ec52f1b --- /dev/null +++ b/backend/api/internal/models/ec_product_image.go @@ -0,0 +1,15 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// EcProductImage 对应 ec_product_image,保存商品受控图片资源。 +type EcProductImage struct { + Entity + EcProductID uint64 `gorm:"column:ec_product_id;not null;index" json:"ec_product_id"` + ImageURI string `gorm:"column:image_uri;type:varchar(512);not null" json:"image_uri"` + SortNo int `gorm:"column:sort_no;not null;default:0" json:"sort_no"` + IsCover bool `gorm:"column:is_cover;not null;default:false" json:"is_cover"` +} + +func init() { database.AppendMigrate(&EcProductImage{}) } +func (table *EcProductImage) TableName() string { return "ec_product_image" } diff --git a/backend/api/internal/models/ec_review.go b/backend/api/internal/models/ec_review.go new file mode 100644 index 0000000..5f83a85 --- /dev/null +++ b/backend/api/internal/models/ec_review.go @@ -0,0 +1,16 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// EcReview 对应 ec_review,保存商品评论与审核状态。 +type EcReview struct { + Entity + EcOrderID uint64 `gorm:"column:ec_order_id;not null;index" json:"ec_order_id"` + EcProductID uint64 `gorm:"column:ec_product_id;not null;index" json:"ec_product_id"` + UserAccountID uint64 `gorm:"column:user_account_id;not null;index" json:"user_account_id"` + Score int `gorm:"column:score;not null;default:5" json:"score"` + Content string `gorm:"column:content;type:text;not null;default:''" json:"content"` +} + +func init() { database.AppendMigrate(&EcReview{}) } +func (table *EcReview) TableName() string { return "ec_review" } diff --git a/backend/api/internal/models/entity.go b/backend/api/internal/models/entity.go index 4e277a5..39effda 100644 --- a/backend/api/internal/models/entity.go +++ b/backend/api/internal/models/entity.go @@ -1,4 +1,4 @@ -// Package models 定义与数据库表同名的领域模型和数据访问方法。 +// Package models 定义与数据表同名的领域模型和数据访问方法。 package models import ( @@ -7,22 +7,21 @@ import ( "github.com/google/uuid" ) -// Entity 是所有主表共享字段;identity 必须由应用生成 UUID V7,禁止自增主键。 +// Entity 是所有主表共享字段。id 是数据库自增主键,identity 是应用生成的 UUID V7 业务标识。 type Entity struct { - Identity uuid.UUID `gorm:"column:identity;type:uuid;primaryKey" json:"identity"` // 主键,UUID V7 - CreatedAt time.Time `gorm:"column:created_at;type:timestamptz;not null" json:"created_at"` // 创建时间 - UpdatedAt time.Time `gorm:"column:updated_at;type:timestamptz;not null" json:"updated_at"` // 更新时间 - CreatedByIdentity *uuid.UUID `gorm:"column:created_by_identity;type:uuid" json:"created_by_identity,omitempty"` // 创建人主键 - UpdatedByIdentity *uuid.UUID `gorm:"column:updated_by_identity;type:uuid" json:"updated_by_identity,omitempty"` // 更新人主键 - Status string `gorm:"column:status;type:varchar(32);not null;default:'draft'" json:"status"` // 业务状态 - Version int `gorm:"column:version;not null;default:1" json:"version"` // 乐观锁版本 + ID uint64 `gorm:"column:id;primaryKey;autoIncrement" json:"id"` // 数据库自增主键 + Identity string `gorm:"column:identity;type:varchar(36);not null;uniqueIndex" json:"identity"` // UUID V7 业务标识 + CreatedAt time.Time `gorm:"column:created_at;type:timestamptz;not null" json:"created_at"` // 创建时间 + UpdatedAt time.Time `gorm:"column:updated_at;type:timestamptz;not null" json:"updated_at"` // 更新时间 + Status string `gorm:"column:status;type:varchar(32);not null;default:'draft'" json:"status"` // 业务状态 + Version int `gorm:"column:version;not null;default:1" json:"version"` // 乐观锁版本 } -// NewIdentity 生成时间有序 UUID V7,生成失败属于不可恢复的运行时错误。 -func NewIdentity() uuid.UUID { +// NewIdentity 生成时间有序的 UUID V7 字符串,生成失败属于不可恢复的运行时错误。 +func NewIdentity() string { identity, err := uuid.NewV7() if err != nil { panic(err) } - return identity + return identity.String() } diff --git a/backend/api/internal/models/fin_payment.go b/backend/api/internal/models/fin_payment.go new file mode 100644 index 0000000..cdc004a --- /dev/null +++ b/backend/api/internal/models/fin_payment.go @@ -0,0 +1,18 @@ +package models + +import ( + "git.apinb.com/bsm-sdk/core/database" + "time" +) + +// FinPayment 对应 fin_payment,保存支付与退款记录。 +type FinPayment struct { + Entity + EcOrderID uint64 `gorm:"column:ec_order_id;not null;index" json:"ec_order_id"` + Channel string `gorm:"column:channel;type:varchar(32);not null" json:"channel"` + Amount int64 `gorm:"column:amount;not null;default:0" json:"amount"` + PaidAt *time.Time `gorm:"column:paid_at;type:timestamptz" json:"paid_at"` +} + +func init() { database.AppendMigrate(&FinPayment{}) } +func (table *FinPayment) TableName() string { return "fin_payment" } diff --git a/backend/api/internal/models/fin_reconciliation.go b/backend/api/internal/models/fin_reconciliation.go new file mode 100644 index 0000000..0369a46 --- /dev/null +++ b/backend/api/internal/models/fin_reconciliation.go @@ -0,0 +1,17 @@ +package models + +import ( + "git.apinb.com/bsm-sdk/core/database" + "time" +) + +// FinReconciliation 对应 fin_reconciliation,保存渠道对账记录。 +type FinReconciliation struct { + Entity + Channel string `gorm:"column:channel;type:varchar(32);not null;index" json:"channel"` + BillDate time.Time `gorm:"column:bill_date;type:date;not null" json:"bill_date"` + DifferenceAmount int64 `gorm:"column:difference_amount;not null;default:0" json:"difference_amount"` +} + +func init() { database.AppendMigrate(&FinReconciliation{}) } +func (table *FinReconciliation) TableName() string { return "fin_reconciliation" } diff --git a/backend/api/internal/models/fin_settlement.go b/backend/api/internal/models/fin_settlement.go new file mode 100644 index 0000000..664c104 --- /dev/null +++ b/backend/api/internal/models/fin_settlement.go @@ -0,0 +1,19 @@ +package models + +import ( + "git.apinb.com/bsm-sdk/core/database" + "time" +) + +// FinSettlement 对应 fin_settlement,保存结算单。 +type FinSettlement struct { + Entity + SettlementNo string `gorm:"column:settlement_no;type:varchar(64);not null;uniqueIndex" json:"settlement_no"` + SubjectType string `gorm:"column:subject_type;type:varchar(32);not null" json:"subject_type"` + SubjectID uint64 `gorm:"column:subject_id;not null;index" json:"subject_id"` + PeriodStart time.Time `gorm:"column:period_start;type:timestamptz;not null" json:"period_start"` + PeriodEnd time.Time `gorm:"column:period_end;type:timestamptz;not null" json:"period_end"` +} + +func init() { database.AppendMigrate(&FinSettlement{}) } +func (table *FinSettlement) TableName() string { return "fin_settlement" } diff --git a/backend/api/internal/models/gas_account.go b/backend/api/internal/models/gas_account.go new file mode 100644 index 0000000..5b1c3bd --- /dev/null +++ b/backend/api/internal/models/gas_account.go @@ -0,0 +1,16 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// GasAccount 对应 gas_account,保存可燃气体站登录账户。 +type GasAccount struct { + Entity + GasBasicID uint64 `gorm:"column:gas_basic_id;not null;index" json:"gas_basic_id"` // 可燃气体站主键 + Username string `gorm:"column:username;type:varchar(64);not null;uniqueIndex" json:"username"` // 登录名称 + DisplayName string `gorm:"column:display_name;type:varchar(64);not null;default:''" json:"display_name"` // 展示名称 + PasswordHash string `gorm:"column:password_hash;type:varchar(255);not null" json:"-"` // 密码哈希 + RoleCode string `gorm:"column:role_code;type:varchar(64);not null" json:"role_code"` // 角色编码 +} + +func init() { database.AppendMigrate(&GasAccount{}) } +func (table *GasAccount) TableName() string { return "gas_account" } diff --git a/backend/api/internal/models/gas_basic.go b/backend/api/internal/models/gas_basic.go new file mode 100644 index 0000000..17db459 --- /dev/null +++ b/backend/api/internal/models/gas_basic.go @@ -0,0 +1,20 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// GasBasic 对应 gas_basic,保存可燃气体站的主体主档案。 +type GasBasic struct { + Entity + Code string `gorm:"column:code;type:varchar(32);not null;uniqueIndex" json:"code"` // 站点编码 + Name string `gorm:"column:name;type:varchar(128);not null" json:"name"` // 站点名称 + CreditCode string `gorm:"column:credit_code;type:varchar(64);not null;default:''" json:"credit_code"` // 统一社会信用代码 + Principal string `gorm:"column:principal;type:varchar(64);not null;default:''" json:"principal"` // 负责人 + Address string `gorm:"column:address;type:varchar(255);not null;default:''" json:"address"` // 站点地址 + Longitude string `gorm:"column:longitude;type:varchar(32);not null;default:''" json:"longitude"` // 经度 + Latitude string `gorm:"column:latitude;type:varchar(32);not null;default:''" json:"latitude"` // 纬度 +} + +func init() { database.AppendMigrate(&GasBasic{}) } + +// TableName 返回与模型、文件名一致的单数数据表名。 +func (table *GasBasic) TableName() string { return "gas_basic" } diff --git a/backend/api/internal/models/idn_account.go b/backend/api/internal/models/idn_account.go deleted file mode 100644 index bbcf84b..0000000 --- a/backend/api/internal/models/idn_account.go +++ /dev/null @@ -1,22 +0,0 @@ -package models - -import "git.apinb.com/bsm-sdk/core/database" - -// IdnAccount 对应 idn_account,表示用户或服务人员身份账户。 -type IdnAccount struct { - Entity - Username string `gorm:"column:username;type:varchar(64);uniqueIndex" json:"username"` // 登录用户名。 - DisplayName string `gorm:"column:display_name;type:varchar(64);not null;default:''" json:"display_name"` // 用户展示名称。 - PasswordHash string `gorm:"column:password_hash;type:varchar(255);not null;default:''" json:"-"` // 密码哈希值,禁止在接口中返回。 - RoleCode string `gorm:"column:role_code;type:varchar(64);not null;default:'user'" json:"role_code"` // 平台角色编码。 - MustChangePassword bool `gorm:"column:must_change_password;not null;default:false" json:"must_change_password"` // 是否必须修改初始密码。 - MFAEnabled bool `gorm:"column:mfa_enabled;not null;default:false" json:"mfa_enabled"` // 是否启用多因素认证。 - Phone string `gorm:"column:phone;type:varchar(32);uniqueIndex;not null" json:"phone"` // 手机号,用于登录和通知。 - AccountType string `gorm:"column:account_type;type:varchar(32);not null" json:"account_type"` // 账号类型,例如 user、operator。 - ServiceArea string `gorm:"column:service_area;type:varchar(128);not null" json:"service_area"` // 服务区域描述。 -} - -func init() { database.AppendMigrate(&IdnAccount{}) } - -// TableName 返回与模型、文件名一致的单数数据表名。 -func (table *IdnAccount) TableName() string { return "idn_account" } diff --git a/backend/api/internal/models/ntf_template.go b/backend/api/internal/models/ntf_template.go new file mode 100644 index 0000000..3f5050d --- /dev/null +++ b/backend/api/internal/models/ntf_template.go @@ -0,0 +1,14 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// NtfTemplate 对应 ntf_template,保存通知模板。 +type NtfTemplate struct { + Entity + TemplateCode string `gorm:"column:template_code;type:varchar(64);not null;uniqueIndex" json:"template_code"` + Channel string `gorm:"column:channel;type:varchar(32);not null" json:"channel"` + Content string `gorm:"column:content;type:text;not null" json:"content"` +} + +func init() { database.AppendMigrate(&NtfTemplate{}) } +func (table *NtfTemplate) TableName() string { return "ntf_template" } diff --git a/backend/api/internal/models/org_delivery_point.go b/backend/api/internal/models/org_delivery_point.go deleted file mode 100644 index 4a46ccb..0000000 --- a/backend/api/internal/models/org_delivery_point.go +++ /dev/null @@ -1,17 +0,0 @@ -package models - -import "git.apinb.com/bsm-sdk/core/database" - -// OrgDeliveryPoint 对应 org_delivery_point,表示末端配送组织单元。 -type OrgDeliveryPoint struct { - Entity - DeliveryCode string `gorm:"column:delivery_code;type:varchar(32);uniqueIndex;not null" json:"delivery_code"` // 配送点编码 - GasStationIdentity string `gorm:"column:gas_station_identity;type:uuid" json:"gas_station_identity"` // 归属气站主键 - Name string `gorm:"column:name;type:varchar(128);not null" json:"name"` // 配送点名称 - ServiceArea string `gorm:"column:service_area;type:varchar(128);not null" json:"service_area"` // 服务区域 -} - -func init() { database.AppendMigrate(&OrgDeliveryPoint{}) } - -// TableName 返回与模型、文件名一致的单数数据表名。 -func (table *OrgDeliveryPoint) TableName() string { return "org_delivery_point" } diff --git a/backend/api/internal/models/org_gas_station.go b/backend/api/internal/models/org_gas_station.go deleted file mode 100644 index 66d512d..0000000 --- a/backend/api/internal/models/org_gas_station.go +++ /dev/null @@ -1,60 +0,0 @@ -package models - -import ( - "errors" - - "git.apinb.com/bsm-sdk/core/database" - "git.apinb.com/bsm-sdk/core/errcode" - "git.apinb.com/heqiapp/platforms/backend/api/internal/impl" - "gorm.io/gorm" -) - -// OrgGasStation 对应 org_gas_station,表示可燃气体站经营主体。 -type OrgGasStation struct { - Entity - StationCode string `gorm:"column:station_code;type:varchar(32);uniqueIndex;not null" json:"station_code"` // 气站编码 - Name string `gorm:"column:name;type:varchar(128);not null" json:"name"` // 气站名称 - Principal string `gorm:"column:principal;type:varchar(64);not null" json:"principal"` // 负责人 - ServiceArea string `gorm:"column:service_area;type:varchar(128);not null" json:"service_area"` // 服务区域 -} - -func init() { - database.AppendMigrate(&OrgGasStation{}) -} - -// TableName 返回与模型、文件名一致的单数数据表名。 -func (table *OrgGasStation) TableName() string { return "org_gas_station" } - -// CreateOrgGasStation 创建待审核气站。 -func CreateOrgGasStation(data *OrgGasStation) error { - if err := impl.DBService.Create(data).Error; err != nil { - return errcode.ErrDB - } - return nil -} - -// ListOrgGasStation 按创建时间倒序查询气站。 -func ListOrgGasStation(page, size int) ([]OrgGasStation, int64, error) { - var list []OrgGasStation - var total int64 - databaseQuery := impl.DBService.Model(&OrgGasStation{}) - if err := databaseQuery.Count(&total).Error; err != nil { - return nil, 0, errcode.ErrDB - } - if err := databaseQuery.Order("created_at desc").Offset((page - 1) * size).Limit(size).Find(&list).Error; err != nil { - return nil, 0, errcode.ErrDB - } - return list, total, nil -} - -// GetOrgGasStationByIdentity 查询单个气站。 -func GetOrgGasStationByIdentity(identity string) (*OrgGasStation, error) { - var data OrgGasStation - if err := impl.DBService.Where("identity = ?", identity).First(&data).Error; err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, errcode.ErrRecordNotFound - } - return nil, errcode.ErrDB - } - return &data, nil -} diff --git a/backend/api/internal/models/org_service_person.go b/backend/api/internal/models/org_service_person.go deleted file mode 100644 index 0662f1a..0000000 --- a/backend/api/internal/models/org_service_person.go +++ /dev/null @@ -1,20 +0,0 @@ -package models - -import "git.apinb.com/bsm-sdk/core/database" - -// OrgServicePerson 对应 org_service_person,表示安装维修、安检或配送服务人员。 -type OrgServicePerson struct { - Entity - AccountIdentity string `gorm:"column:account_identity;type:uuid;uniqueIndex" json:"account_identity"` // 关联 idn_account 主键 - GasStationIdentity string `gorm:"column:gas_station_identity;type:uuid" json:"gas_station_identity"` // 归属气站主键 - DeliveryPointIdentity string `gorm:"column:delivery_point_identity;type:uuid" json:"delivery_point_identity"` // 主归属配送点主键 - Name string `gorm:"column:name;type:varchar(64);not null" json:"name"` // 服务人员姓名 - Roles string `gorm:"column:roles;type:varchar(128);not null" json:"roles"` // 可执行角色集合 - WorkStatus string `gorm:"column:work_status;type:varchar(32);not null" json:"work_status"` // 上班与接单状态 - CredentialStatus string `gorm:"column:credential_status;type:varchar(32);not null" json:"credential_status"` // 资质状态 -} - -func init() { database.AppendMigrate(&OrgServicePerson{}) } - -// TableName 返回与模型、文件名一致的单数数据表名。 -func (table *OrgServicePerson) TableName() string { return "org_service_person" } diff --git a/backend/api/internal/models/platform_menu.go b/backend/api/internal/models/platform_menu.go new file mode 100644 index 0000000..b875dde --- /dev/null +++ b/backend/api/internal/models/platform_menu.go @@ -0,0 +1,19 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// PlatformMenu 对应 platform_menu,定义平台总后台的菜单树和访问路由。 +type PlatformMenu struct { + Entity + ParentID uint64 `gorm:"column:parent_id;not null;default:0;index" json:"parent_id"` // 父菜单自增主键,顶级菜单为 0 + MenuCode string `gorm:"column:menu_code;type:varchar(64);not null;uniqueIndex" json:"menu_code"` // 菜单编码 + Name string `gorm:"column:name;type:varchar(64);not null" json:"name"` // 菜单名称 + Icon string `gorm:"column:icon;type:varchar(64);not null;default:''" json:"icon"` // 前端图标名称 + Path string `gorm:"column:path;type:varchar(255);not null;default:''" json:"path"` // 前端路由地址 + SortNo int `gorm:"column:sort_no;not null;default:0" json:"sort_no"` // 同级排序号 +} + +func init() { database.AppendMigrate(&PlatformMenu{}) } + +// TableName 返回与模型、文件名一致的单数数据表名。 +func (table *PlatformMenu) TableName() string { return "platform_menu" } diff --git a/backend/api/internal/models/platform_role.go b/backend/api/internal/models/platform_role.go new file mode 100644 index 0000000..6b08a8f --- /dev/null +++ b/backend/api/internal/models/platform_role.go @@ -0,0 +1,17 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// PlatformRole 对应 platform_role,定义平台总后台的数据范围与菜单权限角色。 +type PlatformRole struct { + Entity + RoleCode string `gorm:"column:role_code;type:varchar(64);not null;uniqueIndex" json:"role_code"` // 角色编码 + Name string `gorm:"column:name;type:varchar(64);not null" json:"name"` // 角色名称 + DataScope string `gorm:"column:data_scope;type:varchar(32);not null;default:'global'" json:"data_scope"` // 数据权限范围 + IsSystem bool `gorm:"column:is_system;not null;default:false" json:"is_system"` // 是否系统内置角色 +} + +func init() { database.AppendMigrate(&PlatformRole{}) } + +// TableName 返回与模型、文件名一致的单数数据表名。 +func (table *PlatformRole) TableName() string { return "platform_role" } diff --git a/backend/api/internal/models/platform_role_menu_relation.go b/backend/api/internal/models/platform_role_menu_relation.go new file mode 100644 index 0000000..d8ba9eb --- /dev/null +++ b/backend/api/internal/models/platform_role_menu_relation.go @@ -0,0 +1,20 @@ +package models + +import ( + "time" + + "git.apinb.com/bsm-sdk/core/database" +) + +// PlatformRoleMenuRelation 对应 platform_role_menu_relation,记录角色拥有的菜单权限。 +type PlatformRoleMenuRelation struct { + ID uint64 `gorm:"column:id;primaryKey;autoIncrement" json:"id"` // 数据库自增主键 + PlatformRoleID uint64 `gorm:"column:platform_role_id;not null;uniqueIndex:uk_platform_role_menu" json:"platform_role_id"` // 角色自增主键 + PlatformMenuID uint64 `gorm:"column:platform_menu_id;not null;uniqueIndex:uk_platform_role_menu" json:"platform_menu_id"` // 菜单自增主键 + CreatedAt time.Time `gorm:"column:created_at;type:timestamptz;not null" json:"created_at"` // 创建时间 +} + +func init() { database.AppendMigrate(&PlatformRoleMenuRelation{}) } + +// TableName 返回与模型、文件名一致的单数数据表名。 +func (table *PlatformRoleMenuRelation) TableName() string { return "platform_role_menu_relation" } diff --git a/backend/api/internal/models/platfrom_account.go b/backend/api/internal/models/platfrom_account.go new file mode 100644 index 0000000..6730616 --- /dev/null +++ b/backend/api/internal/models/platfrom_account.go @@ -0,0 +1,19 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// PlatfromAccount 对应 platfrom_account,表示平台总后台登录账号。 +type PlatfromAccount struct { + Entity + Username string `gorm:"column:username;type:varchar(64);uniqueIndex;not null" json:"username"` // 登录用户名 + DisplayName string `gorm:"column:display_name;type:varchar(64);not null;default:''" json:"display_name"` // 用户展示名称 + Avatar string `gorm:"column:avatar;type:varchar(512);not null;default:''" json:"avatar"` // 头像资源地址 + PasswordHash string `gorm:"column:password_hash;type:varchar(255);not null;default:''" json:"-"` // 密码哈希值 + PlatformRoleCode string `gorm:"column:platform_role_code;type:varchar(64);not null;default:'root';index" json:"platform_role_code"` // 平台角色编码 + Phone string `gorm:"column:phone;type:varchar(32);uniqueIndex;not null;default:''" json:"phone"` // 手机号 +} + +func init() { database.AppendMigrate(&PlatfromAccount{}) } + +// TableName 返回与模型、文件名一致的单数数据表名。 +func (table *PlatfromAccount) TableName() string { return "platfrom_account" } diff --git a/backend/api/internal/models/query.go b/backend/api/internal/models/query.go index 47e88f6..ce94d4a 100644 --- a/backend/api/internal/models/query.go +++ b/backend/api/internal/models/query.go @@ -2,28 +2,28 @@ package models import "git.apinb.com/heqiapp/platforms/backend/api/internal/impl" -// DashboardOverview 是平台总后台的安全与组织聚合指标。 +// DashboardOverview 是平台总后台的跨组织运营概览指标。 type DashboardOverview struct { - GasStationCount int64 `json:"gas_station_count"` // 启用气站数量 - DeliveryPointCount int64 `json:"delivery_point_count"` // 启用配送点数量 - ServicePersonCount int64 `json:"service_person_count"` // 在岗服务人员数量 - UserCount int64 `json:"user_count"` // 启用普通用户数量 + GasBasicCount int64 `json:"gas_basic_count"` // 启用可燃气体站数量 + DeliveryBasicCount int64 `json:"delivery_basic_count"` // 启用配送点数量 + StaffCount int64 `json:"staff_count"` // 在岗服务人员数量 + UserCount int64 `json:"user_count"` // 启用业主客户数量 PendingSafetyCount int64 `json:"pending_safety_count"` // 待处理安全事件数量 } -// GetDashboardOverview 通过独立查询返回首期仪表盘指标。 +// GetDashboardOverview 通过独立查询返回首页概览指标。 func GetDashboardOverview() (DashboardOverview, error) { var overview DashboardOverview - if err := impl.DBService.Model(&OrgGasStation{}).Where("status = ?", "enabled").Count(&overview.GasStationCount).Error; err != nil { + if err := impl.DBService.Model(&GasBasic{}).Where("status = ?", "enabled").Count(&overview.GasBasicCount).Error; err != nil { return DashboardOverview{}, err } - if err := impl.DBService.Model(&OrgDeliveryPoint{}).Where("status = ?", "enabled").Count(&overview.DeliveryPointCount).Error; err != nil { + if err := impl.DBService.Model(&DeliveryBasic{}).Where("status = ?", "enabled").Count(&overview.DeliveryBasicCount).Error; err != nil { return DashboardOverview{}, err } - if err := impl.DBService.Model(&OrgServicePerson{}).Where("work_status = ?", "on_duty").Count(&overview.ServicePersonCount).Error; err != nil { + if err := impl.DBService.Model(&StaffAccount{}).Where("work_status = ?", "on_duty").Count(&overview.StaffCount).Error; err != nil { return DashboardOverview{}, err } - if err := impl.DBService.Model(&IdnAccount{}).Where("account_type = ? AND status = ?", "user", "enabled").Count(&overview.UserCount).Error; err != nil { + if err := impl.DBService.Model(&UserAccount{}).Where("status = ?", "enabled").Count(&overview.UserCount).Error; err != nil { return DashboardOverview{}, err } if err := impl.DBService.Model(&SafEvent{}).Where("status = ?", "pending").Count(&overview.PendingSafetyCount).Error; err != nil { @@ -32,11 +32,11 @@ func GetDashboardOverview() (DashboardOverview, error) { return overview, nil } -// ListOrgDeliveryPoint 返回配送点分页列表。 -func ListOrgDeliveryPoint(page, size int) ([]OrgDeliveryPoint, int64, error) { - var list []OrgDeliveryPoint +// ListPlatfromAccount 返回平台账号分页列表,敏感字段由接口展示层脱敏。 +func ListPlatfromAccount(page, size int) ([]PlatfromAccount, int64, error) { + var list []PlatfromAccount var total int64 - databaseQuery := impl.DBService.Model(&OrgDeliveryPoint{}) + databaseQuery := impl.DBService.Model(&PlatfromAccount{}) if err := databaseQuery.Count(&total).Error; err != nil { return nil, 0, err } @@ -45,45 +45,3 @@ func ListOrgDeliveryPoint(page, size int) ([]OrgDeliveryPoint, int64, error) { } return list, total, nil } - -// ListOrgServicePerson 返回服务人员分页列表。 -func ListOrgServicePerson(page, size int) ([]OrgServicePerson, int64, error) { - var list []OrgServicePerson - var total int64 - databaseQuery := impl.DBService.Model(&OrgServicePerson{}) - if err := databaseQuery.Count(&total).Error; err != nil { - return nil, 0, err - } - if err := databaseQuery.Order("created_at desc").Offset((page - 1) * size).Limit(size).Find(&list).Error; err != nil { - return nil, 0, err - } - return list, total, nil -} - -// ListIdnAccount 返回普通用户分页列表,手机号脱敏由前端展示层处理。 -func ListIdnAccount(page, size int) ([]IdnAccount, int64, error) { - var list []IdnAccount - var total int64 - databaseQuery := impl.DBService.Model(&IdnAccount{}).Where("account_type = ?", "user") - if err := databaseQuery.Count(&total).Error; err != nil { - return nil, 0, err - } - if err := databaseQuery.Order("created_at desc").Offset((page - 1) * size).Limit(size).Find(&list).Error; err != nil { - return nil, 0, err - } - return list, total, nil -} - -// ListSafEvent 返回安全事件分页列表。 -func ListSafEvent(page, size int) ([]SafEvent, int64, error) { - var list []SafEvent - var total int64 - databaseQuery := impl.DBService.Model(&SafEvent{}) - if err := databaseQuery.Count(&total).Error; err != nil { - return nil, 0, err - } - if err := databaseQuery.Order("level asc, created_at desc").Offset((page - 1) * size).Limit(size).Find(&list).Error; err != nil { - return nil, 0, err - } - return list, total, nil -} diff --git a/backend/api/internal/models/report.go b/backend/api/internal/models/report.go new file mode 100644 index 0000000..9093e42 --- /dev/null +++ b/backend/api/internal/models/report.go @@ -0,0 +1,18 @@ +package models + +import ( + "git.apinb.com/bsm-sdk/core/database" + "time" +) + +// Report 对应 report,保存统计报表档案。 +type Report struct { + Entity + ReportCode string `gorm:"column:report_code;type:varchar(64);not null;uniqueIndex" json:"report_code"` + ReportType string `gorm:"column:report_type;type:varchar(32);not null" json:"report_type"` + StatPeriod string `gorm:"column:stat_period;type:varchar(64);not null" json:"stat_period"` + GeneratedAt time.Time `gorm:"column:generated_at;type:timestamptz;not null" json:"generated_at"` +} + +func init() { database.AppendMigrate(&Report{}) } +func (table *Report) TableName() string { return "report" } diff --git a/backend/api/internal/models/report_item.go b/backend/api/internal/models/report_item.go new file mode 100644 index 0000000..a61b021 --- /dev/null +++ b/backend/api/internal/models/report_item.go @@ -0,0 +1,15 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// ReportItem 对应 report_item,保存报表维度明细。 +type ReportItem struct { + Entity + ReportID uint64 `gorm:"column:report_id;not null;index" json:"report_id"` + Dimension string `gorm:"column:dimension;type:varchar(128);not null" json:"dimension"` + MetricCode string `gorm:"column:metric_code;type:varchar(64);not null" json:"metric_code"` + MetricValue string `gorm:"column:metric_value;type:varchar(128);not null" json:"metric_value"` +} + +func init() { database.AppendMigrate(&ReportItem{}) } +func (table *ReportItem) TableName() string { return "report_item" } diff --git a/backend/api/internal/models/report_metric_snapshot.go b/backend/api/internal/models/report_metric_snapshot.go new file mode 100644 index 0000000..5e40d15 --- /dev/null +++ b/backend/api/internal/models/report_metric_snapshot.go @@ -0,0 +1,19 @@ +package models + +import ( + "git.apinb.com/bsm-sdk/core/database" + "time" +) + +// ReportMetricSnapshot 对应 report_metric_snapshot,保存指标快照。 +type ReportMetricSnapshot struct { + Entity + MetricCode string `gorm:"column:metric_code;type:varchar(64);not null;index" json:"metric_code"` + ScopeType string `gorm:"column:scope_type;type:varchar(32);not null" json:"scope_type"` + ScopeID uint64 `gorm:"column:scope_id;not null;default:0;index" json:"scope_id"` + StatAt time.Time `gorm:"column:stat_at;type:timestamptz;not null;index" json:"stat_at"` + MetricValue string `gorm:"column:metric_value;type:varchar(128);not null" json:"metric_value"` +} + +func init() { database.AppendMigrate(&ReportMetricSnapshot{}) } +func (table *ReportMetricSnapshot) TableName() string { return "report_metric_snapshot" } diff --git a/backend/api/internal/models/saf_event.go b/backend/api/internal/models/saf_event.go index f3238ff..d051f72 100644 --- a/backend/api/internal/models/saf_event.go +++ b/backend/api/internal/models/saf_event.go @@ -1,18 +1,19 @@ package models -import "git.apinb.com/bsm-sdk/core/database" +import ( + "git.apinb.com/bsm-sdk/core/database" + "time" +) -// SafEvent 对应 saf_event,表示需要平台跟踪处置的安全事件。 +// SafEvent 对应 saf_event,保存安全事件统一入口。 type SafEvent struct { Entity - EventCode string `gorm:"column:event_code;type:varchar(32);uniqueIndex;not null" json:"event_code"` // 安全事件编码 - Level int `gorm:"column:level;type:integer;not null" json:"level"` // 风险等级,1 至 3 级 - Title string `gorm:"column:title;type:varchar(256);not null" json:"title"` // 事件说明 + EventCode string `gorm:"column:event_code;type:varchar(64);not null;uniqueIndex" json:"event_code"` + Level int `gorm:"column:level;not null;default:3" json:"level"` + Title string `gorm:"column:title;type:varchar(256);not null;default:''" json:"title"` + SmartCylinderValveIdentity string `gorm:"column:smart_cylinder_valve_identity;type:varchar(36);not null;default:'';index" json:"smart_cylinder_valve_identity"` + SLAAt *time.Time `gorm:"column:sla_at;type:timestamptz" json:"sla_at"` } -func init() { - database.AppendMigrate(&SafEvent{}) -} - -// TableName 返回与模型、文件名一致的单数数据表名。 +func init() { database.AppendMigrate(&SafEvent{}) } func (table *SafEvent) TableName() string { return "saf_event" } diff --git a/backend/api/internal/models/saf_event_disposal.go b/backend/api/internal/models/saf_event_disposal.go new file mode 100644 index 0000000..0657257 --- /dev/null +++ b/backend/api/internal/models/saf_event_disposal.go @@ -0,0 +1,15 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// SafEventDisposal 对应 saf_event_disposal,保存安全处置记录。 +type SafEventDisposal struct { + Entity + SafEventIdentity string `gorm:"column:saf_event_identity;type:varchar(36);not null;index" json:"saf_event_identity"` + Action string `gorm:"column:action;type:varchar(64);not null" json:"action"` + Reason string `gorm:"column:reason;type:text;not null;default:''" json:"reason"` + OperatorIdentity string `gorm:"column:operator_identity;type:varchar(36);not null;default:''" json:"operator_identity"` +} + +func init() { database.AppendMigrate(&SafEventDisposal{}) } +func (table *SafEventDisposal) TableName() string { return "saf_event_disposal" } diff --git a/backend/api/internal/models/saf_inspection.go b/backend/api/internal/models/saf_inspection.go new file mode 100644 index 0000000..c278976 --- /dev/null +++ b/backend/api/internal/models/saf_inspection.go @@ -0,0 +1,15 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// SafInspection 对应 saf_inspection,保存安检与复检记录。 +type SafInspection struct { + Entity + UserAccountID uint64 `gorm:"column:user_account_id;not null;index" json:"user_account_id"` + StaffAccountID uint64 `gorm:"column:staff_account_id;not null;index" json:"staff_account_id"` + Result string `gorm:"column:result;type:varchar(32);not null" json:"result"` + EvidenceURI string `gorm:"column:evidence_uri;type:varchar(512);not null;default:''" json:"evidence_uri"` +} + +func init() { database.AppendMigrate(&SafInspection{}) } +func (table *SafInspection) TableName() string { return "saf_inspection" } diff --git a/backend/api/internal/models/saf_rule.go b/backend/api/internal/models/saf_rule.go new file mode 100644 index 0000000..8dbc1c3 --- /dev/null +++ b/backend/api/internal/models/saf_rule.go @@ -0,0 +1,16 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// SafRule 对应 saf_rule,保存安全规则。 +type SafRule struct { + Entity + RuleCode string `gorm:"column:rule_code;type:varchar(64);not null;uniqueIndex" json:"rule_code"` + VersionNo int `gorm:"column:version_no;not null;default:1" json:"version_no"` + Threshold string `gorm:"column:threshold;type:jsonb;not null;default:'{}'" json:"threshold"` + Action string `gorm:"column:action;type:varchar(64);not null" json:"action"` + GrayScope string `gorm:"column:gray_scope;type:jsonb;not null;default:'{}'" json:"gray_scope"` +} + +func init() { database.AppendMigrate(&SafRule{}) } +func (table *SafRule) TableName() string { return "saf_rule" } diff --git a/backend/api/internal/models/staff_account.go b/backend/api/internal/models/staff_account.go new file mode 100644 index 0000000..7e4a95c --- /dev/null +++ b/backend/api/internal/models/staff_account.go @@ -0,0 +1,22 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// StaffAccount 对应 staff_account,是服务人员唯一的档案和 App 登录账户。 +type StaffAccount struct { + Entity + Username string `gorm:"column:username;type:varchar(64);not null;uniqueIndex" json:"username"` // 登录名称 + PasswordHash string `gorm:"column:password_hash;type:varchar(255);not null" json:"-"` // 密码哈希 + Name string `gorm:"column:name;type:varchar(64);not null" json:"name"` // 人员姓名 + Phone string `gorm:"column:phone;type:varchar(32);not null;default:'';index" json:"phone"` // 联系手机号 + Avatar string `gorm:"column:avatar;type:varchar(512);not null;default:''" json:"avatar"` // 头像资源地址 + RoleCode string `gorm:"column:role_code;type:varchar(64);not null;default:''" json:"role_code"` // 服务角色编码 + GasBasicID uint64 `gorm:"column:gas_basic_id;not null;default:0;index" json:"gas_basic_id"` // 所属可燃气体站主键 + DeliveryBasicID uint64 `gorm:"column:delivery_basic_id;not null;default:0;index" json:"delivery_basic_id"` // 所属配送点主键 + WorkStatus string `gorm:"column:work_status;type:varchar(32);not null;default:'off_duty'" json:"work_status"` // 在岗接单状态 +} + +func init() { database.AppendMigrate(&StaffAccount{}) } + +// TableName 返回与模型、文件名一致的单数数据表名。 +func (table *StaffAccount) TableName() string { return "staff_account" } diff --git a/backend/api/internal/models/staff_credential.go b/backend/api/internal/models/staff_credential.go new file mode 100644 index 0000000..c9e7c34 --- /dev/null +++ b/backend/api/internal/models/staff_credential.go @@ -0,0 +1,18 @@ +package models + +import ( + "git.apinb.com/bsm-sdk/core/database" + "time" +) + +// StaffCredential 对应 staff_credential,保存人员资质。 +type StaffCredential struct { + Entity + StaffAccountID uint64 `gorm:"column:staff_account_id;not null;index" json:"staff_account_id"` + CredentialType string `gorm:"column:credential_type;type:varchar(64);not null" json:"credential_type"` + CredentialNo string `gorm:"column:credential_no;type:varchar(128);not null;default:''" json:"credential_no"` + ExpiredAt *time.Time `gorm:"column:expired_at;type:timestamptz" json:"expired_at"` +} + +func init() { database.AppendMigrate(&StaffCredential{}) } +func (table *StaffCredential) TableName() string { return "staff_credential" } diff --git a/backend/api/internal/models/user_account.go b/backend/api/internal/models/user_account.go new file mode 100644 index 0000000..df18795 --- /dev/null +++ b/backend/api/internal/models/user_account.go @@ -0,0 +1,19 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// UserAccount 对应 user_account,是业主客户唯一的档案和用户端登录账户。 +type UserAccount struct { + Entity + Username string `gorm:"column:username;type:varchar(64);not null;uniqueIndex" json:"username"` // 登录名称 + PasswordHash string `gorm:"column:password_hash;type:varchar(255);not null" json:"-"` // 密码哈希 + Name string `gorm:"column:name;type:varchar(64);not null" json:"name"` // 客户姓名 + Phone string `gorm:"column:phone;type:varchar(32);not null;default:'';index" json:"phone"` // 联系手机号 + Avatar string `gorm:"column:avatar;type:varchar(512);not null;default:''" json:"avatar"` // 头像资源地址 + RealName string `gorm:"column:real_name;type:varchar(64);not null;default:''" json:"real_name"` // 实名认证名称 +} + +func init() { database.AppendMigrate(&UserAccount{}) } + +// TableName 返回与模型、文件名一致的单数数据表名。 +func (table *UserAccount) TableName() string { return "user_account" } diff --git a/backend/api/internal/models/user_address.go b/backend/api/internal/models/user_address.go new file mode 100644 index 0000000..d44b0da --- /dev/null +++ b/backend/api/internal/models/user_address.go @@ -0,0 +1,16 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// UserAddress 对应 user_address,保存用户地址。 +type UserAddress struct { + Entity + UserAccountID uint64 `gorm:"column:user_account_id;not null;index" json:"user_account_id"` + Address string `gorm:"column:address;type:varchar(255);not null" json:"address"` + Longitude string `gorm:"column:longitude;type:varchar(32);not null;default:''" json:"longitude"` + Latitude string `gorm:"column:latitude;type:varchar(32);not null;default:''" json:"latitude"` + IsDefault bool `gorm:"column:is_default;not null;default:false" json:"is_default"` +} + +func init() { database.AppendMigrate(&UserAddress{}) } +func (table *UserAddress) TableName() string { return "user_address" } diff --git a/backend/api/internal/models/user_service_relation.go b/backend/api/internal/models/user_service_relation.go new file mode 100644 index 0000000..e441002 --- /dev/null +++ b/backend/api/internal/models/user_service_relation.go @@ -0,0 +1,15 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// UserServiceRelation 对应 user_service_relation,保存用户服务归属快照。 +type UserServiceRelation struct { + Entity + UserAccountID uint64 `gorm:"column:user_account_id;not null;index" json:"user_account_id"` + GasBasicID uint64 `gorm:"column:gas_basic_id;not null;default:0;index" json:"gas_basic_id"` + DeliveryBasicID uint64 `gorm:"column:delivery_basic_id;not null;default:0;index" json:"delivery_basic_id"` + StaffAccountID uint64 `gorm:"column:staff_account_id;not null;default:0;index" json:"staff_account_id"` +} + +func init() { database.AppendMigrate(&UserServiceRelation{}) } +func (table *UserServiceRelation) TableName() string { return "user_service_relation" } diff --git a/backend/api/internal/models/wallet.go b/backend/api/internal/models/wallet.go new file mode 100644 index 0000000..0036231 --- /dev/null +++ b/backend/api/internal/models/wallet.go @@ -0,0 +1,15 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// Wallet 对应 wallet,保存余额账户。 +type Wallet struct { + Entity + OwnerType string `gorm:"column:owner_type;type:varchar(32);not null" json:"owner_type"` + OwnerID uint64 `gorm:"column:owner_id;not null;index" json:"owner_id"` + BalanceAmount int64 `gorm:"column:balance_amount;not null;default:0" json:"balance_amount"` + FrozenAmount int64 `gorm:"column:frozen_amount;not null;default:0" json:"frozen_amount"` +} + +func init() { database.AppendMigrate(&Wallet{}) } +func (table *Wallet) TableName() string { return "wallet" } diff --git a/backend/api/internal/models/wallet_ledger.go b/backend/api/internal/models/wallet_ledger.go new file mode 100644 index 0000000..8b54d88 --- /dev/null +++ b/backend/api/internal/models/wallet_ledger.go @@ -0,0 +1,16 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// WalletLedger 对应 wallet_ledger,保存不可变资金流水。 +type WalletLedger struct { + Entity + WalletID uint64 `gorm:"column:wallet_id;not null;index" json:"wallet_id"` + Amount int64 `gorm:"column:amount;not null" json:"amount"` + Direction string `gorm:"column:direction;type:varchar(16);not null" json:"direction"` + BalanceAfter int64 `gorm:"column:balance_after;not null" json:"balance_after"` + ReferenceIdentity string `gorm:"column:reference_identity;type:varchar(36);not null;default:'';index" json:"reference_identity"` +} + +func init() { database.AppendMigrate(&WalletLedger{}) } +func (table *WalletLedger) TableName() string { return "wallet_ledger" } diff --git a/backend/api/internal/models/wallet_recharge.go b/backend/api/internal/models/wallet_recharge.go new file mode 100644 index 0000000..46aa000 --- /dev/null +++ b/backend/api/internal/models/wallet_recharge.go @@ -0,0 +1,14 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// WalletRecharge 对应 wallet_recharge,保存充值记录。 +type WalletRecharge struct { + Entity + WalletID uint64 `gorm:"column:wallet_id;not null;index" json:"wallet_id"` + Amount int64 `gorm:"column:amount;not null" json:"amount"` + Channel string `gorm:"column:channel;type:varchar(32);not null" json:"channel"` +} + +func init() { database.AppendMigrate(&WalletRecharge{}) } +func (table *WalletRecharge) TableName() string { return "wallet_recharge" } diff --git a/backend/api/internal/models/wallet_withdrawal.go b/backend/api/internal/models/wallet_withdrawal.go new file mode 100644 index 0000000..68204a9 --- /dev/null +++ b/backend/api/internal/models/wallet_withdrawal.go @@ -0,0 +1,14 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// WalletWithdrawal 对应 wallet_withdrawal,保存提现记录。 +type WalletWithdrawal struct { + Entity + WalletID uint64 `gorm:"column:wallet_id;not null;index" json:"wallet_id"` + Amount int64 `gorm:"column:amount;not null" json:"amount"` + BankAccountMasked string `gorm:"column:bank_account_masked;type:varchar(128);not null;default:''" json:"bank_account_masked"` +} + +func init() { database.AppendMigrate(&WalletWithdrawal{}) } +func (table *WalletWithdrawal) TableName() string { return "wallet_withdrawal" } diff --git a/backend/api/internal/routers/platform.go b/backend/api/internal/routers/platform.go new file mode 100644 index 0000000..eb64b46 --- /dev/null +++ b/backend/api/internal/routers/platform.go @@ -0,0 +1,82 @@ +package routers + +import ( + "fmt" + + "git.apinb.com/bsm-sdk/core/middleware" + "git.apinb.com/heqiapp/platforms/backend/api/internal/logic/platform" + "git.apinb.com/heqiapp/platforms/backend/api/internal/models" + "github.com/gin-gonic/gin" +) + +// RegisterPlatform 注册 /heqi/platform/v1 前缀下的平台总后台路由。 +func RegisterPlatform(serviceKey string, engine *gin.Engine) { + basePath := fmt.Sprintf("/%s/platform/v1", serviceKey) + anonymous := engine.Group(basePath) + anonymous.GET("/ping/hello", platform.PingHello) + anonymous.POST("/auth/login", platform.Login) + + protected := engine.Group(basePath) + protected.Use(middleware.JwtAuth(true)) + protected.GET("/auth/profile", platform.CurrentProfile) + protected.PUT("/auth/password", platform.ChangePassword) + protected.GET("/dashboard/overview", platform.DashboardOverview) + + registerGasRoute(protected) + registerDeliveryRoute(protected) + registerStaffRoute(protected) + registerUserRoute(protected) + registerPlatformRoute(protected) +} + +func registerGasRoute(group *gin.RouterGroup) { + resource := group.Group("/gas/gas_basic") + resource.GET("", platform.ListGasBasic) + resource.POST("", platform.CreateGasBasic) + resource.GET("/:identity", platform.GetGasBasic) + resource.PUT("/:identity", platform.UpdateGasBasic) + resource.PATCH("/:identity/status", func(ctx *gin.Context) { platform.UpdateRecordStatus(ctx, &models.GasBasic{}) }) + resource.DELETE("/:identity", func(ctx *gin.Context) { platform.ArchiveRecord(ctx, &models.GasBasic{}) }) +} + +func registerDeliveryRoute(group *gin.RouterGroup) { + resource := group.Group("/delivery/delivery_basic") + resource.GET("", platform.ListDeliveryBasic) + resource.POST("", platform.CreateDeliveryBasic) + resource.GET("/:identity", platform.GetDeliveryBasic) + resource.PUT("/:identity", platform.UpdateDeliveryBasic) + resource.PATCH("/:identity/status", func(ctx *gin.Context) { platform.UpdateRecordStatus(ctx, &models.DeliveryBasic{}) }) + resource.DELETE("/:identity", func(ctx *gin.Context) { platform.ArchiveRecord(ctx, &models.DeliveryBasic{}) }) +} + +func registerStaffRoute(group *gin.RouterGroup) { + resource := group.Group("/staff") + resource.GET("/account", platform.ListStaff) + resource.POST("/account", platform.CreateStaff) + resource.GET("/:identity", platform.GetStaff) + resource.PUT("/:identity", platform.UpdateStaff) + resource.PATCH("/:identity/status", func(ctx *gin.Context) { platform.UpdateRecordStatus(ctx, &models.StaffAccount{}) }) + resource.DELETE("/:identity", func(ctx *gin.Context) { platform.ArchiveRecord(ctx, &models.StaffAccount{}) }) +} + +func registerUserRoute(group *gin.RouterGroup) { + resource := group.Group("/user") + resource.GET("/account", platform.ListUser) + resource.POST("/account", platform.CreateUser) + resource.GET("/:identity", platform.GetUser) + resource.PUT("/:identity", platform.UpdateUser) + resource.PATCH("/:identity/status", func(ctx *gin.Context) { platform.UpdateRecordStatus(ctx, &models.UserAccount{}) }) + resource.DELETE("/:identity", func(ctx *gin.Context) { platform.ArchiveRecord(ctx, &models.UserAccount{}) }) +} + +func registerPlatformRoute(group *gin.RouterGroup) { + group.GET("/platform/platfrom_account", platform.ListPlatfromAccount) + role := group.Group("/platform/platform_role") + role.GET("", platform.ListPlatformRole) + role.POST("", platform.CreatePlatformRole) + role.GET("/:identity", platform.GetPlatformRole) + role.PUT("/:identity", platform.UpdatePlatformRole) + role.PATCH("/:identity/status", platform.UpdatePlatformRoleStatus) + role.DELETE("/:identity", platform.ArchivePlatformRole) + group.GET("/platform/platform_menu", platform.ListPlatformMenu) +} diff --git a/backend/api/internal/routers/register.go b/backend/api/internal/routers/register.go index 7152919..c350f8f 100644 --- a/backend/api/internal/routers/register.go +++ b/backend/api/internal/routers/register.go @@ -1,33 +1,10 @@ -// Package routers 注册与 sample/server 一致的匿名和 JWT 受保护路由组。 +// Package routers 提供 API 路由注册入口。 package routers -import ( - "fmt" +import "github.com/gin-gonic/gin" - "git.apinb.com/bsm-sdk/core/middleware" - "git.apinb.com/heqiapp/platforms/backend/api/internal/logic/platform" - "github.com/gin-gonic/gin" -) - -// Register 注册路由,请求地址格式: /{serviceKey}/v1/{domain}/{resource}。 -func Register(srvKey string, engine *gin.Engine) { - v1Key := fmt.Sprintf("/%s/%s", srvKey, "v1") - anonymous := engine.Group(v1Key) - anonymous.GET("/ping/hello", platform.PingHello) - anonymous.POST("/auth/login", platform.Login) - - protected := engine.Group(v1Key) - protected.Use(middleware.JwtAuth(true)) - { - protected.GET("/auth/profile", platform.CurrentProfile) - protected.PUT("/auth/password", platform.ChangePassword) - protected.GET("/dashboard/overview", platform.DashboardOverview) - gasStationGroup := protected.Group("/organization/org_gas_station") - gasStationGroup.POST("", platform.CreateOrgGasStation) - gasStationGroup.GET("", platform.ListOrgGasStation) - protected.GET("/organization/org_delivery_point", platform.ListOrgDeliveryPoint) - protected.GET("/organization/org_service_person", platform.ListOrgServicePerson) - protected.GET("/identity/idn_account", platform.ListIdnAccount) - protected.GET("/safety/saf_event", platform.ListSafEvent) - } +// Register 注册路由。 +func Register(serviceKey string, engine *gin.Engine) { + RegisterPlatform(serviceKey, engine) + registerUploadRoute(serviceKey, engine) } diff --git a/backend/api/internal/routers/upload.go b/backend/api/internal/routers/upload.go new file mode 100644 index 0000000..9b014bf --- /dev/null +++ b/backend/api/internal/routers/upload.go @@ -0,0 +1,11 @@ +package routers + +import ( + "git.apinb.com/heqiapp/platforms/backend/api/internal/logic/upload" + "github.com/gin-gonic/gin" +) + +// registerUploadRoute 注册已认证的文件上传接口。 +func registerUploadRoute(serviceKey string, engine *gin.Engine) { + engine.POST("/upload/file", upload.UploadFile) +} diff --git a/backend/migrations/0001_create_org_gas_station.sql b/backend/migrations/0001_create_org_gas_station.sql deleted file mode 100644 index cf783b7..0000000 --- a/backend/migrations/0001_create_org_gas_station.sql +++ /dev/null @@ -1,27 +0,0 @@ --- org_gas_station:可燃气体站主表。identity 由应用生成 UUID V7,禁止自增主键。 -CREATE TABLE IF NOT EXISTS org_gas_station ( - identity uuid PRIMARY KEY, - station_code varchar(32) NOT NULL UNIQUE, - name varchar(128) NOT NULL, - principal varchar(64) NOT NULL, - service_area varchar(128) NOT NULL, - created_at timestamptz NOT NULL, - updated_at timestamptz NOT NULL, - created_by_identity uuid, - updated_by_identity uuid, - status varchar(32) NOT NULL DEFAULT 'draft', - version integer NOT NULL DEFAULT 1 -); - -COMMENT ON TABLE org_gas_station IS '可燃气体站主表'; -COMMENT ON COLUMN org_gas_station.identity IS '主键,应用生成的 UUID V7'; -COMMENT ON COLUMN org_gas_station.station_code IS '气站全局唯一业务编码'; -COMMENT ON COLUMN org_gas_station.name IS '气站名称'; -COMMENT ON COLUMN org_gas_station.principal IS '气站负责人姓名'; -COMMENT ON COLUMN org_gas_station.service_area IS '气站授权服务区域'; -COMMENT ON COLUMN org_gas_station.created_at IS '记录创建时间,UTC'; -COMMENT ON COLUMN org_gas_station.updated_at IS '记录更新时间,UTC'; -COMMENT ON COLUMN org_gas_station.created_by_identity IS '创建人 identity'; -COMMENT ON COLUMN org_gas_station.updated_by_identity IS '更新人 identity'; -COMMENT ON COLUMN org_gas_station.status IS '状态:draft、enabled、frozen、archived'; -COMMENT ON COLUMN org_gas_station.version IS '乐观锁版本'; diff --git a/backend/migrations/0002_create_saf_event.sql b/backend/migrations/0002_create_saf_event.sql deleted file mode 100644 index d658cbe..0000000 --- a/backend/migrations/0002_create_saf_event.sql +++ /dev/null @@ -1,28 +0,0 @@ --- saf_event:安全事件主表。事件和审计记录不允许物理删除。 -CREATE TABLE IF NOT EXISTS saf_event ( - identity uuid PRIMARY KEY, - event_code varchar(32) NOT NULL UNIQUE, - device_identity uuid, - level integer NOT NULL CHECK (level BETWEEN 1 AND 3), - title varchar(256) NOT NULL, - created_at timestamptz NOT NULL, - updated_at timestamptz NOT NULL, - created_by_identity uuid, - updated_by_identity uuid, - status varchar(32) NOT NULL DEFAULT 'pending', - version integer NOT NULL DEFAULT 1 -); - -CREATE INDEX IF NOT EXISTS idx_saf_event_status_level ON saf_event(status, level); -COMMENT ON TABLE saf_event IS '安全事件主表'; -COMMENT ON COLUMN saf_event.identity IS '主键,应用生成的 UUID V7'; -COMMENT ON COLUMN saf_event.event_code IS '安全事件全局唯一业务编码'; -COMMENT ON COLUMN saf_event.device_identity IS '关联 dev_device 的 identity'; -COMMENT ON COLUMN saf_event.level IS '风险等级:1 高风险、2 中风险、3 低风险'; -COMMENT ON COLUMN saf_event.title IS '安全事件说明'; -COMMENT ON COLUMN saf_event.created_at IS '记录创建时间,UTC'; -COMMENT ON COLUMN saf_event.updated_at IS '记录更新时间,UTC'; -COMMENT ON COLUMN saf_event.created_by_identity IS '创建人 identity'; -COMMENT ON COLUMN saf_event.updated_by_identity IS '更新人 identity'; -COMMENT ON COLUMN saf_event.status IS '状态:pending、processing、closed、overdue'; -COMMENT ON COLUMN saf_event.version IS '乐观锁版本'; diff --git a/backend/migrations/0003_create_org_delivery_point_org_service_person_idn_account.sql b/backend/migrations/0003_create_org_delivery_point_org_service_person_idn_account.sql deleted file mode 100644 index 8ebd425..0000000 --- a/backend/migrations/0003_create_org_delivery_point_org_service_person_idn_account.sql +++ /dev/null @@ -1,39 +0,0 @@ --- 首期平台组织与身份主表。所有 identity 均为应用生成的 UUID V7。 -CREATE TABLE IF NOT EXISTS idn_account ( - identity uuid PRIMARY KEY, phone varchar(32) NOT NULL UNIQUE, account_type varchar(32) NOT NULL, - service_area varchar(128) NOT NULL, created_at timestamptz NOT NULL, updated_at timestamptz NOT NULL, - created_by_identity uuid, updated_by_identity uuid, status varchar(32) NOT NULL DEFAULT 'enabled', version integer NOT NULL DEFAULT 1 -); -CREATE TABLE IF NOT EXISTS org_delivery_point ( - identity uuid PRIMARY KEY, delivery_code varchar(32) NOT NULL UNIQUE, gas_station_identity uuid, - name varchar(128) NOT NULL, service_area varchar(128) NOT NULL, created_at timestamptz NOT NULL, updated_at timestamptz NOT NULL, - created_by_identity uuid, updated_by_identity uuid, status varchar(32) NOT NULL DEFAULT 'draft', version integer NOT NULL DEFAULT 1 -); -CREATE TABLE IF NOT EXISTS org_service_person ( - identity uuid PRIMARY KEY, account_identity uuid UNIQUE, gas_station_identity uuid, delivery_point_identity uuid, - name varchar(64) NOT NULL, roles varchar(128) NOT NULL, work_status varchar(32) NOT NULL, credential_status varchar(32) NOT NULL, - created_at timestamptz NOT NULL, updated_at timestamptz NOT NULL, created_by_identity uuid, updated_by_identity uuid, - status varchar(32) NOT NULL DEFAULT 'draft', version integer NOT NULL DEFAULT 1 -); -COMMENT ON TABLE idn_account IS '身份账户主表'; -COMMENT ON COLUMN idn_account.identity IS '主键,应用生成的 UUID V7'; -COMMENT ON COLUMN idn_account.phone IS '手机号,敏感字段,展示时脱敏'; -COMMENT ON COLUMN idn_account.account_type IS '账户类型:user、service_person、admin'; -COMMENT ON COLUMN idn_account.service_area IS '授权服务区域'; -COMMENT ON COLUMN idn_account.status IS '状态:enabled、frozen、archived'; -COMMENT ON TABLE org_delivery_point IS '配送点主表'; -COMMENT ON COLUMN org_delivery_point.identity IS '主键,应用生成的 UUID V7'; -COMMENT ON COLUMN org_delivery_point.delivery_code IS '配送点全局唯一业务编码'; -COMMENT ON COLUMN org_delivery_point.gas_station_identity IS '归属 org_gas_station 的 identity'; -COMMENT ON COLUMN org_delivery_point.name IS '配送点名称'; -COMMENT ON COLUMN org_delivery_point.service_area IS '配送服务区域'; -COMMENT ON COLUMN org_delivery_point.status IS '状态:draft、enabled、frozen、archived'; -COMMENT ON TABLE org_service_person IS '服务人员主表'; -COMMENT ON COLUMN org_service_person.identity IS '主键,应用生成的 UUID V7'; -COMMENT ON COLUMN org_service_person.account_identity IS '关联 idn_account 的 identity'; -COMMENT ON COLUMN org_service_person.gas_station_identity IS '归属 org_gas_station 的 identity'; -COMMENT ON COLUMN org_service_person.delivery_point_identity IS '主归属 org_delivery_point 的 identity'; -COMMENT ON COLUMN org_service_person.roles IS '可执行角色集合'; -COMMENT ON COLUMN org_service_person.work_status IS '上班与接单状态'; -COMMENT ON COLUMN org_service_person.credential_status IS '资质状态'; -COMMENT ON COLUMN org_service_person.status IS '状态:draft、enabled、frozen、archived'; diff --git a/backend/migrations/0004_alter_idn_account_platform_login.sql b/backend/migrations/0004_alter_idn_account_platform_login.sql deleted file mode 100644 index cc76b2f..0000000 --- a/backend/migrations/0004_alter_idn_account_platform_login.sql +++ /dev/null @@ -1,15 +0,0 @@ --- 平台总后台登录字段;所有业务主表仍使用应用生成的 UUID V7 identity。 -ALTER TABLE idn_account ADD COLUMN IF NOT EXISTS username varchar(64); -ALTER TABLE idn_account ADD COLUMN IF NOT EXISTS display_name varchar(64) NOT NULL DEFAULT ''; -ALTER TABLE idn_account ADD COLUMN IF NOT EXISTS password_hash varchar(255) NOT NULL DEFAULT ''; -ALTER TABLE idn_account ADD COLUMN IF NOT EXISTS role_code varchar(64) NOT NULL DEFAULT 'user'; -ALTER TABLE idn_account ADD COLUMN IF NOT EXISTS must_change_password boolean NOT NULL DEFAULT false; -ALTER TABLE idn_account ADD COLUMN IF NOT EXISTS mfa_enabled boolean NOT NULL DEFAULT false; -CREATE UNIQUE INDEX IF NOT EXISTS uk_idn_account_username ON idn_account (username) WHERE username IS NOT NULL; - -COMMENT ON COLUMN idn_account.username IS '登录用户名;平台 root 由 internal/initdb/platform.go 幂等初始化'; -COMMENT ON COLUMN idn_account.display_name IS '后台界面展示名称'; -COMMENT ON COLUMN idn_account.password_hash IS 'bcrypt 密码哈希,禁止在 API 中返回'; -COMMENT ON COLUMN idn_account.role_code IS '平台角色编码'; -COMMENT ON COLUMN idn_account.must_change_password IS '首次登录或重置密码后必须修改密码'; -COMMENT ON COLUMN idn_account.mfa_enabled IS '是否启用多因素认证'; diff --git a/backend/migrations/README.md b/backend/migrations/README.md deleted file mode 100644 index 7476002..0000000 --- a/backend/migrations/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# PostgreSQL 迁移 - -迁移文件名遵循 `<序号>_create_<模块前缀_单数实体>.sql`。每个主表必须以应用生成的 UUID V7 `identity` 为主键,并对表、字段、索引、约束和枚举补充中文注释。 - -当前 API 的 GORM 自动迁移用于本地开发;生产发布必须先评审并执行本目录的显式 SQL 迁移,再部署新版本服务。 diff --git a/docs/05-平台总后台需求-分析.md b/docs/05-平台总后台需求-分析.md new file mode 100644 index 0000000..37319d6 --- /dev/null +++ b/docs/05-平台总后台需求-分析.md @@ -0,0 +1,349 @@ +# 平台总后台需求分析 + +## 1. 文档目标与范围 + +本文将 [平台总后台需求](05-平台总后台需求.md) 拆解为可实施的领域模型、接口边界与 Vue 管理端页面规划,作为平台总后台的产品、前端与后端共同基线。 + +平台总后台是全平台唯一的跨组织治理中心,管理所有可燃气体站、配送点、服务人员、用户、智能瓶阀安全事件、全局规则、资金结算和审计数据。它不替代气站、配送点、生产和 API 中心系统处理各自的日常业务,而是维护主数据、全局策略、跨组织协同和高风险审批。 + +本项目不维护独立数据库迁移功能。表结构由 Go 模型在应用启动时通过 GORM 自动同步;模型、接口契约和中文注释须在同一需求变更中更新。 + +气站与配送点邀请二维码不属于平台总后台本期功能范围;本期不规划二维码数据表、接口、菜单或页面。 + +### 1.1 前后端实现目录 + +| 范围 | 目录 / 文件 | 责任 | +| --- | --- | --- | +| 前端项目 | `frontend/platform_admin` | Vue 平台总后台,承载登录、菜单、页面、数据权限提示和 API 调用 | +| 前端页面 | `frontend/platform_admin/src/views` | 当前后台壳与页面编排;后续可按业务域拆分至 `src/views/` | +| 前端接口 | `frontend/platform_admin/src/api` | 平台总后台 HTTP 客户端、类型和登录会话处理 | +| 后端 API | `backend/api` | Go/Gin 平台总后台 API 进程 | +| 后端路由文件 | `backend/api/internal/routers/platform.go` | 唯一 HTTP 路由注册入口,注册 `/heqi/platform/v1` 前缀及认证路由组 | +| 后端业务逻辑 | `backend/api/internal/logic/platform` | 平台认证、组织、人员、用户、安全、交易、资金与审计逻辑 | +| 后端模型 | `backend/api/internal/models` | GORM 数据模型、表名、数据访问和中文模型注释 | +| 初始数据 | `backend/api/internal/initdb/platform.go` | 初始化 `root` 系统管理员角色与根账户 | + +## 2. 实施原则 + +- 所有表均使用数据库 `id` 自增主键,作为物理主键和内部关联键。 +- 所有主表额外包含 `identity` 字段,类型为 `varchar(36)`,由应用生成 UUID V7;`identity` 是对外接口、审计、跨服务关联使用的唯一业务主键,并建立唯一索引。明细表是否保留 `identity` 由是否需要对外暴露或被审计引用决定。 +- 表名、Go 模型名、模型文件名使用同一单数实体词根;接口仅以 `list`、`items` 表达集合语义,不使用复数实体名。 +- 平台角色权限统一使用 `platform_role` 与 `platform_role_menu_relation`;系统初始化时创建 `root` 系统管理员角色并授予全部菜单权限。 +- 可燃气体站、配送点、服务人员与用户的归属、服务关系和状态变更必须留存历史快照,禁止直接覆盖历史业务归属。 +- 手机号、身份证件、详细地址、精确位置、头像访问地址、支付和资质资料均属于敏感字段;列表默认脱敏,导出与精确轨迹须审批。 +- 高风险安全动作、跨组织变更、组织冻结、资金动作、敏感导出实行职责分离、理由必填和审计留痕。 +- 外部支付、地图、短信、对象存储、IoT、生产系统与 API 网关均通过适配层接入;开发阶段可使用 Mock 边界。 + + +## 4. 数据模型规划 + +### 4.1 公共字段与关联规则 + +所有表统一包含 `id bigint` 自增物理主键、`created_at`、`updated_at`。主表统一增加 `identity varchar(36)`,由应用生成 UUID V7 并设置唯一索引,同时包含 `status`、`version`。跨服务、审计日志和 HTTP 路由只传递 `identity`,数据库内部关联可使用 `<实体词根>_id`;业务编码另设唯一字段,例如 `gas_code`、`delivery_code`、`order_code`。 + +主表的 Go 模型应同时声明 `ID uint64`(自增主键)和 `Identity string`(UUID V7 业务主键);`identity` 不由数据库默认生成,必须在应用层创建记录前写入。 + +### 4.2 身份、组织与服务关系 + +| 实体 | 表 / 模型 / 文件 | 关键字段 | 说明 | +| --- | --- | --- | --- | +| 平台账户 | `platfrom_account` / `PlatfromAccount` / `platfrom_account.go` | `id`、`identity`、`username`、`display_name`、`avatar`、`password_hash`、`platform_role_code`、`phone` | 平台后台登录账户;头像保存受控资源地址 | +| 平台角色 | `platform_role` / `PlatformRole` / `platform_role.go` | `id`、`identity`、`role_code`、`name`、`data_scope`、`is_system` | 角色定义;初始化内置 `root` 系统管理员角色 | +| 气站基础资料 | `gas_basic` / `GasBasic` / `gas_basic.go` | `id`、`identity`、`code`、`name`、`credit_code`、`principal`、`address`、`longitude`、`latitude` | 气站主体主档案 | +| 气站账户 | `gas_account` / `GasAccount` / `gas_account.go` | `id`、`identity`、`gas_basic_id`、`username`、`display_name`、`password_hash`、`role_code` | 气站身份账户 | +| 配送点资料 | `delivery_basic` / `DeliveryBasic` / `delivery_basic.go` | `id`、`identity`、`delivery_code`、`gas_basic_id`、`name`、`principal`、`address` | 末端配送组织单元;可归属平台或气站 | +| 配送点账户 | `delivery_account` / `DeliveryAccount` / `delivery_account.go` | `id`、`identity`、`delivery_basic_id`、`username`、`display_name`、`password_hash`、`role_code` | 配送点身份账户;仅能访问本点数据 | +| 服务人员账户 | `staff_account` / `StaffAccount` / `staff_account.go` | `id`、`identity`、`staff_id`、`username`、`password_hash`、`gas_basic_id`、`delivery_basic_id`、`work_status` | 安装维修、安检、配送人员账号及资料 | +| 人员资质 | `staff_credential` / `StaffCredential` / `staff_credential.go` | `id`、`identity`、`staff_id`、`credential_type`、`credential_no`、`expired_at` | 培训、证照、保险与技能等级 | +| 业主客户账户 | `user_account` / `UserAccount` / `user_account.go` | `id`、`identity`、`user_id`、`username`、`password_hash`、`status` | 用户端登录账户 | +| 用户地址 | `user_address` / `UserAddress` / `user_address.go` | `id`、`identity`、`user_id`、`address`、`longitude`、`latitude`、`is_default` | 地址历史和订单快照来源 | +| 用户服务关系 | `user_service_relation` / `UserServiceRelation` / `user_service_relation.go` | `id`、`identity`、`user_id`、`gas_basic_id`、`delivery_basic_id`、`staff_id` | 用户与气站/配送点的服务归属 | + +### 4.3 设备与安全 + +| 实体 | 表 / 模型 / 文件 | 关键字段 | 说明 | +| --- | --- | --- | --- | +| 智能瓶阀 | `dev_smart_cylinder_valve` / `DevSmartCylinderValve` / `dev_smart_cylinder_valve.go` | `device_no`、`model`、`online_status`、`owner_identity` | 智能瓶阀全生命周期档案 | +| 设备绑定 | `dev_device_binding` / `DevDeviceBinding` / `dev_device_binding.go` | `id`、`identity`、`smart_cylinder_valve_id`、`user_id`、`effective_at`、`expired_at` | 用户/家庭与智能瓶阀授权关系 | +| 遥测 | `dev_telemetry` / `DevTelemetry` / `dev_telemetry.go` | `smart_cylinder_valve_identity`、`reported_at`、`payload`、`quality_flag` | 遥测摘要与质量标记 | +| 安全规则 | `saf_rule` / `SafRule` / `saf_rule.go` | `rule_code`、`version_no`、`threshold`、`action`、`gray_scope` | 告警、自动关阀、静默和灰度规则 | +| 安全事件 | `saf_event` / `SafEvent` / `saf_event.go` | `event_code`、`level`、`smart_cylinder_valve_identity`、`status`、`sla_at` | 告警、安检和人工发现事件统一入口 | +| 安全处置 | `saf_event_disposal` / `SafEventDisposal` / `saf_event_disposal.go` | `saf_event_identity`、`action`、`reason`、`operator_identity` | 派发、升级、关阀、复核和结案记录 | +| 安检记录 | `saf_inspection` / `SafInspection` / `saf_inspection.go` | `id`、`identity`、`user_id`、`staff_id`、`result`、`evidence_uri` | 安检、整改和复检证据 | + +### 4.4 电商、订单与配送轨迹 + +| 实体 | 表 / 模型 / 文件 | 关键字段 | 说明 | +| --- | --- | --- | --- | +| 商品分类 | `ec_category` / `EcCategory` / `ec_category.go` | `id`、`identity`、`parent_id`、`name`、`sort_no`、`status` | 可燃气体商品及服务分类树 | +| 商品 | `ec_product` / `EcProduct` / `ec_product.go` | `id`、`identity`、`ec_category_id`、`product_code`、`name`、`price_amount`、`stock_quantity`、`status` | 可燃气体商品与服务主数据 | +| 商品属性 | `ec_product_attribute` / `EcProductAttribute` / `ec_product_attribute.go` | `id`、`identity`、`ec_product_id`、`name`、`value`、`sort_no` | 商品属性子表,例如规格、重量和服务时长 | +| 商品图片 | `ec_product_image` / `EcProductImage` / `ec_product_image.go` | `id`、`identity`、`ec_product_id`、`image_uri`、`sort_no`、`is_cover` | 商品图片子表,保存受控资源地址 | +| 购物车 | `ec_cart` / `EcCart` / `ec_cart.go` | `id`、`identity`、`user_id`、`ec_product_id`、`quantity`、`selected` | 用户购物车明细 | +| 订单 | `ec_order` / `EcOrder` / `ec_order.go` | `id`、`identity`、`order_no`、`user_id`、`gas_station_id`、`delivery_point_id`、`total_amount`、`status` | 电商订单主表及组织快照 | +| 订单项 | `ec_order_item` / `EcOrderItem` / `ec_order_item.go` | `id`、`identity`、`ec_order_id`、`ec_product_id`、`product_snapshot`、`quantity`、`sale_amount` | 订单商品快照和金额明细 | +| 商品评论 | `ec_review` / `EcReview` / `ec_review.go` | `id`、`identity`、`ec_order_id`、`ec_product_id`、`user_id`、`score`、`content`、`status` | 用户评价、审核和隐藏状态 | +| 配送任务 | `delivery_task` / `DeliveryTask` / `delivery_task.go` | `id`、`identity`、`ec_order_id`、`staff_id`、`delivery_point_id`、`status` | 配送履约任务 | +| 配送轨迹 | `delivery_track` / `DeliveryTrack` / `delivery_track.go` | `id`、`identity`、`delivery_task_id`、`status`、`started_at`、`completed_at` | 用户可见简化配送轨迹 | +| 配送轨迹点 | `delivery_track_point` / `DeliveryTrackPoint` / `delivery_track_point.go` | `id`、`identity`、`delivery_track_id`、`point_type`、`occurred_at`、`longitude`、`latitude` | 精确位置与任务节点;访问受授权控制 | + +### 4.5 财务、钱包、统计报表、内容与审计 + +| 实体 | 表 / 模型 / 文件 | 关键字段 | 说明 | +| --- | --- | --- | --- | +| 支付记录 | `fin_payment` / `FinPayment` / `fin_payment.go` | `id`、`identity`、`ec_order_id`、`channel`、`amount`、`status`、`paid_at` | 支付、退款和外部渠道流水关联 | +| 财务结算 | `fin_settlement` / `FinSettlement` / `fin_settlement.go` | `id`、`identity`、`settlement_no`、`subject_type`、`subject_id`、`period_start`、`period_end`、`status` | 气站、配送点、服务人员结算单 | +| 财务对账 | `fin_reconciliation` / `FinReconciliation` / `fin_reconciliation.go` | `id`、`identity`、`channel`、`bill_date`、`difference_amount`、`status` | 支付渠道对账及差异处理 | +| 钱包 | `wallet` / `Wallet` / `wallet.go` | `id`、`identity`、`owner_type`、`owner_id`、`balance_amount`、`frozen_amount`、`status` | 用户、组织和服务人员的钱包余额账户 | +| 钱包流水 | `wallet_ledger` / `WalletLedger` / `wallet_ledger.go` | `id`、`identity`、`wallet_id`、`amount`、`direction`、`balance_after`、`reference_identity` | 钱包唯一资金事实流水 | +| 钱包充值 | `wallet_recharge` / `WalletRecharge` / `wallet_recharge.go` | `id`、`identity`、`wallet_id`、`amount`、`channel`、`status` | 钱包充值申请和支付结果 | +| 钱包提现 | `wallet_withdrawal` / `WalletWithdrawal` / `wallet_withdrawal.go` | `id`、`identity`、`wallet_id`、`amount`、`bank_account_masked`、`status` | 提现申请、审核与付款凭证 | +| 统计报表 | `report` / `Report` / `report.go` | `id`、`identity`、`report_code`、`report_type`、`stat_period`、`generated_at` | 可下载或在线查看的统计报表主档案 | +| 统计报表明细 | `report_item` / `ReportItem` / `report_item.go` | `id`、`identity`、`report_id`、`dimension`、`metric_code`、`metric_value` | 按组织、区域、商品、时间拆分的报表明细 | +| 内容 | `cnt_content` / `CntContent` / `cnt_content.go` | `content_type`、`title`、`version_no`、`publish_status` | 公告、协议、安全宣教内容 | +| 消息模板 | `ntf_template` / `NtfTemplate` / `ntf_template.go` | `template_code`、`channel`、`content`、`status` | 短信、推送、站内信模板 | +| 客服工单 | `cs_ticket` / `CsTicket` / `cs_ticket.go` | `id`、`identity`、`ticket_no`、`user_id`、`category`、`status`、`priority` | 咨询、投诉、回访与升级 | +| 运营指标快照 | `report_metric_snapshot` / `ReportMetricSnapshot` / `report_metric_snapshot.go` | `id`、`identity`、`metric_code`、`scope_type`、`scope_id`、`stat_at`、`metric_value` | 看板与预警计算结果 | +| 操作审计 | `aud_operation_log` / `AudOperationLog` / `aud_operation_log.go` | `operator_identity`、`action`、`object_type`、`object_identity`、`before_data`、`after_data` | 不可由普通管理员改写或删除 | +| 导出审计 | `aud_export_log` / `AudExportLog` / `aud_export_log.go` | `applicant_identity`、`purpose`、`field_scope`、`approved_at`、`file_uri` | 敏感导出、下载与水印记录 | +| 审批单 | `aud_approval` / `AudApproval` / `aud_approval.go` | `business_type`、`business_identity`、`applicant_identity`、`status` | 双人复核、审批流与意见 | + +## 5. API 路由规则 + +### 5.1 通用约定 + +- 基础路径:`/heqi/platform/v1`;本节列出的路由均为该前缀后的相对路径。 +- 资源路径采用模块名与单数蛇形实体名:`/{domain}/{resource}`,例如 `/gas/gas_station`。 +- 平台总后台接口以 CRUD 为主:`GET` 列表/详情、`POST` 创建、`PUT /:identity` 更新、`PATCH /:identity/status` 启用/停用、`DELETE /:identity` 逻辑删除或归档;主数据不做物理删除。 +- 分页参数统一为 `page`、`size`;筛选参数使用明确字段名;列表返回 `{ total, list }`。 +- 批量启停、导入、导出等扩展动作使用明确动作路径,例如 `/:identity/status`、`/import`、`/export`;请求必须携带 `reason`(如适用)。 +- 认证接口以 `/auth` 开头;除登录和健康检查外,均要求原始 JWT `Authorization` 请求头。 +- 请求和响应字段使用 `snake_case`;时间使用 ISO 8601;金额使用最小货币单位整数;位置字段仅在获授权接口中返回。 + +### 5.2 认证与平台账户 + +| 方法 | 路由 | 作用 | +| --- | --- | --- | +| `POST` | `/auth/login` | 平台账户登录并签发 JWT | +| `GET` | `/auth/profile` | 当前登录账户资料,含头像 | +| `PUT` | `/auth/password` | 修改当前账户密码 | +| `GET` | `/platform/platfrom_account` | 平台账户分页列表 | +| `POST` | `/platform/platfrom_account` | 创建平台账户 | +| `GET` | `/platform/platfrom_account/:identity` | 平台账户详情 | +| `PUT` | `/platform/platfrom_account/:identity` | 更新名称、头像、角色、手机号 | +| `PATCH` | `/platform/platfrom_account/:identity/status` | 启用、冻结、归档账户 | +| `GET/POST` | `/platform/platform_role` | 角色列表、创建角色;初始化内置 `root` 系统管理员角色 | +| `PUT` | `/platform/platform_role/:identity/menu` | 覆盖角色菜单与按钮权限集合 | +| `GET` | `/platform/platform_menu` | 菜单树和当前账户可见菜单 | + +### 5.3 组织、人员和用户 + +| 方法 | 路由 | 作用 | +| --- | --- | --- | +| `GET/POST` | `/gas/gas_station` | 查询、创建可燃气体站 | +| `GET/PUT/DELETE` | `/gas/gas_station/:identity` | 气站详情、更新、逻辑删除/归档 | +| `PATCH` | `/gas/gas_station/:identity/status` | 气站启用、停用、冻结 | +| `GET/POST` | `/gas/gas_account` | 气站账户查询、创建和授权 | +| `GET/POST` | `/delivery/delivery_point` | 查询、创建配送点 | +| `GET/PUT/DELETE` | `/delivery/delivery_point/:identity` | 配送点详情、更新、逻辑删除/归档 | +| `PATCH` | `/delivery/delivery_point/:identity/status` | 配送点启用、停用、冻结 | +| `GET/POST` | `/delivery/delivery_account` | 配送点账户查询、创建和授权 | +| `GET/POST` | `/staff/account` | 服务人员查询、建档或导入 | +| `GET/PUT/DELETE` | `/staff/:identity` | 服务人员详情、更新、逻辑删除/归档 | +| `GET/POST/PUT/DELETE` | `/staff/credential` | 服务人员资质 CRUD | +| `GET/POST` | `/user/account` | 业主客户查询、创建 | +| `GET/PUT/DELETE` | `/user/:identity` | 用户详情、更新、逻辑删除/归档 | +| `PATCH` | `/user/:identity/status` | 冻结登录、限制下单或设备控制 | +| `POST` | `/user/service_relation` | 建立或变更用户服务关系 | + +### 5.4 智能瓶阀安全、订单与配送轨迹 + +| 方法 | 路由 | 作用 | +| --- | --- | --- | +| `GET/POST` | `/device/dev_smart_cylinder_valve` | 智能瓶阀查询、建档 | +| `GET/PUT/DELETE` | `/device/dev_smart_cylinder_valve/:identity` | 智能瓶阀详情、更新、逻辑删除/归档 | +| `GET/POST` | `/safety/saf_event` | 安全事件查询、创建 | +| `GET/PUT/DELETE` | `/safety/saf_event/:identity` | 安全事件详情、更新、逻辑删除/归档 | +| `GET/POST` | `/safety/saf_rule` | 安全规则 CRUD 的列表与创建 | +| `GET/PUT/DELETE` | `/safety/saf_rule/:identity` | 安全规则详情、更新、逻辑删除 | +| `GET/POST` | `/ec/ec_order` | 电商订单查询、创建 | +| `GET/PUT/DELETE` | `/ec/ec_order/:identity` | 电商订单详情、更新、逻辑删除/归档 | +| `GET/POST` | `/delivery/delivery_track` | 配送轨迹查询、创建 | +| `GET/PUT/DELETE` | `/delivery/delivery_track/:identity` | 配送轨迹详情、更新、逻辑删除/归档 | + +### 5.5 电商、财务、钱包、统计报表、内容与审计 + +| 方法 | 路由 | 作用 | +| --- | --- | --- | +| `GET/POST` | `/ec/ec_category` | 商品分类查询、创建 | +| `GET/PUT/DELETE` | `/ec/ec_category/:identity` | 商品分类详情、更新、逻辑删除 | +| `GET/POST` | `/ec/ec_product` | 商品查询、创建 | +| `GET/PUT/DELETE` | `/ec/ec_product/:identity` | 商品详情、更新、逻辑删除 | +| `GET/POST/PUT/DELETE` | `/ec/ec_product_attribute` | 商品属性子表 CRUD | +| `GET/POST/PUT/DELETE` | `/ec/ec_product_image` | 商品图片子表 CRUD | +| `GET/POST/PUT/DELETE` | `/ec/ec_cart` | 购物车 CRUD | +| `GET/POST/PUT/DELETE` | `/ec/ec_review` | 商品评论 CRUD | +| `GET/POST` | `/finance/fin_payment` | 支付记录查询、创建 | +| `GET/PUT/DELETE` | `/finance/fin_payment/:identity` | 支付记录详情、更新、逻辑删除 | +| `GET/POST/PUT/DELETE` | `/finance/fin_settlement` | 财务结算 CRUD | +| `GET/POST/PUT/DELETE` | `/finance/fin_reconciliation` | 财务对账 CRUD | +| `GET` | `/wallet/wallet` | 钱包列表查询 | +| `GET` | `/wallet/wallet/:identity` | 钱包详情查看 | +| `GET` | `/wallet/wallet_ledger` | 钱包流水列表查询 | +| `GET` | `/wallet/wallet_ledger/:identity` | 钱包流水详情查看 | +| `GET` | `/wallet/wallet_recharge` | 钱包充值记录列表查询 | +| `GET` | `/wallet/wallet_withdrawal` | 钱包提现记录列表查询 | +| `GET` | `/report/report` | 统计报表列表查询 | +| `GET` | `/report/report/:identity` | 统计报表详情查看 | +| `GET` | `/report/report_item` | 统计报表明细列表查询 | +| `GET` | `/report/report_item/:identity` | 统计报表明细详情查看 | +| `GET/POST/PUT/DELETE` | `/content/cnt_content` | 内容 CRUD | +| `GET/POST/PUT/DELETE` | `/customer_service/cs_ticket` | 客服工单 CRUD | +| `GET` | `/report/report_metric_snapshot` | 运营指标看板查询 | +| `GET` | `/audit/aud_operation_log` | 操作审计查询 | +| `GET` | `/audit/aud_export_log` | 导出审计查询 | +| `POST` | `/audit/aud_approval/:identity/approve` | 审批通过或驳回 | + +## 6. 前端页面规划 + +### 6.1 全局框架 + +前端项目位于 `frontend/platform_admin`,使用 Vue 3、TypeScript 和 Vite。页面采用“应用壳 + 一级侧边栏 + 二级菜单 + 列表工作区 + 详情抽屉/编辑弹窗”的后台信息架构;每个实体页面围绕其模型的列表、详情、新增、编辑、状态和逻辑删除组织。 + +- 路由配置文件:`frontend/platform_admin/src/router/routes.ts`;菜单配置由 `platform_menu` 驱动并映射到受控本地路由。 +- 页面根目录:`frontend/platform_admin/src/views`;按一级菜单拆分目录,禁止将所有页面堆放在 `App.vue`。 +- 共享组件目录:`frontend/platform_admin/src/components`;提供 `DataTable`、`FilterBar`、`DetailDrawer`、`FormDrawer`、`StatusTag`、`ConfirmDialog` 和 `EmptyState`。 +- 图标库:`lucide-vue-next`;菜单仅保存图标名称,页面通过统一 `IconRenderer` 映射,避免散落硬编码 SVG。 + +| 一级导航 | 页面 | 核心内容 | +| --- | --- | --- | +| 登录 | 登录页 | 账号密码登录、错误提示、服务条款入口 | +| 工作台 | 运营总览 | 气站、配送点、人员、用户、智能瓶阀、安全事件、订单、结算核心指标;异常待办与地图概览 | +| 组织权限 | 可燃气体站列表、站点详情、配送点列表、配送点详情、服务区域、角色权限 | 主档案、审批、归属、服务能力、组织 KPI、账号与数据范围 | +| 人员用户 | 服务人员列表、人员详情、资质审核、调配中心、用户列表、用户 360 | 人员生命周期、任务绩效、资质预警、用户设备/订单/安全/投诉概览 | +| 安全设备 | 智能瓶阀列表、设备详情、安全事件中心、安全规则、安检整改 | 实时状态、遥测摘要、告警处置、规则版本、证据和复核 | +| 电商管理 | 分类管理、商品管理、商品属性、商品图片、购物车、订单、评论 | `ec` 电商实体 CRUD、商品上下架、订单与评论管理 | +| 财务钱包 | 支付记录、财务结算、财务对账、钱包、钱包流水、充值、提现 | `fin` 财务实体 CRUD;钱包、流水、充值和提现记录仅列表与详情查看 | +| 统计报表 | 报表列表、报表明细、指标看板 | 报表生成记录、维度明细和聚合指标只读查询 | +| 内容客服 | 内容中心、消息模板、客服工单 | 草稿/审核/发布/撤回、触达渠道、工单 SLA 与满意度 | +| 配送轨迹 | 配送任务、配送轨迹、轨迹点 | 配送履约记录、轨迹节点和异常信息 CRUD | +| 全局运营 | 指标中心、地图态势、运营规则、消息任务 | 跨组织下钻、阈值预警、规则灰度、触达效果 | +| 审计合规 | 审批中心、操作审计、导出审计、合规工单 | 审批队列、前后值追溯、敏感访问与留存处置 | + +### 6.2 前端目录、菜单与页面映射(以本表为准) + +页面目录统一位于 `frontend/platform_admin/src/views`;`ListPage.vue` 负责筛选、分页和表格,`DetailDrawer.vue` 负责查看详情,`FormDrawer.vue` 负责创建与编辑。钱包、流水和报表目录不创建 `FormDrawer.vue`,只保留列表和详情组件。图标使用 `lucide-vue-next`。 + +| 一级菜单 / 图标 | 二级菜单 / 图标 | 路由 | 目录名 | 文件名 | 核心内容 | +| --- | --- | --- | --- | --- | --- | +| 工作台 `LayoutDashboard` | 运营概览 `ChartNoAxesCombined` | `/dashboard` | `views/dashboard` | `DashboardPage.vue` | 气站、配送点、人员、用户、智能瓶阀、电商订单、财务和安全指标卡片 | +| 气站管理 `Fuel` | 气站管理 `Building2` | `/gas/basic` | `views/gas/basic` | `ListPage.vue` | `gas_basic` CRUD、状态和基础档案 | +| 气站管理 `Fuel` | 气站账户 `UserCog` | `/gas/account` | `views/gas/account` | `ListPage.vue` | `gas_account` CRUD、账号状态和角色 | +| 配送管理 `Truck` | 配送点管理 `Warehouse` | `/delivery/basic` | `views/delivery/basic` | `ListPage.vue` | `delivery_basic` CRUD、归属气站、负责人和状态 | +| 配送管理 `Truck` | 配送点账户 `UserRoundCog` | `/delivery/account` | `views/delivery/account` | `ListPage.vue` | `delivery_account` CRUD、登录账号和权限 | +| 配送管理 `Truck` | 配送任务 `ListTodo` | `/delivery/task` | `views/delivery/task` | `ListPage.vue` | `delivery_task` CRUD、订单、配送员、配送点和状态 | +| 配送管理 `Truck` | 配送轨迹 `Route` | `/delivery/track` | `views/delivery/track` | `ListPage.vue` | `delivery_track`、`delivery_track_point` CRUD 和轨迹时间线 | +| 服务人员 `HardHat` | 人员档案 `Contact` | `/staff/list` | `views/staff/list` | `ListPage.vue` | `staff` CRUD、头像、组织归属、岗位状态 | +| 服务人员 `HardHat` | 人员账户 `Smartphone` | `/staff/account` | `views/staff/account` | `ListPage.vue` | `staff_account` CRUD、App 账号和登录状态 | +| 服务人员 `HardHat` | 人员资质 `FileBadge` | `/staff/credential` | `views/staff/credential` | `ListPage.vue` | `staff_credential` CRUD、证照、有效期和附件 | +| 业主客户 `UsersRound` | 客户档案 `UserRound` | `/user/list` | `views/user/list` | `ListPage.vue` | `user` CRUD、实名状态和账户状态 | +| 业主客户 `UsersRound` | 客户账户 `KeyRound` | `/user/account` | `views/user/account` | `ListPage.vue` | `user_account` CRUD、登录账号和状态 | +| 业主客户 `UsersRound` | 客户地址 `MapPinHouse` | `/user/address` | `views/user/address` | `ListPage.vue` | `user_address` CRUD、默认地址和位置 | +| 业主客户 `UsersRound` | 服务关系 `GitFork` | `/user/service-relation` | `views/user/service-relation` | `ListPage.vue` | `user_service_relation` CRUD、气站/配送点归属 | +| 设备管理 `ShieldAlert` | 智能瓶阀 `Gauge` | `/device/valve` | `views/device/valve` | `ListPage.vue` | `dev_smart_cylinder_valve` CRUD、型号、在线状态、归属 | +| 设备管理 `ShieldAlert` | 设备绑定 `Link2` | `/device/binding` | `views/device/binding` | `ListPage.vue` | `dev_device_binding` CRUD、用户与智能瓶阀绑定 | +| 设备管理 `ShieldAlert` | 安全规则 `Siren` | `/safety/rule` | `views/safety/rule` | `ListPage.vue` | `saf_rule` CRUD、阈值、规则版本和状态 | +| 设备管理 `ShieldAlert` | 安全事件 `TriangleAlert` | `/safety/event` | `views/safety/event` | `ListPage.vue` | `saf_event` CRUD、等级、设备、用户和状态 | +| 设备管理 `ShieldAlert` | 安检记录 `ClipboardCheck` | `/safety/inspection` | `views/safety/inspection` | `ListPage.vue` | `saf_inspection` CRUD、人员、结果和证据 | +| 电商管理 `ShoppingBag` | 商品分类 `FolderTree` | `/ec/category` | `views/ec/category` | `TreePage.vue` | `ec_category` 分类树 CRUD、排序和状态 | +| 电商管理 `ShoppingBag` | 商品管理 `PackageSearch` | `/ec/product` | `views/ec/product` | `ListPage.vue` | `ec_product` CRUD、分类、价格、库存和状态 | +| 电商管理 `ShoppingBag` | 商品属性 `Tags` | `/ec/product-attribute` | `views/ec/product-attribute` | `ListPage.vue` | `ec_product_attribute` CRUD、商品规格与属性 | +| 电商管理 `ShoppingBag` | 商品图片 `Image` | `/ec/product-image` | `views/ec/product-image` | `ListPage.vue` | `ec_product_image` CRUD、封面、排序和预览 | +| 电商管理 `ShoppingBag` | 购物车 `ShoppingCart` | `/ec/cart` | `views/ec/cart` | `ListPage.vue` | `ec_cart` CRUD、用户、商品、数量和选中状态 | +| 电商管理 `ShoppingBag` | 电商订单 `ReceiptText` | `/ec/order` | `views/ec/order` | `ListPage.vue` | `ec_order`、`ec_order_item` CRUD、金额和履约状态 | +| 电商管理 `ShoppingBag` | 商品评论 `MessageSquareText` | `/ec/review` | `views/ec/review` | `ListPage.vue` | `ec_review` CRUD、评分、评论内容和显示状态 | +| 财务管理 `Landmark` | 支付记录 `CreditCard` | `/finance/payment` | `views/finance/payment` | `ListPage.vue` | `fin_payment` CRUD、订单、渠道、金额和支付状态 | +| 财务管理 `Landmark` | 财务结算 `Scale` | `/finance/settlement` | `views/finance/settlement` | `ListPage.vue` | `fin_settlement` CRUD、结算主体、周期和金额 | +| 财务管理 `Landmark` | 财务对账 `BookOpenCheck` | `/finance/reconciliation` | `views/finance/reconciliation` | `ListPage.vue` | `fin_reconciliation` CRUD、渠道账单和差异 | +| 钱包中心 `WalletCards` | 钱包列表 `Wallet` | `/wallet/list` | `views/wallet/list` | `ListPage.vue` | `wallet` 只读列表、余额、冻结金额和状态 | +| 钱包中心 `WalletCards` | 钱包流水 `ListOrdered` | `/wallet/ledger` | `views/wallet/ledger` | `ListPage.vue` | `wallet_ledger` 只读列表、方向、金额和余额快照 | +| 钱包中心 `WalletCards` | 充值记录 `CirclePlus` | `/wallet/recharge` | `views/wallet/recharge` | `ListPage.vue` | `wallet_recharge` 只读列表和详情 | +| 钱包中心 `WalletCards` | 提现记录 `CircleMinus` | `/wallet/withdrawal` | `views/wallet/withdrawal` | `ListPage.vue` | `wallet_withdrawal` 只读列表和详情 | +| 统计报表 `ChartNoAxesCombined` | 报表列表 `FileBarChart` | `/report/list` | `views/report/list` | `ListPage.vue` | `report` 只读列表、周期、生成时间和下载入口 | +| 统计报表 `ChartNoAxesCombined` | 报表明细 `TableProperties` | `/report/item` | `views/report/item` | `ListPage.vue` | `report_item` 只读列表、维度和指标值 | +| 统计报表 `ChartNoAxesCombined` | 指标快照 `ChartLine` | `/report/metric-snapshot` | `views/report/metric-snapshot` | `DashboardPage.vue` | `report_metric_snapshot` 只读图表、同比和环比 | +| 内容客服 `MessagesSquare` | 内容管理 `FileText` | `/content/list` | `views/content/list` | `ListPage.vue` | `cnt_content` CRUD、类型、标题和发布状态 | +| 内容客服 `MessagesSquare` | 消息模板 `Send` | `/content/template` | `views/content/template` | `ListPage.vue` | `ntf_template` CRUD、渠道、模板编码和状态 | +| 内容客服 `MessagesSquare` | 客服工单 `Headset` | `/content/ticket` | `views/content/ticket` | `ListPage.vue` | `cs_ticket` CRUD、客户、分类、优先级和状态 | +| 审计合规 `ScrollText` | 操作审计 `History` | `/audit/operation-log` | `views/audit/operation-log` | `ListPage.vue` | `aud_operation_log` 只读检索、对象、动作和前后值摘要 | +| 审计合规 `ScrollText` | 导出审计 `FileOutput` | `/audit/export-log` | `views/audit/export-log` | `ListPage.vue` | `aud_export_log` 只读检索、用途、字段范围和导出文件 | +| 平台配置 `ShieldCheck` | 平台账户 `ContactRound` | `/platform/account` | `views/platform/account` | `ListPage.vue` | `platfrom_account` 列表、头像、角色、状态;新增/编辑抽屉 | +| 平台配置 `ShieldCheck` | 角色管理 `BadgeCheck` | `/platform/role` | `views/platform/role` | `ListPage.vue` | `platform_role` CRUD,`root` 角色只读保护 | +| 平台配置 `ShieldCheck` | 菜单管理 `MenuSquare` | `/platform/menu` | `views/platform/menu` | `TreePage.vue` | `platform_menu` 树、图标、路由、排序和角色菜单授权 | + +### 6.3 页面类型与组件规范 + +| 页面类型 | 适用实体 | 目录内文件 | 前端职责 | +| --- | --- | --- | --- | +| 标准 CRUD 列表页 | 气站、配送点、人员、用户、电商、财务、内容客服 | `ListPage.vue`、`DetailDrawer.vue`、`FormDrawer.vue` | 筛选、分页、详情、新增、编辑、逻辑删除和状态更新 | +| 树形管理页 | `platform_menu`、`ec_category` | `TreePage.vue`、`FormDrawer.vue` | 层级展示、拖拽排序、节点新增、编辑和逻辑删除 | +| 只读列表页 | 钱包、流水、充值、提现、报表、审计 | `ListPage.vue`、`DetailDrawer.vue` | 条件筛选、分页、详情、复制标识和受控导出;无新增/编辑/删除按钮 | +| 指标看板页 | 工作台、报表指标快照 | `DashboardPage.vue`、`MetricCard.vue`、`TrendChart.vue` | 指标卡、趋势图、筛选条件和下钻链接 | + +### 6.4 重点页面规格 + +| 页面 | 查询区 | 列表/主视图 | 关键动作 | +| --- | --- | --- | --- | +| 可燃气体站列表 | 区域、状态、资质、风险、创建时间 | 站点编码、名称、负责人、服务能力、订单/安全/结算摘要 | 新建、导入、审核、启停、合并、归档 | +| 气站详情 | 固定站点上下文 | 基础档案、服务能力、配送点、人员、用户、设备、财务、资质、审计标签页 | 编辑草稿、提交审核、冻结、查看下钻 | +| 配送点列表 | 归属气站、区域、状态、负载 | 编码、负责人、配送能力、在岗人数、准时率、库存摘要 | 创建、审核、归属变更、启停 | +| 服务人员列表 | 角色、组织、资质、在岗、区域 | 姓名、头像、角色、资质有效期、当前负载、评分、状态 | 导入、审核、授予角色、调配、冻结 | +| 用户 360 | 用户编号/手机号/订单号 | 身份、地址、智能瓶阀、订单、支付摘要、安全事件、工单和服务关系时间线 | 合规处置发起、查看最小必要信息 | +| 安全事件中心 | 等级、状态、设备、区域、SLA | 告警队列、地图、处置时钟和责任方 | 派发、升级、关阀、复核、结案 | +| 商品分类与商品 | 分类、状态、商品编码、创建时间 | 分类树、商品名称、封面、价格、库存、上下架状态 | 新增、编辑、逻辑删除、维护属性和图片 | +| 购物车、订单与评论 | 用户、商品、订单状态、评论状态、日期 | 购物车商品项、订单金额、履约状态、评分和评论内容 | 新增、编辑、逻辑删除、状态更新 | +| 配送轨迹 | 订单、配送员、配送点、日期、异常类型 | 时间线与地图;默认隐藏精确坐标 | 查看简化轨迹、申请精确回放、导出审批 | +| 财务与钱包 | 主体、周期、状态、金额区间、渠道 | 支付、结算、对账、钱包余额、流水、充值和提现 | 财务记录可维护;钱包、流水、充值和提现记录仅列表与详情查看 | +| 统计报表 | 报表类型、统计周期、组织、状态 | 报表编号、生成时间、维度明细和指标值 | 列表筛选、查看报表及明细,不提供新增、编辑、删除 | +| 审计中心 | 操作人、对象、动作、时间、结果 | 不可变日志、前后值摘要、审批关联、导出记录 | 检索、筛选、合规导出申请 | + +### 6.5 页面交互规则 + +- 列表页默认服务端分页;筛选条件可保存为个人视图,不影响他人。 +- 新建、编辑和逻辑删除使用统一表单与二次确认;页面主要完成列表查询、详情、新增、编辑、状态更新和逻辑删除。 +- 状态动作必须展示影响范围提示;安全、支付与敏感导出等高风险能力在后续迭代中再增加审批与复核流程。 +- 详情抽屉展示主字段、创建/更新时间和关联数据;复杂审批时间线不作为本阶段 CRUD 的必做能力。 +- 头像为空时显示名称首字或默认图形;头像 URL 失效时回退为默认图形,不暴露对象存储签名。 + +## 7. 关键流程与验收口径 + +### 7.1 组织准入与跨组织变更 + +1. 运营创建草稿或批量导入。 +2. 系统校验编码唯一、区域冲突、资质有效期、结算主体和未完成任务。 +3. 运营初审,平台管理员或合规员复审。 +4. 审批通过后生效;拒绝、冻结、合并和归档均保留原组织、订单、资金、安全事件和服务关系快照。 + +### 7.2 服务人员准入 + +1. 人员自主注册、组织创建或批量导入形成草稿。 +2. 审核实名、角色、证照、培训、保险、组织和服务区域。 +3. 安全相关角色由安全主管复核;到期后自动限制对应任务能力。 +4. 调配须记录来源、目标、有效期、影响任务与审批意见。 + +### 7.3 电商 CRUD 与财务、钱包、报表查询 + +1. 管理员维护 `ec_category`、`ec_product`、`ec_product_attribute` 和 `ec_product_image`,商品详情聚合展示分类、属性和图片。 +2. 购物车、订单和评论按用户、商品、状态和时间进行查询、详情查看、创建、更新和逻辑删除。 +3. 财务人员维护支付、结算、对账记录;钱包、钱包流水、充值和提现记录由业务动作生成,后台仅支持列表与详情查看。金额字段采用最小货币单位整数。 +4. 运营人员按统计周期、组织、区域和商品维度查询报表、报表明细和指标;报表数据由统计任务生成,后台不提供新增、编辑或删除。 + +### 7.4 最小验收集 + +- 可创建、审核、启停和查询可燃气体站、配送点、服务人员及平台账户。 +- 气站可在授权范围内管理所属配送点、服务人员和用户服务关系;配送点仅管理本点人员和用户关系。 +- 电商分类、商品、属性、图片、购物车、订单和评论均可完成 CRUD。 +- 财务支付、结算和对账记录可完成 CRUD;钱包、钱包流水、充值、提现、统计报表和报表明细仅支持列表与详情查看。 +- 订单详情可查询配送轨迹,轨迹和轨迹点数据均可完成 CRUD。 +- 智能瓶阀安全事件具备分级、派发、升级、处置、复核和审计闭环。 +- 所有高风险操作、资金审批、跨组织变更及敏感导出均可按操作人、对象、时间和理由追溯。 diff --git a/docs/10-技术实现规划.md b/docs/10-技术实现规划.md index 7d439cb..d3e1ab2 100644 --- a/docs/10-技术实现规划.md +++ b/docs/10-技术实现规划.md @@ -63,7 +63,7 @@ flowchart LR | 基线 | 路径 | 使用要求 | | --- | --- | --- | | 前端标准库 | `sample/front` | 五个 Vue 管理系统从该工程统一前端框架、路由、状态管理、请求封装、权限指令、表格表单、主题、错误处理、国际化与测试规范 | -| 后端标准库 | `sample/server` | Go API、Worker、IoT 进程统一沿用配置、日志、错误码、认证、数据库访问、迁移、任务、测试和发布规范 | +| 后端标准库 | `sample/server` | Go API、Worker、IoT 进程统一沿用配置、日志、错误码、认证、数据库访问、任务、测试和发布规范 | 业务项目应通过共享包、模板或上游同步机制复用标准库,禁止将标准库目录复制到每个子项目后自行漂移。标准库升级需要记录版本、影响范围、兼容策略和回滚方式。 @@ -92,7 +92,6 @@ platforms/ api/ # Go HTTP API、BFF、同步领域事务 worker/ # Go 异步任务:派单、告警、通知、对账、超时扫描 iot/ # Go MQTT 协议适配、设备命令、遥测与回执 - migrations/ # PostgreSQL 迁移、初始化数据与回滚说明 contracts/ openapi/ # HTTP API 契约及生成配置 asyncapi/ # MQTT/Redis Streams 事件契约与 Schema @@ -150,7 +149,7 @@ platforms/ - 所有主表必须包含 `identity` 字段,类型为 UUID V7,并作为该表的主键。UUID V7 由应用服务生成,保证时间有序性;禁止使用数据库自增主键、随机 UUID V4 或将业务编号作为主键。 - 引用主表时,外键字段命名为 `<实体名>_identity`,例如 `order_identity`、`service_person_identity`。业务展示编号(订单号、设备编码、站点编码等)应使用独立字段并设置唯一约束,不能替代 `identity`。 - 每个主表还应按需要包含 `created_at`、`updated_at`、`created_by_identity`、`updated_by_identity`、`status`、`version` 等审计/并发字段;资金流水、安全事件、审计日志等不可变记录不得被物理删除。 -- 数据库表、字段、索引、约束和枚举必须编写中文注释;注释说明业务含义、取值/单位、脱敏或留存要求。迁移脚本需同步维护注释,禁止只在设计文档中说明。 +- 数据库表、字段、索引、约束和枚举必须编写中文注释;注释说明业务含义、取值/单位、脱敏或留存要求。模型注释与接口契约必须同步维护,禁止只在设计文档中说明。 #### 实体名、文件名、表名、模型名一致性 @@ -163,25 +162,24 @@ platforms/ | Flutter 模型文件/类型 | `org_gas_station.dart` / `OrgGasStation` | `gas_stations.dart`、`GasStationEntity` | | Vue 模型文件/类型 | `org_gas_station.ts` / `OrgGasStation` | `gasStation.ts`、`GasStations` | | OpenAPI/AsyncAPI Schema | `org_gas_station` | `GasStationDto`、`gas_stations` | -| 迁移文件 | `<时间戳>_create_org_gas_station.sql` | `<时间戳>_create_gas_stations.sql` | - 所有实体一律使用单数:一个 `org_gas_station` 既可表示单个站点模型,也可作为列表返回项的模型名称。列表、批量和分页仅在 API 动词或响应字段表达,例如 `GET /org/gas-station/list`、`items: []`;不改变实体名。 - 关联表使用参与实体的单数词根和明确关系词,例如 `org_user_service_relation`、`idn_account_role_relation`,不得使用 `users_roles`、`user_roles` 等复数或含糊名称。 - `ord_delivery_track` 是配送任务的状态轨迹主表,`dsp_delivery_track_point` 是其定位点明细表;二者均为独立实体,不得再创建同义的 `delivery_tracks`、`track_points` 等表或模型。定位点通过 `delivery_track_identity` 关联主表。 - 钱包事实流水的唯一实体名为 `wal_wallet_ledger`;用户和服务人员的资金归属通过关联对象字段区分,禁止另建同义的 `wal_ledger`、`wallet_ledgers` 或 `service_wallet_ledger`。 -- 文件目录可以按业务模块组织,但目录名不参与实体命名;模型、迁移、契约、测试文件都必须能从其文件名唯一定位到同名的数据库表和模型。 -- 新增实体前应先登记规范名称;重命名须同时修改表、模型、文件、契约、迁移和中文注释,并进行全仓引用检查,禁止仅改其中一层。 +- 文件目录可以按业务模块组织,但目录名不参与实体命名;模型、契约、测试文件都必须能从其文件名唯一定位到同名的数据库表和模型。 +- 新增实体前应先登记规范名称;重命名须同时修改表、模型、文件、契约和中文注释,并进行全仓引用检查,禁止仅改其中一层。 ### 7.2 代码与模型中文注释规范 - Go、Flutter 和 Vue 代码中的业务类型、领域模型、枚举、公开接口、复杂规则、状态机、金额计算、权限判断和异步事件必须使用中文注释说明业务意图。 - 中文注释应解释“为什么”和业务口径,不重复代码字面含义;对外 API 的字段说明、OpenAPI/AsyncAPI Schema 描述和错误码说明同样必须为中文。 -- 模型注释应与数据库注释和接口契约保持一致。需求变更导致字段、状态或规则变化时,代码、迁移、模型和契约注释必须在同一变更中更新。 +- 模型注释应与数据库注释和接口契约保持一致。需求变更导致字段、状态或规则变化时,代码、模型和契约注释必须在同一变更中更新。 - 注释中应使用与表名/模型名一致的中文业务名称,例如“气站”对应 `org_gas_station`,不能在同一业务语境混用“站点”“气站信息”“GasStations”等不同实体名。 - 禁止以无意义拼音、英文缩写或临时注释代替业务说明;第三方库、协议标准和专有名词可保留其原文,并在首次出现处附中文解释。 - API 使用 OpenAPI;IoT/事件使用 AsyncAPI 或明确的版本化 Schema;客户端由契约生成类型。 - Redis Streams 的生产者、消费者、重试和死信处理均须有监控;任何消费者可安全重复执行,Redis 不可用时由 Outbox 补偿投递。 -- 所有管理端沿用 `sample/front` 的鉴权、数据权限、错误处理和审计埋点;所有 Go 进程沿用 `sample/server` 的配置、日志、迁移和健康检查规范。 +- 所有管理端沿用 `sample/front` 的鉴权、数据权限、错误处理和审计埋点;所有 Go 进程沿用 `sample/server` 的配置、日志和健康检查规范。 - 单元测试覆盖规则、金额、状态机、权限;集成测试覆盖支付回调、设备回执、派单和并发库存;端到端测试覆盖高风险安全闭环。 -- CI 必须执行静态检查、依赖漏洞扫描、迁移检查、契约兼容性检查和关键路径自动化测试;CD 必须先执行数据库迁移兼容性检查、健康检查和可回滚发布。 +- CI 必须执行静态检查、依赖漏洞扫描、契约兼容性检查和关键路径自动化测试;CD 必须执行健康检查和可回滚发布。 diff --git a/docs/11-数据接口与安全.md b/docs/11-数据接口与安全.md index a08f35a..2b63c27 100644 --- a/docs/11-数据接口与安全.md +++ b/docs/11-数据接口与安全.md @@ -5,7 +5,7 @@ ### 数据模型强制约定 - 主表命名使用领域模块前缀,具体前缀以 [技术实现规划](10-技术实现规划.md) 的“数据模型与命名强制规范”为准;禁止跨模块使用无前缀的通用表名。 -- 同一实体的数据库表、迁移文件、Go/Flutter/Vue 模型文件、模型类型和 OpenAPI/AsyncAPI Schema 必须使用相同的模块前缀与单数实体词根。例如 `org_gas_station`、`org_gas_station.go` 和 `OrgGasStation` 属于同一实体;禁止使用 `org_gas_stations`、`GasStations` 等复数或不同词根。 +- 同一实体的数据库表、Go/Flutter/Vue 模型文件、模型类型和 OpenAPI/AsyncAPI Schema 必须使用相同的模块前缀与单数实体词根。例如 `org_gas_station`、`org_gas_station.go` 和 `OrgGasStation` 属于同一实体;禁止使用 `org_gas_stations`、`GasStations` 等复数或不同词根。 - 每个主表必须以 `identity` 字段作为 UUID V7 主键。所有关联字段使用 `<实体名>_identity` 命名,业务编号仅作展示和检索,不作为主键或跨表关联依据。 - 表、字段、索引、约束、枚举及接口模型必须有中文注释;涉及金额、单位、状态、定位、脱敏和留存的数据须在注释中明确口径。 diff --git a/docs/12-验收与迭代规划.md b/docs/12-验收与迭代规划.md index 8e8cd9a..8b4e8c6 100644 --- a/docs/12-验收与迭代规划.md +++ b/docs/12-验收与迭代规划.md @@ -38,7 +38,7 @@ | AC-21 | 服务人员作业前置与离线补传 | 自主注册仅生成待审核账户;资质、每日培训、上班、区域和授权设备任一不满足时不能开始任务;弱网补传保留原始采集时间并去重,不能伪造轨迹或覆盖现场事实 | | AC-22 | 设备共享与紧急联系人 | 设备所有者可独立授予或撤销成员查看/控制权限;高风险告警自动关阀后仅通知已授权紧急联系人,且审计完整 | | AC-23 | 二维码与轨迹隐私 | 二维码不包含用户隐私、账号凭证或接口密钥;用户只看本人订单简化轨迹,精确轨迹回放/导出须经审批、水印和审计,非履约位置不可访问 | -| AC-24 | 钱包实体命名一致性 | 数据库迁移、表、Go/Flutter/Vue 模型和契约均使用 `wal_wallet_ledger`;不得出现 `wal_ledger`、复数表名或同义钱包流水实体 | +| AC-24 | 钱包实体命名一致性 | 数据库表、Go/Flutter/Vue 模型和契约均使用 `wal_wallet_ledger`;不得出现 `wal_ledger`、复数表名或同义钱包流水实体 | ## 3. 非功能验收 diff --git a/docs/README.md b/docs/README.md index 46f88cc..7a3f693 100644 --- a/docs/README.md +++ b/docs/README.md @@ -24,7 +24,7 @@ - “应/必须”表示上线验收项;“建议”表示增强项;“可选”表示扩展能力。 - 需求变更应先更新本目录中的对应文档,并记录版本、变更人、变更原因和影响范围。 - 两类 App 的最新需求以 [03-用户端 App 需求](03-用户端App需求.md) 与 [04-服务端 App 需求](04-服务端App需求.md) 为端侧基线。涉及邀请注册、服务关系、配送轨迹、现场取证、人员准入或离线定位的变更,必须同步审查总览、流程、后台、技术、接口与验收文档。 -- 同一数据实体的表名、模型名、文件名、迁移和接口 Schema 必须遵循 [技术实现规划](10-技术实现规划.md) 的唯一命名;命名变更须在变更记录中说明旧名、目标名和兼容/迁移方案。 +- 同一数据实体的表名、模型名、文件名和接口 Schema 必须遵循 [技术实现规划](10-技术实现规划.md) 的唯一命名;命名变更须在变更记录中说明旧名、目标名和兼容方案。 - 涉及阀门自动关闭、告警分级、支付、合同、提现、隐私信息的变更,须由产品、技术、安全/法务共同评审。 - 原附件只给出功能脑图,未明确的业务口径已在文档中标记为“待确认”或作为可配置规则提出,不应直接视为既定政策。 diff --git a/frontend/platform_admin/README.md b/frontend/platform_admin/README.md new file mode 100644 index 0000000..7bd86ab --- /dev/null +++ b/frontend/platform_admin/README.md @@ -0,0 +1,68 @@ +# Arco Design Pro Vite + +基于 [Arco Design Pro](https://arco.design/pro/) 的 Vue 3 中后台模板,使用 Vite 8 + Pinia + TypeScript 构建。 + +## 环境要求 + +- Node.js >= 20.19.0 +- pnpm + +## 常用命令 + +```bash +pnpm install # 安装依赖 +pnpm dev # 开发服务器 +pnpm build # 生产构建 +pnpm report # 构建并生成 bundle 分析报告 +pnpm type:check # TypeScript 检查 +pnpm lint # Biome 代码检查 +pnpm lint:fix # 自动修复 +``` + +## 目录结构 + +``` +src/ +├── api/ # 接口定义(按业务域) +├── assets/ # 静态资源与全局样式 +├── components/ # 全局 / 布局级组件 +├── directive/ # 自定义指令 +├── hooks/ # 组合式函数 +├── layout/ # 页面布局 +├── locale/ # i18n 入口与全局文案 +├── mocks/ # Mock 数据(开发环境) +│ ├── handlers/ # 全局 mock 处理器 +│ └── setup.ts # mock 启用与响应包装 +├── plugins/ # 应用插件(如 HTTP 拦截器) +├── router/ # 路由与守卫 +├── store/ # Pinia 状态 +├── types/ # 全局类型 +├── utils/ # 工具函数 +└── views/ # 页面(每页可含 components/、locale/、mock.ts) +config/ +└── vite.config.ts # Vite 配置 +public/ # 静态公共资源 +``` + +## Mock 说明 + +仅在开发环境(`import.meta.env.DEV`)下,`main.ts` 会动态加载 `src/mocks/index.ts`;生产构建不会打入 mockjs。 + +- 全局 handler 位于 `mocks/handlers/` +- 页面级 mock 保留在 `views/**/mock.ts`,由 `import.meta.glob` 自动注册 + +## 环境变量 + +| 变量 | 说明 | +|------|------| +| `VITE_API_BASE_URL` | 后端 API 地址(见 `.env.development`) | +| `VITE_ERROR_REPORT_URL` | 可选,配置后启用前端错误上报(`utils/error-report.ts`) | + +## i18n 说明 + +- 菜单等全局文案:`locale/zh-CN.ts`、`locale/en-US.ts` +- 页面文案:`views/**/locale/` 与 `components/**/locale/`,通过 `import.meta.glob` 自动聚合 + +## 模板标记 + +路由与部分功能块带有 `/** simple */` … `/** simple end */` 注释,表示 Arco Pro「精简版 / 完整版」的可选模块边界。 diff --git a/frontend/platform_admin/biome-report.json b/frontend/platform_admin/biome-report.json new file mode 100644 index 0000000..c1fc301 Binary files /dev/null and b/frontend/platform_admin/biome-report.json differ diff --git a/frontend/platform_admin/biome.json b/frontend/platform_admin/biome.json new file mode 100644 index 0000000..de78d06 --- /dev/null +++ b/frontend/platform_admin/biome.json @@ -0,0 +1,51 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.5.0/schema.json", + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + }, + "files": { + "ignoreUnknown": false, + "includes": [ + "src/**", + "config/**", + "*.ts", + "*.js", + "*.vue", + "components.d.ts" + ] + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 2, + "lineWidth": 80 + }, + "javascript": { + "formatter": { + "quoteStyle": "single", + "semicolons": "always", + "quoteProperties": "asNeeded" + } + }, + "linter": { + "enabled": true, + "rules": { + "preset": "recommended", + "correctness": { + "noUnusedVariables": "warn", + "useExhaustiveDependencies": "off" + }, + "style": { + "noNonNullAssertion": "off" + }, + "suspicious": { + "noExplicitAny": "off" + }, + "a11y": { + "noSvgWithoutTitle": "off" + } + } + } +} diff --git a/frontend/platform_admin/components.d.ts b/frontend/platform_admin/components.d.ts new file mode 100644 index 0000000..99c6524 --- /dev/null +++ b/frontend/platform_admin/components.d.ts @@ -0,0 +1,14 @@ +/* eslint-disable */ +// @ts-nocheck +// Generated by unplugin-vue-components +// Read more: https://github.com/vuejs/core/pull/3399 +// biome-ignore lint: disable +export {} + +/* prettier-ignore */ +declare module 'vue' { + export interface GlobalComponents { + RouterLink: typeof import('vue-router')['RouterLink'] + RouterView: typeof import('vue-router')['RouterView'] + } +} diff --git a/frontend/platform_admin/config/vite.config.ts b/frontend/platform_admin/config/vite.config.ts new file mode 100644 index 0000000..6daf4ef --- /dev/null +++ b/frontend/platform_admin/config/vite.config.ts @@ -0,0 +1,113 @@ +import { vitePluginForArco } from '@arco-plugins/vite-vue'; +import vue from '@vitejs/plugin-vue'; +import vueJsx from '@vitejs/plugin-vue-jsx'; +import { resolve } from 'path'; +import visualizer from 'rollup-plugin-visualizer'; +import { ArcoResolver } from 'unplugin-vue-components/resolvers'; +import Components from 'unplugin-vue-components/vite'; +import { defineConfig, type PluginOption } from 'vite'; +import compressPlugin from 'vite-plugin-compression'; +import { ViteImageOptimizer } from 'vite-plugin-image-optimizer'; +import svgLoader from 'vite-svg-loader'; + +const manualChunkGroups: Record = { + arco: ['@arco-design/web-vue'], + chart: ['echarts', 'vue-echarts'], + vue: ['vue', 'vue-router', 'pinia', '@vueuse/core', 'vue-i18n'], +}; + +function manualChunks(id: string) { + if (!id.includes('node_modules')) return; + for (const [chunkName, packages] of Object.entries(manualChunkGroups)) { + for (const pkg of packages) { + if (id.includes(`node_modules/${pkg}`)) { + return chunkName; + } + } + } +} + +export default defineConfig(({ command, mode }) => { + const isDev = command === 'serve'; + const isReport = mode === 'report'; + + const plugins: PluginOption[] = [ + vue(), + vueJsx(), + svgLoader({ svgoConfig: {} }), + vitePluginForArco({}), + ]; + + if (!isDev) { + plugins.push( + Components({ + dirs: [], + deep: false, + resolvers: [ArcoResolver()], + }), + compressPlugin({ ext: '.gz' }), + ViteImageOptimizer({ + png: { quality: 80 }, + jpeg: { quality: 80 }, + jpg: { quality: 80 }, + webp: { quality: 80 }, + }), + ); + + if (isReport) { + plugins.push( + visualizer({ + filename: './node_modules/.cache/visualizer/stats.html', + open: true, + gzipSize: true, + brotliSize: true, + }), + ); + } + } + + return { + plugins, + resolve: { + alias: [ + { find: '@', replacement: resolve(__dirname, '../src') }, + { find: 'assets', replacement: resolve(__dirname, '../src/assets') }, + { + find: 'vue-i18n', + replacement: 'vue-i18n/dist/vue-i18n.runtime.esm-bundler.js', + }, + { + find: 'vue', + replacement: 'vue/dist/vue.esm-bundler.js', + }, + ], + extensions: ['.ts', '.js'], + }, + css: { + preprocessorOptions: { + less: { + modifyVars: { + hack: `true; @import (reference) "${resolve( + 'src/assets/style/breakpoint.less', + )}";`, + }, + javascriptEnabled: true, + }, + }, + }, + server: isDev + ? { + open: true, + fs: { strict: true }, + } + : undefined, + build: isDev + ? undefined + : { + rollupOptions: { + output: { manualChunks }, + }, + chunkSizeWarningLimit: 2000, + }, + }; +}); diff --git a/frontend/platform_admin/index.html b/frontend/platform_admin/index.html index aa27b4f..52452ac 100644 --- a/frontend/platform_admin/index.html +++ b/frontend/platform_admin/index.html @@ -1,12 +1,13 @@ - + + - 可燃气体平台总后台 + Arco Design Pro - 开箱即用的中台前端/设计解决方案
- + diff --git a/frontend/platform_admin/package.json b/frontend/platform_admin/package.json index 9d11d72..73544c1 100644 --- a/frontend/platform_admin/package.json +++ b/frontend/platform_admin/package.json @@ -1,20 +1,58 @@ { - "name": "platform-admin", - "version": "0.1.0", + "name": "arco-design-pro-vue", + "description": "Arco Design Pro for Vue", + "version": "1.0.0", "private": true, - "type": "module", + "author": "ArcoDesign Team", + "license": "MIT", "scripts": { - "dev": "vite", - "build": "vue-tsc --noEmit && vite build", - "type:check": "vue-tsc --noEmit" + "dev": "vite --config ./config/vite.config.ts", + "build": "vue-tsc -p tsconfig.build.json --noEmit && vite build --config ./config/vite.config.ts", + "report": "vite build --config ./config/vite.config.ts --mode report", + "preview": "pnpm run build && vite preview --host", + "type:check": "vue-tsc -p tsconfig.build.json --noEmit --skipLibCheck", + "lint": "biome check .", + "lint:fix": "biome check --write .", + "format": "biome format --write ." }, "dependencies": { - "vue": "^3.5.13" + "@arco-design/web-vue": "^2.58.0", + "@vueuse/core": "^13.9.0", + "axios": "^1.8.4", + "dayjs": "^1.11.13", + "echarts": "^6.1.0", + "lodash-es": "^4.17.21", + "mitt": "^3.0.1", + "nprogress": "^0.2.0", + "pinia": "^3.0.1", + "sortablejs": "^1.15.6", + "vue": "^3.5.13", + "vue-echarts": "^8.0.1", + "vue-i18n": "^11.1.2", + "vue-router": "^4.5.0" }, "devDependencies": { + "@arco-plugins/vite-vue": "^1.4.6", + "@biomejs/biome": "^2.5.0", + "@types/lodash-es": "^4.17.12", + "@types/mockjs": "^1.0.10", + "@types/nprogress": "^0.2.3", + "@types/sortablejs": "^1.15.8", "@vitejs/plugin-vue": "^6.0.0", + "@vitejs/plugin-vue-jsx": "^5.0.0", + "less": "^4.2.2", + "mockjs": "^1.1.0", + "rollup-plugin-visualizer": "^6.0.3", + "sharp": "^0.34.1", "typescript": "^5.8.3", + "unplugin-vue-components": "^28.8.0", "vite": "^8.0.0", + "vite-plugin-compression": "^0.5.1", + "vite-plugin-image-optimizer": "^2.0.0", + "vite-svg-loader": "^5.1.0", "vue-tsc": "^2.2.8" + }, + "engines": { + "node": ">=20.19.0" } } diff --git a/frontend/platform_admin/pnpm-lock.yaml b/frontend/platform_admin/pnpm-lock.yaml index 1d9ab1e..0b1b5b4 100644 --- a/frontend/platform_admin/pnpm-lock.yaml +++ b/frontend/platform_admin/pnpm-lock.yaml @@ -8,25 +8,186 @@ importers: .: dependencies: + '@arco-design/web-vue': + specifier: ^2.58.0 + version: 2.58.0(vue@3.5.38(typescript@5.9.3)) + '@vueuse/core': + specifier: ^13.9.0 + version: 13.9.0(vue@3.5.38(typescript@5.9.3)) + axios: + specifier: ^1.8.4 + version: 1.18.0 + dayjs: + specifier: ^1.11.13 + version: 1.11.21 + echarts: + specifier: ^6.1.0 + version: 6.1.0 + lodash-es: + specifier: ^4.17.21 + version: 4.18.1 + mitt: + specifier: ^3.0.1 + version: 3.0.1 + nprogress: + specifier: ^0.2.0 + version: 0.2.0 + pinia: + specifier: ^3.0.1 + version: 3.0.4(typescript@5.9.3)(vue@3.5.38(typescript@5.9.3)) + sortablejs: + specifier: ^1.15.6 + version: 1.15.7 vue: specifier: ^3.5.13 - version: 3.5.40(typescript@5.9.3) + version: 3.5.38(typescript@5.9.3) + vue-echarts: + specifier: ^8.0.1 + version: 8.0.1(echarts@6.1.0)(vue@3.5.38(typescript@5.9.3)) + vue-i18n: + specifier: ^11.1.2 + version: 11.4.6(vue@3.5.38(typescript@5.9.3)) + vue-router: + specifier: ^4.5.0 + version: 4.6.4(vue@3.5.38(typescript@5.9.3)) devDependencies: + '@arco-plugins/vite-vue': + specifier: ^1.4.6 + version: 1.4.6 + '@biomejs/biome': + specifier: ^2.5.0 + version: 2.5.0 + '@types/lodash-es': + specifier: ^4.17.12 + version: 4.17.12 + '@types/mockjs': + specifier: ^1.0.10 + version: 1.0.10 + '@types/nprogress': + specifier: ^0.2.3 + version: 0.2.3 + '@types/sortablejs': + specifier: ^1.15.8 + version: 1.15.9 '@vitejs/plugin-vue': specifier: ^6.0.0 - version: 6.0.8(vite@8.1.5)(vue@3.5.40(typescript@5.9.3)) + version: 6.0.7(vite@8.0.16(@types/node@26.0.0)(jiti@2.6.1)(less@4.6.6)(yaml@2.9.0))(vue@3.5.38(typescript@5.9.3)) + '@vitejs/plugin-vue-jsx': + specifier: ^5.0.0 + version: 5.1.5(vite@8.0.16(@types/node@26.0.0)(jiti@2.6.1)(less@4.6.6)(yaml@2.9.0))(vue@3.5.38(typescript@5.9.3)) + less: + specifier: ^4.2.2 + version: 4.6.6 + mockjs: + specifier: ^1.1.0 + version: 1.1.0 + rollup-plugin-visualizer: + specifier: ^6.0.3 + version: 6.0.11(rolldown@1.0.3)(rollup@4.62.1) + sharp: + specifier: ^0.34.1 + version: 0.34.5 typescript: specifier: ^5.8.3 version: 5.9.3 + unplugin-vue-components: + specifier: ^28.8.0 + version: 28.8.0(@babel/parser@7.29.7)(vue@3.5.38(typescript@5.9.3)) vite: specifier: ^8.0.0 - version: 8.1.5 + version: 8.0.16(@types/node@26.0.0)(jiti@2.6.1)(less@4.6.6)(yaml@2.9.0) + vite-plugin-compression: + specifier: ^0.5.1 + version: 0.5.1(vite@8.0.16(@types/node@26.0.0)(jiti@2.6.1)(less@4.6.6)(yaml@2.9.0)) + vite-plugin-image-optimizer: + specifier: ^2.0.0 + version: 2.0.3(sharp@0.34.5)(vite@8.0.16(@types/node@26.0.0)(jiti@2.6.1)(less@4.6.6)(yaml@2.9.0)) + vite-svg-loader: + specifier: ^5.1.0 + version: 5.1.1(vue@3.5.38(typescript@5.9.3)) vue-tsc: specifier: ^2.2.8 version: 2.2.12(typescript@5.9.3) packages: + '@arco-design/color@0.4.0': + resolution: {integrity: sha512-s7p9MSwJgHeL8DwcATaXvWT3m2SigKpxx4JA1BGPHL4gfvaQsmQfrLBDpjOJFJuJ2jG2dMt3R3P8Pm9E65q18g==} + + '@arco-design/web-vue@2.58.0': + resolution: {integrity: sha512-b1vdPYOmjG5VAkVa7jlVwCb+WynBK+rnKN8zH3yKohpZObZbostRd3HgYNtjjZjGVU3OqR0Yy2FX7ftgF0bcOw==} + peerDependencies: + vue: '>=3.1.0' + + '@arco-plugins/vite-vue@1.4.6': + resolution: {integrity: sha512-i7asMOIWMKbTBo/ftJ5Kge+3X56b4dUyp1BNtYGc5IXVtCZ5mwnCVTNmfgzkKGXHRWEu01O5JXy/OMbUvzGYQQ==} + + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.7': + resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-annotate-as-pure@7.29.7': + resolution: {integrity: sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-create-class-features-plugin@7.29.7': + resolution: {integrity: sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-member-expression-to-functions@7.29.7': + resolution: {integrity: sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-optimise-call-expression@7.29.7': + resolution: {integrity: sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==} + engines: {node: '>=6.9.0'} + + '@babel/helper-plugin-utils@7.29.7': + resolution: {integrity: sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-replace-supers@7.29.7': + resolution: {integrity: sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-skip-transparent-expression-wrappers@7.29.7': + resolution: {integrity: sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==} + engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.29.7': resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} engines: {node: '>=6.9.0'} @@ -35,127 +196,403 @@ packages: resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.29.7': + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} + engines: {node: '>=6.9.0'} + '@babel/parser@7.29.7': resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} engines: {node: '>=6.0.0'} hasBin: true + '@babel/plugin-syntax-jsx@7.29.7': + resolution: {integrity: sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.29.7': + resolution: {integrity: sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-typescript@7.29.7': + resolution: {integrity: sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.7': + resolution: {integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==} + engines: {node: '>=6.9.0'} + '@babel/types@7.29.7': resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} engines: {node: '>=6.9.0'} - '@emnapi/core@1.11.1': - resolution: {integrity: sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==} + '@biomejs/biome@2.5.0': + resolution: {integrity: sha512-4kURkd9hAPrdDM3C9n82ycYgx8hvQcW6MjKTEejruj8rK0N8P3OPpdy8BvI8kt3KWY4ycF5XtDOrktetEfhfuw==} + engines: {node: '>=14.21.3'} + hasBin: true + + '@biomejs/cli-darwin-arm64@2.5.0': + resolution: {integrity: sha512-Mn3Fwi3SA5fgmfCPqmzpWF2DLZnms3BVAhM088nTnGrTZmHS3wwIjcoZPqpXeNgd3DrrLH6xp8vTLIBuJoZiXw==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [darwin] + + '@biomejs/cli-darwin-x64@2.5.0': + resolution: {integrity: sha512-rg3VPL5P8mYro6pqlXYXuJWph21slVp3SZtAqWSrkZs40d2gTzYmHF8E/X1iTID25btmNKltNDJ926sqVBp7DQ==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [darwin] + + '@biomejs/cli-linux-arm64-musl@2.5.0': + resolution: {integrity: sha512-vQdM4oSGaf7ZNeGO9w5+Y8SBtyser9M6znxYbm7Ec8wInxJu1WiKxFYZW5Auj2d80bcVvefuGGRxoFOE0eee8g==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@biomejs/cli-linux-arm64@2.5.0': + resolution: {integrity: sha512-tl+LW8fdD96/xdeWtWwc82LIOc5CoY7N2AsogLTp5R4ECErYt+8Jl/N68ezN9vzSiqPTxw6vjcihoLPYKZHrlw==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@biomejs/cli-linux-x64-musl@2.5.0': + resolution: {integrity: sha512-+9hIcMngJ+yGUahXqZuZ8CoWKJE9SAZsFsM3QDvXpNsLbXZ9lqVzgBhOk/jTSYkOA0GLP9eu3teukqpLUojHMg==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@biomejs/cli-linux-x64@2.5.0': + resolution: {integrity: sha512-zpEGf4RQbFEh8Vt7OmavLyyOzRbtcE9osCqrS1kfvt8jDvxwhKXLSf7n0ebr/ov0RJ9ssP+lhs6C8a9WwFvrQA==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@biomejs/cli-win32-arm64@2.5.0': + resolution: {integrity: sha512-jB0wAvTLI4itx5VidqVUejPQFhRUxiZ9l9FvZ26D5fl6t3qme+ZB4PD3bTSeL1vZ8NI2Rx/zj6H9zcESuGHKGw==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [win32] + + '@biomejs/cli-win32-x64@2.5.0': + resolution: {integrity: sha512-VT/lF+GId+67j8aDfLkxdxNoVApsPSTbyAtB3jJq0IWTrY77WXfbPfpngxq0bA6JCEv/7k8C9qWjDRKRznDlyw==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [win32] + + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} + + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} '@emnapi/runtime@1.11.1': resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} - '@emnapi/wasi-threads@1.2.2': - resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@intlify/core-base@11.4.6': + resolution: {integrity: sha512-EOeHO95XESK9IFHgHeZXunsM/WBAoCA0DlaWODvx14vKmetAuS97t+l6Xe9hTUqntPpF93vtVSjjUDafw3wXMw==} + engines: {node: '>= 22'} + + '@intlify/devtools-types@11.4.6': + resolution: {integrity: sha512-wowQPpNem56b2d43IJmqbrzG2FeBKe5f/kUGlpNuBmXs6OSqncF8m1+1lxHuW8ISZJF0ma2RkW3iLkw0g0G4VA==} + engines: {node: '>= 22'} + + '@intlify/message-compiler@11.4.6': + resolution: {integrity: sha512-5nj3jULqeTAC1WovwMs1LQWgatTa2pM/rXN9T3XW8rdOtXW9ZF6/GLSNFTKDQmPLwclhPdgUWLJ/4w3fMeeC/Q==} + engines: {node: '>= 22'} + + '@intlify/shared@11.4.6': + resolution: {integrity: sha512-m1p1HHAMLhqSpTRH7VnXdrN0CQ4y+9vunFkpLkbD8soIuBsnQdawZXqMCgvwI2UVF9Ww7sVaw7g9tV2VO7shoA==} + engines: {node: '>= 22'} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - '@napi-rs/wasm-runtime@1.1.6': - resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==} + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@napi-rs/wasm-runtime@1.1.5': + resolution: {integrity: sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==} peerDependencies: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 - '@oxc-project/types@0.139.0': - resolution: {integrity: sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==} + '@oxc-project/types@0.133.0': + resolution: {integrity: sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==} - '@rolldown/binding-android-arm64@1.1.5': - resolution: {integrity: sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==} + '@rolldown/binding-android-arm64@1.0.3': + resolution: {integrity: sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.1.5': - resolution: {integrity: sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==} + '@rolldown/binding-darwin-arm64@1.0.3': + resolution: {integrity: sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.1.5': - resolution: {integrity: sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==} + '@rolldown/binding-darwin-x64@1.0.3': + resolution: {integrity: sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.1.5': - resolution: {integrity: sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==} + '@rolldown/binding-freebsd-x64@1.0.3': + resolution: {integrity: sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.1.5': - resolution: {integrity: sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.3': + resolution: {integrity: sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.1.5': - resolution: {integrity: sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==} + '@rolldown/binding-linux-arm64-gnu@1.0.3': + resolution: {integrity: sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.1.5': - resolution: {integrity: sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==} + '@rolldown/binding-linux-arm64-musl@1.0.3': + resolution: {integrity: sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rolldown/binding-linux-ppc64-gnu@1.1.5': - resolution: {integrity: sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==} + '@rolldown/binding-linux-ppc64-gnu@1.0.3': + resolution: {integrity: sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.1.5': - resolution: {integrity: sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==} + '@rolldown/binding-linux-s390x-gnu@1.0.3': + resolution: {integrity: sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.1.5': - resolution: {integrity: sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==} + '@rolldown/binding-linux-x64-gnu@1.0.3': + resolution: {integrity: sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.1.5': - resolution: {integrity: sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==} + '@rolldown/binding-linux-x64-musl@1.0.3': + resolution: {integrity: sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rolldown/binding-openharmony-arm64@1.1.5': - resolution: {integrity: sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==} + '@rolldown/binding-openharmony-arm64@1.0.3': + resolution: {integrity: sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.1.5': - resolution: {integrity: sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==} + '@rolldown/binding-wasm32-wasi@1.0.3': + resolution: {integrity: sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] - '@rolldown/binding-win32-arm64-msvc@1.1.5': - resolution: {integrity: sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw==} + '@rolldown/binding-win32-arm64-msvc@1.0.3': + resolution: {integrity: sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.1.5': - resolution: {integrity: sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==} + '@rolldown/binding-win32-x64-msvc@1.0.3': + resolution: {integrity: sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -163,11 +600,183 @@ packages: '@rolldown/pluginutils@1.0.1': resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} - '@tybys/wasm-util@0.10.3': - resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} + '@rollup/rollup-android-arm-eabi@4.62.1': + resolution: {integrity: sha512-WUtumI+yIc7YXY3ZtN68V50CHEjgopo0rIZ90+ZqlZzIGroVn3qkfK7wkdl+HebaxenGQMrlB/KJs+aLMZg9lQ==} + cpu: [arm] + os: [android] - '@vitejs/plugin-vue@6.0.8': - resolution: {integrity: sha512-0ZjgOg7oO6farnNGup7yvoM/YXZV84OZxHAwtflItNa/6zzQyVb5LNxyea3FEKEX2XlagIKzrlH7wwxkKgtiew==} + '@rollup/rollup-android-arm64@4.62.1': + resolution: {integrity: sha512-ivTbxKROae184UB9SNQGOmXCwdgq1rb1OfDOXHOw9bHHVtoUSQoyLwAgxcd9zlef+vtPnyqN22HrYvaI7K12Zw==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.62.1': + resolution: {integrity: sha512-+nRm4AIocYcaE5yP07KGybXGDGfBCXOSY7EE7GeGvA8rzK+eiZteAgn9VNkn8sw/+FWR+9FLyph0gUNuY75KuQ==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.62.1': + resolution: {integrity: sha512-63zVs6JwE9i3BMhHm1Gi5+LP8dRKQVrD5UzgjDgZfptON38vfStA4iAK0DpxqTmI8udUzr1Qwk1tEhLRcj7PVA==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.62.1': + resolution: {integrity: sha512-uXASB7+/ZbR7q4RC35T/xTwQt4Qwt8e1my8E7hI6PxaQxuNiuvM+B/I58xvJLaVYOmCGy9cu3Ky1SSY4ia/G0Q==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.62.1': + resolution: {integrity: sha512-BqeibWSAOg/6bwxDnJ1Z4806jc6kIuGYCDS52DY4u23EgcK3DMrm4rrODmPTltA8EFlvhz2gXGhs/RwgWuto/w==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.62.1': + resolution: {integrity: sha512-9ryebRuEJ1OcKl9ZWWyXZ84OrpqXl8qwa99ZwrVn1uzBu9TwNqpyoScK7yF/+WoHW0dBGUR3tAHem7nWP1ismQ==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm-musleabihf@4.62.1': + resolution: {integrity: sha512-HOHv0qumBDTLxM/j5nE2X6SVHGK2F5r211WqFn0PB+lJL3o4HBP9CsjlcdwIk6aILYeRveltSVmvv9NSW3vnWg==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-arm64-gnu@4.62.1': + resolution: {integrity: sha512-jrDLxV5iWL8fdpj5N5+9ZAd2BjD3U6h1eiVhOCDQhvKG+C0uJt3phgIsS7sWKTk4LLaom87dMJCIXnakXEs4fA==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.62.1': + resolution: {integrity: sha512-kaKe83aR+a5bvGTdXFlUzGUFPHoSm2zo1PFalUuwqj7+txbLm4jyXwM4IkmrEWK9yAWE9qO654XuBb8dqgSP4A==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loong64-gnu@4.62.1': + resolution: {integrity: sha512-tp+VgVhkZ9iNDGezXQnBx0h+ZraZJCKtbrsxGRSO3Y+Ta/YrUfLxlKXU4IiBm9AWlj9EDH1Djrvsl6ledeUdJg==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-loong64-musl@4.62.1': + resolution: {integrity: sha512-LN9invzRf8ejduiGlrtr46Gk08Uh/1eiMMLgo/CNPHeRpYH8EYW6YQuAqkoxItk+Rtmod1raQ8W49sO+hP+6hQ==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-ppc64-gnu@4.62.1': + resolution: {integrity: sha512-F2Abce1ndQR8UXEX8Bj3EFd5jlw/u0rlbjmsEzBPty/YJ8H57x3POPnBxr7Mbi8m7UNwukwFW6Z20I+hrQvWdQ==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-ppc64-musl@4.62.1': + resolution: {integrity: sha512-nmJq25UletS/fI3icrKsBH8KDkTf7cSGTY5bkWI9z3+4oHj1DxHQkWCP8uP7m+AEhc1fc73AcycZam4iViAoNQ==} + cpu: [ppc64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-riscv64-gnu@4.62.1': + resolution: {integrity: sha512-HqWXZHGXFrKmSs3qOmNBfLY34CzYDt3HU2oQq2cplmU1gEADa2dWf6xcjrQuHYbNYZpJY2+rLNAbHyXtrO/0PQ==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-musl@4.62.1': + resolution: {integrity: sha512-xYDVRyJEbrzr14Z2hqe59C1pwosdl9Td0ik5gu5x85mVswTweg492as4Vzs/8zKkvvUgO5VdGRL7OzN+W9Z6+w==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-s390x-gnu@4.62.1': + resolution: {integrity: sha512-X6n4yZUYAGSZTsIRjHUFkRZy/ml+EyS5vsgnyUOfhflKros0TEjX9yAoFqiRdJSfmykStVUyfcFDy/tHJ64JuQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.62.1': + resolution: {integrity: sha512-nVQGk/jStQc2V4rrkI+vPD2J+85boKqS4R4nOdPhc3eWw0kyW/b+AYRGoH8qo057XSVqaTx13AliH5qPeLTtgQ==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.62.1': + resolution: {integrity: sha512-Ae54IyMwpY3JsYjBH4k29vQ9FSoILwJdh7j7c9lmLOczKnU/WL5jMRL9epsgPrs+ph48YVTsy6PkQDq0nK8Kvg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-openbsd-x64@4.62.1': + resolution: {integrity: sha512-7oOS0UqUXLRi2dVeEXdQxbml854xxQSx+6Pdnuo4G0iAIRiPBCIyzhLIv8oSmvqLkAftGaRk+ft70fVHXjsXsQ==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.62.1': + resolution: {integrity: sha512-e6kAhhmUK3pwICnBtsQFkg/czVxFlY5e4Ppi4fuXWvOwiHOXlgQMEvpg0H5ceuEh2T1nyI0U6SfhV3qojKWpAg==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.62.1': + resolution: {integrity: sha512-xXRJSv00uVmj5DwS9DwIvS+Re5VdDnaspDfk7GzsnhP1IbTzFjJwhY+c3j3jr/2pP/prBrXvZ1OmjjhkkAOUlQ==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.62.1': + resolution: {integrity: sha512-D3S8+6cSEW0QZZHcKKDQ/Fsz/eqvYmJbtkZZziFxEb4Fi4fyWTCaMs1p5siQ85/T6gNdYKJ3OIJ4M/phYQgICA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.62.1': + resolution: {integrity: sha512-CRVGPQKdEB/ujGfrq3SgITWc2N9iWM+sqaBKHh62Dc6xRLQGTVrqHpOVEitfly941kr244j14sswRw47bmMjjg==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.62.1': + resolution: {integrity: sha512-/N8QHE1y6A9nmN3HCIFZWr5FUu/rKcT/A7JgaMJH3dcvL5RS++o0brK5SitYVTis/dJFiasK7Xva0cqeWYmCzQ==} + cpu: [x64] + os: [win32] + + '@tybys/wasm-util@0.10.2': + resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/lodash-es@4.17.12': + resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==} + + '@types/lodash@4.17.24': + resolution: {integrity: sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==} + + '@types/mockjs@1.0.10': + resolution: {integrity: sha512-SXgrhajHG7boLv6oU93CcmdDm0HYRiceuz6b+7z+/2lCJPTWDv0V5YiwFHT2ejE4bQqgSXQiVPQYPWv7LGsK1g==} + + '@types/node@16.18.126': + resolution: {integrity: sha512-OTcgaiwfGFBKacvfwuHzzn1KLxH/er8mluiy8/uM3sGXHaRe73RrSIj01jow9t4kJEW633Ov+cOexXeiApTyAw==} + + '@types/node@26.0.0': + resolution: {integrity: sha512-vf2YFi1iY9lHGwNJMs01biZFbKJkrZR1T6/MlzjhJLPdntOHLhTrDSnSVcdtvjihi4VQNlrFRIxLsDBlQpAipA==} + + '@types/nprogress@0.2.3': + resolution: {integrity: sha512-k7kRA033QNtC+gLc4VPlfnue58CM1iQLgn1IMAU8VPHGOj7oIHPp9UlhedEnD/Gl8evoCjwkZjlBORtZ3JByUA==} + + '@types/sortablejs@1.15.9': + resolution: {integrity: sha512-7HP+rZGE2p886PKV9c9OJzLBI6BBJu1O7lJGYnPyG3fS4/duUCcngkNCjsLwIMV+WMqANe3tt4irrXHSIe68OQ==} + + '@types/web-bluetooth@0.0.21': + resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} + + '@vitejs/plugin-vue-jsx@5.1.5': + resolution: {integrity: sha512-jIAsvHOEtWpslLOI2MeElGFxH7M8pM83BU/Tor4RLyiwH0FM4nUW3xdvbw20EeU9wc5IspQwMq225K3CMnJEpA==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + vue: ^3.0.0 + + '@vitejs/plugin-vue@6.0.7': + resolution: {integrity: sha512-km+p+XdSz9Sxm5rqUbqcSfZYaAniKxWBj1KURl+Jr7UaPvvX7BmaWMdP69I5rrFDeQGyxAG7NXdc57vz+snhWg==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -182,21 +791,49 @@ packages: '@volar/typescript@2.4.15': resolution: {integrity: sha512-2aZ8i0cqPGjXb4BhkMsPYDkkuc2ZQ6yOpqwAuNwUoncELqoy5fRgOQtLR9gB0g902iS0NAkvpIzs27geVyVdPg==} - '@vue/compiler-core@3.5.40': - resolution: {integrity: sha512-39E8IgOhTbVDnoJFMKc2DvYnypcZwUqgUhQkccva/0m6FUwtIKSGV7n1hpVmYcFaoRAwf9pBcwnKlCEsN63ZEQ==} + '@vue/babel-helper-vue-transform-on@2.0.1': + resolution: {integrity: sha512-uZ66EaFbnnZSYqYEyplWvn46GhZ1KuYSThdT68p+am7MgBNbQ3hphTL9L+xSIsWkdktwhPYLwPgVWqo96jDdRA==} - '@vue/compiler-dom@3.5.40': - resolution: {integrity: sha512-pwkx4vqlqOspFstrcmzwkKLePVMD3PT65imRzLhanU2V1Fj4K13g6OXjanOyzw3aTAuRk84BOmY8f3rEHqPaVA==} + '@vue/babel-plugin-jsx@2.0.1': + resolution: {integrity: sha512-a8CaLQjD/s4PVdhrLD/zT574ZNPnZBOY+IhdtKWRB4HRZ0I2tXBi5ne7d9eCfaYwp5gU5+4KIyFTV1W1YL9xZA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + peerDependenciesMeta: + '@babel/core': + optional: true - '@vue/compiler-sfc@3.5.40': - resolution: {integrity: sha512-gIf497P4kpuALcvs5n3AEg1Vdn0pSY4XbjASIfHNYF1/MP3T2Mf2STERTubysBxCRxzJGJYtF/O7vwJrxFB3Vw==} + '@vue/babel-plugin-resolve-type@2.0.1': + resolution: {integrity: sha512-ybwgIuRGRRBhOU37GImDoWQoz+TlSqap65qVI6iwg/J7FfLTLmMf97TS7xQH9I7Qtr/gp161kYVdhr1ZMraSYQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 - '@vue/compiler-ssr@3.5.40': - resolution: {integrity: sha512-rrE5xiXG663+vHCHa3J9p2z5OcBRjXmoqenprJxAFQxg5pSshzeBiCE6pu46axapRJ2Adk0YDA2BRZVjiHXnhg==} + '@vue/compiler-core@3.5.38': + resolution: {integrity: sha512-s99aGxWYig9ErHbct27KXEGhrBYlRI6c4MwAgXErOAbX9xiW37/uMa+XUDO69zLz83dng8UUZ70CTOJrLrYrEQ==} + + '@vue/compiler-dom@3.5.38': + resolution: {integrity: sha512-JTqp25l8aFfJYF7/KmsXZjAxJz7T+SjmTJLoXVjHtc2BrSgSiW2n9Aem/cWq1OPe68A8JL06B3eVdhlP0H4TVw==} + + '@vue/compiler-sfc@3.5.38': + resolution: {integrity: sha512-DuA2GiZawSEW442iw/9+Fkol8hTgb4Ke5KkhmSry65QA7YuyMbIdy8p0XZRMvNwJdgRz307W8g1CSzdvS4nuNg==} + + '@vue/compiler-ssr@3.5.38': + resolution: {integrity: sha512-7s+W5Gc42FGxZMcuwl8H5B29T8BJPMdBT7KHFE+BbAuZ/iTEdTtv7z2XiMjiaUUw4w3ZcCEdHs36RuYJ2VA7bA==} '@vue/compiler-vue2@2.7.16': resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} + '@vue/devtools-api@6.6.4': + resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} + + '@vue/devtools-api@7.7.9': + resolution: {integrity: sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==} + + '@vue/devtools-kit@7.7.9': + resolution: {integrity: sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==} + + '@vue/devtools-shared@7.7.9': + resolution: {integrity: sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==} + '@vue/language-core@2.2.12': resolution: {integrity: sha512-IsGljWbKGU1MZpBPN+BvPAdr55YPkj2nB/TBNGNC32Vy2qLG25DYu/NBN2vNtZqdRbTRjaoYrahLrToim2NanA==} peerDependencies: @@ -205,47 +842,289 @@ packages: typescript: optional: true - '@vue/reactivity@3.5.40': - resolution: {integrity: sha512-B7ot9UlUZOi1zbq61/LvE88ZLTV8IlajTdiZTAEiDQgrnIMIZoPr9kGw0Zw46ObW62O9+H/Be3kMbfb7kYPQZA==} + '@vue/reactivity@3.5.38': + resolution: {integrity: sha512-pG6LV/NDNRbKizcUjFFLAfjaL8mcv4DmR9avNcUw2gDHBzZneuS2TWCmp633ynzxz9YYKNeEPK2I8Wraqy2HUQ==} - '@vue/runtime-core@3.5.40': - resolution: {integrity: sha512-KAZLweuZ6uUJPK1PMSQPgBU5gCjgrrfjUhSglmU9NhH+Zjepa8cnwSydPWDWHDwOgY4g3VcZ+PljbiHlURNCbw==} + '@vue/runtime-core@3.5.38': + resolution: {integrity: sha512-iyW8WVfF1CpCXxncZY5Ei6rSd6oZr5DgEom//fUjRBRl56AXPD+s9ATvukRt77ZFTuYlnVA1bxY+dJB94tWVYw==} - '@vue/runtime-dom@3.5.40': - resolution: {integrity: sha512-ZfrX8ssZQds900L9pr8AuK05ddnMsR4MPMZr8cPN9GoqoPWcXLhjvvbIA2SMv+7a97sJ1vv9pj/zxK0Cq/eEFQ==} + '@vue/runtime-dom@3.5.38': + resolution: {integrity: sha512-apX2wt9sdfDshS+a2xueFZLVpt0GkRJZSoPmrW/SA4yzXTznhfcMVW59gr7h4YQeY0vJhdJkk2rsIDwgfFgC5A==} - '@vue/server-renderer@3.5.40': - resolution: {integrity: sha512-XNJym9WpevhTVt1HuwOrCRJ5Q+9z4BjTMrDtjTrvx74SmUll8spNTw6whWJa9mEkO4PKn5TihI/bm/8ds2QVJw==} + '@vue/server-renderer@3.5.38': + resolution: {integrity: sha512-vue8vbf2QlV4quHqzwmJy6dWfmRhP1J8l4wtZg60CL6VoKqcPY2oe7may3+1d9qfpedjK5PRLFqd5k3Isj9mUw==} + peerDependencies: + vue: 3.5.38 - '@vue/shared@3.5.40': - resolution: {integrity: sha512-WxnBtruIqOoV3rA4jeKDWzrYI5h7Cp4+pjwDi8kWGHz+IslhiN+wguLVVhtv2l8VoU02rzDCVfDjgCl1lNpZVg==} + '@vue/shared@3.5.38': + resolution: {integrity: sha512-FTW0AFZNaK5/mOqvGBwVfUlNLU38TiQn4+DQgIFUnrBBJQ1crMJ82yeGQLV5jyKFsO8yRukpbuP7x+nRbH6aug==} + + '@vueuse/core@13.9.0': + resolution: {integrity: sha512-ts3regBQyURfCE2BcytLqzm8+MmLlo5Ln/KLoxDVcsZ2gzIwVNnQpQOL/UKV8alUqjSZOlpFZcRNsLRqj+OzyA==} + peerDependencies: + vue: ^3.5.0 + + '@vueuse/metadata@13.9.0': + resolution: {integrity: sha512-1AFRvuiGphfF7yWixZa0KwjYH8ulyjDCC0aFgrGRz8+P4kvDFSdXLVfTk5xAN9wEuD1J6z4/myMoYbnHoX07zg==} + + '@vueuse/shared@13.9.0': + resolution: {integrity: sha512-e89uuTLMh0U5cZ9iDpEI2senqPGfbPRTHM/0AaQkcxnpqjkZqDYP8rpfm7edOz8s+pOCOROEy1PIveSW8+fL5g==} + peerDependencies: + vue: ^3.5.0 + + acorn@8.17.0: + resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} + engines: {node: '>=0.4.0'} + hasBin: true + + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} alien-signals@1.0.13: resolution: {integrity: sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==} + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + axios@1.18.0: + resolution: {integrity: sha512-E32NzpYKp++W7XRe52rHiXV2ehxmh3wbdgO7MHeFM+vqxLBYHzt0ElkiImtOBxtOmyp0yoC8C6uESVV84Y2/hw==} + + b-tween@0.3.3: + resolution: {integrity: sha512-oEHegcRpA7fAuc9KC4nktucuZn2aS8htymCPcP3qkEGPqiBH+GfqtqoG2l7LxHngg6O0HFM7hOeOYExl1Oz4ZA==} + + b-validate@1.5.3: + resolution: {integrity: sha512-iCvCkGFskbaYtfQ0a3GmcQCHl/Sv1GufXFGuUQ+FE+WJa7A/espLOuFIn09B944V8/ImPj71T4+rTASxO2PAuA==} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - brace-expansion@2.1.2: - resolution: {integrity: sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==} + baseline-browser-mapping@2.10.38: + resolution: {integrity: sha512-31/02mVB4yuQU6adKk5SlY6m+mxDwUq5KZkyYgnLrrKl7TEm1+3PyDtDBz2kOv/wxZz41GHsvV1A/u6RmiyBvw==} + engines: {node: '>=6.0.0'} + hasBin: true + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + birpc@2.9.0: + resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==} + + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + + brace-expansion@2.1.1: + resolution: {integrity: sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.28.2: + resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + caniuse-lite@1.0.30001799: + resolution: {integrity: sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + color-string@1.9.1: + resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + + color@3.2.1: + resolution: {integrity: sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + commander@15.0.0: + resolution: {integrity: sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==} + engines: {node: '>=22.12.0'} + + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + + compute-scroll-into-view@1.0.20: + resolution: {integrity: sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + confbox@0.2.4: + resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + copy-anything@3.0.5: + resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} + engines: {node: '>=12.13'} + + copy-anything@4.0.5: + resolution: {integrity: sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==} + engines: {node: '>=18'} + + css-select@5.2.2: + resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} + + css-tree@2.2.1: + resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + + css-tree@2.3.1: + resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + + css-what@6.2.2: + resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} + engines: {node: '>= 6'} + + csso@5.0.5: + resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + dayjs@1.11.21: + resolution: {integrity: sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==} + de-indent@1.0.2: resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + define-lazy-prop@2.0.0: + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} + engines: {node: '>=8'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + echarts@6.1.0: + resolution: {integrity: sha512-q0yaFPggC9FUdsWH4blavRWFmxdrIodbkoKNAjJudAI6CA9gNPxHtV2RcZNEepZVlk4yvBYkOkbk6HIVpIyHZA==} + + electron-to-chromium@1.5.376: + resolution: {integrity: sha512-cUVA7/RvbFTEuw/i3obUwDTRIXojaxkResf+ibByPFxjc6XK3VNtcQXV0NSbAlJ0FMjcJGgftVVB4Qo184EXvA==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + entities@7.0.1: resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} engines: {node: '>=0.12'} + errno@0.1.8: + resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} + hasBin: true + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + exsolve@1.0.8: + resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -255,131 +1134,495 @@ packages: picomatch: optional: true + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + follow-redirects@1.16.0: + resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + form-data@4.0.6: + resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==} + engines: {node: '>= 6'} + + fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + he@1.2.0: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true - lightningcss-android-arm64@1.33.0: - resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} + hookable@5.5.3: + resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + image-size@0.5.5: + resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==} + engines: {node: '>=0.10.0'} + hasBin: true + + is-arrayish@0.3.4: + resolution: {integrity: sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-what@4.1.16: + resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} + engines: {node: '>=12.13'} + + is-what@5.5.0: + resolution: {integrity: sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==} + engines: {node: '>=18'} + + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonfile@6.2.1: + resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==} + + less@4.6.6: + resolution: {integrity: sha512-ooPSwQGQ2sVe8Dh1jVsbKKsRR2gd8lFK72BDkeSzjnD1T5aIHL65hCMfO0GVmtriKgDKrQv6xp9UrihUsWuAzA==} + engines: {node: '>=18'} + hasBin: true + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [android] - lightningcss-darwin-arm64@1.33.0: - resolution: {integrity: sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==} + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] - lightningcss-darwin-x64@1.33.0: - resolution: {integrity: sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==} + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] - lightningcss-freebsd-x64@1.33.0: - resolution: {integrity: sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==} + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] - lightningcss-linux-arm-gnueabihf@1.33.0: - resolution: {integrity: sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==} + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] - lightningcss-linux-arm64-gnu@1.33.0: - resolution: {integrity: sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==} + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] libc: [glibc] - lightningcss-linux-arm64-musl@1.33.0: - resolution: {integrity: sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==} + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] libc: [musl] - lightningcss-linux-x64-gnu@1.33.0: - resolution: {integrity: sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==} + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] libc: [glibc] - lightningcss-linux-x64-musl@1.33.0: - resolution: {integrity: sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==} + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] libc: [musl] - lightningcss-win32-arm64-msvc@1.33.0: - resolution: {integrity: sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==} + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] - lightningcss-win32-x64-msvc@1.33.0: - resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==} + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] - lightningcss@1.33.0: - resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} + local-pkg@1.2.1: + resolution: {integrity: sha512-++gUqRDEvcnN6Zhqrr+y/CkVEHhlrR96vZn3nZZPYzMcBUyBtTKzB9NadClFIsIVSsu+3i9tfk/erqy9kAmt7Q==} + engines: {node: '>=14'} + + lodash-es@4.18.1: + resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + make-dir@5.1.0: + resolution: {integrity: sha512-IfpFq6UM39dUNiphpA6uDezNx/AvWyhwfICWPR3t1VspkgkMZrL+Rk1RbN1bx+aeNYwOrqGJgEgV3yotk+ZUVw==} + engines: {node: '>=18'} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mdn-data@2.0.28: + resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} + + mdn-data@2.0.30: + resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + minimatch@9.0.9: resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} engines: {node: '>=16 || 14 >=14.17'} + mitt@3.0.1: + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} + + mockjs@1.1.0: + resolution: {integrity: sha512-eQsKcWzIaZzEZ07NuEyO4Nw65g0hdWAyurVol1IPl1gahRwY+svqzfgfey8U8dahLwG44d6/RwEzuK52rSa/JQ==} + hasBin: true + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + muggle-string@0.4.1: resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} - nanoid@3.3.16: - resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==} + nanoid@3.3.13: + resolution: {integrity: sha512-sPdqC6ByMVVGvF1ynvvMo0/o+oD1VX7DaHhijt1bFgjvBkHBib4t49GoNDhf2NDta4oeUNlaGbSt5K7qjZ955Q==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + needle@3.5.0: + resolution: {integrity: sha512-jaQyPKKk2YokHrEg+vFDYxXIHTCBgiZwSHOoVx/8V3GIBS8/VN6NdVRmg8q1ERtPkMvmOvebsgga4sAj5hls/w==} + engines: {node: '>= 4.4.x'} + hasBin: true + + node-releases@2.0.48: + resolution: {integrity: sha512-1uz8041X6LoI6ZSdZacM9lVY28vuzDlSKitnpbSNK0RfKoIJkX29NBPVEFXhnuSuEOA9Ww0xnPJ+ILWbGAv8DA==} + engines: {node: '>=18'} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + nprogress@0.2.0: + resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==} + + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + + number-precision@1.6.0: + resolution: {integrity: sha512-05OLPgbgmnixJw+VvEh18yNPUo3iyp4BEWJcrLu4X9W05KmMifN7Mu5exYvQXqxxeNWhvIF+j3Rij+HmddM/hQ==} + + open@8.4.2: + resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} + engines: {node: '>=12'} + + parse-node-version@1.0.1: + resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} + engines: {node: '>= 0.10'} + path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + perfect-debounce@1.0.0: + resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - picomatch@4.0.5: - resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} + engines: {node: '>=8.6'} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} - postcss@8.5.23: - resolution: {integrity: sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==} + pinia@3.0.4: + resolution: {integrity: sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==} + peerDependencies: + typescript: '>=4.5.0' + vue: ^3.5.11 + peerDependenciesMeta: + typescript: + optional: true + + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + pkg-types@2.3.1: + resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==} + + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} engines: {node: ^10 || ^12 || >=14} - rolldown@1.1.5: - resolution: {integrity: sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==} + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} + + prr@1.0.1: + resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} + + quansync@0.2.11: + resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + resize-observer-polyfill@1.5.1: + resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==} + + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + + rolldown@1.0.3: + resolution: {integrity: sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true + rollup-plugin-visualizer@6.0.11: + resolution: {integrity: sha512-TBwVHVY7buHjIKVLqr9scTVFwqZqMXINcCphPwIWKPDCOBIa+jCQfafvbjRJDZgXdq/A996Dy6yGJ/+/NtAXDQ==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + rolldown: 1.x || ^1.0.0-beta + rollup: 2.x || 3.x || 4.x + peerDependenciesMeta: + rolldown: + optional: true + rollup: + optional: true + + rollup@4.62.1: + resolution: {integrity: sha512-XTvxjHHM/0J/WZBg+ehDbAZgIpZoIZtWO+aImyuhjoyQa56NBX/bqnXw32rT27fkjSRrqthOgkLjRVtwXFI7jQ==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + sax@1.6.0: + resolution: {integrity: sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==} + engines: {node: '>=11.0.0'} + + scroll-into-view-if-needed@2.2.31: + resolution: {integrity: sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.8.4: + resolution: {integrity: sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==} + engines: {node: '>=10'} + hasBin: true + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + simple-swizzle@0.2.4: + resolution: {integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==} + + sortablejs@1.15.7: + resolution: {integrity: sha512-Kk8wLQPlS+yi1ZEf48a4+fzHa4yxjC30M/Sr2AnQu+f/MPwvvX9XjZ6OWejiz8crBsLwSq8GHqaxaET7u6ux0A==} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + + speakingurl@14.0.1: + resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} + engines: {node: '>=0.10.0'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + superjson@2.2.6: + resolution: {integrity: sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==} + engines: {node: '>=16'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + svgo@3.3.3: + resolution: {integrity: sha512-+wn7I4p7YgJhHs38k2TNjy1vCfPIfLIJWR5MnCStsN8WuuTcBnRKcMHQLMM2ijxGZmDoZwNv8ipl5aTTen62ng==} + engines: {node: '>=14.0.0'} + hasBin: true + tinyglobby@0.2.17: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + tslib@2.3.0: + resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==} + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -388,13 +1631,73 @@ packages: engines: {node: '>=14.17'} hasBin: true - vite@8.1.5: - resolution: {integrity: sha512-7ULLwsCdYx/nRyrpiEwvqb5TFHrMVZyBt+rg/OAXT7rgj/z+DtTDyKFeLAdDkubDVDKD8jOsndmy7m55XcfUsw==} + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} + + undici-types@8.3.0: + resolution: {integrity: sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + unplugin-utils@0.2.5: + resolution: {integrity: sha512-gwXJnPRewT4rT7sBi/IvxKTjsms7jX7QIDLOClApuZwR49SXbrB1z2NLUZ+vDHyqCj/n58OzRRqaW+B8OZi8vg==} + engines: {node: '>=18.12.0'} + + unplugin-vue-components@28.8.0: + resolution: {integrity: sha512-2Q6ZongpoQzuXDK0ZsVzMoshH0MWZQ1pzVL538G7oIDKRTVzHjppBDS8aB99SADGHN3lpGU7frraCG6yWNoL5Q==} + engines: {node: '>=14'} + peerDependencies: + '@babel/parser': ^7.15.8 + '@nuxt/kit': ^3.2.2 || ^4.0.0 + vue: 2 || 3 + peerDependenciesMeta: + '@babel/parser': + optional: true + '@nuxt/kit': + optional: true + + unplugin@2.3.11: + resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} + engines: {node: '>=18.12.0'} + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + vite-plugin-compression@0.5.1: + resolution: {integrity: sha512-5QJKBDc+gNYVqL/skgFAP81Yuzo9R+EAf19d+EtsMF/i8kFUpNi3J/H01QD3Oo8zBQn+NzoCIFkpPLynoOzaJg==} + peerDependencies: + vite: '>=2.0.0' + + vite-plugin-image-optimizer@2.0.3: + resolution: {integrity: sha512-1vrFOTcpSvv6DCY7h8UXab4wqMAjTJB/ndOzG/Kmj1oDOuPF6mbjkNQoGzzCEYeWGe7qU93jc8oQqvoJ57al3A==} + engines: {node: '>=18.17.0'} + peerDependencies: + sharp: '>=0.34.0' + svgo: '>=4' + vite: '>=5' + peerDependenciesMeta: + sharp: + optional: true + svgo: + optional: true + + vite-svg-loader@5.1.1: + resolution: {integrity: sha512-RPzcXA/EpKJA0585x58DBgs7my2VfeJ+j2j1EoHY4Zh82Y7hV4cR1fElgy2aZi85+QSrcLLoTStQ5uZjD68u+Q==} + peerDependencies: + vue: '>=3.2.13' + + vite@8.0.16: + resolution: {integrity: sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: '@types/node': ^20.19.0 || >=22.12.0 - '@vitejs/devtools': ^0.3.0 + '@vitejs/devtools': ^0.1.18 esbuild: ^0.27.0 || ^0.28.0 jiti: '>=1.21.0' less: ^4.0.0 @@ -434,38 +1737,306 @@ packages: vscode-uri@3.1.0: resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + vue-echarts@8.0.1: + resolution: {integrity: sha512-23rJTFLu1OUEGRWjJGmdGt8fP+8+ja1gVgzMYPIPaHWpXegcO1viIAaeu2H4QHESlVeHzUAHIxKXGrwjsyXAaA==} + peerDependencies: + echarts: ^6.0.0 + vue: ^3.3.0 + + vue-i18n@11.4.6: + resolution: {integrity: sha512-l0gE7Rfy0phCa5ChKYkOq543Wgd39BCK6hkktfr1Ed4D99oRkgPK9ffShASZdeC8OJxGfdWmpYoAaAH6iLEuIg==} + engines: {node: '>= 22'} + peerDependencies: + vue: ^3.0.0 + + vue-router@4.6.4: + resolution: {integrity: sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==} + peerDependencies: + vue: ^3.5.0 + vue-tsc@2.2.12: resolution: {integrity: sha512-P7OP77b2h/Pmk+lZdJ0YWs+5tJ6J2+uOQPo7tlBnY44QqQSPYvS0qVT4wqDJgwrZaLe47etJLLQRFia71GYITw==} hasBin: true peerDependencies: typescript: '>=5.0.0' - vue@3.5.40: - resolution: {integrity: sha512-+8PJ4SJXdn/cHGImF4CKdxlWHIN5Dkt7DoufRREM6h6uVCx2m7QxgcEQmmzyOK8A9mcafg7sFbJFYsdFVubTig==} + vue@3.5.38: + resolution: {integrity: sha512-vAMKHfImQlYSy0C+PBue4s3ERZ2xGKfgZg5GXAsLInq1dyh2H78ILVP5sK0KPFPVW4kv+OGCIvBEondcjpZp7A==} peerDependencies: typescript: '*' peerDependenciesMeta: typescript: optional: true + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yaml@2.9.0: + resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} + engines: {node: '>= 14.6'} + hasBin: true + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.3: + resolution: {integrity: sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==} + engines: {node: '>=12'} + + zrender@6.1.0: + resolution: {integrity: sha512-oEGMDB6pOP2S6OwRR4PdVv610zrjnA3Bh+JnSG12fYJlBKjtNAoEb5fSUoCOOINlH96I2fU38/A2UpRKs67xYQ==} + snapshots: + '@arco-design/color@0.4.0': + dependencies: + color: 3.2.1 + + '@arco-design/web-vue@2.58.0(vue@3.5.38(typescript@5.9.3))': + dependencies: + '@arco-design/color': 0.4.0 + b-tween: 0.3.3 + b-validate: 1.5.3 + compute-scroll-into-view: 1.0.20 + dayjs: 1.11.21 + number-precision: 1.6.0 + resize-observer-polyfill: 1.5.1 + scroll-into-view-if-needed: 2.2.31 + vue: 3.5.38(typescript@5.9.3) + + '@arco-plugins/vite-vue@1.4.6': + dependencies: + '@babel/generator': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + '@types/node': 16.18.126 + transitivePeerDependencies: + - supports-color + + '@babel/code-frame@7.29.7': + dependencies: + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.7': {} + + '@babel/core@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helpers': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.7': + dependencies: + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-annotate-as-pure@7.29.7': + dependencies: + '@babel/types': 7.29.7 + + '@babel/helper-compilation-targets@7.29.7': + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + browserslist: 4.28.2 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-create-class-features-plugin@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-member-expression-to-functions': 7.29.7 + '@babel/helper-optimise-call-expression': 7.29.7 + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + '@babel/traverse': 7.29.7 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/helper-globals@7.29.7': {} + + '@babel/helper-member-expression-to-functions@7.29.7': + dependencies: + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-imports@7.29.7': + dependencies: + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-optimise-call-expression@7.29.7': + dependencies: + '@babel/types': 7.29.7 + + '@babel/helper-plugin-utils@7.29.7': {} + + '@babel/helper-replace-supers@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-member-expression-to-functions': 7.29.7 + '@babel/helper-optimise-call-expression': 7.29.7 + '@babel/traverse': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-skip-transparent-expression-wrappers@7.29.7': + dependencies: + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + '@babel/helper-string-parser@7.29.7': {} '@babel/helper-validator-identifier@7.29.7': {} + '@babel/helper-validator-option@7.29.7': {} + + '@babel/helpers@7.29.7': + dependencies: + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 + '@babel/parser@7.29.7': dependencies: '@babel/types': 7.29.7 + '@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-typescript@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7) + transitivePeerDependencies: + - supports-color + + '@babel/template@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + + '@babel/traverse@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + '@babel/types@7.29.7': dependencies: '@babel/helper-string-parser': 7.29.7 '@babel/helper-validator-identifier': 7.29.7 - '@emnapi/core@1.11.1': + '@biomejs/biome@2.5.0': + optionalDependencies: + '@biomejs/cli-darwin-arm64': 2.5.0 + '@biomejs/cli-darwin-x64': 2.5.0 + '@biomejs/cli-linux-arm64': 2.5.0 + '@biomejs/cli-linux-arm64-musl': 2.5.0 + '@biomejs/cli-linux-x64': 2.5.0 + '@biomejs/cli-linux-x64-musl': 2.5.0 + '@biomejs/cli-win32-arm64': 2.5.0 + '@biomejs/cli-win32-x64': 2.5.0 + + '@biomejs/cli-darwin-arm64@2.5.0': + optional: true + + '@biomejs/cli-darwin-x64@2.5.0': + optional: true + + '@biomejs/cli-linux-arm64-musl@2.5.0': + optional: true + + '@biomejs/cli-linux-arm64@2.5.0': + optional: true + + '@biomejs/cli-linux-x64-musl@2.5.0': + optional: true + + '@biomejs/cli-linux-x64@2.5.0': + optional: true + + '@biomejs/cli-win32-arm64@2.5.0': + optional: true + + '@biomejs/cli-win32-x64@2.5.0': + optional: true + + '@emnapi/core@1.10.0': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.10.0': dependencies: - '@emnapi/wasi-threads': 1.2.2 tslib: 2.8.1 optional: true @@ -474,83 +2045,325 @@ snapshots: tslib: 2.8.1 optional: true - '@emnapi/wasi-threads@1.2.2': + '@emnapi/wasi-threads@1.2.1': dependencies: tslib: 2.8.1 optional: true + '@img/colour@1.1.0': {} + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.11.1 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@intlify/core-base@11.4.6': + dependencies: + '@intlify/devtools-types': 11.4.6 + '@intlify/message-compiler': 11.4.6 + '@intlify/shared': 11.4.6 + + '@intlify/devtools-types@11.4.6': + dependencies: + '@intlify/core-base': 11.4.6 + '@intlify/shared': 11.4.6 + + '@intlify/message-compiler@11.4.6': + dependencies: + '@intlify/shared': 11.4.6 + source-map-js: 1.2.1 + + '@intlify/shared@11.4.6': {} + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + '@jridgewell/sourcemap-codec@1.5.5': {} - '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': + '@jridgewell/trace-mapping@0.3.31': dependencies: - '@emnapi/core': 1.11.1 - '@emnapi/runtime': 1.11.1 - '@tybys/wasm-util': 0.10.3 - optional: true + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 - '@oxc-project/types@0.139.0': {} - - '@rolldown/binding-android-arm64@1.1.5': - optional: true - - '@rolldown/binding-darwin-arm64@1.1.5': - optional: true - - '@rolldown/binding-darwin-x64@1.1.5': - optional: true - - '@rolldown/binding-freebsd-x64@1.1.5': - optional: true - - '@rolldown/binding-linux-arm-gnueabihf@1.1.5': - optional: true - - '@rolldown/binding-linux-arm64-gnu@1.1.5': - optional: true - - '@rolldown/binding-linux-arm64-musl@1.1.5': - optional: true - - '@rolldown/binding-linux-ppc64-gnu@1.1.5': - optional: true - - '@rolldown/binding-linux-s390x-gnu@1.1.5': - optional: true - - '@rolldown/binding-linux-x64-gnu@1.1.5': - optional: true - - '@rolldown/binding-linux-x64-musl@1.1.5': - optional: true - - '@rolldown/binding-openharmony-arm64@1.1.5': - optional: true - - '@rolldown/binding-wasm32-wasi@1.1.5': + '@napi-rs/wasm-runtime@1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: - '@emnapi/core': 1.11.1 - '@emnapi/runtime': 1.11.1 - '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@tybys/wasm-util': 0.10.2 optional: true - '@rolldown/binding-win32-arm64-msvc@1.1.5': + '@oxc-project/types@0.133.0': {} + + '@rolldown/binding-android-arm64@1.0.3': optional: true - '@rolldown/binding-win32-x64-msvc@1.1.5': + '@rolldown/binding-darwin-arm64@1.0.3': + optional: true + + '@rolldown/binding-darwin-x64@1.0.3': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.3': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.3': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.3': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.3': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.3': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.3': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.3': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.3': optional: true '@rolldown/pluginutils@1.0.1': {} - '@tybys/wasm-util@0.10.3': + '@rollup/rollup-android-arm-eabi@4.62.1': + optional: true + + '@rollup/rollup-android-arm64@4.62.1': + optional: true + + '@rollup/rollup-darwin-arm64@4.62.1': + optional: true + + '@rollup/rollup-darwin-x64@4.62.1': + optional: true + + '@rollup/rollup-freebsd-arm64@4.62.1': + optional: true + + '@rollup/rollup-freebsd-x64@4.62.1': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.62.1': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.62.1': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.62.1': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.62.1': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.62.1': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.62.1': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.62.1': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.62.1': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.62.1': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.62.1': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.62.1': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.62.1': + optional: true + + '@rollup/rollup-linux-x64-musl@4.62.1': + optional: true + + '@rollup/rollup-openbsd-x64@4.62.1': + optional: true + + '@rollup/rollup-openharmony-arm64@4.62.1': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.62.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.62.1': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.62.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.62.1': + optional: true + + '@tybys/wasm-util@0.10.2': dependencies: tslib: 2.8.1 optional: true - '@vitejs/plugin-vue@6.0.8(vite@8.1.5)(vue@3.5.40(typescript@5.9.3))': + '@types/estree@1.0.9': + optional: true + + '@types/lodash-es@4.17.12': + dependencies: + '@types/lodash': 4.17.24 + + '@types/lodash@4.17.24': {} + + '@types/mockjs@1.0.10': {} + + '@types/node@16.18.126': {} + + '@types/node@26.0.0': + dependencies: + undici-types: 8.3.0 + optional: true + + '@types/nprogress@0.2.3': {} + + '@types/sortablejs@1.15.9': {} + + '@types/web-bluetooth@0.0.21': {} + + '@vitejs/plugin-vue-jsx@5.1.5(vite@8.0.16(@types/node@26.0.0)(jiti@2.6.1)(less@4.6.6)(yaml@2.9.0))(vue@3.5.38(typescript@5.9.3))': + dependencies: + '@babel/core': 7.29.7 + '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7) + '@rolldown/pluginutils': 1.0.1 + '@vue/babel-plugin-jsx': 2.0.1(@babel/core@7.29.7) + vite: 8.0.16(@types/node@26.0.0)(jiti@2.6.1)(less@4.6.6)(yaml@2.9.0) + vue: 3.5.38(typescript@5.9.3) + transitivePeerDependencies: + - supports-color + + '@vitejs/plugin-vue@6.0.7(vite@8.0.16(@types/node@26.0.0)(jiti@2.6.1)(less@4.6.6)(yaml@2.9.0))(vue@3.5.38(typescript@5.9.3))': dependencies: '@rolldown/pluginutils': 1.0.1 - vite: 8.1.5 - vue: 3.5.40(typescript@5.9.3) + vite: 8.0.16(@types/node@26.0.0)(jiti@2.6.1)(less@4.6.6)(yaml@2.9.0) + vue: 3.5.38(typescript@5.9.3) '@volar/language-core@2.4.15': dependencies: @@ -564,47 +2377,96 @@ snapshots: path-browserify: 1.0.1 vscode-uri: 3.1.0 - '@vue/compiler-core@3.5.40': + '@vue/babel-helper-vue-transform-on@2.0.1': {} + + '@vue/babel-plugin-jsx@2.0.1(@babel/core@7.29.7)': + dependencies: + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7) + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + '@vue/babel-helper-vue-transform-on': 2.0.1 + '@vue/babel-plugin-resolve-type': 2.0.1(@babel/core@7.29.7) + '@vue/shared': 3.5.38 + optionalDependencies: + '@babel/core': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@vue/babel-plugin-resolve-type@2.0.1(@babel/core@7.29.7)': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/parser': 7.29.7 + '@vue/compiler-sfc': 3.5.38 + transitivePeerDependencies: + - supports-color + + '@vue/compiler-core@3.5.38': dependencies: '@babel/parser': 7.29.7 - '@vue/shared': 3.5.40 + '@vue/shared': 3.5.38 entities: 7.0.1 estree-walker: 2.0.2 source-map-js: 1.2.1 - '@vue/compiler-dom@3.5.40': + '@vue/compiler-dom@3.5.38': dependencies: - '@vue/compiler-core': 3.5.40 - '@vue/shared': 3.5.40 + '@vue/compiler-core': 3.5.38 + '@vue/shared': 3.5.38 - '@vue/compiler-sfc@3.5.40': + '@vue/compiler-sfc@3.5.38': dependencies: '@babel/parser': 7.29.7 - '@vue/compiler-core': 3.5.40 - '@vue/compiler-dom': 3.5.40 - '@vue/compiler-ssr': 3.5.40 - '@vue/shared': 3.5.40 + '@vue/compiler-core': 3.5.38 + '@vue/compiler-dom': 3.5.38 + '@vue/compiler-ssr': 3.5.38 + '@vue/shared': 3.5.38 estree-walker: 2.0.2 magic-string: 0.30.21 - postcss: 8.5.23 + postcss: 8.5.15 source-map-js: 1.2.1 - '@vue/compiler-ssr@3.5.40': + '@vue/compiler-ssr@3.5.38': dependencies: - '@vue/compiler-dom': 3.5.40 - '@vue/shared': 3.5.40 + '@vue/compiler-dom': 3.5.38 + '@vue/shared': 3.5.38 '@vue/compiler-vue2@2.7.16': dependencies: de-indent: 1.0.2 he: 1.2.0 + '@vue/devtools-api@6.6.4': {} + + '@vue/devtools-api@7.7.9': + dependencies: + '@vue/devtools-kit': 7.7.9 + + '@vue/devtools-kit@7.7.9': + dependencies: + '@vue/devtools-shared': 7.7.9 + birpc: 2.9.0 + hookable: 5.5.3 + mitt: 3.0.1 + perfect-debounce: 1.0.0 + speakingurl: 14.0.1 + superjson: 2.2.6 + + '@vue/devtools-shared@7.7.9': + dependencies: + rfdc: 1.4.1 + '@vue/language-core@2.2.12(typescript@5.9.3)': dependencies: '@volar/language-core': 2.4.15 - '@vue/compiler-dom': 3.5.40 + '@vue/compiler-dom': 3.5.38 '@vue/compiler-vue2': 2.7.16 - '@vue/shared': 3.5.40 + '@vue/shared': 3.5.38 alien-signals: 1.0.13 minimatch: 9.0.9 muggle-string: 0.4.1 @@ -612,187 +2474,926 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@vue/reactivity@3.5.40': + '@vue/reactivity@3.5.38': dependencies: - '@vue/shared': 3.5.40 + '@vue/shared': 3.5.38 - '@vue/runtime-core@3.5.40': + '@vue/runtime-core@3.5.38': dependencies: - '@vue/reactivity': 3.5.40 - '@vue/shared': 3.5.40 + '@vue/reactivity': 3.5.38 + '@vue/shared': 3.5.38 - '@vue/runtime-dom@3.5.40': + '@vue/runtime-dom@3.5.38': dependencies: - '@vue/reactivity': 3.5.40 - '@vue/runtime-core': 3.5.40 - '@vue/shared': 3.5.40 + '@vue/reactivity': 3.5.38 + '@vue/runtime-core': 3.5.38 + '@vue/shared': 3.5.38 csstype: 3.2.3 - '@vue/server-renderer@3.5.40': + '@vue/server-renderer@3.5.38(vue@3.5.38(typescript@5.9.3))': dependencies: - '@vue/compiler-ssr': 3.5.40 - '@vue/runtime-dom': 3.5.40 - '@vue/shared': 3.5.40 + '@vue/compiler-ssr': 3.5.38 + '@vue/shared': 3.5.38 + vue: 3.5.38(typescript@5.9.3) - '@vue/shared@3.5.40': {} + '@vue/shared@3.5.38': {} + + '@vueuse/core@13.9.0(vue@3.5.38(typescript@5.9.3))': + dependencies: + '@types/web-bluetooth': 0.0.21 + '@vueuse/metadata': 13.9.0 + '@vueuse/shared': 13.9.0(vue@3.5.38(typescript@5.9.3)) + vue: 3.5.38(typescript@5.9.3) + + '@vueuse/metadata@13.9.0': {} + + '@vueuse/shared@13.9.0(vue@3.5.38(typescript@5.9.3))': + dependencies: + vue: 3.5.38(typescript@5.9.3) + + acorn@8.17.0: {} + + agent-base@6.0.2: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color alien-signals@1.0.13: {} + ansi-colors@4.1.3: {} + + ansi-regex@5.0.1: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.2 + + asynckit@0.4.0: {} + + axios@1.18.0: + dependencies: + follow-redirects: 1.16.0 + form-data: 4.0.6 + https-proxy-agent: 5.0.1 + proxy-from-env: 2.1.0 + transitivePeerDependencies: + - debug + - supports-color + + b-tween@0.3.3: {} + + b-validate@1.5.3: {} + balanced-match@1.0.2: {} - brace-expansion@2.1.2: + baseline-browser-mapping@2.10.38: {} + + binary-extensions@2.3.0: {} + + birpc@2.9.0: {} + + boolbase@1.0.0: {} + + brace-expansion@2.1.1: dependencies: balanced-match: 1.0.2 + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.28.2: + dependencies: + baseline-browser-mapping: 2.10.38 + caniuse-lite: 1.0.30001799 + electron-to-chromium: 1.5.376 + node-releases: 2.0.48 + update-browserslist-db: 1.2.3(browserslist@4.28.2) + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + caniuse-lite@1.0.30001799: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.3: {} + + color-name@1.1.4: {} + + color-string@1.9.1: + dependencies: + color-name: 1.1.4 + simple-swizzle: 0.2.4 + + color@3.2.1: + dependencies: + color-convert: 1.9.3 + color-string: 1.9.1 + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + commander@15.0.0: {} + + commander@7.2.0: {} + + compute-scroll-into-view@1.0.20: {} + + confbox@0.1.8: {} + + confbox@0.2.4: {} + + convert-source-map@2.0.0: {} + + copy-anything@3.0.5: + dependencies: + is-what: 4.1.16 + + copy-anything@4.0.5: + dependencies: + is-what: 5.5.0 + + css-select@5.2.2: + dependencies: + boolbase: 1.0.0 + css-what: 6.2.2 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + + css-tree@2.2.1: + dependencies: + mdn-data: 2.0.28 + source-map-js: 1.2.1 + + css-tree@2.3.1: + dependencies: + mdn-data: 2.0.30 + source-map-js: 1.2.1 + + css-what@6.2.2: {} + + csso@5.0.5: + dependencies: + css-tree: 2.2.1 + csstype@3.2.3: {} + dayjs@1.11.21: {} + de-indent@1.0.2: {} + debug@4.4.3: + dependencies: + ms: 2.1.3 + + define-lazy-prop@2.0.0: {} + + delayed-stream@1.0.0: {} + detect-libc@2.1.2: {} + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + domelementtype@2.3.0: {} + + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + echarts@6.1.0: + dependencies: + tslib: 2.3.0 + zrender: 6.1.0 + + electron-to-chromium@1.5.376: {} + + emoji-regex@8.0.0: {} + + entities@4.5.0: {} + entities@7.0.1: {} + errno@0.1.8: + dependencies: + prr: 1.0.1 + optional: true + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.2: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.4 + + escalade@3.2.0: {} + estree-walker@2.0.2: {} - fdir@6.5.0(picomatch@4.0.5): + exsolve@1.0.8: {} + + fdir@6.5.0(picomatch@4.0.4): optionalDependencies: - picomatch: 4.0.5 + picomatch: 4.0.4 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + follow-redirects@1.16.0: {} + + form-data@4.0.6: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.4 + mime-types: 2.1.35 + + fs-extra@10.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.1 + universalify: 2.0.1 fsevents@2.3.3: optional: true + function-bind@1.1.2: {} + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.2 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + has-flag@4.0.0: {} + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + he@1.2.0: {} - lightningcss-android-arm64@1.33.0: + hookable@5.5.3: {} + + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 optional: true - lightningcss-darwin-arm64@1.33.0: + image-size@0.5.5: optional: true - lightningcss-darwin-x64@1.33.0: + is-arrayish@0.3.4: {} + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-docker@2.2.1: {} + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + is-what@4.1.16: {} + + is-what@5.5.0: {} + + is-wsl@2.2.0: + dependencies: + is-docker: 2.2.1 + + jiti@2.6.1: optional: true - lightningcss-freebsd-x64@1.33.0: + js-tokens@4.0.0: {} + + jsesc@3.1.0: {} + + json5@2.2.3: {} + + jsonfile@6.2.1: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + less@4.6.6: + dependencies: + copy-anything: 3.0.5 + parse-node-version: 1.0.1 + optionalDependencies: + errno: 0.1.8 + graceful-fs: 4.2.11 + image-size: 0.5.5 + make-dir: 5.1.0 + mime: 1.6.0 + needle: 3.5.0 + source-map: 0.6.1 + + lightningcss-android-arm64@1.32.0: optional: true - lightningcss-linux-arm-gnueabihf@1.33.0: + lightningcss-darwin-arm64@1.32.0: optional: true - lightningcss-linux-arm64-gnu@1.33.0: + lightningcss-darwin-x64@1.32.0: optional: true - lightningcss-linux-arm64-musl@1.33.0: + lightningcss-freebsd-x64@1.32.0: optional: true - lightningcss-linux-x64-gnu@1.33.0: + lightningcss-linux-arm-gnueabihf@1.32.0: optional: true - lightningcss-linux-x64-musl@1.33.0: + lightningcss-linux-arm64-gnu@1.32.0: optional: true - lightningcss-win32-arm64-msvc@1.33.0: + lightningcss-linux-arm64-musl@1.32.0: optional: true - lightningcss-win32-x64-msvc@1.33.0: + lightningcss-linux-x64-gnu@1.32.0: optional: true - lightningcss@1.33.0: + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: dependencies: detect-libc: 2.1.2 optionalDependencies: - lightningcss-android-arm64: 1.33.0 - lightningcss-darwin-arm64: 1.33.0 - lightningcss-darwin-x64: 1.33.0 - lightningcss-freebsd-x64: 1.33.0 - lightningcss-linux-arm-gnueabihf: 1.33.0 - lightningcss-linux-arm64-gnu: 1.33.0 - lightningcss-linux-arm64-musl: 1.33.0 - lightningcss-linux-x64-gnu: 1.33.0 - lightningcss-linux-x64-musl: 1.33.0 - lightningcss-win32-arm64-msvc: 1.33.0 - lightningcss-win32-x64-msvc: 1.33.0 + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + local-pkg@1.2.1: + dependencies: + mlly: 1.8.2 + pkg-types: 2.3.1 + quansync: 0.2.11 + + lodash-es@4.18.1: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + make-dir@5.1.0: + optional: true + + math-intrinsics@1.1.0: {} + + mdn-data@2.0.28: {} + + mdn-data@2.0.30: {} + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime@1.6.0: + optional: true + minimatch@9.0.9: dependencies: - brace-expansion: 2.1.2 + brace-expansion: 2.1.1 + + mitt@3.0.1: {} + + mlly@1.8.2: + dependencies: + acorn: 8.17.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.4 + + mockjs@1.1.0: + dependencies: + commander: 15.0.0 + + ms@2.1.3: {} muggle-string@0.4.1: {} - nanoid@3.3.16: {} + nanoid@3.3.13: {} + + needle@3.5.0: + dependencies: + iconv-lite: 0.6.3 + sax: 1.6.0 + optional: true + + node-releases@2.0.48: {} + + normalize-path@3.0.0: {} + + nprogress@0.2.0: {} + + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + + number-precision@1.6.0: {} + + open@8.4.2: + dependencies: + define-lazy-prop: 2.0.0 + is-docker: 2.2.1 + is-wsl: 2.2.0 + + parse-node-version@1.0.1: {} path-browserify@1.0.1: {} + pathe@2.0.3: {} + + perfect-debounce@1.0.0: {} + picocolors@1.1.1: {} - picomatch@4.0.5: {} + picomatch@2.3.2: {} - postcss@8.5.23: + picomatch@4.0.4: {} + + pinia@3.0.4(typescript@5.9.3)(vue@3.5.38(typescript@5.9.3)): dependencies: - nanoid: 3.3.16 + '@vue/devtools-api': 7.7.9 + vue: 3.5.38(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.2 + pathe: 2.0.3 + + pkg-types@2.3.1: + dependencies: + confbox: 0.2.4 + exsolve: 1.0.8 + pathe: 2.0.3 + + postcss@8.5.15: + dependencies: + nanoid: 3.3.13 picocolors: 1.1.1 source-map-js: 1.2.1 - rolldown@1.1.5: + proxy-from-env@2.1.0: {} + + prr@1.0.1: + optional: true + + quansync@0.2.11: {} + + readdirp@3.6.0: dependencies: - '@oxc-project/types': 0.139.0 + picomatch: 2.3.2 + + require-directory@2.1.1: {} + + resize-observer-polyfill@1.5.1: {} + + rfdc@1.4.1: {} + + rolldown@1.0.3: + dependencies: + '@oxc-project/types': 0.133.0 '@rolldown/pluginutils': 1.0.1 optionalDependencies: - '@rolldown/binding-android-arm64': 1.1.5 - '@rolldown/binding-darwin-arm64': 1.1.5 - '@rolldown/binding-darwin-x64': 1.1.5 - '@rolldown/binding-freebsd-x64': 1.1.5 - '@rolldown/binding-linux-arm-gnueabihf': 1.1.5 - '@rolldown/binding-linux-arm64-gnu': 1.1.5 - '@rolldown/binding-linux-arm64-musl': 1.1.5 - '@rolldown/binding-linux-ppc64-gnu': 1.1.5 - '@rolldown/binding-linux-s390x-gnu': 1.1.5 - '@rolldown/binding-linux-x64-gnu': 1.1.5 - '@rolldown/binding-linux-x64-musl': 1.1.5 - '@rolldown/binding-openharmony-arm64': 1.1.5 - '@rolldown/binding-wasm32-wasi': 1.1.5 - '@rolldown/binding-win32-arm64-msvc': 1.1.5 - '@rolldown/binding-win32-x64-msvc': 1.1.5 + '@rolldown/binding-android-arm64': 1.0.3 + '@rolldown/binding-darwin-arm64': 1.0.3 + '@rolldown/binding-darwin-x64': 1.0.3 + '@rolldown/binding-freebsd-x64': 1.0.3 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.3 + '@rolldown/binding-linux-arm64-gnu': 1.0.3 + '@rolldown/binding-linux-arm64-musl': 1.0.3 + '@rolldown/binding-linux-ppc64-gnu': 1.0.3 + '@rolldown/binding-linux-s390x-gnu': 1.0.3 + '@rolldown/binding-linux-x64-gnu': 1.0.3 + '@rolldown/binding-linux-x64-musl': 1.0.3 + '@rolldown/binding-openharmony-arm64': 1.0.3 + '@rolldown/binding-wasm32-wasi': 1.0.3 + '@rolldown/binding-win32-arm64-msvc': 1.0.3 + '@rolldown/binding-win32-x64-msvc': 1.0.3 + + rollup-plugin-visualizer@6.0.11(rolldown@1.0.3)(rollup@4.62.1): + dependencies: + open: 8.4.2 + picomatch: 4.0.4 + source-map: 0.7.6 + yargs: 17.7.3 + optionalDependencies: + rolldown: 1.0.3 + rollup: 4.62.1 + + rollup@4.62.1: + dependencies: + '@types/estree': 1.0.9 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.62.1 + '@rollup/rollup-android-arm64': 4.62.1 + '@rollup/rollup-darwin-arm64': 4.62.1 + '@rollup/rollup-darwin-x64': 4.62.1 + '@rollup/rollup-freebsd-arm64': 4.62.1 + '@rollup/rollup-freebsd-x64': 4.62.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.62.1 + '@rollup/rollup-linux-arm-musleabihf': 4.62.1 + '@rollup/rollup-linux-arm64-gnu': 4.62.1 + '@rollup/rollup-linux-arm64-musl': 4.62.1 + '@rollup/rollup-linux-loong64-gnu': 4.62.1 + '@rollup/rollup-linux-loong64-musl': 4.62.1 + '@rollup/rollup-linux-ppc64-gnu': 4.62.1 + '@rollup/rollup-linux-ppc64-musl': 4.62.1 + '@rollup/rollup-linux-riscv64-gnu': 4.62.1 + '@rollup/rollup-linux-riscv64-musl': 4.62.1 + '@rollup/rollup-linux-s390x-gnu': 4.62.1 + '@rollup/rollup-linux-x64-gnu': 4.62.1 + '@rollup/rollup-linux-x64-musl': 4.62.1 + '@rollup/rollup-openbsd-x64': 4.62.1 + '@rollup/rollup-openharmony-arm64': 4.62.1 + '@rollup/rollup-win32-arm64-msvc': 4.62.1 + '@rollup/rollup-win32-ia32-msvc': 4.62.1 + '@rollup/rollup-win32-x64-gnu': 4.62.1 + '@rollup/rollup-win32-x64-msvc': 4.62.1 + fsevents: 2.3.3 + optional: true + + safer-buffer@2.1.2: + optional: true + + sax@1.6.0: {} + + scroll-into-view-if-needed@2.2.31: + dependencies: + compute-scroll-into-view: 1.0.20 + + semver@6.3.1: {} + + semver@7.8.4: {} + + sharp@0.34.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.4 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + + simple-swizzle@0.2.4: + dependencies: + is-arrayish: 0.3.4 + + sortablejs@1.15.7: {} source-map-js@1.2.1: {} + source-map@0.6.1: + optional: true + + source-map@0.7.6: {} + + speakingurl@14.0.1: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + superjson@2.2.6: + dependencies: + copy-anything: 4.0.5 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + svgo@3.3.3: + dependencies: + commander: 7.2.0 + css-select: 5.2.2 + css-tree: 2.3.1 + css-what: 6.2.2 + csso: 5.0.5 + picocolors: 1.1.1 + sax: 1.6.0 + tinyglobby@0.2.17: dependencies: - fdir: 6.5.0(picomatch@4.0.5) - picomatch: 4.0.5 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + tslib@2.3.0: {} tslib@2.8.1: optional: true typescript@5.9.3: {} - vite@8.1.5: + ufo@1.6.4: {} + + undici-types@8.3.0: + optional: true + + universalify@2.0.1: {} + + unplugin-utils@0.2.5: dependencies: - lightningcss: 1.33.0 - picomatch: 4.0.5 - postcss: 8.5.23 - rolldown: 1.1.5 + pathe: 2.0.3 + picomatch: 4.0.4 + + unplugin-vue-components@28.8.0(@babel/parser@7.29.7)(vue@3.5.38(typescript@5.9.3)): + dependencies: + chokidar: 3.6.0 + debug: 4.4.3 + local-pkg: 1.2.1 + magic-string: 0.30.21 + mlly: 1.8.2 + tinyglobby: 0.2.17 + unplugin: 2.3.11 + unplugin-utils: 0.2.5 + vue: 3.5.38(typescript@5.9.3) + optionalDependencies: + '@babel/parser': 7.29.7 + transitivePeerDependencies: + - supports-color + + unplugin@2.3.11: + dependencies: + '@jridgewell/remapping': 2.3.5 + acorn: 8.17.0 + picomatch: 4.0.4 + webpack-virtual-modules: 0.6.2 + + update-browserslist-db@1.2.3(browserslist@4.28.2): + dependencies: + browserslist: 4.28.2 + escalade: 3.2.0 + picocolors: 1.1.1 + + vite-plugin-compression@0.5.1(vite@8.0.16(@types/node@26.0.0)(jiti@2.6.1)(less@4.6.6)(yaml@2.9.0)): + dependencies: + chalk: 4.1.2 + debug: 4.4.3 + fs-extra: 10.1.0 + vite: 8.0.16(@types/node@26.0.0)(jiti@2.6.1)(less@4.6.6)(yaml@2.9.0) + transitivePeerDependencies: + - supports-color + + vite-plugin-image-optimizer@2.0.3(sharp@0.34.5)(vite@8.0.16(@types/node@26.0.0)(jiti@2.6.1)(less@4.6.6)(yaml@2.9.0)): + dependencies: + ansi-colors: 4.1.3 + pathe: 2.0.3 + vite: 8.0.16(@types/node@26.0.0)(jiti@2.6.1)(less@4.6.6)(yaml@2.9.0) + optionalDependencies: + sharp: 0.34.5 + + vite-svg-loader@5.1.1(vue@3.5.38(typescript@5.9.3)): + dependencies: + debug: 4.4.3 + svgo: 3.3.3 + vue: 3.5.38(typescript@5.9.3) + transitivePeerDependencies: + - supports-color + + vite@8.0.16(@types/node@26.0.0)(jiti@2.6.1)(less@4.6.6)(yaml@2.9.0): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.15 + rolldown: 1.0.3 tinyglobby: 0.2.17 optionalDependencies: + '@types/node': 26.0.0 fsevents: 2.3.3 + jiti: 2.6.1 + less: 4.6.6 + yaml: 2.9.0 vscode-uri@3.1.0: {} + vue-echarts@8.0.1(echarts@6.1.0)(vue@3.5.38(typescript@5.9.3)): + dependencies: + echarts: 6.1.0 + vue: 3.5.38(typescript@5.9.3) + + vue-i18n@11.4.6(vue@3.5.38(typescript@5.9.3)): + dependencies: + '@intlify/core-base': 11.4.6 + '@intlify/devtools-types': 11.4.6 + '@intlify/shared': 11.4.6 + '@vue/devtools-api': 6.6.4 + vue: 3.5.38(typescript@5.9.3) + + vue-router@4.6.4(vue@3.5.38(typescript@5.9.3)): + dependencies: + '@vue/devtools-api': 6.6.4 + vue: 3.5.38(typescript@5.9.3) + vue-tsc@2.2.12(typescript@5.9.3): dependencies: '@volar/typescript': 2.4.15 '@vue/language-core': 2.2.12(typescript@5.9.3) typescript: 5.9.3 - vue@3.5.40(typescript@5.9.3): + vue@3.5.38(typescript@5.9.3): dependencies: - '@vue/compiler-dom': 3.5.40 - '@vue/compiler-sfc': 3.5.40 - '@vue/runtime-dom': 3.5.40 - '@vue/server-renderer': 3.5.40 - '@vue/shared': 3.5.40 + '@vue/compiler-dom': 3.5.38 + '@vue/compiler-sfc': 3.5.38 + '@vue/runtime-dom': 3.5.38 + '@vue/server-renderer': 3.5.38(vue@3.5.38(typescript@5.9.3)) + '@vue/shared': 3.5.38 optionalDependencies: typescript: 5.9.3 + + webpack-virtual-modules@0.6.2: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + y18n@5.0.8: {} + + yallist@3.1.1: {} + + yaml@2.9.0: + optional: true + + yargs-parser@21.1.1: {} + + yargs@17.7.3: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + zrender@6.1.0: + dependencies: + tslib: 2.3.0 diff --git a/frontend/platform_admin/public/avatar-default.svg b/frontend/platform_admin/public/avatar-default.svg new file mode 100644 index 0000000..66674c1 --- /dev/null +++ b/frontend/platform_admin/public/avatar-default.svg @@ -0,0 +1,10 @@ + diff --git a/frontend/platform_admin/public/favicon.svg b/frontend/platform_admin/public/favicon.svg new file mode 100644 index 0000000..3215438 --- /dev/null +++ b/frontend/platform_admin/public/favicon.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/platform_admin/scripts/audit-check.mjs b/frontend/platform_admin/scripts/audit-check.mjs new file mode 100644 index 0000000..3a363ff --- /dev/null +++ b/frontend/platform_admin/scripts/audit-check.mjs @@ -0,0 +1,51 @@ +import fs from 'node:fs'; +import path from 'node:path'; + +function walk(dir, acc = []) { + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + const full = path.join(dir, entry.name); + if (entry.isDirectory() && entry.name !== 'node_modules') { + walk(full, acc); + } else if (/\.(ts|vue)$/.test(entry.name)) { + acc.push(full); + } + } + return acc; +} + +const srcFiles = walk('src'); +const badPlaceholder = []; +const zhLocales = srcFiles.filter((f) => f.includes(`${path.sep}locale${path.sep}zh-CN.ts`)); + +for (const file of srcFiles) { + const text = fs.readFileSync(file, 'utf8'); + if (text.includes("'???'") || /'(\?\?[^']*)'/.test(text)) { + badPlaceholder.push(file); + } +} + +let zhOk = 0; +for (const file of zhLocales) { + if (/[\u4e00-\u9fff]/.test(fs.readFileSync(file, 'utf8'))) zhOk += 1; +} + +let mockInDist = false; +if (fs.existsSync('dist/assets')) { + for (const name of fs.readdirSync('dist/assets')) { + if (!name.endsWith('.js')) continue; + const chunk = fs.readFileSync(path.join('dist/assets', name), 'utf8'); + if (chunk.includes('mockjs') || chunk.includes('Mock.mock')) { + mockInDist = true; + break; + } + } +} + +console.log(JSON.stringify({ + badPlaceholder: badPlaceholder.length, + zhLocales: `${zhOk}/${zhLocales.length}`, + mockInDist, + hasGit: fs.existsSync('.env.development') && fs.readFileSync('.env.development', 'utf8').includes('VITE_API_BASE_URL=http'), + settingsHttp: fs.readFileSync('src/locale/zh-CN/settings.ts', 'utf8').includes('http.logout.title'), + rootMenu: fs.readFileSync('src/locale/zh-CN.ts', 'utf8').includes('仪表盘'), +}, null, 2)); diff --git a/frontend/platform_admin/scripts/restore-p0-vue.mjs b/frontend/platform_admin/scripts/restore-p0-vue.mjs new file mode 100644 index 0000000..f8580a9 --- /dev/null +++ b/frontend/platform_admin/scripts/restore-p0-vue.mjs @@ -0,0 +1,67 @@ +import fs from 'node:fs'; +import path from 'node:path'; + +const BASE = + 'https://raw.githubusercontent.com/arco-design/arco-design-pro-vue/main/arco-design-pro-vite/src'; + +const vueFiles = [ + 'views/visualization/multi-dimension-data-analysis/components/content-publishing-source.vue', + 'views/user/info/components/my-project.vue', + 'views/user/info/components/my-team.vue', + 'views/user/setting/components/enterprise-certification.vue', +]; + +async function download(relPath) { + const res = await fetch(`${BASE}/${relPath}`); + if (!res.ok) throw new Error(`${relPath}: HTTP ${res.status}`); + return res.text(); +} + +function patchForProject(content, relPath) { + let text = content; + + if (relPath.includes('my-project.vue')) { + text = text.replace( + "import { queryMyProjectList, MyProjectRecord } from '@/api/user-center';", + "import { type MyProjectRecord, queryMyProjectList } from '@/api/user';", + ); + text = text.replace(/\{\{ project\.contributors \}\}\s*/g, ''); + } + + if (relPath.includes('my-team.vue')) { + text = text.replace( + "import { queryMyTeamList, MyTeamRecord } from '@/api/user-center';", + "import { type MyTeamRecord, queryMyTeamList } from '@/api/user';", + ); + } + + if (relPath.includes('enterprise-certification.vue')) { + text = text.replace( + "import { EnterpriseCertificationModel } from '@/api/user-center';", + "import type { EnterpriseCertificationModel } from '@/api/user';", + ); + text = text.replace( + /type: Object as PropType/, + 'type: Object as PropType,', + ); + } + + return text; +} + +async function main() { + for (const relPath of vueFiles) { + let content = await download(relPath); + content = patchForProject(content, relPath); + const fullPath = path.join('src', relPath); + fs.mkdirSync(path.dirname(fullPath), { recursive: true }); + fs.writeFileSync(fullPath, content, 'utf8'); + const hasCn = /[\u4e00-\u9fff]/.test(content); + console.log(`OK ${relPath} (cn=${hasCn})`); + } +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/frontend/platform_admin/scripts/restore-zh-cn-locales.mjs b/frontend/platform_admin/scripts/restore-zh-cn-locales.mjs new file mode 100644 index 0000000..44e289a --- /dev/null +++ b/frontend/platform_admin/scripts/restore-zh-cn-locales.mjs @@ -0,0 +1,109 @@ +import fs from 'node:fs'; +import path from 'node:path'; + +const BASE = + 'https://raw.githubusercontent.com/arco-design/arco-design-pro-vue/main/arco-design-pro-vite/src'; + +const localeFiles = [ + 'locale/zh-CN/settings.ts', + 'views/login/locale/zh-CN.ts', + 'views/form/group/locale/zh-CN.ts', + 'views/form/step/locale/zh-CN.ts', + 'views/dashboard/workplace/locale/zh-CN.ts', + 'views/dashboard/monitor/locale/zh-CN.ts', + 'views/list/card/locale/zh-CN.ts', + 'views/list/search-table/locale/zh-CN.ts', + 'views/profile/basic/locale/zh-CN.ts', + 'views/result/success/locale/zh-CN.ts', + 'views/result/error/locale/zh-CN.ts', + 'views/exception/403/locale/zh-CN.ts', + 'views/exception/404/locale/zh-CN.ts', + 'views/user/info/locale/zh-CN.ts', + 'views/user/setting/locale/zh-CN.ts', + 'views/visualization/data-analysis/locale/zh-CN.ts', + 'views/visualization/multi-dimension-data-analysis/locale/zh-CN.ts', +]; + +const rootZhCN = `import { mergeLocaleModules } from './merge-locales'; +import localeSettings from './zh-CN/settings'; + +const componentLocales = mergeLocaleModules( + import.meta.glob('@/components/**/locale/zh-CN.ts', { eager: true }), +); +const viewLocales = mergeLocaleModules( + import.meta.glob('@/views/**/locale/zh-CN.ts', { eager: true }), +); + +export default { + 'menu.dashboard': '仪表盘', + 'menu.server.dashboard': '仪表盘-服务端', + 'menu.server.workplace': '工作台-服务端', + 'menu.server.monitor': '实时监控-服务端', + 'menu.list': '列表页', + 'menu.result': '结果页', + 'menu.exception': '异常页', + 'menu.form': '表单页', + 'menu.profile': '详情页', + 'menu.visualization': '数据可视化', + 'menu.user': '个人中心', + 'menu.arcoWebsite': 'Arco Design', + 'menu.faq': '常见问题', + 'navbar.docs': '文档中心', + 'navbar.action.locale': '切换为中文', + ...localeSettings, + ...componentLocales, + ...viewLocales, +}; +`; + +async function download(relPath) { + const url = `${BASE}/${relPath}`; + const res = await fetch(url); + if (!res.ok) { + throw new Error(`${relPath}: HTTP ${res.status}`); + } + return res.text(); +} + +async function main() { + for (const relPath of localeFiles) { + const content = await download(relPath); + const dest = path.join('src', relPath.replace(/^locale\//, 'locale/')); + const fullPath = path.join('src', relPath); + fs.mkdirSync(path.dirname(fullPath), { recursive: true }); + fs.writeFileSync(fullPath, content, 'utf8'); + const hasCn = /[\u4e00-\u9fff]/.test(content); + console.log(`OK ${relPath} (cn=${hasCn})`); + } + + fs.writeFileSync(path.join('src', 'locale/zh-CN.ts'), rootZhCN, 'utf8'); + console.log('OK locale/zh-CN.ts (cn=true)'); + + // search-table column setting label + const stPath = path.join('src', 'views/list/search-table/index.vue'); + let st = fs.readFileSync(stPath, 'utf8'); + st = st.replace( + "{{ item.title === '#' ? '???' : item.title }}", + "{{ item.title === '#' ? '序列号' : item.title }}", + ); + fs.writeFileSync(stPath, st, 'utf8'); + console.log('OK search-table/index.vue'); + + // verify + let bad = 0; + for (const relPath of ['locale/zh-CN.ts', ...localeFiles]) { + const fullPath = path.join('src', relPath); + const text = fs.readFileSync(fullPath, 'utf8'); + if (text.includes("'???'") || text.includes("'??'")) { + console.error('STILL BAD:', relPath); + bad += 1; + } + } + if (bad) process.exit(1); + console.log('All locale files verified'); +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/frontend/platform_admin/src/App.vue b/frontend/platform_admin/src/App.vue index 9ec9c90..865fb27 100644 --- a/frontend/platform_admin/src/App.vue +++ b/frontend/platform_admin/src/App.vue @@ -1,6 +1,6 @@ @@ -90,7 +81,7 @@ onMounted(loadData);