From 402f050b17ce0cababdb02226f9db08fcd8cf73c Mon Sep 17 00:00:00 2001 From: yanweidong Date: Tue, 4 Aug 2026 15:21:39 +0800 Subject: [PATCH] feat: add producer account management --- backend/api/internal/initdb/platform_test.go | 2 +- backend/api/internal/logic/common/resource.go | 5 +- backend/api/internal/logic/platform/menu.go | 7 +- .../logic/platform/product/producer.go | 108 ++++++++++++++++++ .../logic/platform/product/product.go | 8 +- .../logic/platform/product/product_test.go | 9 ++ .../logic/platform/resource_contract.go | 4 +- backend/api/internal/models/entity.go | 12 +- backend/api/internal/models/entity_test.go | 21 ++++ .../internal/models/platform_models_test.go | 1 + .../api/internal/models/producer_account.go | 22 ++++ backend/api/internal/models/product_info.go | 25 ++-- backend/api/internal/routers/platform.go | 9 ++ backend/api/internal/routers/platform_test.go | 4 + docs/05-平台总后台需求.md | 9 +- .../src/views/login/components/login-form.vue | 2 +- .../src/views/login/components/login-form.vue | 2 +- frontend/platform_admin/src/api/resources.ts | 4 +- .../src/contracts/platform-resources.json | 2 +- .../src/router/routes/modules/platform.ts | 1 + .../src/views/login/components/login-form.vue | 2 +- 21 files changed, 223 insertions(+), 36 deletions(-) create mode 100644 backend/api/internal/logic/platform/product/producer.go create mode 100644 backend/api/internal/models/entity_test.go create mode 100644 backend/api/internal/models/producer_account.go diff --git a/backend/api/internal/initdb/platform_test.go b/backend/api/internal/initdb/platform_test.go index 3d4a205..04574af 100644 --- a/backend/api/internal/initdb/platform_test.go +++ b/backend/api/internal/initdb/platform_test.go @@ -20,7 +20,7 @@ func TestInitPlatformAccessSeedsRootRole(t *testing.T) { t.Fatal(err) } - mock.ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "platform_role" WHERE role_code = $1 ORDER BY "platform_role"."id" LIMIT $2`)). + mock.ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "platform_role" WHERE role_code = $1 AND "platform_role"."deleted_at" IS NULL ORDER BY "platform_role"."id" LIMIT $2`)). WithArgs("root", 1). WillReturnRows(sqlmock.NewRows([]string{"id", "identity", "status", "role_code", "name", "location_scope", "is_system"}). AddRow(uint64(1), "root-role", 1, "root", "Root", "precise", true)) diff --git a/backend/api/internal/logic/common/resource.go b/backend/api/internal/logic/common/resource.go index d1aae0d..a2e2f7c 100644 --- a/backend/api/internal/logic/common/resource.go +++ b/backend/api/internal/logic/common/resource.go @@ -1,4 +1,4 @@ -package common +package common import ( "encoding/json" @@ -408,6 +408,7 @@ var relationIdentityModels = map[string]any{ "user_account_id": &models.UserAccount{}, "staff_account_id": &models.StaffAccount{}, "product_type_id": &models.ProductType{}, + "producer_account_id": &models.ProducerAccount{}, "product_info_id": &models.ProductInfo{}, "warehouse_id": &models.ProductWarehouse{}, "ec_category_id": &models.EcCategory{}, @@ -419,7 +420,7 @@ var relationIdentityModels = map[string]any{ "gasorder_track_id": &models.GasorderTrack{}, "platform_role_id": &models.PlatformRole{}, "wallet_basic_id": &models.WalletBasic{}, - "payment_order_id": &models.PaymentOrder{}, + "payment_order_id": &models.PaymentOrder{}, "wallet_bank_id": &models.WalletBank{}, "related_record_id": &models.WalletRecord{}, } diff --git a/backend/api/internal/logic/platform/menu.go b/backend/api/internal/logic/platform/menu.go index 360f785..033ee72 100644 --- a/backend/api/internal/logic/platform/menu.go +++ b/backend/api/internal/logic/platform/menu.go @@ -46,9 +46,10 @@ var PlatformMenus = [][]Menu{ }, { {Identity: "device", GroupCode: "device", Name: "智能气阀管理", Icon: "icon-common", Path: "/product", SortNo: 60, Status: common.StatusEnable}, - {Identity: "product_type", ParentIdentity: "device", GroupCode: "device", Name: "类型管理", Path: "/product/product-type", SortNo: 1, Status: common.StatusEnable}, - {Identity: "product_warehouse", ParentIdentity: "device", GroupCode: "device", Name: "库房管理", Path: "/product/warehouse", SortNo: 2, Status: common.StatusEnable}, - {Identity: "product_info", ParentIdentity: "device", GroupCode: "device", Name: "智能气阀管理", Path: "/product/product-info", SortNo: 3, Status: common.StatusEnable}, + {Identity: "producer_account", ParentIdentity: "device", GroupCode: "device", Name: "生产商管理", Path: "/product/producers", SortNo: 1, Status: common.StatusEnable}, + {Identity: "product_type", ParentIdentity: "device", GroupCode: "device", Name: "类型管理", Path: "/product/product-type", SortNo: 2, Status: common.StatusEnable}, + {Identity: "product_warehouse", ParentIdentity: "device", GroupCode: "device", Name: "库房管理", Path: "/product/warehouse", SortNo: 3, Status: common.StatusEnable}, + {Identity: "product_info", ParentIdentity: "device", GroupCode: "device", Name: "智能气阀管理", Path: "/product/product-info", SortNo: 4, Status: common.StatusEnable}, }, { {Identity: "gasorder", GroupCode: "gasorder", Name: "气体配送订单管理", Icon: "icon-list", Path: "/gasorder", SortNo: 70, Status: common.StatusEnable}, diff --git a/backend/api/internal/logic/platform/product/producer.go b/backend/api/internal/logic/platform/product/producer.go new file mode 100644 index 0000000..a3fbdfa --- /dev/null +++ b/backend/api/internal/logic/platform/product/producer.go @@ -0,0 +1,108 @@ +package product + +import ( + "strings" + + "git.apinb.com/bsm-sdk/core/errcode" + "git.apinb.com/bsm-sdk/core/infra" + "git.apinb.com/heqiapp/platforms/backend/api/internal/impl" + "git.apinb.com/heqiapp/platforms/backend/api/internal/logic/common" + "git.apinb.com/heqiapp/platforms/backend/api/internal/models" + "github.com/gin-gonic/gin" +) + +type producerAccountCreateRequest struct { + ProducerCode string `json:"producer_code" binding:"required,max=64"` + Name string `json:"name" binding:"required,max=128"` + CreditCode string `json:"credit_code" binding:"max=64"` + Principal string `json:"principal" binding:"max=64"` + Phone string `json:"phone" binding:"max=32"` + Address string `json:"address" binding:"max=255"` + Username string `json:"username" binding:"required,max=64"` + Password string `json:"password" binding:"required"` + DisplayName string `json:"display_name" binding:"max=64"` + RoleCode string `json:"role_code" binding:"max=64"` + Remark string `json:"remark"` +} + +type producerAccountUpdateRequest struct { + Name string `json:"name" binding:"required,max=128"` + CreditCode string `json:"credit_code" binding:"max=64"` + Principal string `json:"principal" binding:"max=64"` + Phone string `json:"phone" binding:"max=32"` + Address string `json:"address" binding:"max=255"` + DisplayName string `json:"display_name" binding:"max=64"` + RoleCode string `json:"role_code" binding:"max=64"` + Password string `json:"password"` + Remark string `json:"remark"` +} + +func ListProducerAccount(ctx *gin.Context) { common.ListResource(ctx, &models.ProducerAccount{}) } +func GetProducerAccount(ctx *gin.Context) { common.GetResource(ctx, &models.ProducerAccount{}) } + +func CreateProducerAccount(ctx *gin.Context) { + var request producerAccountCreateRequest + if ctx.ShouldBindJSON(&request) != nil || !common.IsValidAccountPassword(request.Password) { + infra.Response.Error(ctx, errcode.ErrInvalidArgument) + return + } + hash, err := common.PasswordHash(request.Password) + if err != nil { + infra.Response.Error(ctx, err) + return + } + roleCode := strings.TrimSpace(request.RoleCode) + if roleCode == "" { + roleCode = "admin" + } + data := models.ProducerAccount{Entity: common.NewEntity(common.StatusEnable), ProducerCode: strings.TrimSpace(request.ProducerCode), Name: strings.TrimSpace(request.Name), CreditCode: strings.TrimSpace(request.CreditCode), Principal: strings.TrimSpace(request.Principal), Phone: strings.TrimSpace(request.Phone), Address: strings.TrimSpace(request.Address), Username: strings.TrimSpace(request.Username), DisplayName: strings.TrimSpace(request.DisplayName), PasswordHash: hash, RoleCode: roleCode, Remark: request.Remark} + if err := impl.DBService.Create(&data).Error; err != nil { + infra.Response.Error(ctx, err) + return + } + common.RespondCreatedResource(ctx, data) +} + +func UpdateProducerAccount(ctx *gin.Context) { + var request producerAccountUpdateRequest + if ctx.ShouldBindJSON(&request) != nil { + infra.Response.Error(ctx, errcode.ErrInvalidArgument) + return + } + values := gin.H{"name": strings.TrimSpace(request.Name), "credit_code": strings.TrimSpace(request.CreditCode), "principal": strings.TrimSpace(request.Principal), "phone": strings.TrimSpace(request.Phone), "address": strings.TrimSpace(request.Address), "display_name": strings.TrimSpace(request.DisplayName), "role_code": strings.TrimSpace(request.RoleCode), "remark": request.Remark} + if request.Password != "" { + if !common.IsValidAccountPassword(request.Password) { + infra.Response.Error(ctx, errcode.ErrInvalidArgument) + return + } + hash, err := common.PasswordHash(request.Password) + if err != nil { + infra.Response.Error(ctx, err) + return + } + values["password_hash"] = hash + } + common.UpdateAllowedByIdentity(ctx, &models.ProducerAccount{}, values, []string{"name", "credit_code", "principal", "phone", "address", "display_name", "role_code", "remark", "password_hash"}) +} + +func DeleteProducerAccount(ctx *gin.Context) { + var producer models.ProducerAccount + if err := impl.DBService.Where("identity = ?", ctx.Param("identity")).First(&producer).Error; err != nil { + common.RespondRecordError(ctx, err) + return + } + var references int64 + if err := impl.DBService.Unscoped().Model(&models.ProductInfo{}).Where("producer_account_id = ?", producer.ID).Count(&references).Error; err != nil { + infra.Response.Error(ctx, err) + return + } + if references > 0 { + infra.Response.Error(ctx, errcode.ErrInvalidArgument) + return + } + if err := impl.DBService.Delete(&producer).Error; err != nil { + infra.Response.Error(ctx, err) + return + } + infra.Response.Success(ctx, gin.H{"deleted": true}) +} diff --git a/backend/api/internal/logic/platform/product/product.go b/backend/api/internal/logic/platform/product/product.go index 27650a6..c2d6781 100644 --- a/backend/api/internal/logic/platform/product/product.go +++ b/backend/api/internal/logic/platform/product/product.go @@ -44,7 +44,7 @@ func createProductInfo(ctx *gin.Context, fields []string, relations []common.Res delete(values, "reason") delete(values, "remark") data := models.ProductInfo{Entity: common.NewEntity(common.StatusDisable), ProductStatus: common.StatusPending, Params: "{}"} - if err := decodeValues(values, &data); err != nil || data.Code == "" || data.Name == "" || data.ProducedAt.IsZero() || !validProductOwnership(data) { + if err := decodeValues(values, &data); err != nil || data.Code == "" || data.Name == "" || !validProductProducer(data) || data.ProducedAt.IsZero() || !validProductOwnership(data) { infra.Response.Error(ctx, errcode.ErrInvalidArgument) return } @@ -91,7 +91,7 @@ func updateProductInfo(ctx *gin.Context, fields []string, relations []common.Res delete(values, "code") } preview := current - if err := decodeValues(values, &preview); err != nil || !validProductOwnership(preview) { + if err := decodeValues(values, &preview); err != nil || !validProductProducer(preview) || !validProductOwnership(preview) { return errors.New("product can have at most one current owner") } ownershipChanged := ownershipValuesChanged(current, values) @@ -379,6 +379,10 @@ func validProductOwnership(product models.ProductInfo) bool { return count <= 1 } +func validProductProducer(product models.ProductInfo) bool { + return product.ProducerAccountID != 0 +} + func ownershipValuesChanged(current models.ProductInfo, values map[string]any) bool { for key, old := range map[string]uint64{ "warehouse_id": current.WarehouseID, "gas_basic_id": current.GasBasicID, diff --git a/backend/api/internal/logic/platform/product/product_test.go b/backend/api/internal/logic/platform/product/product_test.go index cb4f4eb..5f484ff 100644 --- a/backend/api/internal/logic/platform/product/product_test.go +++ b/backend/api/internal/logic/platform/product/product_test.go @@ -85,3 +85,12 @@ func TestProductHasAtMostOneCurrentOwner(t *testing.T) { t.Fatal("conflicting warehouse and user owners were accepted") } } + +func TestProductRequiresProducer(t *testing.T) { + if validProductProducer(models.ProductInfo{}) { + t.Fatal("product without producer was accepted") + } + if !validProductProducer(models.ProductInfo{ProducerAccountID: 1}) { + t.Fatal("product with producer was rejected") + } +} diff --git a/backend/api/internal/logic/platform/resource_contract.go b/backend/api/internal/logic/platform/resource_contract.go index 24f7b11..11bd759 100644 --- a/backend/api/internal/logic/platform/resource_contract.go +++ b/backend/api/internal/logic/platform/resource_contract.go @@ -1,4 +1,4 @@ -package platform +package platform import ( "net/http" @@ -81,7 +81,7 @@ func ExpectedResources() []ResourceContract { resourceContract("delivery", "delivery_basic", Writable, "list"), resourceContract("delivery", "delivery_account", Writable, "list"), resourceContract("staff", "staff_account", Writable, "list"), resourceContract("staff", "staff_credential", Writable, "list"), resourceContract("user", "user_account", Writable, "list"), resourceContract("user", "user_address", Writable, "list"), resourceContract("user", "user_service_relation", Writable, "list"), - resourceContract("product", "product_type", Editable, "list"), resourceContract("product", "product_warehouse", Editable, "list"), resourceContract("product", "product_info", Editable, "list"), resourceContract("product", "product_repair", Editable, "list"), resourceContract("product", "product_owner", ReadOnly, "list"), + resourceContract("product", "producer_account", Writable, "list"), resourceContract("product", "product_type", Editable, "list"), resourceContract("product", "product_warehouse", Editable, "list"), resourceContract("product", "product_info", Editable, "list"), resourceContract("product", "product_repair", Editable, "list"), resourceContract("product", "product_owner", ReadOnly, "list"), resourceContract("ec", "ec_category", Writable, "list"), resourceContract("ec", "ec_product", Writable, "list"), resourceContract("ec", "ec_product_attribute", Writable, "list"), resourceContract("ec", "ec_product_image", Writable, "list"), resourceContract("ec", "ec_cart", ReadOnly, "list"), resourceContract("ec", "ec_order", ReadOnly, "list"), resourceContract("ec", "ec_order_item", ReadOnly, "list"), resourceContract("ec", "ec_review", ReadOnly, "list"), resourceContract("gasorder", "gasorder_contract", Managed, "list"), resourceContract("gasorder", "gasorder_contract_product", AppendOnly, "list"), resourceContract("gasorder", "gasorder_contract_revision", ReadOnly, "list"), resourceContract("gasorder", "gasorder_basic", AppendOnly, "list"), resourceContract("gasorder", "gasorder_item", ReadOnly, "list"), resourceContract("gasorder", "gasorder_assign", ReadOnly, "list"), resourceContract("gasorder", "gasorder_status", ReadOnly, "list"), diff --git a/backend/api/internal/models/entity.go b/backend/api/internal/models/entity.go index b4c3bf6..2bf9b5f 100644 --- a/backend/api/internal/models/entity.go +++ b/backend/api/internal/models/entity.go @@ -5,15 +5,17 @@ import ( "time" "github.com/google/uuid" + "gorm.io/gorm" ) // Entity 是所有主表共享字段。id 是数据库自增主键,identity 是应用生成的 UUID V7 业务标识。 type Entity struct { - 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;index" json:"created_at"` // 创建时间 - UpdatedAt time.Time `gorm:"column:updated_at;type:timestamptz;not null" json:"updated_at"` // 更新时间 - Status int `gorm:"column:status;not null;default:0;index" json:"status"` // 通用记录状态 + 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;index" json:"created_at"` // 创建时间 + UpdatedAt time.Time `gorm:"column:updated_at;type:timestamptz;not null" json:"updated_at"` // 更新时间 + DeletedAt gorm.DeletedAt `gorm:"index"` // 软删除时间,非空表示记录已删除但仍保留在数据库中 + Status int `gorm:"column:status;not null;default:0;index" json:"status"` // 通用记录状态 } // NewIdentity 生成时间有序的 UUID V7 字符串,生成失败属于不可恢复的运行时错误。 diff --git a/backend/api/internal/models/entity_test.go b/backend/api/internal/models/entity_test.go new file mode 100644 index 0000000..ff91d84 --- /dev/null +++ b/backend/api/internal/models/entity_test.go @@ -0,0 +1,21 @@ +package models + +import ( + "reflect" + "testing" + + "gorm.io/gorm" +) + +func TestEntityDeletedAtEnablesSoftDelete(t *testing.T) { + field, ok := reflect.TypeOf(Entity{}).FieldByName("DeletedAt") + if !ok { + t.Fatal("Entity 缺少 DeletedAt 软删除字段") + } + if field.Type != reflect.TypeOf(gorm.DeletedAt{}) { + t.Fatalf("DeletedAt 类型为 %v,期望 gorm.DeletedAt", field.Type) + } + if got := field.Tag.Get("gorm"); got != "index" { + t.Fatalf("DeletedAt gorm 标签为 %q,期望 %q", got, "index") + } +} diff --git a/backend/api/internal/models/platform_models_test.go b/backend/api/internal/models/platform_models_test.go index eaf77a4..6f6ce27 100644 --- a/backend/api/internal/models/platform_models_test.go +++ b/backend/api/internal/models/platform_models_test.go @@ -11,6 +11,7 @@ func TestPlatformModelTableNames(t *testing.T) { {name: "account", table: &PlatformAccount{}, want: "platform_account"}, {name: "role", table: &PlatformRole{}, want: "platform_role"}, {name: "role menu", table: &PlatformRoleMenu{}, want: "platform_role_menu"}, + {name: "producer account", table: &ProducerAccount{}, want: "producer_account"}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { diff --git a/backend/api/internal/models/producer_account.go b/backend/api/internal/models/producer_account.go new file mode 100644 index 0000000..8b04891 --- /dev/null +++ b/backend/api/internal/models/producer_account.go @@ -0,0 +1,22 @@ +package models + +import "git.apinb.com/bsm-sdk/core/database" + +// ProducerAccount 对应 producer_account,保存可登录的生产商企业主数据。 +type ProducerAccount struct { + Entity // 公共实体字段 + ProducerCode string `gorm:"column:producer_code;type:varchar(64);not null;uniqueIndex" json:"producer_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:'';index" json:"credit_code"` // 统一社会信用代码 + Principal string `gorm:"column:principal;type:varchar(64);not null;default:''" json:"principal"` // 企业负责人 + Phone string `gorm:"column:phone;type:varchar(32);not null;default:''" json:"phone"` // 联系电话 + Address string `gorm:"column:address;type:varchar(255);not null;default:''" json:"address"` // 企业地址 + 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;default:'admin'" json:"role_code"` // 生产商端角色编码 + Remark string `gorm:"column:remark;type:text;not null;default:''" json:"remark"` // 备注 +} + +func init() { database.AppendMigrate(&ProducerAccount{}) } +func (table *ProducerAccount) TableName() string { return "producer_account" } diff --git a/backend/api/internal/models/product_info.go b/backend/api/internal/models/product_info.go index 9f449e2..17ebc5b 100644 --- a/backend/api/internal/models/product_info.go +++ b/backend/api/internal/models/product_info.go @@ -8,18 +8,19 @@ import ( // ProductInfo 对应 product_info,保存一物一码的实体产品档案。 type ProductInfo struct { - Entity // 公共实体字段 - ProductStatus int `gorm:"column:product_status;not null;default:10;index" json:"product_status"` // 产品业务状态 - Code string `gorm:"column:code;type:varchar(64);not null;uniqueIndex" json:"code"` // 产品唯一标识 - Name string `gorm:"column:name;type:varchar(128);not null" json:"name"` // 产品名称 - ProductTypeID uint64 `gorm:"column:product_type_id;not null;index" json:"product_type_id"` // 产品类型自增主键 - Params string `gorm:"column:params;type:text;not null;default:'{}'" json:"params"` // 产品参数 JSON 对象文本 - WarehouseID uint64 `gorm:"column:warehouse_id;not null;default:0;index" json:"warehouse_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"` // 当前归属配送站自增主键 - UserAccountID uint64 `gorm:"column:user_account_id;not null;default:0;index" json:"user_account_id"` // 当前归属用户自增主键 - ProducedAt time.Time `gorm:"column:produced_at;type:timestamptz;not null" json:"produced_at"` // 生产时间 - EnabledAt *time.Time `gorm:"column:enabled_at;type:timestamptz" json:"enabled_at"` // 首次启用时间 + Entity // 公共实体字段 + ProductStatus int `gorm:"column:product_status;not null;default:10;index" json:"product_status"` // 产品业务状态 + Code string `gorm:"column:code;type:varchar(64);not null;uniqueIndex" json:"code"` // 产品唯一标识 + Name string `gorm:"column:name;type:varchar(128);not null" json:"name"` // 产品名称 + ProducerAccountID uint64 `gorm:"column:producer_account_id;not null;default:0;index" json:"producer_account_id"` // 生产商自增主键;历史数据迁移前可为 0,新建和编辑必须关联有效生产商 + ProductTypeID uint64 `gorm:"column:product_type_id;not null;index" json:"product_type_id"` // 产品类型自增主键 + Params string `gorm:"column:params;type:text;not null;default:'{}'" json:"params"` // 产品参数 JSON 对象文本 + WarehouseID uint64 `gorm:"column:warehouse_id;not null;default:0;index" json:"warehouse_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"` // 当前归属配送站自增主键 + UserAccountID uint64 `gorm:"column:user_account_id;not null;default:0;index" json:"user_account_id"` // 当前归属用户自增主键 + ProducedAt time.Time `gorm:"column:produced_at;type:timestamptz;not null" json:"produced_at"` // 生产时间 + EnabledAt *time.Time `gorm:"column:enabled_at;type:timestamptz" json:"enabled_at"` // 首次启用时间 } func init() { database.AppendMigrate(&ProductInfo{}) } diff --git a/backend/api/internal/routers/platform.go b/backend/api/internal/routers/platform.go index 13ef9c4..ba38f64 100644 --- a/backend/api/internal/routers/platform.go +++ b/backend/api/internal/routers/platform.go @@ -107,10 +107,19 @@ func registerGasorderRoute(group *gin.RouterGroup) { } func registerProductRoute(group *gin.RouterGroup) { + producer := group.Group("/producer_account") + producer.GET("", product.ListProducerAccount) + producer.POST("", product.CreateProducerAccount) + producer.GET("/:identity", product.GetProducerAccount) + producer.PUT("/:identity", product.UpdateProducerAccount) + producer.PATCH("/:identity/status", func(ctx *gin.Context) { common.UpdateRecordStatus(ctx, &models.ProducerAccount{}) }) + producer.DELETE("/:identity", product.DeleteProducerAccount) + registerRestrictedNoDeleteResource(group, "/product_type", &models.ProductType{}, []string{"code", "name"}) registerRestrictedNoDeleteResource(group, "/product_warehouse", &models.ProductWarehouse{}, []string{"code", "name", "address", "manager", "phone"}) infoRelations := []common.ResourceRelation{ + requiredRelation("producer_account_identity", "producer_account_id", &models.ProducerAccount{}), requiredRelation("product_type_identity", "product_type_id", &models.ProductType{}), optionalRelation("warehouse_identity", "warehouse_id", &models.ProductWarehouse{}), optionalRelation("gas_basic_identity", "gas_basic_id", &models.GasBasic{}), diff --git a/backend/api/internal/routers/platform_test.go b/backend/api/internal/routers/platform_test.go index de01548..0ff9b35 100644 --- a/backend/api/internal/routers/platform_test.go +++ b/backend/api/internal/routers/platform_test.go @@ -166,6 +166,10 @@ func TestPlatformProductCommerceAndDeliveryRoutesFollowTheirContracts(t *testing assertRouteMethods(t, routes, path+"/:identity/status", http.MethodPatch) assertNoRouteMethods(t, routes, path+"/:identity", http.MethodDelete) } + producer := "/heqi/platform/v1/producer_account" + assertRouteMethods(t, routes, producer, http.MethodGet, http.MethodPost) + assertRouteMethods(t, routes, producer+"/:identity", http.MethodGet, http.MethodPut, http.MethodDelete) + assertRouteMethods(t, routes, producer+"/:identity/status", http.MethodPatch) owner := "/heqi/platform/v1/product_owner" assertRouteMethods(t, routes, owner, http.MethodGet) assertNoRouteMethods(t, routes, owner, http.MethodPost) diff --git a/docs/05-平台总后台需求.md b/docs/05-平台总后台需求.md index 4310b94..3dd2eef 100644 --- a/docs/05-平台总后台需求.md +++ b/docs/05-平台总后台需求.md @@ -22,7 +22,7 @@ - 气站管理系统:站点经营、站内库存和日常订单运营仍由后续气站端主责。 - 配送点管理系统:末端调度、配送仓和配送作业仍由后续配送点端主责。 -- 生产管理系统:设备生产、质检、序列号注入和出厂追溯尚未在本后台实现。 +- 生产管理系统:设备生产、质检、序列号注入和出厂追溯仍由独立生产端主责;平台后台仅治理生产商账户主数据及智能气阀的生产商归属。 - API 中心:开放 API 产品、调用方、凭证和配额管理尚未实现。 - 用户端与服务端 App:本后台不承担用户设备控制、配送员定位采集或现场取证。 @@ -107,7 +107,7 @@ ## 6. 已实现功能域 -当前资源契约共 47 个资源。下表中的路径均相对于 `/heqi/platform/v1`。 +当前资源契约共 48 个资源。下表中的路径均相对于 `/heqi/platform/v1`。 ### 6.1 机构管理 @@ -143,13 +143,14 @@ | 资源 | 路径 | 模式 | 已实现能力 | | --- | --- | --- | --- | +| 生产商 | `/producer_account` | 可写 | 生产商企业与登录账户新增、查询、编辑、启停和软删除;已被智能气阀引用时禁止删除 | | 类型 | `/product_type` | 可编辑 | 类型新增、编辑和启停 | | 库房 | `/product_warehouse` | 可编辑 | 库房新增、编辑和启停 | | 智能气阀 | `/product_info` | 可编辑 | 档案新增、编辑、启停和专用生命周期流转 | | 检修记录 | `/product_repair` | 可编辑 | 检修记录新增、编辑和状态调整 | | 归属记录 | `/product_owner` | 只读 | 查询每次归属变更的动作、操作者、原因和时间 | -智能气阀必须关联类型,可选关联库房、气站、配送点或用户。归属组合由后端校验,不允许形成非法多重归属。生命周期支持待处理、在库、运输中、使用中、维修中和已报废;状态变化使用 `/product_info/:identity/lifecycle`,不能通过通用编辑直接改写。归属变化自动追加归属记录。 +智能气阀必须关联生产商和类型,可选关联库房、气站、配送点或用户。生产商登录密码仅保存哈希且不通过资源接口返回;独立生产端登录路由待生产管理系统落地时接入。归属组合由后端校验,不允许形成非法多重归属。生命周期支持待处理、在库、运输中、使用中、维修中和已报废;状态变化使用 `/product_info/:identity/lifecycle`,不能通过通用编辑直接改写。归属变化自动追加归属记录。 ### 6.5 配送合同 @@ -275,7 +276,7 @@ 1. 匿名用户只能访问健康检查和登录;受保护资源缺少有效 JWT 时被拒绝。 2. 非 root 角色只能访问已分配菜单及其明确依赖资源,不能通过猜测路径访问同级资源。 -3. 47 个资源的后端契约、实际路由、前端资源定义和页面加载关系一致。 +3. 48 个资源的后端契约、实际路由、前端资源定义和页面加载关系一致。 4. 所有表保留自增 `id` 主键;主资源通过 UUID V7 `identity` 对外访问,前端不依赖内部 ID。 5. 气站必须先审核再启停,驳回原因和审核人可追溯。 6. 智能气阀归属和生命周期变更合法,并自动记录归属历史。 diff --git a/frontend/delivery_admin/src/views/login/components/login-form.vue b/frontend/delivery_admin/src/views/login/components/login-form.vue index ae268f9..4e6deb5 100644 --- a/frontend/delivery_admin/src/views/login/components/login-form.vue +++ b/frontend/delivery_admin/src/views/login/components/login-form.vue @@ -82,7 +82,7 @@ const userStore = useUserStore(); const loginConfig = useStorage('login-config', { rememberPassword: true, - username: 'admin', + username: '', password: '', }); const userInfo = reactive({ diff --git a/frontend/gas_admin/src/views/login/components/login-form.vue b/frontend/gas_admin/src/views/login/components/login-form.vue index 49b617b..b813a88 100644 --- a/frontend/gas_admin/src/views/login/components/login-form.vue +++ b/frontend/gas_admin/src/views/login/components/login-form.vue @@ -82,7 +82,7 @@ const userStore = useUserStore(); const loginConfig = useStorage('login-config', { rememberPassword: true, - username: 'admin', + username: '', password: '', }); const userInfo = reactive({ diff --git a/frontend/platform_admin/src/api/resources.ts b/frontend/platform_admin/src/api/resources.ts index c793aec..505dcab 100644 --- a/frontend/platform_admin/src/api/resources.ts +++ b/frontend/platform_admin/src/api/resources.ts @@ -59,6 +59,7 @@ export type ResourceUiDefinition = { const fieldLabels: Record = { code: '编码', + producer_code: '生产商编码', name: '名称', username: '用户名', password: '密码', @@ -299,9 +300,10 @@ export const resources: ResourceUiDefinition[] = [ define('user_address', '用户地址', 'writable', [relation('user_account_identity', '/user_account', true), f('address', { required: true }), f('longitude'), f('latitude'), f('is_default')]), define('user_service_relation', '用户服务关系', 'writable', [relation('user_account_identity', '/user_account', true), relation('gas_basic_identity', '/gas_basic'), relation('delivery_basic_identity', '/delivery_basic'), relation('staff_account_identity', '/staff_account')]), + define('producer_account', '生产商管理', 'writable', [f('producer_code', { required: true }), f('name', { required: true }), f('credit_code'), f('principal'), f('phone'), f('address'), f('username', { required: true }), f('password', { required: true }), f('display_name'), f('role_code'), f('remark')]), define('product_type', '智能气阀类型', 'editable', [f('code', { required: true }), f('name', { required: true })]), define('product_warehouse', '智能气阀库房', 'editable', [f('code', { required: true }), f('name', { required: true }), f('address'), f('manager'), f('phone')]), - define('product_info', '智能气阀', 'editable', [f('code', { required: true }), f('name', { required: true }), relation('product_type_identity', '/product_type', true), f('params', { required: true }), relation('warehouse_identity', '/product_warehouse'), relation('gas_basic_identity', '/gas_basic'), relation('delivery_basic_identity', '/delivery_basic'), relation('user_account_identity', '/user_account'), f('produced_at', { required: true })], 'list', [ + define('product_info', '智能气阀', 'editable', [f('code', { required: true }), f('name', { required: true }), relation('producer_account_identity', '/producer_account', true), relation('product_type_identity', '/product_type', true), f('params', { required: true }), relation('warehouse_identity', '/product_warehouse'), relation('gas_basic_identity', '/gas_basic'), relation('delivery_basic_identity', '/delivery_basic'), relation('user_account_identity', '/user_account'), f('produced_at', { required: true })], 'list', [ { name: '修改智能气阀状态', resource: '/product_info/:identity/lifecycle', method: 'PATCH', fields: [f('product_status', { required: true, type: 'select', options: [{ label: '待处理', value: 10 }, { label: '在库', value: 28 }, { label: '运输中', value: 29 }, { label: '使用中', value: 30 }, { label: '维修中', value: 31 }, { label: '已报废', value: 27 }] })] }, ]), define('product_repair', '智能气阀检修记录', 'editable', [relation('product_info_identity', '/product_info', true), f('repair_no', { required: true }), f('repair_type', { required: true }), f('started_at', { required: true }), f('completed_at'), f('result', { type: 'select', options: [{ label: '待处理', value: 'pending' }, { label: '通过', value: 'passed' }, { label: '未通过', value: 'failed' }] }), f('target_product_status', { type: 'select', options: [{ label: '在库', value: 28 }, { label: '运输中', value: 29 }, { label: '使用中', value: 30 }, { label: '报废', value: 27 }] }), f('content'), f('operator'), f('remark')]), diff --git a/frontend/platform_admin/src/contracts/platform-resources.json b/frontend/platform_admin/src/contracts/platform-resources.json index e8cf01a..88040a6 100644 --- a/frontend/platform_admin/src/contracts/platform-resources.json +++ b/frontend/platform_admin/src/contracts/platform-resources.json @@ -1 +1 @@ -{"resources":[{"domain":"gas","name":"gas_basic","path":"/gas_basic","pageKind":"list","mode":"writable"},{"domain":"gas","name":"gas_account","path":"/gas_account","pageKind":"list","mode":"writable"},{"domain":"delivery","name":"delivery_basic","path":"/delivery_basic","pageKind":"list","mode":"writable"},{"domain":"delivery","name":"delivery_account","path":"/delivery_account","pageKind":"list","mode":"writable"},{"domain":"staff","name":"staff_account","path":"/staff_account","pageKind":"list","mode":"writable"},{"domain":"staff","name":"staff_credential","path":"/staff_credential","pageKind":"list","mode":"writable"},{"domain":"user","name":"user_account","path":"/user_account","pageKind":"list","mode":"writable"},{"domain":"user","name":"user_address","path":"/user_address","pageKind":"list","mode":"writable"},{"domain":"user","name":"user_service_relation","path":"/user_service_relation","pageKind":"list","mode":"writable"},{"domain":"product","name":"product_type","path":"/product_type","pageKind":"list","mode":"editable"},{"domain":"product","name":"product_warehouse","path":"/product_warehouse","pageKind":"list","mode":"editable"},{"domain":"product","name":"product_info","path":"/product_info","pageKind":"list","mode":"editable"},{"domain":"product","name":"product_repair","path":"/product_repair","pageKind":"list","mode":"editable"},{"domain":"product","name":"product_owner","path":"/product_owner","pageKind":"list","mode":"readonly"},{"domain":"ec","name":"ec_category","path":"/ec_category","pageKind":"list","mode":"writable"},{"domain":"ec","name":"ec_product","path":"/ec_product","pageKind":"list","mode":"writable"},{"domain":"ec","name":"ec_product_attribute","path":"/ec_product_attribute","pageKind":"list","mode":"writable"},{"domain":"ec","name":"ec_product_image","path":"/ec_product_image","pageKind":"list","mode":"writable"},{"domain":"ec","name":"ec_cart","path":"/ec_cart","pageKind":"list","mode":"readonly"},{"domain":"ec","name":"ec_order","path":"/ec_order","pageKind":"list","mode":"readonly"},{"domain":"ec","name":"ec_order_item","path":"/ec_order_item","pageKind":"list","mode":"readonly"},{"domain":"ec","name":"ec_review","path":"/ec_review","pageKind":"list","mode":"readonly"},{"domain":"gasorder","name":"gasorder_contract","path":"/gasorder_contract","pageKind":"list","mode":"managed"},{"domain":"gasorder","name":"gasorder_contract_product","path":"/gasorder_contract_product","pageKind":"list","mode":"append_only"},{"domain":"gasorder","name":"gasorder_contract_revision","path":"/gasorder_contract_revision","pageKind":"list","mode":"readonly"},{"domain":"gasorder","name":"gasorder_basic","path":"/gasorder_basic","pageKind":"list","mode":"append_only"},{"domain":"gasorder","name":"gasorder_item","path":"/gasorder_item","pageKind":"list","mode":"readonly"},{"domain":"gasorder","name":"gasorder_assign","path":"/gasorder_assign","pageKind":"list","mode":"readonly"},{"domain":"gasorder","name":"gasorder_status","path":"/gasorder_status","pageKind":"list","mode":"readonly"},{"domain":"gasorder","name":"gasorder_track","path":"/gasorder_track","pageKind":"list","mode":"readonly"},{"domain":"gasorder","name":"gasorder_track_point","path":"/gasorder_track_point","pageKind":"list","mode":"readonly"},{"domain":"gasorder","name":"gasorder_confirm","path":"/gasorder_confirm","pageKind":"list","mode":"readonly"},{"domain":"gasorder","name":"gasorder_payment","path":"/gasorder_payment","pageKind":"list","mode":"readonly"},{"domain":"finance","name":"fin_payment","path":"/fin_payment","pageKind":"list","mode":"readonly"},{"domain":"finance","name":"fin_settlement","path":"/fin_settlement","pageKind":"list","mode":"writable"},{"domain":"finance","name":"fin_reconciliation","path":"/fin_reconciliation","pageKind":"list","mode":"readonly"},{"domain":"content","name":"cms_content","path":"/cms_content","pageKind":"list","mode":"writable"},{"domain":"customer_service","name":"cs_ticket","path":"/cs_ticket","pageKind":"list","mode":"writable"},{"domain":"platform","name":"platform_account","path":"/platform_account","pageKind":"list","mode":"writable"},{"domain":"platform","name":"platform_role","path":"/platform_role","pageKind":"list","mode":"writable"},{"domain":"platform","name":"platform_menu","path":"/platform_menu","pageKind":"tree","mode":"readonly"},{"domain":"wallet","name":"wallet_basic","path":"/wallet_basic","pageKind":"list","mode":"readonly"},{"domain":"wallet","name":"wallet_bank","path":"/wallet_bank","pageKind":"list","mode":"readonly"},{"domain":"wallet","name":"payment_order","path":"/payment_order","pageKind":"list","mode":"readonly"},{"domain":"wallet","name":"wallet_record","path":"/wallet_record","pageKind":"list","mode":"readonly"},{"domain":"wallet","name":"payment_refund","path":"/payment_refund","pageKind":"list","mode":"readonly"},{"domain":"wallet","name":"wallet_apply_cash","path":"/wallet_apply_cash","pageKind":"list","mode":"readonly"}],"routes":[{"method":"GET","path":"/gasorder_contract"},{"method":"GET","path":"/gasorder_contract_product"},{"method":"GET","path":"/gasorder_contract_product/:identity"},{"method":"GET","path":"/gasorder_contract_revision"},{"method":"GET","path":"/gasorder_contract_revision/:identity"},{"method":"GET","path":"/gasorder_contract/:identity"},{"method":"GET","path":"/gasorder_confirm"},{"method":"GET","path":"/gasorder_confirm/:identity"},{"method":"GET","path":"/gasorder_track"},{"method":"GET","path":"/gasorder_track_point"},{"method":"GET","path":"/gasorder_track_point/:identity"},{"method":"GET","path":"/gasorder_track/:identity"},{"method":"GET","path":"/gasorder_basic"},{"method":"GET","path":"/gasorder_basic/:identity"},{"method":"GET","path":"/gasorder_item"},{"method":"GET","path":"/gasorder_item/:identity"},{"method":"GET","path":"/gasorder_assign"},{"method":"GET","path":"/gasorder_assign/:identity"},{"method":"GET","path":"/gasorder_status"},{"method":"GET","path":"/gasorder_status/:identity"},{"method":"GET","path":"/gasorder_payment"},{"method":"GET","path":"/gasorder_payment/:identity"},{"method":"GET","path":"/gas_basic"},{"method":"GET","path":"/gas_basic/:identity"},{"method":"GET","path":"/gas_account"},{"method":"GET","path":"/gas_account/:identity"},{"method":"GET","path":"/product_type"},{"method":"GET","path":"/product_type/:identity"},{"method":"GET","path":"/product_warehouse"},{"method":"GET","path":"/product_warehouse/:identity"},{"method":"GET","path":"/product_info"},{"method":"GET","path":"/product_info/:identity"},{"method":"GET","path":"/product_repair"},{"method":"GET","path":"/product_repair/:identity"},{"method":"GET","path":"/product_owner"},{"method":"GET","path":"/product_owner/:identity"},{"method":"GET","path":"/platform_role"},{"method":"GET","path":"/platform_role/:identity"},{"method":"GET","path":"/platform_role/:identity/menu"},{"method":"GET","path":"/platform_account"},{"method":"GET","path":"/platform_account/:identity"},{"method":"GET","path":"/platform_menu"},{"method":"GET","path":"/platform_menu/:identity"},{"method":"GET","path":"/payment_order"},{"method":"GET","path":"/payment_order/:identity"},{"method":"GET","path":"/payment_refund"},{"method":"GET","path":"/payment_refund/:identity"},{"method":"GET","path":"/ping/hello"},{"method":"GET","path":"/ec_product"},{"method":"GET","path":"/ec_product_attribute"},{"method":"GET","path":"/ec_product_attribute/:identity"},{"method":"GET","path":"/ec_product_image"},{"method":"GET","path":"/ec_product_image/:identity"},{"method":"GET","path":"/ec_product/:identity"},{"method":"GET","path":"/ec_category"},{"method":"GET","path":"/ec_category/:identity"},{"method":"GET","path":"/ec_cart"},{"method":"GET","path":"/ec_cart/:identity"},{"method":"GET","path":"/ec_order"},{"method":"GET","path":"/ec_order_item"},{"method":"GET","path":"/ec_order_item/:identity"},{"method":"GET","path":"/ec_order/:identity"},{"method":"GET","path":"/ec_review"},{"method":"GET","path":"/ec_review/:identity"},{"method":"GET","path":"/wallet_basic"},{"method":"GET","path":"/wallet_basic/:identity"},{"method":"GET","path":"/wallet_bank"},{"method":"GET","path":"/wallet_bank/:identity"},{"method":"GET","path":"/wallet_record"},{"method":"GET","path":"/wallet_record/:identity"},{"method":"GET","path":"/wallet_apply_cash"},{"method":"GET","path":"/wallet_apply_cash/:identity"},{"method":"GET","path":"/user_account"},{"method":"GET","path":"/user_account/:identity"},{"method":"GET","path":"/user_address"},{"method":"GET","path":"/user_address/:identity"},{"method":"GET","path":"/user_service_relation"},{"method":"GET","path":"/user_service_relation/:identity"},{"method":"GET","path":"/fin_payment"},{"method":"GET","path":"/fin_payment/:identity"},{"method":"GET","path":"/fin_settlement"},{"method":"GET","path":"/fin_settlement/:identity"},{"method":"GET","path":"/fin_reconciliation"},{"method":"GET","path":"/fin_reconciliation/:identity"},{"method":"GET","path":"/delivery_basic"},{"method":"GET","path":"/delivery_basic/:identity"},{"method":"GET","path":"/delivery_account"},{"method":"GET","path":"/delivery_account/:identity"},{"method":"GET","path":"/dashboard/overview"},{"method":"GET","path":"/staff_account"},{"method":"GET","path":"/staff_account/:identity"},{"method":"GET","path":"/staff_credential"},{"method":"GET","path":"/staff_credential/:identity"},{"method":"GET","path":"/cms_content"},{"method":"GET","path":"/cms_content/:identity"},{"method":"GET","path":"/cs_ticket"},{"method":"GET","path":"/cs_ticket/:identity"},{"method":"GET","path":"/auth/profile"},{"method":"POST","path":"/gasorder_basic"},{"method":"POST","path":"/gasorder_basic/:identity/assign"},{"method":"POST","path":"/gasorder_basic/:identity/awaiting-confirmation"},{"method":"POST","path":"/gasorder_basic/:identity/ready"},{"method":"POST","path":"/gasorder_basic/:identity/recover"},{"method":"POST","path":"/gasorder_basic/:identity/complete"},{"method":"POST","path":"/gasorder_basic/:identity/cancel"},{"method":"POST","path":"/gasorder_basic/:identity/filling"},{"method":"POST","path":"/gasorder_basic/:identity/delivering"},{"method":"POST","path":"/gasorder_basic/:identity/exception"},{"method":"POST","path":"/gasorder_contract"},{"method":"POST","path":"/gasorder_contract/:identity/activate"},{"method":"POST","path":"/gasorder_contract/:identity/renew"},{"method":"POST","path":"/gasorder_contract/:identity/terminate"},{"method":"POST","path":"/gasorder_contract_product"},{"method":"POST","path":"/gasorder_contract_product/:identity/unbind"},{"method":"POST","path":"/gas_basic"},{"method":"POST","path":"/gas_basic/:identity/review"},{"method":"POST","path":"/gas_account"},{"method":"POST","path":"/product_type"},{"method":"POST","path":"/product_warehouse"},{"method":"POST","path":"/product_info"},{"method":"POST","path":"/product_repair"},{"method":"POST","path":"/payment_refund/:identity/approve"},{"method":"POST","path":"/payment_refund/:identity/reject"},{"method":"POST","path":"/platform_account"},{"method":"POST","path":"/platform_role"},{"method":"POST","path":"/wallet_apply_cash/:identity/approve"},{"method":"POST","path":"/wallet_apply_cash/:identity/reject"},{"method":"POST","path":"/wallet_apply_cash/:identity/complete"},{"method":"POST","path":"/wallet_basic/owner/:owner_type/:owner_identity"},{"method":"POST","path":"/wallet_basic/:identity/recharge"},{"method":"POST","path":"/ec_product"},{"method":"POST","path":"/ec_product_attribute"},{"method":"POST","path":"/ec_product_image"},{"method":"POST","path":"/ec_category"},{"method":"POST","path":"/user_account"},{"method":"POST","path":"/user_address"},{"method":"POST","path":"/user_service_relation"},{"method":"POST","path":"/delivery_basic"},{"method":"POST","path":"/delivery_account"},{"method":"POST","path":"/staff_account"},{"method":"POST","path":"/staff_credential"},{"method":"POST","path":"/cms_content"},{"method":"POST","path":"/cs_ticket"},{"method":"POST","path":"/auth/login"},{"method":"POST","path":"/fin_settlement"},{"method":"PUT","path":"/product_type/:identity"},{"method":"PUT","path":"/product_warehouse/:identity"},{"method":"PUT","path":"/product_info/:identity"},{"method":"PUT","path":"/product_repair/:identity"},{"method":"PUT","path":"/platform_role/:identity"},{"method":"PUT","path":"/platform_role/:identity/menu"},{"method":"PUT","path":"/platform_account/:identity"},{"method":"PUT","path":"/ec_product_attribute/:identity"},{"method":"PUT","path":"/ec_product_image/:identity"},{"method":"PUT","path":"/ec_product/:identity"},{"method":"PUT","path":"/ec_category/:identity"},{"method":"PUT","path":"/gas_basic/:identity"},{"method":"PUT","path":"/gas_account/:identity"},{"method":"PUT","path":"/gasorder_contract/:identity"},{"method":"PUT","path":"/user_account/:identity"},{"method":"PUT","path":"/user_address/:identity"},{"method":"PUT","path":"/user_service_relation/:identity"},{"method":"PUT","path":"/delivery_basic/:identity"},{"method":"PUT","path":"/delivery_account/:identity"},{"method":"PUT","path":"/staff_account/:identity"},{"method":"PUT","path":"/staff_credential/:identity"},{"method":"PUT","path":"/cms_content/:identity"},{"method":"PUT","path":"/cs_ticket/:identity"},{"method":"PUT","path":"/auth/password"},{"method":"PUT","path":"/fin_settlement/:identity"},{"method":"PATCH","path":"/product_info/:identity/status"},{"method":"PATCH","path":"/product_info/:identity/lifecycle"},{"method":"PATCH","path":"/product_type/:identity/status"},{"method":"PATCH","path":"/product_warehouse/:identity/status"},{"method":"PATCH","path":"/product_repair/:identity/status"},{"method":"PATCH","path":"/platform_account/:identity/status"},{"method":"PATCH","path":"/platform_role/:identity/status"},{"method":"PATCH","path":"/ec_product_attribute/:identity/status"},{"method":"PATCH","path":"/ec_product_image/:identity/status"},{"method":"PATCH","path":"/ec_product/:identity/status"},{"method":"PATCH","path":"/ec_category/:identity/status"},{"method":"PATCH","path":"/user_account/:identity/status"},{"method":"PATCH","path":"/user_address/:identity/status"},{"method":"PATCH","path":"/user_service_relation/:identity/status"},{"method":"PATCH","path":"/gas_basic/:identity/status"},{"method":"PATCH","path":"/gas_account/:identity/status"},{"method":"PATCH","path":"/delivery_basic/:identity/status"},{"method":"PATCH","path":"/delivery_account/:identity/status"},{"method":"PATCH","path":"/staff_account/:identity/status"},{"method":"PATCH","path":"/staff_credential/:identity/status"},{"method":"PATCH","path":"/cms_content/:identity/status"},{"method":"PATCH","path":"/cs_ticket/:identity/status"},{"method":"PATCH","path":"/wallet_basic/:identity/status"},{"method":"PATCH","path":"/fin_settlement/:identity/status"},{"method":"DELETE","path":"/ec_product_attribute/:identity"},{"method":"DELETE","path":"/ec_product_image/:identity"},{"method":"DELETE","path":"/ec_product/:identity"},{"method":"DELETE","path":"/ec_category/:identity"},{"method":"DELETE","path":"/user_account/:identity"},{"method":"DELETE","path":"/user_address/:identity"},{"method":"DELETE","path":"/user_service_relation/:identity"},{"method":"DELETE","path":"/gas_basic/:identity"},{"method":"DELETE","path":"/gas_account/:identity"},{"method":"DELETE","path":"/delivery_basic/:identity"},{"method":"DELETE","path":"/delivery_account/:identity"},{"method":"DELETE","path":"/staff_account/:identity"},{"method":"DELETE","path":"/staff_credential/:identity"},{"method":"DELETE","path":"/cms_content/:identity"},{"method":"DELETE","path":"/cs_ticket/:identity"},{"method":"DELETE","path":"/platform_account/:identity"},{"method":"DELETE","path":"/platform_role/:identity"},{"method":"DELETE","path":"/fin_settlement/:identity"}]} +{"resources":[{"domain":"gas","name":"gas_basic","path":"/gas_basic","pageKind":"list","mode":"writable"},{"domain":"gas","name":"gas_account","path":"/gas_account","pageKind":"list","mode":"writable"},{"domain":"delivery","name":"delivery_basic","path":"/delivery_basic","pageKind":"list","mode":"writable"},{"domain":"delivery","name":"delivery_account","path":"/delivery_account","pageKind":"list","mode":"writable"},{"domain":"staff","name":"staff_account","path":"/staff_account","pageKind":"list","mode":"writable"},{"domain":"staff","name":"staff_credential","path":"/staff_credential","pageKind":"list","mode":"writable"},{"domain":"user","name":"user_account","path":"/user_account","pageKind":"list","mode":"writable"},{"domain":"user","name":"user_address","path":"/user_address","pageKind":"list","mode":"writable"},{"domain":"user","name":"user_service_relation","path":"/user_service_relation","pageKind":"list","mode":"writable"},{"domain":"product","name":"producer_account","path":"/producer_account","pageKind":"list","mode":"writable"},{"domain":"product","name":"product_type","path":"/product_type","pageKind":"list","mode":"editable"},{"domain":"product","name":"product_warehouse","path":"/product_warehouse","pageKind":"list","mode":"editable"},{"domain":"product","name":"product_info","path":"/product_info","pageKind":"list","mode":"editable"},{"domain":"product","name":"product_repair","path":"/product_repair","pageKind":"list","mode":"editable"},{"domain":"product","name":"product_owner","path":"/product_owner","pageKind":"list","mode":"readonly"},{"domain":"ec","name":"ec_category","path":"/ec_category","pageKind":"list","mode":"writable"},{"domain":"ec","name":"ec_product","path":"/ec_product","pageKind":"list","mode":"writable"},{"domain":"ec","name":"ec_product_attribute","path":"/ec_product_attribute","pageKind":"list","mode":"writable"},{"domain":"ec","name":"ec_product_image","path":"/ec_product_image","pageKind":"list","mode":"writable"},{"domain":"ec","name":"ec_cart","path":"/ec_cart","pageKind":"list","mode":"readonly"},{"domain":"ec","name":"ec_order","path":"/ec_order","pageKind":"list","mode":"readonly"},{"domain":"ec","name":"ec_order_item","path":"/ec_order_item","pageKind":"list","mode":"readonly"},{"domain":"ec","name":"ec_review","path":"/ec_review","pageKind":"list","mode":"readonly"},{"domain":"gasorder","name":"gasorder_contract","path":"/gasorder_contract","pageKind":"list","mode":"managed"},{"domain":"gasorder","name":"gasorder_contract_product","path":"/gasorder_contract_product","pageKind":"list","mode":"append_only"},{"domain":"gasorder","name":"gasorder_contract_revision","path":"/gasorder_contract_revision","pageKind":"list","mode":"readonly"},{"domain":"gasorder","name":"gasorder_basic","path":"/gasorder_basic","pageKind":"list","mode":"append_only"},{"domain":"gasorder","name":"gasorder_item","path":"/gasorder_item","pageKind":"list","mode":"readonly"},{"domain":"gasorder","name":"gasorder_assign","path":"/gasorder_assign","pageKind":"list","mode":"readonly"},{"domain":"gasorder","name":"gasorder_status","path":"/gasorder_status","pageKind":"list","mode":"readonly"},{"domain":"gasorder","name":"gasorder_track","path":"/gasorder_track","pageKind":"list","mode":"readonly"},{"domain":"gasorder","name":"gasorder_track_point","path":"/gasorder_track_point","pageKind":"list","mode":"readonly"},{"domain":"gasorder","name":"gasorder_confirm","path":"/gasorder_confirm","pageKind":"list","mode":"readonly"},{"domain":"gasorder","name":"gasorder_payment","path":"/gasorder_payment","pageKind":"list","mode":"readonly"},{"domain":"finance","name":"fin_payment","path":"/fin_payment","pageKind":"list","mode":"readonly"},{"domain":"finance","name":"fin_settlement","path":"/fin_settlement","pageKind":"list","mode":"writable"},{"domain":"finance","name":"fin_reconciliation","path":"/fin_reconciliation","pageKind":"list","mode":"readonly"},{"domain":"content","name":"cms_content","path":"/cms_content","pageKind":"list","mode":"writable"},{"domain":"customer_service","name":"cs_ticket","path":"/cs_ticket","pageKind":"list","mode":"writable"},{"domain":"platform","name":"platform_account","path":"/platform_account","pageKind":"list","mode":"writable"},{"domain":"platform","name":"platform_role","path":"/platform_role","pageKind":"list","mode":"writable"},{"domain":"platform","name":"platform_menu","path":"/platform_menu","pageKind":"tree","mode":"readonly"},{"domain":"wallet","name":"wallet_basic","path":"/wallet_basic","pageKind":"list","mode":"readonly"},{"domain":"wallet","name":"wallet_bank","path":"/wallet_bank","pageKind":"list","mode":"readonly"},{"domain":"wallet","name":"payment_order","path":"/payment_order","pageKind":"list","mode":"readonly"},{"domain":"wallet","name":"wallet_record","path":"/wallet_record","pageKind":"list","mode":"readonly"},{"domain":"wallet","name":"payment_refund","path":"/payment_refund","pageKind":"list","mode":"readonly"},{"domain":"wallet","name":"wallet_apply_cash","path":"/wallet_apply_cash","pageKind":"list","mode":"readonly"}],"routes":[{"method":"GET","path":"/gasorder_contract"},{"method":"GET","path":"/gasorder_contract_product"},{"method":"GET","path":"/gasorder_contract_product/:identity"},{"method":"GET","path":"/gasorder_contract_revision"},{"method":"GET","path":"/gasorder_contract_revision/:identity"},{"method":"GET","path":"/gasorder_contract/:identity"},{"method":"GET","path":"/gasorder_confirm"},{"method":"GET","path":"/gasorder_confirm/:identity"},{"method":"GET","path":"/gasorder_track"},{"method":"GET","path":"/gasorder_track_point"},{"method":"GET","path":"/gasorder_track_point/:identity"},{"method":"GET","path":"/gasorder_track/:identity"},{"method":"GET","path":"/gasorder_basic"},{"method":"GET","path":"/gasorder_basic/:identity"},{"method":"GET","path":"/gasorder_item"},{"method":"GET","path":"/gasorder_item/:identity"},{"method":"GET","path":"/gasorder_assign"},{"method":"GET","path":"/gasorder_assign/:identity"},{"method":"GET","path":"/gasorder_status"},{"method":"GET","path":"/gasorder_status/:identity"},{"method":"GET","path":"/gasorder_payment"},{"method":"GET","path":"/gasorder_payment/:identity"},{"method":"GET","path":"/gas_basic"},{"method":"GET","path":"/gas_basic/:identity"},{"method":"GET","path":"/gas_account"},{"method":"GET","path":"/gas_account/:identity"},{"method":"GET","path":"/product_type"},{"method":"GET","path":"/product_type/:identity"},{"method":"GET","path":"/product_warehouse"},{"method":"GET","path":"/product_warehouse/:identity"},{"method":"GET","path":"/product_info"},{"method":"GET","path":"/product_info/:identity"},{"method":"GET","path":"/product_repair"},{"method":"GET","path":"/product_repair/:identity"},{"method":"GET","path":"/product_owner"},{"method":"GET","path":"/product_owner/:identity"},{"method":"GET","path":"/producer_account"},{"method":"GET","path":"/producer_account/:identity"},{"method":"GET","path":"/platform_role"},{"method":"GET","path":"/platform_role/:identity"},{"method":"GET","path":"/platform_role/:identity/menu"},{"method":"GET","path":"/platform_account"},{"method":"GET","path":"/platform_account/:identity"},{"method":"GET","path":"/platform_menu"},{"method":"GET","path":"/platform_menu/:identity"},{"method":"GET","path":"/payment_order"},{"method":"GET","path":"/payment_order/:identity"},{"method":"GET","path":"/payment_refund"},{"method":"GET","path":"/payment_refund/:identity"},{"method":"GET","path":"/ping/hello"},{"method":"GET","path":"/ec_product"},{"method":"GET","path":"/ec_product_attribute"},{"method":"GET","path":"/ec_product_attribute/:identity"},{"method":"GET","path":"/ec_product_image"},{"method":"GET","path":"/ec_product_image/:identity"},{"method":"GET","path":"/ec_product/:identity"},{"method":"GET","path":"/ec_category"},{"method":"GET","path":"/ec_category/:identity"},{"method":"GET","path":"/ec_cart"},{"method":"GET","path":"/ec_cart/:identity"},{"method":"GET","path":"/ec_order"},{"method":"GET","path":"/ec_order_item"},{"method":"GET","path":"/ec_order_item/:identity"},{"method":"GET","path":"/ec_order/:identity"},{"method":"GET","path":"/ec_review"},{"method":"GET","path":"/ec_review/:identity"},{"method":"GET","path":"/wallet_basic"},{"method":"GET","path":"/wallet_basic/:identity"},{"method":"GET","path":"/wallet_bank"},{"method":"GET","path":"/wallet_bank/:identity"},{"method":"GET","path":"/wallet_record"},{"method":"GET","path":"/wallet_record/:identity"},{"method":"GET","path":"/wallet_apply_cash"},{"method":"GET","path":"/wallet_apply_cash/:identity"},{"method":"GET","path":"/user_account"},{"method":"GET","path":"/user_account/:identity"},{"method":"GET","path":"/user_address"},{"method":"GET","path":"/user_address/:identity"},{"method":"GET","path":"/user_service_relation"},{"method":"GET","path":"/user_service_relation/:identity"},{"method":"GET","path":"/fin_payment"},{"method":"GET","path":"/fin_payment/:identity"},{"method":"GET","path":"/fin_settlement"},{"method":"GET","path":"/fin_settlement/:identity"},{"method":"GET","path":"/fin_reconciliation"},{"method":"GET","path":"/fin_reconciliation/:identity"},{"method":"GET","path":"/delivery_basic"},{"method":"GET","path":"/delivery_basic/:identity"},{"method":"GET","path":"/delivery_account"},{"method":"GET","path":"/delivery_account/:identity"},{"method":"GET","path":"/dashboard/overview"},{"method":"GET","path":"/staff_account"},{"method":"GET","path":"/staff_account/:identity"},{"method":"GET","path":"/staff_credential"},{"method":"GET","path":"/staff_credential/:identity"},{"method":"GET","path":"/cms_content"},{"method":"GET","path":"/cms_content/:identity"},{"method":"GET","path":"/cs_ticket"},{"method":"GET","path":"/cs_ticket/:identity"},{"method":"GET","path":"/auth/profile"},{"method":"POST","path":"/gasorder_basic"},{"method":"POST","path":"/gasorder_basic/:identity/assign"},{"method":"POST","path":"/gasorder_basic/:identity/awaiting-confirmation"},{"method":"POST","path":"/gasorder_basic/:identity/ready"},{"method":"POST","path":"/gasorder_basic/:identity/recover"},{"method":"POST","path":"/gasorder_basic/:identity/complete"},{"method":"POST","path":"/gasorder_basic/:identity/cancel"},{"method":"POST","path":"/gasorder_basic/:identity/filling"},{"method":"POST","path":"/gasorder_basic/:identity/delivering"},{"method":"POST","path":"/gasorder_basic/:identity/exception"},{"method":"POST","path":"/gasorder_contract"},{"method":"POST","path":"/gasorder_contract/:identity/activate"},{"method":"POST","path":"/gasorder_contract/:identity/renew"},{"method":"POST","path":"/gasorder_contract/:identity/terminate"},{"method":"POST","path":"/gasorder_contract_product"},{"method":"POST","path":"/gasorder_contract_product/:identity/unbind"},{"method":"POST","path":"/gas_basic"},{"method":"POST","path":"/gas_basic/:identity/review"},{"method":"POST","path":"/gas_account"},{"method":"POST","path":"/product_type"},{"method":"POST","path":"/product_warehouse"},{"method":"POST","path":"/product_info"},{"method":"POST","path":"/product_repair"},{"method":"POST","path":"/producer_account"},{"method":"POST","path":"/payment_refund/:identity/approve"},{"method":"POST","path":"/payment_refund/:identity/reject"},{"method":"POST","path":"/platform_account"},{"method":"POST","path":"/platform_role"},{"method":"POST","path":"/wallet_apply_cash/:identity/approve"},{"method":"POST","path":"/wallet_apply_cash/:identity/reject"},{"method":"POST","path":"/wallet_apply_cash/:identity/complete"},{"method":"POST","path":"/wallet_basic/owner/:owner_type/:owner_identity"},{"method":"POST","path":"/wallet_basic/:identity/recharge"},{"method":"POST","path":"/ec_product"},{"method":"POST","path":"/ec_product_attribute"},{"method":"POST","path":"/ec_product_image"},{"method":"POST","path":"/ec_category"},{"method":"POST","path":"/user_account"},{"method":"POST","path":"/user_address"},{"method":"POST","path":"/user_service_relation"},{"method":"POST","path":"/delivery_basic"},{"method":"POST","path":"/delivery_account"},{"method":"POST","path":"/staff_account"},{"method":"POST","path":"/staff_credential"},{"method":"POST","path":"/cms_content"},{"method":"POST","path":"/cs_ticket"},{"method":"POST","path":"/auth/login"},{"method":"POST","path":"/fin_settlement"},{"method":"PUT","path":"/product_type/:identity"},{"method":"PUT","path":"/product_warehouse/:identity"},{"method":"PUT","path":"/product_info/:identity"},{"method":"PUT","path":"/product_repair/:identity"},{"method":"PUT","path":"/producer_account/:identity"},{"method":"PUT","path":"/platform_role/:identity"},{"method":"PUT","path":"/platform_role/:identity/menu"},{"method":"PUT","path":"/platform_account/:identity"},{"method":"PUT","path":"/ec_product_attribute/:identity"},{"method":"PUT","path":"/ec_product_image/:identity"},{"method":"PUT","path":"/ec_product/:identity"},{"method":"PUT","path":"/ec_category/:identity"},{"method":"PUT","path":"/gas_basic/:identity"},{"method":"PUT","path":"/gas_account/:identity"},{"method":"PUT","path":"/gasorder_contract/:identity"},{"method":"PUT","path":"/user_account/:identity"},{"method":"PUT","path":"/user_address/:identity"},{"method":"PUT","path":"/user_service_relation/:identity"},{"method":"PUT","path":"/delivery_basic/:identity"},{"method":"PUT","path":"/delivery_account/:identity"},{"method":"PUT","path":"/staff_account/:identity"},{"method":"PUT","path":"/staff_credential/:identity"},{"method":"PUT","path":"/cms_content/:identity"},{"method":"PUT","path":"/cs_ticket/:identity"},{"method":"PUT","path":"/auth/password"},{"method":"PUT","path":"/fin_settlement/:identity"},{"method":"PATCH","path":"/product_info/:identity/status"},{"method":"PATCH","path":"/product_info/:identity/lifecycle"},{"method":"PATCH","path":"/product_type/:identity/status"},{"method":"PATCH","path":"/product_warehouse/:identity/status"},{"method":"PATCH","path":"/product_repair/:identity/status"},{"method":"PATCH","path":"/producer_account/:identity/status"},{"method":"PATCH","path":"/platform_account/:identity/status"},{"method":"PATCH","path":"/platform_role/:identity/status"},{"method":"PATCH","path":"/ec_product_attribute/:identity/status"},{"method":"PATCH","path":"/ec_product_image/:identity/status"},{"method":"PATCH","path":"/ec_product/:identity/status"},{"method":"PATCH","path":"/ec_category/:identity/status"},{"method":"PATCH","path":"/user_account/:identity/status"},{"method":"PATCH","path":"/user_address/:identity/status"},{"method":"PATCH","path":"/user_service_relation/:identity/status"},{"method":"PATCH","path":"/gas_basic/:identity/status"},{"method":"PATCH","path":"/gas_account/:identity/status"},{"method":"PATCH","path":"/delivery_basic/:identity/status"},{"method":"PATCH","path":"/delivery_account/:identity/status"},{"method":"PATCH","path":"/staff_account/:identity/status"},{"method":"PATCH","path":"/staff_credential/:identity/status"},{"method":"PATCH","path":"/cms_content/:identity/status"},{"method":"PATCH","path":"/cs_ticket/:identity/status"},{"method":"PATCH","path":"/wallet_basic/:identity/status"},{"method":"PATCH","path":"/fin_settlement/:identity/status"},{"method":"DELETE","path":"/ec_product_attribute/:identity"},{"method":"DELETE","path":"/ec_product_image/:identity"},{"method":"DELETE","path":"/ec_product/:identity"},{"method":"DELETE","path":"/ec_category/:identity"},{"method":"DELETE","path":"/user_account/:identity"},{"method":"DELETE","path":"/user_address/:identity"},{"method":"DELETE","path":"/user_service_relation/:identity"},{"method":"DELETE","path":"/platform_account/:identity"},{"method":"DELETE","path":"/platform_role/:identity"},{"method":"DELETE","path":"/producer_account/:identity"},{"method":"DELETE","path":"/gas_basic/:identity"},{"method":"DELETE","path":"/gas_account/:identity"},{"method":"DELETE","path":"/delivery_basic/:identity"},{"method":"DELETE","path":"/delivery_account/:identity"},{"method":"DELETE","path":"/staff_account/:identity"},{"method":"DELETE","path":"/staff_credential/:identity"},{"method":"DELETE","path":"/cms_content/:identity"},{"method":"DELETE","path":"/cs_ticket/:identity"},{"method":"DELETE","path":"/fin_settlement/:identity"}]} diff --git a/frontend/platform_admin/src/router/routes/modules/platform.ts b/frontend/platform_admin/src/router/routes/modules/platform.ts index 7e2ebe9..4d6fd62 100644 --- a/frontend/platform_admin/src/router/routes/modules/platform.ts +++ b/frontend/platform_admin/src/router/routes/modules/platform.ts @@ -81,6 +81,7 @@ const routes: AppRouteRecordRaw[] = [ child('user', 'contract-revisions', 'contract-revisions', '合同修订记录', '/gasorder_contract_revision', 'gasorder_contract', true, 'user-contracts'), ]), group('product', 'product', '智能气阀管理', 'icon-common', 50, [ + child('product', 'producers', 'producers', '生产商管理', '/producer_account', 'producer_account'), child('product', 'product-type', 'type', '类型管理', '/product_type', 'product_type'), child('product', 'warehouse', 'warehouse', '库房管理', '/product_warehouse', 'product_warehouse'), child('product', 'product-info', 'info', '智能气阀管理', '/product_info', 'product_info'), diff --git a/frontend/platform_admin/src/views/login/components/login-form.vue b/frontend/platform_admin/src/views/login/components/login-form.vue index 7ae824a..8146940 100644 --- a/frontend/platform_admin/src/views/login/components/login-form.vue +++ b/frontend/platform_admin/src/views/login/components/login-form.vue @@ -82,7 +82,7 @@ const userStore = useUserStore(); const loginConfig = useStorage('login-config', { rememberPassword: true, - username: 'admin', + username: '', password: '', }); const userInfo = reactive({