refactor platform menus and entity statuses
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"git.apinb.com/heqiapp/platforms/backend/api/internal/logic/common"
|
||||||
"git.apinb.com/heqiapp/platforms/backend/api/internal/models"
|
"git.apinb.com/heqiapp/platforms/backend/api/internal/models"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
@@ -18,44 +19,16 @@ const (
|
|||||||
PlatformRootRoleCode = "root"
|
PlatformRootRoleCode = "root"
|
||||||
)
|
)
|
||||||
|
|
||||||
// InitPlatformAccess 幂等初始化 root 角色、菜单和 root 的全菜单授权。
|
// InitPlatformAccess 幂等初始化 root 角色;菜单定义位于逻辑层静态数据中。
|
||||||
func InitPlatformAccess(database *gorm.DB) error {
|
func InitPlatformAccess(database *gorm.DB) error {
|
||||||
rootRole := models.PlatformRole{
|
rootRole := models.PlatformRole{
|
||||||
Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled", Version: 1},
|
Entity: models.Entity{Identity: models.NewIdentity(), Status: common.StatusEnable, Version: 1},
|
||||||
RoleCode: PlatformRootRoleCode,
|
RoleCode: PlatformRootRoleCode,
|
||||||
Name: "系统管理员",
|
Name: "系统管理员",
|
||||||
DataScope: "global",
|
DataScope: "global",
|
||||||
IsSystem: true,
|
IsSystem: true,
|
||||||
}
|
}
|
||||||
if err := database.Where("role_code = ?", rootRole.RoleCode).FirstOrCreate(&rootRole).Error; err != nil {
|
return database.Where("role_code = ?", rootRole.RoleCode).FirstOrCreate(&rootRole).Error
|
||||||
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: "device", Name: "设备管理", Icon: "icon-storage", Path: "/device", SortNo: 60},
|
|
||||||
{Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled", Version: 1}, MenuCode: "ec", Name: "电商管理", Icon: "icon-shopping", Path: "/ec/product", SortNo: 80},
|
|
||||||
{Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled", Version: 1}, MenuCode: "finance", Name: "财务管理", Icon: "icon-safe", Path: "/finance/payment", SortNo: 90},
|
|
||||||
{Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled", Version: 1}, MenuCode: "wallet", Name: "钱包中心", Icon: "icon-wallet", Path: "/wallet/list", SortNo: 100},
|
|
||||||
{Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled", Version: 1}, MenuCode: "content", Name: "内容管理", Icon: "icon-file", Path: "/content", SortNo: 120},
|
|
||||||
{Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled", Version: 1}, MenuCode: "customer_service", Name: "客户服务", Icon: "icon-customer-service", Path: "/customer_service", SortNo: 140},
|
|
||||||
{Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled", Version: 1}, MenuCode: "platform", Name: "平台配置", Icon: "icon-settings", Path: "/platform/account", SortNo: 160},
|
|
||||||
}
|
|
||||||
for index := range menus {
|
|
||||||
menu := menus[index]
|
|
||||||
if err := database.Where("menu_code = ?", menu.MenuCode).FirstOrCreate(&menu).Error; err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
relation := models.PlatformRoleMenu{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 账号。
|
// InitPlatformRoot 幂等创建平台总后台 root 账号。
|
||||||
@@ -75,7 +48,7 @@ func InitPlatformRoot(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
account = models.PlatformAccount{
|
account = models.PlatformAccount{
|
||||||
Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled"},
|
Entity: models.Entity{Identity: models.NewIdentity(), Status: common.StatusEnable},
|
||||||
Username: PlatformRootUsername,
|
Username: PlatformRootUsername,
|
||||||
DisplayName: "平台根管理员",
|
DisplayName: "平台根管理员",
|
||||||
PasswordHash: string(passwordHash),
|
PasswordHash: string(passwordHash),
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestInitPlatformAccessSeedsEveryProtectedFrontendDomain(t *testing.T) {
|
func TestInitPlatformAccessSeedsRootRole(t *testing.T) {
|
||||||
sqlDatabase, mock, err := sqlmock.New()
|
sqlDatabase, mock, err := sqlmock.New()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -23,23 +23,7 @@ func TestInitPlatformAccessSeedsEveryProtectedFrontendDomain(t *testing.T) {
|
|||||||
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 ORDER BY "platform_role"."id" LIMIT $2`)).
|
||||||
WithArgs("root", 1).
|
WithArgs("root", 1).
|
||||||
WillReturnRows(sqlmock.NewRows([]string{"id", "identity", "status", "version", "role_code", "name", "data_scope", "is_system"}).
|
WillReturnRows(sqlmock.NewRows([]string{"id", "identity", "status", "version", "role_code", "name", "data_scope", "is_system"}).
|
||||||
AddRow(uint64(1), "root-role", "enabled", 1, "root", "Root", "global", true))
|
AddRow(uint64(1), "root-role", 1, 1, "root", "Root", "global", true))
|
||||||
|
|
||||||
domains := []string{
|
|
||||||
"dashboard", "gas", "delivery", "staff", "user", "device",
|
|
||||||
"ec", "finance", "wallet", "content", "customer_service", "platform",
|
|
||||||
}
|
|
||||||
for index, domain := range domains {
|
|
||||||
menuID := uint64(index + 10)
|
|
||||||
mock.ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "platform_menu" WHERE menu_code = $1 ORDER BY "platform_menu"."id" LIMIT $2`)).
|
|
||||||
WithArgs(domain, 1).
|
|
||||||
WillReturnRows(sqlmock.NewRows([]string{"id", "identity", "status", "version", "parent_id", "menu_code", "name", "icon", "path", "sort_no"}).
|
|
||||||
AddRow(menuID, domain+"-menu", "enabled", 1, uint64(0), domain, domain, "", "/"+domain, index))
|
|
||||||
mock.ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "platform_role_menu" WHERE platform_role_id = $1 AND platform_menu_id = $2 ORDER BY "platform_role_menu"."id" LIMIT $3`)).
|
|
||||||
WithArgs(uint64(1), menuID, 1).
|
|
||||||
WillReturnRows(sqlmock.NewRows([]string{"id", "platform_role_id", "platform_menu_id"}).
|
|
||||||
AddRow(uint64(index+100), uint64(1), menuID))
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := InitPlatformAccess(database); err != nil {
|
if err := InitPlatformAccess(database); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ func FilterFields(values map[string]any, allowedFields []string) gin.H {
|
|||||||
// UpdateRecordStatus 更新主表状态,停用和归档均保留历史记录。
|
// UpdateRecordStatus 更新主表状态,停用和归档均保留历史记录。
|
||||||
func UpdateRecordStatus(ctx *gin.Context, model any) {
|
func UpdateRecordStatus(ctx *gin.Context, model any) {
|
||||||
var request struct {
|
var request struct {
|
||||||
Status string `json:"status" binding:"required,max=32"`
|
Status int `json:"status" binding:"required"`
|
||||||
}
|
}
|
||||||
if err := ctx.ShouldBindJSON(&request); err != nil {
|
if err := ctx.ShouldBindJSON(&request); err != nil {
|
||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||||||
@@ -51,10 +51,10 @@ func UpdateRecordStatus(ctx *gin.Context, model any) {
|
|||||||
|
|
||||||
// ArchiveRecord 通过 archived 状态实现逻辑删除,不物理删除主数据。
|
// ArchiveRecord 通过 archived 状态实现逻辑删除,不物理删除主数据。
|
||||||
func ArchiveRecord(ctx *gin.Context, model any) {
|
func ArchiveRecord(ctx *gin.Context, model any) {
|
||||||
UpdateAllowedByIdentity(ctx, model, gin.H{"status": "archived"}, []string{"status"})
|
UpdateAllowedByIdentity(ctx, model, gin.H{"status": StatusArchived}, []string{"status"})
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEntity(status string) models.Entity {
|
func NewEntity(status int) models.Entity {
|
||||||
return models.Entity{Identity: models.NewIdentity(), Status: status, Version: 1}
|
return models.Entity{Identity: models.NewIdentity(), Status: status, Version: 1}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import (
|
|||||||
"git.apinb.com/bsm-sdk/core/errcode"
|
"git.apinb.com/bsm-sdk/core/errcode"
|
||||||
"git.apinb.com/bsm-sdk/core/infra"
|
"git.apinb.com/bsm-sdk/core/infra"
|
||||||
"git.apinb.com/bsm-sdk/core/middleware"
|
"git.apinb.com/bsm-sdk/core/middleware"
|
||||||
"git.apinb.com/heqiapp/platforms/backend/api/internal/impl"
|
|
||||||
"git.apinb.com/heqiapp/platforms/backend/api/internal/models"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -18,24 +16,3 @@ func RequirePlatformRoot(ctx *gin.Context) bool {
|
|||||||
infra.Response.Error(ctx, errcode.ErrPermissionDenied)
|
infra.Response.Error(ctx, errcode.ErrPermissionDenied)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadPlatformMenus returns the menus granted to one platform role.
|
|
||||||
func LoadPlatformMenus(roleCode string) ([]models.PlatformMenu, error) {
|
|
||||||
var menus []models.PlatformMenu
|
|
||||||
if roleCode == "root" {
|
|
||||||
err := impl.DBService.Order("sort_no asc, id asc").Find(&menus).Error
|
|
||||||
return menus, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var role models.PlatformRole
|
|
||||||
if err := impl.DBService.Where("role_code = ? AND status = ?", roleCode, "enabled").First(&role).Error; err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err := impl.DBService.
|
|
||||||
Select("platform_menu.*").
|
|
||||||
Joins("JOIN platform_role_menu ON platform_role_menu.platform_menu_id = platform_menu.id").
|
|
||||||
Where("platform_role_menu.platform_role_id = ? AND platform_menu.status = ?", role.ID, "enabled").
|
|
||||||
Order("sort_no asc, id asc").
|
|
||||||
Find(&menus).Error
|
|
||||||
return menus, err
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ func createResource(ctx *gin.Context, model any, allowedFields []string, relatio
|
|||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
data.Elem().FieldByName("Entity").Set(reflect.ValueOf(NewEntity("draft")))
|
data.Elem().FieldByName("Entity").Set(reflect.ValueOf(NewEntity(StatusDraft)))
|
||||||
if err := impl.DBService.Create(data.Interface()).Error; err != nil {
|
if err := impl.DBService.Create(data.Interface()).Error; err != nil {
|
||||||
infra.Response.Error(ctx, err)
|
infra.Response.Error(ctx, err)
|
||||||
return
|
return
|
||||||
@@ -347,7 +347,6 @@ var relationIdentityModels = map[string]any{
|
|||||||
"gasorder_basic_id": &models.GasorderBasic{},
|
"gasorder_basic_id": &models.GasorderBasic{},
|
||||||
"gasorder_track_id": &models.GasorderTrack{},
|
"gasorder_track_id": &models.GasorderTrack{},
|
||||||
"platform_role_id": &models.PlatformRole{},
|
"platform_role_id": &models.PlatformRole{},
|
||||||
"platform_menu_id": &models.PlatformMenu{},
|
|
||||||
"wallet_basic_id": &models.WalletBasic{},
|
"wallet_basic_id": &models.WalletBasic{},
|
||||||
"wallet_payment_id": &models.WalletPayment{},
|
"wallet_payment_id": &models.WalletPayment{},
|
||||||
"wallet_bank_id": &models.WalletBank{},
|
"wallet_bank_id": &models.WalletBank{},
|
||||||
|
|||||||
55
backend/api/internal/logic/common/status.go
Normal file
55
backend/api/internal/logic/common/status.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
// 公共实体状态。所有嵌入 models.Entity 的模型统一使用这些整数值。
|
||||||
|
const (
|
||||||
|
StatusDraft = 0 // 草稿
|
||||||
|
StatusEnable = 1 // 启用
|
||||||
|
StatusDisable = 2 // 停用
|
||||||
|
StatusArchived = 3 // 已归档
|
||||||
|
StatusFrozen = 4 // 已冻结
|
||||||
|
|
||||||
|
StatusPending = 10 // 待处理
|
||||||
|
StatusActive = 11 // 生效中
|
||||||
|
StatusExpired = 12 // 已过期
|
||||||
|
StatusTerminated = 13 // 已终止
|
||||||
|
StatusRecorded = 14 // 已记录
|
||||||
|
StatusBound = 15 // 已绑定
|
||||||
|
StatusCreated = 16 // 已创建
|
||||||
|
StatusOrdered = 17 // 已下单
|
||||||
|
StatusAssigned = 18 // 已分配
|
||||||
|
StatusFilling = 19 // 充装中
|
||||||
|
StatusReady = 20 // 已就绪
|
||||||
|
StatusException = 21 // 异常
|
||||||
|
StatusCancelled = 22 // 已取消
|
||||||
|
StatusCompleted = 23 // 已完成
|
||||||
|
StatusPosted = 24 // 已入账
|
||||||
|
StatusApproved = 25 // 已通过
|
||||||
|
StatusRejected = 26 // 已驳回
|
||||||
|
StatusScrapped = 27 // 已报废
|
||||||
|
StatusInStock = 28 // 在库
|
||||||
|
StatusInTransit = 29 // 运输中
|
||||||
|
StatusInUse = 30 // 使用中
|
||||||
|
StatusRepairing = 31 // 维修中
|
||||||
|
StatusOpen = 32 // 待受理
|
||||||
|
StatusDelivering = 33 // 配送中
|
||||||
|
StatusAwaitingConfirmation = 34 // 待确认
|
||||||
|
StatusPaid = 35 // 已支付
|
||||||
|
StatusPublished = 36 // 已发布
|
||||||
|
StatusSuccess = 37 // 成功
|
||||||
|
StatusMatched = 38 // 已匹配
|
||||||
|
)
|
||||||
|
|
||||||
|
var statusNames = map[int]string{
|
||||||
|
StatusDraft: "draft", StatusEnable: "enabled", StatusDisable: "disabled", StatusArchived: "archived", StatusFrozen: "frozen",
|
||||||
|
StatusPending: "pending", StatusActive: "active", StatusExpired: "expired", StatusTerminated: "terminated",
|
||||||
|
StatusRecorded: "recorded", StatusBound: "bound", StatusCreated: "created", StatusOrdered: "ordered",
|
||||||
|
StatusAssigned: "assigned", StatusFilling: "filling", StatusReady: "ready", StatusException: "exception",
|
||||||
|
StatusCancelled: "cancelled", StatusCompleted: "completed", StatusPosted: "posted", StatusApproved: "approved",
|
||||||
|
StatusRejected: "rejected", StatusScrapped: "scrapped", StatusInStock: "in_stock", StatusInTransit: "in_transit",
|
||||||
|
StatusInUse: "in_use", StatusRepairing: "repairing", StatusOpen: "open", StatusDelivering: "delivering",
|
||||||
|
StatusAwaitingConfirmation: "awaiting_confirmation",
|
||||||
|
StatusPaid: "paid", StatusPublished: "published", StatusSuccess: "success", StatusMatched: "matched",
|
||||||
|
}
|
||||||
|
|
||||||
|
// StatusName 返回状态整数对应的稳定英文名称,供审计快照字段使用。
|
||||||
|
func StatusName(status int) string { return statusNames[status] }
|
||||||
@@ -49,7 +49,7 @@ func Login(ctx *gin.Context) {
|
|||||||
infra.Response.Error(ctx, err)
|
infra.Response.Error(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if account.Status != "enabled" {
|
if account.Status != common.StatusEnable {
|
||||||
infra.Response.Error(ctx, errcode.ErrAccountDisabled)
|
infra.Response.Error(ctx, errcode.ErrAccountDisabled)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -91,7 +91,7 @@ func CurrentProfile(ctx *gin.Context) {
|
|||||||
infra.Response.Error(ctx, errcode.ErrRecordNotFound)
|
infra.Response.Error(ctx, errcode.ErrRecordNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
menus, err := common.LoadPlatformMenus(account.PlatformRoleCode)
|
menus, err := LoadPlatformMenus(account.PlatformRoleCode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
infra.Response.Error(ctx, errcode.ErrPermissionDenied)
|
infra.Response.Error(ctx, errcode.ErrPermissionDenied)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ func CreateDeliveryAccount(ctx *gin.Context) {
|
|||||||
infra.Response.Error(ctx, err)
|
infra.Response.Error(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
account := models.DeliveryAccount{Entity: common.NewEntity("enabled"), DeliveryBasicID: deliveryBasicID, Username: request.Username, DisplayName: request.DisplayName, PasswordHash: hash, RoleCode: request.RoleCode}
|
account := models.DeliveryAccount{Entity: common.NewEntity(common.StatusEnable), DeliveryBasicID: deliveryBasicID, Username: request.Username, DisplayName: request.DisplayName, PasswordHash: hash, RoleCode: request.RoleCode}
|
||||||
if err := impl.DBService.Create(&account).Error; err != nil {
|
if err := impl.DBService.Create(&account).Error; err != nil {
|
||||||
infra.Response.Error(ctx, err)
|
infra.Response.Error(ctx, err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ func CreateDeliveryBasic(ctx *gin.Context) {
|
|||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
delivery := models.DeliveryBasic{Entity: common.NewEntity("draft"), DeliveryCode: request.DeliveryCode, GasBasicID: gasBasicID, Name: request.Name, Principal: request.Principal, Address: request.Address}
|
delivery := models.DeliveryBasic{Entity: common.NewEntity(common.StatusDraft), DeliveryCode: request.DeliveryCode, GasBasicID: gasBasicID, Name: request.Name, Principal: request.Principal, Address: request.Address}
|
||||||
if err := impl.DBService.Create(&delivery).Error; err != nil {
|
if err := impl.DBService.Create(&delivery).Error; err != nil {
|
||||||
infra.Response.Error(ctx, err)
|
infra.Response.Error(ctx, err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ type ecCategoryView struct {
|
|||||||
ParentIdentity string `json:"parent_identity,omitempty"`
|
ParentIdentity string `json:"parent_identity,omitempty"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
SortNo int `json:"sort_no"`
|
SortNo int `json:"sort_no"`
|
||||||
Status string `json:"status"`
|
Status int `json:"status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func ecCategoryViews(list []models.EcCategory) ([]ecCategoryView, error) {
|
func ecCategoryViews(list []models.EcCategory) ([]ecCategoryView, error) {
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ func CreateGasAccount(ctx *gin.Context) {
|
|||||||
infra.Response.Error(ctx, err)
|
infra.Response.Error(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
account := models.GasAccount{Entity: common.NewEntity("enabled"), GasBasicID: gasBasicID, Username: request.Username, DisplayName: request.DisplayName, PasswordHash: hash, RoleCode: request.RoleCode}
|
account := models.GasAccount{Entity: common.NewEntity(common.StatusEnable), GasBasicID: gasBasicID, Username: request.Username, DisplayName: request.DisplayName, PasswordHash: hash, RoleCode: request.RoleCode}
|
||||||
if err := impl.DBService.Create(&account).Error; err != nil {
|
if err := impl.DBService.Create(&account).Error; err != nil {
|
||||||
infra.Response.Error(ctx, err)
|
infra.Response.Error(ctx, err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ func CreateGasBasic(ctx *gin.Context) {
|
|||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
request.Entity = common.NewEntity("draft")
|
request.Entity = common.NewEntity(common.StatusDraft)
|
||||||
if err := impl.DBService.Create(&request).Error; err != nil {
|
if err := impl.DBService.Create(&request).Error; err != nil {
|
||||||
infra.Response.Error(ctx, err)
|
infra.Response.Error(ctx, err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ func CreateGasorderContract(ctx *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
contract := models.GasorderContract{
|
contract := models.GasorderContract{
|
||||||
Entity: models.Entity{Identity: models.NewIdentity(), Status: "draft", Version: 1},
|
Entity: models.Entity{Identity: models.NewIdentity(), Status: common.StatusDraft, Version: 1},
|
||||||
ContractNo: request.ContractNo, UserAccountID: userID, GasBasicID: gasID, DeliveryBasicID: deliveryID,
|
ContractNo: request.ContractNo, UserAccountID: userID, GasBasicID: gasID, DeliveryBasicID: deliveryID,
|
||||||
Title: request.Title, Terms: request.Terms, FileURI: request.FileURI, DefaultDeliveryFee: request.DefaultDeliveryFee,
|
Title: request.Title, Terms: request.Terms, FileURI: request.FileURI, DefaultDeliveryFee: request.DefaultDeliveryFee,
|
||||||
SignedAt: request.SignedAt, EffectiveAt: request.EffectiveAt, ExpiredAt: request.ExpiredAt,
|
SignedAt: request.SignedAt, EffectiveAt: request.EffectiveAt, ExpiredAt: request.ExpiredAt,
|
||||||
@@ -182,7 +182,7 @@ func UpdateGasorderContract(ctx *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
result := impl.DBService.Model(&models.GasorderContract{}).
|
result := impl.DBService.Model(&models.GasorderContract{}).
|
||||||
Where("identity = ? AND status = ?", ctx.Param("identity"), "draft").
|
Where("identity = ? AND status = ?", ctx.Param("identity"), common.StatusDraft).
|
||||||
Updates(map[string]any{"delivery_basic_id": deliveryID, "title": request.Title, "terms": request.Terms,
|
Updates(map[string]any{"delivery_basic_id": deliveryID, "title": request.Title, "terms": request.Terms,
|
||||||
"file_uri": request.FileURI, "default_delivery_fee": request.DefaultDeliveryFee,
|
"file_uri": request.FileURI, "default_delivery_fee": request.DefaultDeliveryFee,
|
||||||
"signed_at": request.SignedAt, "effective_at": request.EffectiveAt, "expired_at": request.ExpiredAt})
|
"signed_at": request.SignedAt, "effective_at": request.EffectiveAt, "expired_at": request.ExpiredAt})
|
||||||
@@ -194,11 +194,11 @@ func UpdateGasorderContract(ctx *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ActivateGasorderContract(ctx *gin.Context) {
|
func ActivateGasorderContract(ctx *gin.Context) {
|
||||||
changeGasorderContract(ctx, "activate", "active")
|
changeGasorderContract(ctx, "activate", common.StatusActive)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TerminateGasorderContract(ctx *gin.Context) {
|
func TerminateGasorderContract(ctx *gin.Context) {
|
||||||
changeGasorderContract(ctx, "terminate", "terminated")
|
changeGasorderContract(ctx, "terminate", common.StatusTerminated)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RenewGasorderContract(ctx *gin.Context) {
|
func RenewGasorderContract(ctx *gin.Context) {
|
||||||
@@ -218,13 +218,13 @@ func RenewGasorderContract(ctx *gin.Context) {
|
|||||||
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).Where("identity = ?", ctx.Param("identity")).First(&contract).Error; err != nil {
|
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).Where("identity = ?", ctx.Param("identity")).First(&contract).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if contract.Status != "active" && contract.Status != "expired" && contract.Status != "terminated" {
|
if contract.Status != common.StatusActive && contract.Status != common.StatusExpired && contract.Status != common.StatusTerminated {
|
||||||
return errors.New("contract cannot be renewed")
|
return errors.New("contract cannot be renewed")
|
||||||
}
|
}
|
||||||
if err := tx.Model(&contract).Updates(map[string]any{"status": "active", "effective_at": request.EffectiveAt, "expired_at": request.ExpiredAt}).Error; err != nil {
|
if err := tx.Model(&contract).Updates(map[string]any{"status": common.StatusActive, "effective_at": request.EffectiveAt, "expired_at": request.ExpiredAt}).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
contract.Status, contract.EffectiveAt, contract.ExpiredAt = "active", request.EffectiveAt, request.ExpiredAt
|
contract.Status, contract.EffectiveAt, contract.ExpiredAt = common.StatusActive, request.EffectiveAt, request.ExpiredAt
|
||||||
return tx.Create(contractRevision(contract, "renew", request.Reason, operatorIdentity, operatorName)).Error
|
return tx.Create(contractRevision(contract, "renew", request.Reason, operatorIdentity, operatorName)).Error
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -234,7 +234,7 @@ func RenewGasorderContract(ctx *gin.Context) {
|
|||||||
infra.Response.Success(ctx, gin.H{"updated": true})
|
infra.Response.Success(ctx, gin.H{"updated": true})
|
||||||
}
|
}
|
||||||
|
|
||||||
func changeGasorderContract(ctx *gin.Context, action, target string) {
|
func changeGasorderContract(ctx *gin.Context, action string, target int) {
|
||||||
var request struct {
|
var request struct {
|
||||||
Reason string `json:"reason" binding:"required"`
|
Reason string `json:"reason" binding:"required"`
|
||||||
}
|
}
|
||||||
@@ -248,13 +248,13 @@ func changeGasorderContract(ctx *gin.Context, action, target string) {
|
|||||||
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).Where("identity = ?", ctx.Param("identity")).First(&contract).Error; err != nil {
|
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).Where("identity = ?", ctx.Param("identity")).First(&contract).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if action == "activate" && contract.Status != "draft" && contract.Status != "terminated" {
|
if action == "activate" && contract.Status != common.StatusDraft && contract.Status != common.StatusTerminated {
|
||||||
return errors.New("contract cannot be activated")
|
return errors.New("contract cannot be activated")
|
||||||
}
|
}
|
||||||
if action == "terminate" && contract.Status != "active" {
|
if action == "terminate" && contract.Status != common.StatusActive {
|
||||||
return errors.New("contract cannot be terminated")
|
return errors.New("contract cannot be terminated")
|
||||||
}
|
}
|
||||||
if target == "active" {
|
if target == common.StatusActive {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
if contract.EffectiveAt.After(now) || (contract.ExpiredAt != nil && !contract.ExpiredAt.After(now)) {
|
if contract.EffectiveAt.After(now) || (contract.ExpiredAt != nil && !contract.ExpiredAt.After(now)) {
|
||||||
return errors.New("contract outside effective period")
|
return errors.New("contract outside effective period")
|
||||||
@@ -280,7 +280,7 @@ func changeGasorderContract(ctx *gin.Context, action, target string) {
|
|||||||
|
|
||||||
func contractRevision(contract models.GasorderContract, action, reason, operatorIdentity, operatorName string) *models.GasorderContractRevision {
|
func contractRevision(contract models.GasorderContract, action, reason, operatorIdentity, operatorName string) *models.GasorderContractRevision {
|
||||||
return &models.GasorderContractRevision{
|
return &models.GasorderContractRevision{
|
||||||
Entity: models.Entity{Identity: models.NewIdentity(), Status: "recorded", Version: 1},
|
Entity: models.Entity{Identity: models.NewIdentity(), Status: common.StatusRecorded, Version: 1},
|
||||||
GasorderContractID: contract.ID, Action: action, ContractStatus: contract.Status,
|
GasorderContractID: contract.ID, Action: action, ContractStatus: contract.Status,
|
||||||
EffectiveAt: contract.EffectiveAt, ExpiredAt: contract.ExpiredAt,
|
EffectiveAt: contract.EffectiveAt, ExpiredAt: contract.ExpiredAt,
|
||||||
OperatorIdentity: operatorIdentity, OperatorName: operatorName, OccurredAt: time.Now(), Reason: reason,
|
OperatorIdentity: operatorIdentity, OperatorName: operatorName, OccurredAt: time.Now(), Reason: reason,
|
||||||
@@ -302,13 +302,13 @@ func BindGasorderContractProduct(ctx *gin.Context) {
|
|||||||
common.RespondRecordError(ctx, err)
|
common.RespondRecordError(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if contract.Status != "draft" && contract.Status != "active" {
|
if contract.Status != common.StatusDraft && contract.Status != common.StatusActive {
|
||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var product models.ProductInfo
|
var product models.ProductInfo
|
||||||
if err := impl.DBService.Where("identity = ?", request.ProductIdentity).First(&product).Error; err != nil ||
|
if err := impl.DBService.Where("identity = ?", request.ProductIdentity).First(&product).Error; err != nil ||
|
||||||
!product.IsEnabled || product.Status == "scrapped" || product.UserAccountID != contract.UserAccountID {
|
!product.IsEnabled || product.Status == common.StatusScrapped || product.UserAccountID != contract.UserAccountID {
|
||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -318,7 +318,7 @@ func BindGasorderContractProduct(ctx *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
binding := models.GasorderContractProduct{
|
binding := models.GasorderContractProduct{
|
||||||
Entity: models.Entity{Identity: models.NewIdentity(), Status: "bound", Version: 1},
|
Entity: models.Entity{Identity: models.NewIdentity(), Status: common.StatusBound, Version: 1},
|
||||||
GasorderContractID: contract.ID, ProductInfoID: product.ID, ProductCode: product.Code,
|
GasorderContractID: contract.ID, ProductInfoID: product.ID, ProductCode: product.Code,
|
||||||
ProductTypeName: productType.Name, ProductParams: product.Params, UnitPrice: request.UnitPrice, BoundAt: time.Now(),
|
ProductTypeName: productType.Name, ProductParams: product.Params, UnitPrice: request.UnitPrice, BoundAt: time.Now(),
|
||||||
}
|
}
|
||||||
@@ -376,7 +376,7 @@ func CreateGasorderBasic(ctx *gin.Context) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
if contract.Status != "active" || contract.EffectiveAt.After(now) || (contract.ExpiredAt != nil && !contract.ExpiredAt.After(now)) {
|
if contract.Status != common.StatusActive || contract.EffectiveAt.After(now) || (contract.ExpiredAt != nil && !contract.ExpiredAt.After(now)) {
|
||||||
return errors.New("contract is not active")
|
return errors.New("contract is not active")
|
||||||
}
|
}
|
||||||
if request.CreatorType == "user" && creatorID != contract.UserAccountID {
|
if request.CreatorType == "user" && creatorID != contract.UserAccountID {
|
||||||
@@ -401,13 +401,13 @@ func CreateGasorderBasic(ctx *gin.Context) {
|
|||||||
for _, binding := range bindings {
|
for _, binding := range bindings {
|
||||||
var product models.ProductInfo
|
var product models.ProductInfo
|
||||||
if err := tx.Where("id = ?", binding.ProductInfoID).First(&product).Error; err != nil ||
|
if err := tx.Where("id = ?", binding.ProductInfoID).First(&product).Error; err != nil ||
|
||||||
!product.IsEnabled || product.Status == "scrapped" || product.UserAccountID != contract.UserAccountID {
|
!product.IsEnabled || product.Status == common.StatusScrapped || product.UserAccountID != contract.UserAccountID {
|
||||||
return errors.New("contract product is no longer eligible")
|
return errors.New("contract product is no longer eligible")
|
||||||
}
|
}
|
||||||
var activeOrderCount int64
|
var activeOrderCount int64
|
||||||
if err := tx.Table("gasorder_item").
|
if err := tx.Table("gasorder_item").
|
||||||
Joins("JOIN gasorder_basic ON gasorder_basic.id = gasorder_item.gasorder_basic_id").
|
Joins("JOIN gasorder_basic ON gasorder_basic.id = gasorder_item.gasorder_basic_id").
|
||||||
Where("gasorder_item.product_info_id = ? AND gasorder_basic.status NOT IN ?", binding.ProductInfoID, []string{"completed", "cancelled"}).
|
Where("gasorder_item.product_info_id = ? AND gasorder_basic.status NOT IN ?", binding.ProductInfoID, []int{common.StatusCompleted, common.StatusCancelled}).
|
||||||
Count(&activeOrderCount).Error; err != nil || activeOrderCount != 0 {
|
Count(&activeOrderCount).Error; err != nil || activeOrderCount != 0 {
|
||||||
return errors.New("contract product already has an active order")
|
return errors.New("contract product already has an active order")
|
||||||
}
|
}
|
||||||
@@ -418,7 +418,7 @@ func CreateGasorderBasic(ctx *gin.Context) {
|
|||||||
return errors.New("invalid payable amount")
|
return errors.New("invalid payable amount")
|
||||||
}
|
}
|
||||||
order = models.GasorderBasic{
|
order = models.GasorderBasic{
|
||||||
Entity: models.Entity{Identity: models.NewIdentity(), Status: "created", Version: 1},
|
Entity: models.Entity{Identity: models.NewIdentity(), Status: common.StatusCreated, Version: 1},
|
||||||
OrderNo: models.NewIdentity(), RequestNo: request.RequestNo, GasorderContractID: contract.ID,
|
OrderNo: models.NewIdentity(), RequestNo: request.RequestNo, GasorderContractID: contract.ID,
|
||||||
UserAccountID: contract.UserAccountID, CreatorType: request.CreatorType, CreatorID: creatorID,
|
UserAccountID: contract.UserAccountID, CreatorType: request.CreatorType, CreatorID: creatorID,
|
||||||
CreatorIdentity: request.CreatorIdentity, GasBasicID: contract.GasBasicID, DeliveryBasicID: contract.DeliveryBasicID,
|
CreatorIdentity: request.CreatorIdentity, GasBasicID: contract.GasBasicID, DeliveryBasicID: contract.DeliveryBasicID,
|
||||||
@@ -433,7 +433,7 @@ func CreateGasorderBasic(ctx *gin.Context) {
|
|||||||
}
|
}
|
||||||
for _, binding := range bindings {
|
for _, binding := range bindings {
|
||||||
item := models.GasorderItem{
|
item := models.GasorderItem{
|
||||||
Entity: models.Entity{Identity: models.NewIdentity(), Status: "ordered", Version: 1},
|
Entity: models.Entity{Identity: models.NewIdentity(), Status: common.StatusOrdered, Version: 1},
|
||||||
GasorderBasicID: order.ID, GasorderContractProductID: binding.ID, ProductInfoID: binding.ProductInfoID,
|
GasorderBasicID: order.ID, GasorderContractProductID: binding.ID, ProductInfoID: binding.ProductInfoID,
|
||||||
ProductCode: binding.ProductCode, ProductTypeName: binding.ProductTypeName,
|
ProductCode: binding.ProductCode, ProductTypeName: binding.ProductTypeName,
|
||||||
ProductParams: binding.ProductParams, UnitPrice: binding.UnitPrice,
|
ProductParams: binding.ProductParams, UnitPrice: binding.UnitPrice,
|
||||||
@@ -442,7 +442,7 @@ func CreateGasorderBasic(ctx *gin.Context) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tx.Create(gasorderStatusRecord(order.ID, "", "created", "order created", operatorIdentity, operatorName)).Error
|
return tx.Create(gasorderStatusRecord(order.ID, common.StatusDraft, common.StatusCreated, "order created", operatorIdentity, operatorName)).Error
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||||||
@@ -462,13 +462,13 @@ func AssignGasorderBasic(ctx *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
var delivery models.DeliveryBasic
|
var delivery models.DeliveryBasic
|
||||||
if err := impl.DBService.Where("identity = ?", request.DeliveryIdentity).First(&delivery).Error; err != nil || delivery.Status != "enabled" {
|
if err := impl.DBService.Where("identity = ?", request.DeliveryIdentity).First(&delivery).Error; err != nil || delivery.Status != common.StatusEnable {
|
||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var staff models.StaffAccount
|
var staff models.StaffAccount
|
||||||
if err := impl.DBService.Where("identity = ?", request.StaffIdentity).First(&staff).Error; err != nil ||
|
if err := impl.DBService.Where("identity = ?", request.StaffIdentity).First(&staff).Error; err != nil ||
|
||||||
staff.Status != "enabled" || staff.WorkStatus == "off_duty" {
|
staff.Status != common.StatusEnable || staff.WorkStatus == "off_duty" {
|
||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -478,17 +478,17 @@ func AssignGasorderBasic(ctx *gin.Context) {
|
|||||||
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).Where("identity = ?", ctx.Param("identity")).First(&order).Error; err != nil {
|
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).Where("identity = ?", ctx.Param("identity")).First(&order).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if order.Status != "created" && order.Status != "assigned" {
|
if order.Status != common.StatusCreated && order.Status != common.StatusAssigned {
|
||||||
return errors.New("order cannot be assigned")
|
return errors.New("order cannot be assigned")
|
||||||
}
|
}
|
||||||
previous := order.Status
|
previous := order.Status
|
||||||
if err := tx.Model(&order).Updates(map[string]any{
|
if err := tx.Model(&order).Updates(map[string]any{
|
||||||
"delivery_basic_id": delivery.ID, "staff_account_id": staff.ID, "status": "assigned",
|
"delivery_basic_id": delivery.ID, "staff_account_id": staff.ID, "status": common.StatusAssigned,
|
||||||
}).Error; err != nil {
|
}).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
assignment := models.GasorderAssign{
|
assignment := models.GasorderAssign{
|
||||||
Entity: models.Entity{Identity: models.NewIdentity(), Status: "recorded", Version: 1},
|
Entity: models.Entity{Identity: models.NewIdentity(), Status: common.StatusRecorded, Version: 1},
|
||||||
GasorderBasicID: order.ID, GasBasicID: order.GasBasicID, DeliveryBasicID: delivery.ID,
|
GasorderBasicID: order.ID, GasBasicID: order.GasBasicID, DeliveryBasicID: delivery.ID,
|
||||||
StaffAccountID: staff.ID, AssignerIdentity: operatorIdentity, AssignerName: operatorName,
|
StaffAccountID: staff.ID, AssignerIdentity: operatorIdentity, AssignerName: operatorName,
|
||||||
AssignedAt: time.Now(), Reason: request.Reason,
|
AssignedAt: time.Now(), Reason: request.Reason,
|
||||||
@@ -496,8 +496,8 @@ func AssignGasorderBasic(ctx *gin.Context) {
|
|||||||
if err := tx.Create(&assignment).Error; err != nil {
|
if err := tx.Create(&assignment).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if previous != "assigned" {
|
if previous != common.StatusAssigned {
|
||||||
return tx.Create(gasorderStatusRecord(order.ID, previous, "assigned", request.Reason, operatorIdentity, operatorName)).Error
|
return tx.Create(gasorderStatusRecord(order.ID, previous, common.StatusAssigned, request.Reason, operatorIdentity, operatorName)).Error
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
@@ -505,21 +505,24 @@ func AssignGasorderBasic(ctx *gin.Context) {
|
|||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
infra.Response.Success(ctx, gin.H{"updated": true, "status": "assigned"})
|
infra.Response.Success(ctx, gin.H{"updated": true, "status": common.StatusAssigned})
|
||||||
}
|
}
|
||||||
|
|
||||||
func GasorderStartFilling(ctx *gin.Context) {
|
func GasorderStartFilling(ctx *gin.Context) {
|
||||||
transitionGasorder(ctx, "filling", map[string]bool{"assigned": true})
|
transitionGasorder(ctx, common.StatusFilling, map[int]bool{common.StatusAssigned: true})
|
||||||
}
|
}
|
||||||
func GasorderReady(ctx *gin.Context) {
|
func GasorderReady(ctx *gin.Context) {
|
||||||
transitionGasorder(ctx, "ready", map[string]bool{"filling": true})
|
transitionGasorder(ctx, common.StatusReady, map[int]bool{common.StatusFilling: true})
|
||||||
}
|
}
|
||||||
func GasorderCancel(ctx *gin.Context) {
|
func GasorderCancel(ctx *gin.Context) {
|
||||||
transitionGasorder(ctx, "cancelled", map[string]bool{"created": true, "assigned": true})
|
transitionGasorder(ctx, common.StatusCancelled, map[int]bool{common.StatusCreated: true, common.StatusAssigned: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
func GasorderException(ctx *gin.Context) {
|
func GasorderException(ctx *gin.Context) {
|
||||||
transitionGasorder(ctx, "exception", map[string]bool{"filling": true, "ready": true, "delivering": true, "awaiting_confirmation": true})
|
transitionGasorder(ctx, common.StatusException, map[int]bool{
|
||||||
|
common.StatusFilling: true, common.StatusReady: true,
|
||||||
|
common.StatusDelivering: true, common.StatusAwaitingConfirmation: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func GasorderRecover(ctx *gin.Context) {
|
func GasorderRecover(ctx *gin.Context) {
|
||||||
@@ -536,14 +539,14 @@ func GasorderRecover(ctx *gin.Context) {
|
|||||||
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).Where("identity = ?", ctx.Param("identity")).First(&order).Error; err != nil {
|
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).Where("identity = ?", ctx.Param("identity")).First(&order).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if order.Status != "exception" || order.PreviousStatus == "" {
|
if order.Status != common.StatusException || order.PreviousStatus == common.StatusDraft {
|
||||||
return errors.New("order cannot recover")
|
return errors.New("order cannot recover")
|
||||||
}
|
}
|
||||||
target := order.PreviousStatus
|
target := order.PreviousStatus
|
||||||
if err := tx.Model(&order).Updates(map[string]any{"status": target, "previous_status": ""}).Error; err != nil {
|
if err := tx.Model(&order).Updates(map[string]any{"status": target, "previous_status": common.StatusDraft}).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return tx.Create(gasorderStatusRecord(order.ID, "exception", target, request.Reason, operatorIdentity, operatorName)).Error
|
return tx.Create(gasorderStatusRecord(order.ID, common.StatusException, target, request.Reason, operatorIdentity, operatorName)).Error
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||||||
@@ -552,7 +555,7 @@ func GasorderRecover(ctx *gin.Context) {
|
|||||||
infra.Response.Success(ctx, gin.H{"updated": true})
|
infra.Response.Success(ctx, gin.H{"updated": true})
|
||||||
}
|
}
|
||||||
|
|
||||||
func transitionGasorder(ctx *gin.Context, target string, allowed map[string]bool) {
|
func transitionGasorder(ctx *gin.Context, target int, allowed map[int]bool) {
|
||||||
var request struct {
|
var request struct {
|
||||||
Reason string `json:"reason" binding:"required"`
|
Reason string `json:"reason" binding:"required"`
|
||||||
}
|
}
|
||||||
@@ -566,11 +569,11 @@ func transitionGasorder(ctx *gin.Context, target string, allowed map[string]bool
|
|||||||
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).Where("identity = ?", ctx.Param("identity")).First(&order).Error; err != nil {
|
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).Where("identity = ?", ctx.Param("identity")).First(&order).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !allowed[order.Status] || (target == "filling" && order.DeliveryBasicID == 0) {
|
if !allowed[order.Status] || (target == common.StatusFilling && order.DeliveryBasicID == 0) {
|
||||||
return errors.New("invalid order transition")
|
return errors.New("invalid order transition")
|
||||||
}
|
}
|
||||||
updates := map[string]any{"status": target}
|
updates := map[string]any{"status": target}
|
||||||
if target == "exception" {
|
if target == common.StatusException {
|
||||||
updates["previous_status"] = order.Status
|
updates["previous_status"] = order.Status
|
||||||
}
|
}
|
||||||
if err := tx.Model(&order).Updates(updates).Error; err != nil {
|
if err := tx.Model(&order).Updates(updates).Error; err != nil {
|
||||||
@@ -585,9 +588,9 @@ func transitionGasorder(ctx *gin.Context, target string, allowed map[string]bool
|
|||||||
infra.Response.Success(ctx, gin.H{"updated": true, "status": target})
|
infra.Response.Success(ctx, gin.H{"updated": true, "status": target})
|
||||||
}
|
}
|
||||||
|
|
||||||
func gasorderStatusRecord(orderID uint64, from, to, reason, operatorIdentity, operatorName string) *models.GasorderStatus {
|
func gasorderStatusRecord(orderID uint64, from, to int, reason, operatorIdentity, operatorName string) *models.GasorderStatus {
|
||||||
return &models.GasorderStatus{
|
return &models.GasorderStatus{
|
||||||
Entity: models.Entity{Identity: models.NewIdentity(), Status: "recorded", Version: 1},
|
Entity: models.Entity{Identity: models.NewIdentity(), Status: common.StatusRecorded, Version: 1},
|
||||||
GasorderBasicID: orderID, FromStatus: from, ToStatus: to,
|
GasorderBasicID: orderID, FromStatus: from, ToStatus: to,
|
||||||
OperatorIdentity: operatorIdentity, OperatorName: operatorName, OccurredAt: time.Now(), Reason: reason,
|
OperatorIdentity: operatorIdentity, OperatorName: operatorName, OccurredAt: time.Now(), Reason: reason,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,21 +19,21 @@ func TestGasorderCreatorTypesCoverEveryConfirmedOrigin(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGasorderStatusRecordIsImmutableSnapshot(t *testing.T) {
|
func TestGasorderStatusRecordIsImmutableSnapshot(t *testing.T) {
|
||||||
record := gasorderStatusRecord(7, "assigned", "filling", "start filling", "operator-a", "Operator")
|
record := gasorderStatusRecord(7, common.StatusAssigned, common.StatusFilling, "start filling", "operator-a", "Operator")
|
||||||
if record.GasorderBasicID != 7 || record.FromStatus != "assigned" || record.ToStatus != "filling" {
|
if record.GasorderBasicID != 7 || record.FromStatus != common.StatusAssigned || record.ToStatus != common.StatusFilling {
|
||||||
t.Fatalf("unexpected status record: %#v", record)
|
t.Fatalf("unexpected status record: %#v", record)
|
||||||
}
|
}
|
||||||
if record.Status != "recorded" || record.OccurredAt.IsZero() {
|
if record.Status != common.StatusRecorded || record.OccurredAt.IsZero() {
|
||||||
t.Fatalf("status record lacks immutable metadata: %#v", record)
|
t.Fatalf("status record lacks immutable metadata: %#v", record)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContractRevisionKeepsSingleContractHistory(t *testing.T) {
|
func TestContractRevisionKeepsSingleContractHistory(t *testing.T) {
|
||||||
contract := models.GasorderContract{
|
contract := models.GasorderContract{
|
||||||
Entity: models.Entity{ID: 9, Status: "active"},
|
Entity: models.Entity{ID: 9, Status: common.StatusActive},
|
||||||
}
|
}
|
||||||
revision := contractRevision(contract, "renew", "annual renewal", "operator-a", "Operator")
|
revision := contractRevision(contract, "renew", "annual renewal", "operator-a", "Operator")
|
||||||
if revision.GasorderContractID != 9 || revision.Action != "renew" || revision.ContractStatus != "active" {
|
if revision.GasorderContractID != 9 || revision.Action != "renew" || revision.ContractStatus != common.StatusActive {
|
||||||
t.Fatalf("unexpected contract revision: %#v", revision)
|
t.Fatalf("unexpected contract revision: %#v", revision)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
147
backend/api/internal/logic/platform/menu.go
Normal file
147
backend/api/internal/logic/platform/menu.go
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
package platform
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Menu 是平台后台的静态菜单定义,不对应数据库表。
|
||||||
|
type Menu struct {
|
||||||
|
Identity string `json:"identity"`
|
||||||
|
ParentIdentity string `json:"parent_identity,omitempty"`
|
||||||
|
MenuCode string `json:"menu_code"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Icon string `json:"icon"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
SortNo int `json:"sort_no"`
|
||||||
|
Status int `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlatformMenus 使用二维数据组织菜单;每一行表示一个菜单分组。
|
||||||
|
var PlatformMenus = [][]Menu{
|
||||||
|
{
|
||||||
|
{Identity: "dashboard", MenuCode: "dashboard", Name: "工作台", Icon: "icon-dashboard", Path: "/dashboard", SortNo: 10, Status: common.StatusEnable},
|
||||||
|
{Identity: "dashboard_overview", ParentIdentity: "dashboard", MenuCode: "dashboard", Name: "数据概览", Path: "/dashboard/overview", SortNo: 1, Status: common.StatusEnable},
|
||||||
|
{Identity: "dashboard_reports", ParentIdentity: "dashboard", MenuCode: "dashboard", Name: "统计报表", Path: "/dashboard/reports", SortNo: 2, Status: common.StatusEnable},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{Identity: "gas", MenuCode: "gas", Name: "气站管理", Icon: "icon-storage", Path: "/gas", SortNo: 20, Status: common.StatusEnable},
|
||||||
|
{Identity: "gas_basic", ParentIdentity: "gas", MenuCode: "gas", Name: "气站", Path: "/gas/gas-basic", SortNo: 1, Status: common.StatusEnable},
|
||||||
|
{Identity: "gas_account", ParentIdentity: "gas", MenuCode: "gas", Name: "气站账户", Path: "/gas/gas-account", SortNo: 2, Status: common.StatusEnable},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{Identity: "delivery", MenuCode: "delivery", Name: "配送站管理", Icon: "icon-send", Path: "/delivery", SortNo: 30, Status: common.StatusEnable},
|
||||||
|
{Identity: "delivery_basic", ParentIdentity: "delivery", MenuCode: "delivery", Name: "配送站", Path: "/delivery/delivery-basic", SortNo: 1, Status: common.StatusEnable},
|
||||||
|
{Identity: "delivery_account", ParentIdentity: "delivery", MenuCode: "delivery", Name: "配送站账户", Path: "/delivery/delivery-account", SortNo: 2, Status: common.StatusEnable},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{Identity: "staff", MenuCode: "staff", Name: "工作人员管理", Icon: "icon-user-group", Path: "/staff", SortNo: 40, Status: common.StatusEnable},
|
||||||
|
{Identity: "staff_account", ParentIdentity: "staff", MenuCode: "staff", Name: "工作人员", Path: "/staff/staff-account", SortNo: 1, Status: common.StatusEnable},
|
||||||
|
{Identity: "staff_credential", ParentIdentity: "staff", MenuCode: "staff", Name: "人员资质", Path: "/staff/staff-credential", SortNo: 2, Status: common.StatusEnable},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{Identity: "user", MenuCode: "user", Name: "用户管理", Icon: "icon-user", Path: "/user", SortNo: 50, Status: common.StatusEnable},
|
||||||
|
{Identity: "user_account", ParentIdentity: "user", MenuCode: "user", Name: "用户账户", Path: "/user/user-account", SortNo: 1, Status: common.StatusEnable},
|
||||||
|
{Identity: "user_address", ParentIdentity: "user", MenuCode: "user", Name: "用户地址", Path: "/user/user-address", SortNo: 2, Status: common.StatusEnable},
|
||||||
|
{Identity: "user_service_relation", ParentIdentity: "user", MenuCode: "user", Name: "服务关系", Path: "/user/service-relation", SortNo: 3, Status: common.StatusEnable},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{Identity: "device", MenuCode: "device", Name: "产品管理", Icon: "icon-common", Path: "/product", SortNo: 60, Status: common.StatusEnable},
|
||||||
|
{Identity: "product_type", ParentIdentity: "device", MenuCode: "device", Name: "产品类型", Path: "/product/product-type", SortNo: 1, Status: common.StatusEnable},
|
||||||
|
{Identity: "product_warehouse", ParentIdentity: "device", MenuCode: "device", Name: "库房", Path: "/product/warehouse", SortNo: 2, Status: common.StatusEnable},
|
||||||
|
{Identity: "product_info", ParentIdentity: "device", MenuCode: "device", Name: "产品信息", Path: "/product/product-info", SortNo: 3, Status: common.StatusEnable},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{Identity: "gasorder", MenuCode: "delivery", Name: "气体配送订单管理", Icon: "icon-list", Path: "/gasorder", SortNo: 70, Status: common.StatusEnable},
|
||||||
|
{Identity: "gasorder_contract", ParentIdentity: "gasorder", MenuCode: "delivery", Name: "合同管理", Path: "/gasorder/contracts", SortNo: 1, Status: common.StatusEnable},
|
||||||
|
{Identity: "gasorder_basic", ParentIdentity: "gasorder", MenuCode: "delivery", Name: "配送订单", Path: "/gasorder/orders", SortNo: 2, Status: common.StatusEnable},
|
||||||
|
{Identity: "gasorder_track", ParentIdentity: "gasorder", MenuCode: "delivery", Name: "运行轨迹", Path: "/gasorder/tracks", SortNo: 3, Status: common.StatusEnable},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{Identity: "ec", MenuCode: "ec", Name: "商城管理", Icon: "icon-gift", Path: "/ec", SortNo: 80, Status: common.StatusEnable},
|
||||||
|
{Identity: "ec_category", ParentIdentity: "ec", MenuCode: "ec", Name: "商品分类", Path: "/ec/categories", SortNo: 1, Status: common.StatusEnable},
|
||||||
|
{Identity: "ec_product", ParentIdentity: "ec", MenuCode: "ec", Name: "商品", Path: "/ec/products", SortNo: 2, Status: common.StatusEnable},
|
||||||
|
{Identity: "ec_cart", ParentIdentity: "ec", MenuCode: "ec", Name: "购物车", Path: "/ec/carts", SortNo: 3, Status: common.StatusEnable},
|
||||||
|
{Identity: "ec_order", ParentIdentity: "ec", MenuCode: "ec", Name: "商城订单", Path: "/ec/orders", SortNo: 4, Status: common.StatusEnable},
|
||||||
|
{Identity: "ec_review", ParentIdentity: "ec", MenuCode: "ec", Name: "商品评价", Path: "/ec/reviews", SortNo: 5, Status: common.StatusEnable},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{Identity: "wallet", MenuCode: "wallet", Name: "钱包管理", Icon: "icon-safe", Path: "/wallet", SortNo: 90, Status: common.StatusEnable},
|
||||||
|
{Identity: "wallet_basic", ParentIdentity: "wallet", MenuCode: "wallet", Name: "钱包", Path: "/wallet/wallet-basic", SortNo: 1, Status: common.StatusEnable},
|
||||||
|
{Identity: "wallet_bank", ParentIdentity: "wallet", MenuCode: "wallet", Name: "银行卡", Path: "/wallet/banks", SortNo: 2, Status: common.StatusEnable},
|
||||||
|
{Identity: "wallet_payment", ParentIdentity: "wallet", MenuCode: "wallet", Name: "支付记录", Path: "/wallet/payments", SortNo: 3, Status: common.StatusEnable},
|
||||||
|
{Identity: "wallet_record", ParentIdentity: "wallet", MenuCode: "wallet", Name: "钱包流水", Path: "/wallet/records", SortNo: 4, Status: common.StatusEnable},
|
||||||
|
{Identity: "wallet_refund", ParentIdentity: "wallet", MenuCode: "wallet", Name: "退款记录", Path: "/wallet/refunds", SortNo: 5, Status: common.StatusEnable},
|
||||||
|
{Identity: "wallet_apply_cash", ParentIdentity: "wallet", MenuCode: "wallet", Name: "提现申请", Path: "/wallet/apply-cash", SortNo: 6, Status: common.StatusEnable},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{Identity: "finance", MenuCode: "finance", Name: "财务管理", Icon: "icon-bar-chart", Path: "/finance", SortNo: 100, Status: common.StatusEnable},
|
||||||
|
{Identity: "fin_payment", ParentIdentity: "finance", MenuCode: "finance", Name: "支付记录", Path: "/finance/payments", SortNo: 1, Status: common.StatusEnable},
|
||||||
|
{Identity: "fin_settlement", ParentIdentity: "finance", MenuCode: "finance", Name: "财务结算", Path: "/finance/settlements", SortNo: 2, Status: common.StatusEnable},
|
||||||
|
{Identity: "fin_reconciliation", ParentIdentity: "finance", MenuCode: "finance", Name: "财务对账", Path: "/finance/reconciliations", SortNo: 3, Status: common.StatusEnable},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{Identity: "content", MenuCode: "content", Name: "内容管理", Icon: "icon-file", Path: "/content", SortNo: 110, Status: common.StatusEnable},
|
||||||
|
{Identity: "cms_content", ParentIdentity: "content", MenuCode: "content", Name: "内容", Path: "/content/contents", SortNo: 1, Status: common.StatusEnable},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{Identity: "customer_service", MenuCode: "customer_service", Name: "客服管理", Icon: "icon-customer-service", Path: "/customer-service", SortNo: 120, Status: common.StatusEnable},
|
||||||
|
{Identity: "cs_ticket", ParentIdentity: "customer_service", MenuCode: "customer_service", Name: "客服工单", Path: "/customer-service/tickets", SortNo: 1, Status: common.StatusEnable},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{Identity: "platform", MenuCode: "platform", Name: "平台管理", Icon: "icon-settings", Path: "/platform", SortNo: 130, Status: common.StatusEnable},
|
||||||
|
{Identity: "platform_account", ParentIdentity: "platform", MenuCode: "platform", Name: "平台账户", Path: "/platform/accounts", SortNo: 1, Status: common.StatusEnable},
|
||||||
|
{Identity: "platform_role", ParentIdentity: "platform", MenuCode: "platform", Name: "平台角色", Path: "/platform/roles", SortNo: 2, Status: common.StatusEnable},
|
||||||
|
{Identity: "platform_menu", ParentIdentity: "platform", MenuCode: "platform", Name: "平台菜单", Path: "/platform/menus", SortNo: 3, Status: common.StatusEnable},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllPlatformMenus 返回静态菜单的扁平副本。
|
||||||
|
func AllPlatformMenus() []Menu {
|
||||||
|
menus := make([]Menu, 0, len(PlatformMenus))
|
||||||
|
for _, group := range PlatformMenus {
|
||||||
|
menus = append(menus, group...)
|
||||||
|
}
|
||||||
|
return menus
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindPlatformMenu 根据稳定 identity 查找静态菜单。
|
||||||
|
func FindPlatformMenu(identity string) (Menu, bool) {
|
||||||
|
for _, menu := range AllPlatformMenus() {
|
||||||
|
if menu.Identity == identity {
|
||||||
|
return menu, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Menu{}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadPlatformMenus 返回角色获授权的静态菜单;root 默认拥有全部菜单。
|
||||||
|
func LoadPlatformMenus(roleCode string) ([]Menu, error) {
|
||||||
|
menus := AllPlatformMenus()
|
||||||
|
if roleCode == "root" {
|
||||||
|
return menus, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var role models.PlatformRole
|
||||||
|
if err := impl.DBService.Where("role_code = ? AND status = ?", roleCode, common.StatusEnable).First(&role).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var codes []string
|
||||||
|
if err := impl.DBService.Model(&models.PlatformRoleMenu{}).
|
||||||
|
Where("platform_role_id = ?", role.ID).
|
||||||
|
Pluck("menu_code", &codes).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
allowed := make(map[string]struct{}, len(codes))
|
||||||
|
for _, code := range codes {
|
||||||
|
allowed[code] = struct{}{}
|
||||||
|
}
|
||||||
|
filtered := make([]Menu, 0, len(menus))
|
||||||
|
for _, menu := range menus {
|
||||||
|
if _, ok := allowed[menu.MenuCode]; ok {
|
||||||
|
filtered = append(filtered, menu)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filtered, nil
|
||||||
|
}
|
||||||
41
backend/api/internal/logic/platform/menu_test.go
Normal file
41
backend/api/internal/logic/platform/menu_test.go
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package platform
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestPlatformMenusAreStaticTwoDimensionalData(t *testing.T) {
|
||||||
|
if len(PlatformMenus) == 0 {
|
||||||
|
t.Fatal("PlatformMenus must contain menu groups")
|
||||||
|
}
|
||||||
|
seen := make(map[string]bool)
|
||||||
|
for _, group := range PlatformMenus {
|
||||||
|
if len(group) < 2 {
|
||||||
|
t.Fatal("each platform menu group must include a first-level menu and at least one second-level menu")
|
||||||
|
}
|
||||||
|
parent := group[0]
|
||||||
|
if parent.ParentIdentity != "" {
|
||||||
|
t.Fatalf("first menu in group must be first-level: %#v", parent)
|
||||||
|
}
|
||||||
|
for index, menu := range group {
|
||||||
|
if menu.Identity == "" || menu.MenuCode == "" {
|
||||||
|
t.Fatalf("menu identity and code are required: %#v", menu)
|
||||||
|
}
|
||||||
|
if index > 0 && menu.ParentIdentity != parent.Identity {
|
||||||
|
t.Fatalf("second-level menu %s must reference parent %s", menu.Identity, parent.Identity)
|
||||||
|
}
|
||||||
|
if seen[menu.Identity] {
|
||||||
|
t.Fatalf("duplicate menu identity: %s", menu.Identity)
|
||||||
|
}
|
||||||
|
seen[menu.Identity] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRootLoadsAllStaticPlatformMenus(t *testing.T) {
|
||||||
|
menus, err := LoadPlatformMenus("root")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(menus) != len(AllPlatformMenus()) {
|
||||||
|
t.Fatalf("root menu count = %d, want %d", len(menus), len(AllPlatformMenus()))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,15 +4,14 @@ import (
|
|||||||
"git.apinb.com/bsm-sdk/core/errcode"
|
"git.apinb.com/bsm-sdk/core/errcode"
|
||||||
"git.apinb.com/bsm-sdk/core/infra"
|
"git.apinb.com/bsm-sdk/core/infra"
|
||||||
"git.apinb.com/bsm-sdk/core/middleware"
|
"git.apinb.com/bsm-sdk/core/middleware"
|
||||||
"git.apinb.com/heqiapp/platforms/backend/api/internal/logic/common"
|
platformbase "git.apinb.com/heqiapp/platforms/backend/api/internal/logic/platform"
|
||||||
"git.apinb.com/heqiapp/platforms/backend/api/internal/models"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const platformMenusContextKey = "platform_authorized_menus"
|
const platformMenusContextKey = "platform_authorized_menus"
|
||||||
|
|
||||||
func platformMenuAllowsPath(menus []models.PlatformMenu, requestPath string) bool {
|
func platformMenuAllowsPath(menus []platformbase.Menu, requestPath string) bool {
|
||||||
marker := "/platform/v1/"
|
marker := "/platform/v1/"
|
||||||
index := strings.Index(requestPath, marker)
|
index := strings.Index(requestPath, marker)
|
||||||
if index < 0 {
|
if index < 0 {
|
||||||
@@ -70,7 +69,7 @@ func RequirePlatformMenuAccess() gin.HandlerFunc {
|
|||||||
ctx.Next()
|
ctx.Next()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
menus, err := common.LoadPlatformMenus(claims.Role)
|
menus, err := platformbase.LoadPlatformMenus(claims.Role)
|
||||||
if err != nil || !platformMenuAllowsPath(menus, ctx.Request.URL.Path) {
|
if err != nil || !platformMenuAllowsPath(menus, ctx.Request.URL.Path) {
|
||||||
infra.Response.Error(ctx, errcode.ErrPermissionDenied)
|
infra.Response.Error(ctx, errcode.ErrPermissionDenied)
|
||||||
ctx.Abort()
|
ctx.Abort()
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ func CreatePlatformAccount(ctx *gin.Context) {
|
|||||||
infra.Response.Error(ctx, err)
|
infra.Response.Error(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
account := models.PlatformAccount{Entity: common.NewEntity("enabled"), Username: request.Username, DisplayName: request.DisplayName, Avatar: request.Avatar, PasswordHash: hash, PlatformRoleCode: request.PlatformRoleCode, Phone: request.Phone}
|
account := models.PlatformAccount{Entity: common.NewEntity(common.StatusEnable), Username: request.Username, DisplayName: request.DisplayName, Avatar: request.Avatar, PasswordHash: hash, PlatformRoleCode: request.PlatformRoleCode, Phone: request.Phone}
|
||||||
if err := impl.DBService.Create(&account).Error; err != nil {
|
if err := impl.DBService.Create(&account).Error; err != nil {
|
||||||
infra.Response.Error(ctx, err)
|
infra.Response.Error(ctx, err)
|
||||||
return
|
return
|
||||||
@@ -138,5 +138,5 @@ func isAssignablePlatformRole(roleCode string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
var role models.PlatformRole
|
var role models.PlatformRole
|
||||||
return impl.DBService.Where("role_code = ? AND status = ? AND is_system = ?", roleCode, "enabled", false).First(&role).Error == nil
|
return impl.DBService.Where("role_code = ? AND status = ? AND is_system = ?", roleCode, common.StatusEnable, false).First(&role).Error == nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,125 +4,31 @@ import (
|
|||||||
"git.apinb.com/bsm-sdk/core/errcode"
|
"git.apinb.com/bsm-sdk/core/errcode"
|
||||||
"git.apinb.com/bsm-sdk/core/infra"
|
"git.apinb.com/bsm-sdk/core/infra"
|
||||||
"git.apinb.com/bsm-sdk/core/middleware"
|
"git.apinb.com/bsm-sdk/core/middleware"
|
||||||
"git.apinb.com/heqiapp/platforms/backend/api/internal/impl"
|
platformbase "git.apinb.com/heqiapp/platforms/backend/api/internal/logic/platform"
|
||||||
"git.apinb.com/heqiapp/platforms/backend/api/internal/logic/common"
|
|
||||||
"git.apinb.com/heqiapp/platforms/backend/api/internal/models"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
type platformMenuRequest struct {
|
// GetPlatformMenu 返回一项静态菜单定义。
|
||||||
ParentIdentity string `json:"parent_identity"`
|
|
||||||
MenuCode string `json:"menu_code" binding:"required,max=64"`
|
|
||||||
Name string `json:"name" binding:"required,max=64"`
|
|
||||||
Icon string `json:"icon" binding:"max=64"`
|
|
||||||
Path string `json:"path" binding:"max=255"`
|
|
||||||
SortNo int `json:"sort_no"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type platformMenuView struct {
|
|
||||||
Identity string `json:"identity"`
|
|
||||||
ParentIdentity string `json:"parent_identity,omitempty"`
|
|
||||||
MenuCode string `json:"menu_code"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Icon string `json:"icon"`
|
|
||||||
Path string `json:"path"`
|
|
||||||
SortNo int `json:"sort_no"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func platformMenuViews(list []models.PlatformMenu) []platformMenuView {
|
|
||||||
identities := make(map[uint64]string, len(list))
|
|
||||||
for _, item := range list {
|
|
||||||
identities[item.ID] = item.Identity
|
|
||||||
}
|
|
||||||
views := make([]platformMenuView, 0, len(list))
|
|
||||||
for _, item := range list {
|
|
||||||
views = append(views, platformMenuView{Identity: item.Identity, ParentIdentity: identities[item.ParentID], MenuCode: item.MenuCode, Name: item.Name, Icon: item.Icon, Path: item.Path, SortNo: item.SortNo, Status: item.Status})
|
|
||||||
}
|
|
||||||
return views
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetPlatformMenu(ctx *gin.Context) {
|
func GetPlatformMenu(ctx *gin.Context) {
|
||||||
var menu models.PlatformMenu
|
menu, ok := platformbase.FindPlatformMenu(ctx.Param("identity"))
|
||||||
if err := impl.DBService.Where("identity = ?", ctx.Param("identity")).First(&menu).Error; err != nil {
|
if !ok {
|
||||||
common.RespondRecordError(ctx, err)
|
infra.Response.Error(ctx, errcode.ErrRecordNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
list := []models.PlatformMenu{menu}
|
infra.Response.Success(ctx, menu)
|
||||||
if menu.ParentID != 0 {
|
|
||||||
var parent models.PlatformMenu
|
|
||||||
if err := impl.DBService.Select("id", "identity").First(&parent, menu.ParentID).Error; err == nil {
|
|
||||||
list = append(list, parent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
views := platformMenuViews(list)
|
|
||||||
infra.Response.Success(ctx, views[0])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreatePlatformMenu(ctx *gin.Context) {
|
// ListPlatformMenu 返回当前角色获授权的静态菜单。
|
||||||
if !common.RequirePlatformRoot(ctx) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var request platformMenuRequest
|
|
||||||
if err := ctx.ShouldBindJSON(&request); err != nil {
|
|
||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
parentID, err := common.ResolveIdentityID(&models.PlatformMenu{}, request.ParentIdentity, false)
|
|
||||||
if err != nil {
|
|
||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
menu := models.PlatformMenu{Entity: common.NewEntity("enabled"), ParentID: parentID, MenuCode: request.MenuCode, Name: request.Name, Icon: request.Icon, Path: request.Path, SortNo: request.SortNo}
|
|
||||||
if err := impl.DBService.Create(&menu).Error; err != nil {
|
|
||||||
infra.Response.Error(ctx, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
common.RespondCreatedResource(ctx, menu)
|
|
||||||
}
|
|
||||||
|
|
||||||
func UpdatePlatformMenu(ctx *gin.Context) {
|
|
||||||
if !common.RequirePlatformRoot(ctx) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var request platformMenuRequest
|
|
||||||
if err := ctx.ShouldBindJSON(&request); err != nil {
|
|
||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
parentID, err := common.ResolveIdentityID(&models.PlatformMenu{}, request.ParentIdentity, false)
|
|
||||||
if err != nil {
|
|
||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
common.UpdateAllowedByIdentity(ctx, &models.PlatformMenu{}, gin.H{"parent_id": parentID, "name": request.Name, "icon": request.Icon, "path": request.Path, "sort_no": request.SortNo}, []string{"parent_id", "name", "icon", "path", "sort_no"})
|
|
||||||
}
|
|
||||||
|
|
||||||
func UpdatePlatformMenuStatus(ctx *gin.Context) {
|
|
||||||
if !common.RequirePlatformRoot(ctx) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
common.UpdateRecordStatus(ctx, &models.PlatformMenu{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func ArchivePlatformMenu(ctx *gin.Context) {
|
|
||||||
if !common.RequirePlatformRoot(ctx) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
common.ArchiveRecord(ctx, &models.PlatformMenu{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListPlatformMenu 返回菜单树构建所需的有序菜单列表。
|
|
||||||
func ListPlatformMenu(ctx *gin.Context) {
|
func ListPlatformMenu(ctx *gin.Context) {
|
||||||
claims, err := middleware.ParseAuth(ctx)
|
claims, err := middleware.ParseAuth(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
infra.Response.Error(ctx, err)
|
infra.Response.Error(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
list, err := common.LoadPlatformMenus(claims.Role)
|
list, err := platformbase.LoadPlatformMenus(claims.Role)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
infra.Response.Error(ctx, err)
|
infra.Response.Error(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
infra.Response.Success(ctx, gin.H{"total": len(list), "list": platformMenuViews(list)})
|
infra.Response.Success(ctx, gin.H{"total": len(list), "list": list})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ func CreatePlatformRole(ctx *gin.Context) {
|
|||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
request.Entity = common.NewEntity("enabled")
|
request.Entity = common.NewEntity(common.StatusEnable)
|
||||||
request.IsSystem = false
|
request.IsSystem = false
|
||||||
if request.DataScope == "" {
|
if request.DataScope == "" {
|
||||||
request.DataScope = "global"
|
request.DataScope = "global"
|
||||||
@@ -68,7 +68,7 @@ func UpdatePlatformRoleStatus(ctx *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
var request struct {
|
var request struct {
|
||||||
Status string `json:"status" binding:"required,max=32"`
|
Status int `json:"status" binding:"required"`
|
||||||
}
|
}
|
||||||
if err := ctx.ShouldBindJSON(&request); err != nil {
|
if err := ctx.ShouldBindJSON(&request); err != nil {
|
||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||||||
@@ -100,5 +100,5 @@ func ArchivePlatformRole(ctx *gin.Context) {
|
|||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
common.UpdateAllowedByIdentity(ctx, &models.PlatformRole{}, gin.H{"status": "archived"}, []string{"status"})
|
common.UpdateAllowedByIdentity(ctx, &models.PlatformRole{}, gin.H{"status": common.StatusArchived}, []string{"status"})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"git.apinb.com/bsm-sdk/core/infra"
|
"git.apinb.com/bsm-sdk/core/infra"
|
||||||
"git.apinb.com/heqiapp/platforms/backend/api/internal/impl"
|
"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/logic/common"
|
||||||
|
platformbase "git.apinb.com/heqiapp/platforms/backend/api/internal/logic/platform"
|
||||||
"git.apinb.com/heqiapp/platforms/backend/api/internal/models"
|
"git.apinb.com/heqiapp/platforms/backend/api/internal/models"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
@@ -35,20 +36,19 @@ func ReplacePlatformRoleMenus(ctx *gin.Context) {
|
|||||||
if role.IsSystem {
|
if role.IsSystem {
|
||||||
return errSystemPlatformRole
|
return errSystemPlatformRole
|
||||||
}
|
}
|
||||||
var menus []models.PlatformMenu
|
menuCodes := make(map[string]struct{}, len(request.MenuIdentities))
|
||||||
if len(request.MenuIdentities) > 0 {
|
for _, identity := range request.MenuIdentities {
|
||||||
if err := transaction.Where("identity IN ?", request.MenuIdentities).Find(&menus).Error; err != nil {
|
menu, ok := platformbase.FindPlatformMenu(identity)
|
||||||
return err
|
if !ok {
|
||||||
}
|
|
||||||
if len(menus) != len(request.MenuIdentities) {
|
|
||||||
return gorm.ErrRecordNotFound
|
return gorm.ErrRecordNotFound
|
||||||
}
|
}
|
||||||
|
menuCodes[menu.MenuCode] = struct{}{}
|
||||||
}
|
}
|
||||||
if err := transaction.Where("platform_role_id = ?", role.ID).Delete(&models.PlatformRoleMenu{}).Error; err != nil {
|
if err := transaction.Where("platform_role_id = ?", role.ID).Delete(&models.PlatformRoleMenu{}).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, menu := range menus {
|
for menuCode := range menuCodes {
|
||||||
relation := models.PlatformRoleMenu{PlatformRoleID: role.ID, PlatformMenuID: menu.ID}
|
relation := models.PlatformRoleMenu{PlatformRoleID: role.ID, MenuCode: menuCode}
|
||||||
if err := transaction.Create(&relation).Error; err != nil {
|
if err := transaction.Create(&relation).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -79,14 +79,22 @@ func ListPlatformRoleMenuIdentities(ctx *gin.Context) {
|
|||||||
common.RespondRecordError(ctx, err)
|
common.RespondRecordError(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var identities []string
|
var codes []string
|
||||||
if err := impl.DBService.Model(&models.PlatformMenu{}).
|
if err := impl.DBService.Model(&models.PlatformRoleMenu{}).
|
||||||
Joins("JOIN platform_role_menu ON platform_role_menu.platform_menu_id = platform_menu.id").
|
Where("platform_role_id = ?", role.ID).
|
||||||
Where("platform_role_menu.platform_role_id = ?", role.ID).
|
Pluck("menu_code", &codes).Error; err != nil {
|
||||||
Order("platform_menu.sort_no asc, platform_menu.id asc").
|
|
||||||
Pluck("platform_menu.identity", &identities).Error; err != nil {
|
|
||||||
infra.Response.Error(ctx, err)
|
infra.Response.Error(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
assigned := make(map[string]struct{}, len(codes))
|
||||||
|
for _, code := range codes {
|
||||||
|
assigned[code] = struct{}{}
|
||||||
|
}
|
||||||
|
identities := make([]string, 0, len(codes))
|
||||||
|
for _, menu := range platformbase.AllPlatformMenus() {
|
||||||
|
if _, ok := assigned[menu.MenuCode]; ok {
|
||||||
|
identities = append(identities, menu.Identity)
|
||||||
|
}
|
||||||
|
}
|
||||||
infra.Response.Success(ctx, gin.H{"menu_identities": identities})
|
infra.Response.Success(ctx, gin.H{"menu_identities": identities})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,9 @@ var productOwnerActions = map[string]bool{
|
|||||||
"created": true, "warehouse": true, "assigned": true, "returned": true, "manual": true,
|
"created": true, "warehouse": true, "assigned": true, "returned": true, "manual": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
var productLifecycleStatuses = map[string]bool{
|
var productLifecycleStatuses = map[int]bool{
|
||||||
"pending": true, "in_stock": true, "in_transit": true, "in_use": true, "repairing": true, "scrapped": true,
|
common.StatusPending: true, common.StatusInStock: true, common.StatusInTransit: true,
|
||||||
|
common.StatusInUse: true, common.StatusRepairing: true, common.StatusScrapped: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProductInfoHandlers(relations ...common.ResourceRelation) (gin.HandlerFunc, gin.HandlerFunc, gin.HandlerFunc, gin.HandlerFunc) {
|
func ProductInfoHandlers(relations ...common.ResourceRelation) (gin.HandlerFunc, gin.HandlerFunc, gin.HandlerFunc, gin.HandlerFunc) {
|
||||||
@@ -41,12 +42,12 @@ func createProductInfo(ctx *gin.Context, fields []string, relations []common.Res
|
|||||||
delete(values, "action")
|
delete(values, "action")
|
||||||
delete(values, "reason")
|
delete(values, "reason")
|
||||||
delete(values, "remark")
|
delete(values, "remark")
|
||||||
data := models.ProductInfo{Entity: common.NewEntity("pending"), Params: "{}", IsEnabled: false}
|
data := models.ProductInfo{Entity: common.NewEntity(common.StatusPending), Params: "{}", IsEnabled: false}
|
||||||
if err := decodeValues(values, &data); err != nil || data.Code == "" || data.Name == "" || data.ProducedAt.IsZero() {
|
if err := decodeValues(values, &data); err != nil || data.Code == "" || data.Name == "" || data.ProducedAt.IsZero() {
|
||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
data.Status = "pending"
|
data.Status = common.StatusPending
|
||||||
if data.IsEnabled {
|
if data.IsEnabled {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
data.EnabledAt = &now
|
data.EnabledAt = &now
|
||||||
@@ -92,11 +93,15 @@ func updateProductInfo(ctx *gin.Context, fields []string, relations []common.Res
|
|||||||
if _, changingCode := values["code"]; changingCode {
|
if _, changingCode := values["code"]; changingCode {
|
||||||
delete(values, "code")
|
delete(values, "code")
|
||||||
}
|
}
|
||||||
if status, ok := values["status"].(string); ok && !productLifecycleStatuses[status] {
|
if rawStatus, supplied := values["status"]; supplied {
|
||||||
|
status, ok := intValue(rawStatus)
|
||||||
|
if !ok || !productLifecycleStatuses[status] {
|
||||||
return errors.New("invalid product status")
|
return errors.New("invalid product status")
|
||||||
}
|
}
|
||||||
|
values["status"] = status
|
||||||
|
}
|
||||||
if enabled, ok := values["is_enabled"].(bool); ok && enabled && !current.IsEnabled {
|
if enabled, ok := values["is_enabled"].(bool); ok && enabled && !current.IsEnabled {
|
||||||
if current.Status == "scrapped" {
|
if current.Status == common.StatusScrapped {
|
||||||
return errors.New("scrapped product cannot be enabled")
|
return errors.New("scrapped product cannot be enabled")
|
||||||
}
|
}
|
||||||
if current.EnabledAt == nil {
|
if current.EnabledAt == nil {
|
||||||
@@ -161,7 +166,7 @@ func listProductOwners(ctx *gin.Context) {
|
|||||||
|
|
||||||
func UpdateProductInfoStatus(ctx *gin.Context) {
|
func UpdateProductInfoStatus(ctx *gin.Context) {
|
||||||
var request struct {
|
var request struct {
|
||||||
Status string `json:"status" binding:"required,max=32"`
|
Status int `json:"status" binding:"required"`
|
||||||
}
|
}
|
||||||
if err := ctx.ShouldBindJSON(&request); err != nil || !productLifecycleStatuses[request.Status] {
|
if err := ctx.ShouldBindJSON(&request); err != nil || !productLifecycleStatuses[request.Status] {
|
||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||||||
@@ -184,7 +189,7 @@ func createProductRepair(ctx *gin.Context, fields []string, relations []common.R
|
|||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
data := models.ProductRepair{Entity: common.NewEntity("active"), Result: "pending"}
|
data := models.ProductRepair{Entity: common.NewEntity(common.StatusActive), Result: "pending"}
|
||||||
if err := decodeValues(values, &data); err != nil || data.Result != "pending" || !validRepair(data) || data.ProductInfoID == 0 || data.RepairNo == "" {
|
if err := decodeValues(values, &data); err != nil || data.Result != "pending" || !validRepair(data) || data.ProductInfoID == 0 || data.RepairNo == "" {
|
||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||||||
return
|
return
|
||||||
@@ -193,7 +198,7 @@ func createProductRepair(ctx *gin.Context, fields []string, relations []common.R
|
|||||||
if err := tx.Create(&data).Error; err != nil {
|
if err := tx.Create(&data).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return tx.Model(&models.ProductInfo{}).Where("id = ?", data.ProductInfoID).Update("status", "repairing").Error
|
return tx.Model(&models.ProductInfo{}).Where("id = ?", data.ProductInfoID).Update("status", common.StatusRepairing).Error
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
infra.Response.Error(ctx, err)
|
infra.Response.Error(ctx, err)
|
||||||
@@ -254,7 +259,7 @@ func validRepair(repair models.ProductRepair) bool {
|
|||||||
return repair.CompletedAt == nil
|
return repair.CompletedAt == nil
|
||||||
case "passed", "failed":
|
case "passed", "failed":
|
||||||
return repair.CompletedAt != nil && !repair.CompletedAt.Before(repair.StartedAt) &&
|
return repair.CompletedAt != nil && !repair.CompletedAt.Before(repair.StartedAt) &&
|
||||||
productLifecycleStatuses[repair.TargetStatus] && repair.TargetStatus != "repairing"
|
productLifecycleStatuses[repair.TargetStatus] && repair.TargetStatus != common.StatusRepairing
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -271,7 +276,7 @@ func createProductOwner(ctx *gin.Context, fields []string, relations []common.Re
|
|||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
data := models.ProductOwner{Entity: common.NewEntity("recorded")}
|
data := models.ProductOwner{Entity: common.NewEntity(common.StatusRecorded)}
|
||||||
if err := decodeValues(values, &data); err != nil || data.ProductInfoID == 0 || data.OccurredAt.IsZero() {
|
if err := decodeValues(values, &data); err != nil || data.ProductInfoID == 0 || data.OccurredAt.IsZero() {
|
||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||||||
return
|
return
|
||||||
@@ -304,14 +309,14 @@ func decodeValues(values map[string]any, target any) error {
|
|||||||
return json.Unmarshal(encoded, target)
|
return json.Unmarshal(encoded, target)
|
||||||
}
|
}
|
||||||
|
|
||||||
func initialProductStatus(product models.ProductInfo) string {
|
func initialProductStatus(product models.ProductInfo) int {
|
||||||
if product.WarehouseID != 0 {
|
if product.WarehouseID != 0 {
|
||||||
return "in_stock"
|
return common.StatusInStock
|
||||||
}
|
}
|
||||||
if product.UserAccountID != 0 {
|
if product.UserAccountID != 0 {
|
||||||
return "in_use"
|
return common.StatusInUse
|
||||||
}
|
}
|
||||||
return "pending"
|
return common.StatusPending
|
||||||
}
|
}
|
||||||
|
|
||||||
func ownershipValuesChanged(current models.ProductInfo, values map[string]any) bool {
|
func ownershipValuesChanged(current models.ProductInfo, values map[string]any) bool {
|
||||||
@@ -339,9 +344,20 @@ func numericID(value any) (uint64, bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func intValue(value any) (int, bool) {
|
||||||
|
switch raw := value.(type) {
|
||||||
|
case int:
|
||||||
|
return raw, true
|
||||||
|
case float64:
|
||||||
|
return int(raw), raw == float64(int(raw))
|
||||||
|
default:
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func newProductOwner(product models.ProductInfo, action, reason, remark, operatorIdentity, operatorName string, occurredAt time.Time) *models.ProductOwner {
|
func newProductOwner(product models.ProductInfo, action, reason, remark, operatorIdentity, operatorName string, occurredAt time.Time) *models.ProductOwner {
|
||||||
return &models.ProductOwner{
|
return &models.ProductOwner{
|
||||||
Entity: models.Entity{Identity: models.NewIdentity(), Status: "recorded", Version: 1},
|
Entity: models.Entity{Identity: models.NewIdentity(), Status: common.StatusRecorded, Version: 1},
|
||||||
ProductInfoID: product.ID, WarehouseID: product.WarehouseID, GasBasicID: product.GasBasicID,
|
ProductInfoID: product.ID, WarehouseID: product.WarehouseID, GasBasicID: product.GasBasicID,
|
||||||
DeliveryBasicID: product.DeliveryBasicID, UserAccountID: product.UserAccountID,
|
DeliveryBasicID: product.DeliveryBasicID, UserAccountID: product.UserAccountID,
|
||||||
Action: action, OccurredAt: occurredAt, Reason: reason, Remark: remark,
|
Action: action, OccurredAt: occurredAt, Reason: reason, Remark: remark,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"git.apinb.com/heqiapp/platforms/backend/api/internal/logic/common"
|
||||||
"git.apinb.com/heqiapp/platforms/backend/api/internal/models"
|
"git.apinb.com/heqiapp/platforms/backend/api/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -21,14 +22,14 @@ func TestValidParamsTextRequiresJSONObjectText(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestInitialProductStatusPrefersActualWarehouse(t *testing.T) {
|
func TestInitialProductStatusPrefersActualWarehouse(t *testing.T) {
|
||||||
if got := initialProductStatus(models.ProductInfo{WarehouseID: 1, UserAccountID: 2}); got != "in_stock" {
|
if got := initialProductStatus(models.ProductInfo{WarehouseID: 1, UserAccountID: 2}); got != common.StatusInStock {
|
||||||
t.Fatalf("warehouse product status = %s", got)
|
t.Fatalf("warehouse product status = %d", got)
|
||||||
}
|
}
|
||||||
if got := initialProductStatus(models.ProductInfo{UserAccountID: 2}); got != "in_use" {
|
if got := initialProductStatus(models.ProductInfo{UserAccountID: 2}); got != common.StatusInUse {
|
||||||
t.Fatalf("user product status = %s", got)
|
t.Fatalf("user product status = %d", got)
|
||||||
}
|
}
|
||||||
if got := initialProductStatus(models.ProductInfo{}); got != "pending" {
|
if got := initialProductStatus(models.ProductInfo{}); got != common.StatusPending {
|
||||||
t.Fatalf("unlocated product status = %s", got)
|
t.Fatalf("unlocated product status = %d", got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,13 +39,13 @@ func TestValidRepairEnforcesCompletionRules(t *testing.T) {
|
|||||||
if !validRepair(models.ProductRepair{StartedAt: started, Result: "pending"}) {
|
if !validRepair(models.ProductRepair{StartedAt: started, Result: "pending"}) {
|
||||||
t.Fatal("pending repair was rejected")
|
t.Fatal("pending repair was rejected")
|
||||||
}
|
}
|
||||||
if !validRepair(models.ProductRepair{StartedAt: started, CompletedAt: &completed, Result: "passed", TargetStatus: "in_stock"}) {
|
if !validRepair(models.ProductRepair{StartedAt: started, CompletedAt: &completed, Result: "passed", TargetStatus: common.StatusInStock}) {
|
||||||
t.Fatal("completed repair was rejected")
|
t.Fatal("completed repair was rejected")
|
||||||
}
|
}
|
||||||
if validRepair(models.ProductRepair{StartedAt: started, Result: "passed", TargetStatus: "in_stock"}) {
|
if validRepair(models.ProductRepair{StartedAt: started, Result: "passed", TargetStatus: common.StatusInStock}) {
|
||||||
t.Fatal("completed result without completion time was accepted")
|
t.Fatal("completed result without completion time was accepted")
|
||||||
}
|
}
|
||||||
if validRepair(models.ProductRepair{StartedAt: completed, CompletedAt: &started, Result: "failed", TargetStatus: "in_stock"}) {
|
if validRepair(models.ProductRepair{StartedAt: completed, CompletedAt: &started, Result: "failed", TargetStatus: common.StatusInStock}) {
|
||||||
t.Fatal("completion before start was accepted")
|
t.Fatal("completion before start was accepted")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package platform
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"git.apinb.com/heqiapp/platforms/backend/api/internal/logic/common"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -55,7 +56,7 @@ func (d ResourceDefinition) Allows(method string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func archiveValues() gin.H {
|
func archiveValues() gin.H {
|
||||||
return gin.H{"status": "archived"}
|
return gin.H{"status": common.StatusArchived}
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterFields(values map[string]any, allowedFields []string) gin.H {
|
func filterFields(values map[string]any, allowedFields []string) gin.H {
|
||||||
@@ -87,7 +88,7 @@ func ExpectedResources() []ResourceContract {
|
|||||||
resourceContract("gasorder", "gasorder_track", ReadOnly, "list"), resourceContract("gasorder", "gasorder_track_point", ReadOnly, "list"), resourceContract("gasorder", "gasorder_confirm", ReadOnly, "list"), resourceContract("gasorder", "gasorder_payment", ReadOnly, "list"),
|
resourceContract("gasorder", "gasorder_track", ReadOnly, "list"), resourceContract("gasorder", "gasorder_track_point", ReadOnly, "list"), resourceContract("gasorder", "gasorder_confirm", ReadOnly, "list"), resourceContract("gasorder", "gasorder_payment", ReadOnly, "list"),
|
||||||
resourceContract("finance", "fin_payment", Writable, "list"), resourceContract("finance", "fin_settlement", Writable, "list"), resourceContract("finance", "fin_reconciliation", Writable, "list"),
|
resourceContract("finance", "fin_payment", Writable, "list"), resourceContract("finance", "fin_settlement", Writable, "list"), resourceContract("finance", "fin_reconciliation", Writable, "list"),
|
||||||
resourceContract("content", "cms_content", Writable, "list"), resourceContract("customer_service", "cs_ticket", Writable, "list"),
|
resourceContract("content", "cms_content", Writable, "list"), resourceContract("customer_service", "cs_ticket", Writable, "list"),
|
||||||
resourceContract("platform", "platform_account", Writable, "list"), resourceContract("platform", "platform_role", Writable, "list"), resourceContract("platform", "platform_menu", Writable, "tree"),
|
resourceContract("platform", "platform_account", Writable, "list"), resourceContract("platform", "platform_role", Writable, "list"), resourceContract("platform", "platform_menu", ReadOnly, "tree"),
|
||||||
resourceContract("wallet", "wallet_basic", ReadOnly, "list"), resourceContract("wallet", "wallet_bank", ReadOnly, "list"), resourceContract("wallet", "wallet_payment", ReadOnly, "list"), resourceContract("wallet", "wallet_record", ReadOnly, "list"), resourceContract("wallet", "wallet_refund", ReadOnly, "list"), resourceContract("wallet", "wallet_apply_cash", ReadOnly, "list"),
|
resourceContract("wallet", "wallet_basic", ReadOnly, "list"), resourceContract("wallet", "wallet_bank", ReadOnly, "list"), resourceContract("wallet", "wallet_payment", ReadOnly, "list"), resourceContract("wallet", "wallet_record", ReadOnly, "list"), resourceContract("wallet", "wallet_refund", ReadOnly, "list"), resourceContract("wallet", "wallet_apply_cash", ReadOnly, "list"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ func CreateStaffCredential(ctx *gin.Context) {
|
|||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
credential := models.StaffCredential{Entity: common.NewEntity("enabled"), StaffAccountID: staffAccountID, CredentialType: request.CredentialType, CredentialNo: request.CredentialNo, ExpiredAt: request.ExpiredAt}
|
credential := models.StaffCredential{Entity: common.NewEntity(common.StatusEnable), StaffAccountID: staffAccountID, CredentialType: request.CredentialType, CredentialNo: request.CredentialNo, ExpiredAt: request.ExpiredAt}
|
||||||
if err := impl.DBService.Create(&credential).Error; err != nil {
|
if err := impl.DBService.Create(&credential).Error; err != nil {
|
||||||
infra.Response.Error(ctx, err)
|
infra.Response.Error(ctx, err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ func CreateStaff(ctx *gin.Context) {
|
|||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
staff := models.StaffAccount{Entity: common.NewEntity("draft"), Username: request.Username, PasswordHash: hash, Name: request.Name, Phone: request.Phone, Avatar: request.Avatar, RoleCode: request.RoleCode, GasBasicID: gasBasicID, DeliveryBasicID: deliveryBasicID, WorkStatus: request.WorkStatus}
|
staff := models.StaffAccount{Entity: common.NewEntity(common.StatusDraft), Username: request.Username, PasswordHash: hash, Name: request.Name, Phone: request.Phone, Avatar: request.Avatar, RoleCode: request.RoleCode, GasBasicID: gasBasicID, DeliveryBasicID: deliveryBasicID, WorkStatus: request.WorkStatus}
|
||||||
if staff.WorkStatus == "" {
|
if staff.WorkStatus == "" {
|
||||||
staff.WorkStatus = "off_duty"
|
staff.WorkStatus = "off_duty"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ func CreateUserAddress(ctx *gin.Context) {
|
|||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
address := models.UserAddress{Entity: common.NewEntity("enabled"), UserAccountID: userAccountID, Address: request.Address, Longitude: request.Longitude, Latitude: request.Latitude, IsDefault: request.IsDefault}
|
address := models.UserAddress{Entity: common.NewEntity(common.StatusEnable), UserAccountID: userAccountID, Address: request.Address, Longitude: request.Longitude, Latitude: request.Latitude, IsDefault: request.IsDefault}
|
||||||
if err := impl.DBService.Create(&address).Error; err != nil {
|
if err := impl.DBService.Create(&address).Error; err != nil {
|
||||||
infra.Response.Error(ctx, err)
|
infra.Response.Error(ctx, err)
|
||||||
return
|
return
|
||||||
@@ -70,7 +70,7 @@ func CreateUserServiceRelation(ctx *gin.Context) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
relation := models.UserServiceRelation{Entity: common.NewEntity("enabled"), UserAccountID: userAccountID, GasBasicID: gasBasicID, DeliveryBasicID: deliveryBasicID, StaffAccountID: staffAccountID}
|
relation := models.UserServiceRelation{Entity: common.NewEntity(common.StatusEnable), UserAccountID: userAccountID, GasBasicID: gasBasicID, DeliveryBasicID: deliveryBasicID, StaffAccountID: staffAccountID}
|
||||||
if err := impl.DBService.Create(&relation).Error; err != nil {
|
if err := impl.DBService.Create(&relation).Error; err != nil {
|
||||||
infra.Response.Error(ctx, err)
|
infra.Response.Error(ctx, err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ func CreateUser(ctx *gin.Context) {
|
|||||||
infra.Response.Error(ctx, err)
|
infra.Response.Error(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
user := models.UserAccount{Entity: common.NewEntity("enabled"), Username: request.Username, PasswordHash: hash, Name: request.Name, Phone: request.Phone, Avatar: request.Avatar, RealName: request.RealName}
|
user := models.UserAccount{Entity: common.NewEntity(common.StatusEnable), Username: request.Username, PasswordHash: hash, Name: request.Name, Phone: request.Phone, Avatar: request.Avatar, RealName: request.RealName}
|
||||||
if err := impl.DBService.Create(&user).Error; err != nil {
|
if err := impl.DBService.Create(&user).Error; err != nil {
|
||||||
infra.Response.Error(ctx, err)
|
infra.Response.Error(ctx, err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ func GetOrCreateOwnerWallet(ctx *gin.Context) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
candidate := models.WalletBasic{
|
candidate := models.WalletBasic{
|
||||||
Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled", Version: 1},
|
Entity: models.Entity{Identity: models.NewIdentity(), Status: common.StatusEnable, Version: 1},
|
||||||
OwnerType: ownerType, OwnerID: ownerID, OwnerIdentity: ownerIdentity,
|
OwnerType: ownerType, OwnerID: ownerID, OwnerIdentity: ownerIdentity,
|
||||||
}
|
}
|
||||||
if err := tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&candidate).Error; err != nil {
|
if err := tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&candidate).Error; err != nil {
|
||||||
@@ -169,9 +169,10 @@ func resolveWalletOwner(ownerType, ownerIdentity string) (uint64, error) {
|
|||||||
|
|
||||||
func UpdateWalletBasicStatus(ctx *gin.Context) {
|
func UpdateWalletBasicStatus(ctx *gin.Context) {
|
||||||
var request struct {
|
var request struct {
|
||||||
Status string `json:"status" binding:"required"`
|
Status int `json:"status" binding:"required"`
|
||||||
}
|
}
|
||||||
if err := ctx.ShouldBindJSON(&request); err != nil || (request.Status != "enabled" && request.Status != "disabled") {
|
if err := ctx.ShouldBindJSON(&request); err != nil ||
|
||||||
|
(request.Status != common.StatusEnable && request.Status != common.StatusDisable && request.Status != common.StatusFrozen) {
|
||||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -209,7 +210,7 @@ func RechargeWalletBasic(ctx *gin.Context) {
|
|||||||
}
|
}
|
||||||
updates := map[string]any{"balance": gorm.Expr("balance + ?", request.Amount)}
|
updates := map[string]any{"balance": gorm.Expr("balance + ?", request.Amount)}
|
||||||
query := tx.Model(&models.WalletBasic{}).
|
query := tx.Model(&models.WalletBasic{}).
|
||||||
Where("id = ? AND status = ? AND balance <= ?", wallet.ID, "enabled", math.MaxInt64-request.Amount)
|
Where("id = ? AND status = ? AND balance <= ?", wallet.ID, common.StatusEnable, math.MaxInt64-request.Amount)
|
||||||
if request.Withdrawable {
|
if request.Withdrawable {
|
||||||
updates["withdrawal_balance"] = gorm.Expr("withdrawal_balance + ?", request.Amount)
|
updates["withdrawal_balance"] = gorm.Expr("withdrawal_balance + ?", request.Amount)
|
||||||
query = query.Where("withdrawal_balance <= ?", math.MaxInt64-request.Amount)
|
query = query.Where("withdrawal_balance <= ?", math.MaxInt64-request.Amount)
|
||||||
@@ -226,7 +227,7 @@ func RechargeWalletBasic(ctx *gin.Context) {
|
|||||||
}
|
}
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
record = models.WalletRecord{
|
record = models.WalletRecord{
|
||||||
Entity: models.Entity{Identity: models.NewIdentity(), Status: "posted", Version: 1},
|
Entity: models.Entity{Identity: models.NewIdentity(), Status: common.StatusPosted, Version: 1},
|
||||||
WalletBasicID: wallet.ID, RecordNo: models.NewIdentity(), RequestNo: request.RequestNo,
|
WalletBasicID: wallet.ID, RecordNo: models.NewIdentity(), RequestNo: request.RequestNo,
|
||||||
Direction: "income", TradeType: "recharge", Amount: request.Amount,
|
Direction: "income", TradeType: "recharge", Amount: request.Amount,
|
||||||
BalanceAfter: wallet.Balance, WithdrawalBalanceAfter: wallet.WithdrawalBalance,
|
BalanceAfter: wallet.Balance, WithdrawalBalanceAfter: wallet.WithdrawalBalance,
|
||||||
@@ -250,14 +251,14 @@ func RechargeWalletBasic(ctx *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ApproveWalletApplyCash(ctx *gin.Context) {
|
func ApproveWalletApplyCash(ctx *gin.Context) {
|
||||||
reviewWalletApplyCash(ctx, "approved")
|
reviewWalletApplyCash(ctx, common.StatusApproved)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RejectWalletApplyCash(ctx *gin.Context) {
|
func RejectWalletApplyCash(ctx *gin.Context) {
|
||||||
reviewWalletApplyCash(ctx, "rejected")
|
reviewWalletApplyCash(ctx, common.StatusRejected)
|
||||||
}
|
}
|
||||||
|
|
||||||
func reviewWalletApplyCash(ctx *gin.Context, targetStatus string) {
|
func reviewWalletApplyCash(ctx *gin.Context, targetStatus int) {
|
||||||
if !common.RequirePlatformRoot(ctx) {
|
if !common.RequirePlatformRoot(ctx) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -278,11 +279,11 @@ func reviewWalletApplyCash(ctx *gin.Context, targetStatus string) {
|
|||||||
if application.Status == targetStatus {
|
if application.Status == targetStatus {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if application.Status != "pending" {
|
if application.Status != common.StatusPending {
|
||||||
return errors.New("cash application is not pending")
|
return errors.New("cash application is not pending")
|
||||||
}
|
}
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
if targetStatus == "rejected" {
|
if targetStatus == common.StatusRejected {
|
||||||
result := tx.Model(&models.WalletBasic{}).
|
result := tx.Model(&models.WalletBasic{}).
|
||||||
Where("id = ? AND withdrawal_balance <= ?", application.WalletBasicID, math.MaxInt64-application.Amount).
|
Where("id = ? AND withdrawal_balance <= ?", application.WalletBasicID, math.MaxInt64-application.Amount).
|
||||||
Update("withdrawal_balance", gorm.Expr("withdrawal_balance + ?", application.Amount))
|
Update("withdrawal_balance", gorm.Expr("withdrawal_balance + ?", application.Amount))
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ type Entity struct {
|
|||||||
Identity string `gorm:"column:identity;type:varchar(36);not null;uniqueIndex" json:"identity"` // UUID V7 业务标识
|
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"` // 创建时间
|
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"` // 更新时间
|
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"` // 业务状态
|
Status int `gorm:"column:status;not null;default:0" json:"status"` // 业务状态
|
||||||
Version int `gorm:"column:version;not null;default:1" json:"version"` // 乐观锁版本
|
Version int `gorm:"column:version;not null;default:1" json:"version"` // 乐观锁版本
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ type GasorderBasic struct {
|
|||||||
DeliveryFee int64 `gorm:"column:delivery_fee;not null;default:0;check:delivery_fee >= 0" json:"delivery_fee"` // 配送费,单位分
|
DeliveryFee int64 `gorm:"column:delivery_fee;not null;default:0;check:delivery_fee >= 0" json:"delivery_fee"` // 配送费,单位分
|
||||||
DiscountAmount int64 `gorm:"column:discount_amount;not null;default:0;check:discount_amount >= 0" json:"discount_amount"` // 优惠金额,单位分
|
DiscountAmount int64 `gorm:"column:discount_amount;not null;default:0;check:discount_amount >= 0" json:"discount_amount"` // 优惠金额,单位分
|
||||||
PayableAmount int64 `gorm:"column:payable_amount;not null;check:payable_amount > 0" json:"payable_amount"` // 应付金额,单位分
|
PayableAmount int64 `gorm:"column:payable_amount;not null;check:payable_amount > 0" json:"payable_amount"` // 应付金额,单位分
|
||||||
PreviousStatus string `gorm:"column:previous_status;type:varchar(32);not null;default:''" json:"previous_status"` // 异常前状态
|
PreviousStatus int `gorm:"column:previous_status;not null;default:0" json:"previous_status"` // 异常前状态
|
||||||
OperatorIdentity string `gorm:"column:operator_identity;type:varchar(36);not null;default:''" json:"operator_identity"` // 建单操作人标识
|
OperatorIdentity string `gorm:"column:operator_identity;type:varchar(36);not null;default:''" json:"operator_identity"` // 建单操作人标识
|
||||||
OperatorName string `gorm:"column:operator_name;type:varchar(64);not null;default:''" json:"operator_name"` // 建单操作人姓名快照
|
OperatorName string `gorm:"column:operator_name;type:varchar(64);not null;default:''" json:"operator_name"` // 建单操作人姓名快照
|
||||||
Remark string `gorm:"column:remark;type:text;not null;default:''" json:"remark"` // 订单备注
|
Remark string `gorm:"column:remark;type:text;not null;default:''" json:"remark"` // 订单备注
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ type GasorderContractRevision struct {
|
|||||||
Entity // 公共实体字段
|
Entity // 公共实体字段
|
||||||
GasorderContractID uint64 `gorm:"column:gasorder_contract_id;not null;index" json:"gasorder_contract_id"` // 合同自增主键
|
GasorderContractID uint64 `gorm:"column:gasorder_contract_id;not null;index" json:"gasorder_contract_id"` // 合同自增主键
|
||||||
Action string `gorm:"column:action;type:varchar(32);not null;index" json:"action"` // 合同变更动作
|
Action string `gorm:"column:action;type:varchar(32);not null;index" json:"action"` // 合同变更动作
|
||||||
ContractStatus string `gorm:"column:contract_status;type:varchar(32);not null" json:"contract_status"` // 合同状态快照
|
ContractStatus int `gorm:"column:contract_status;not null" json:"contract_status"` // 合同状态快照
|
||||||
EffectiveAt time.Time `gorm:"column:effective_at;type:timestamptz;not null" json:"effective_at"` // 生效时间快照
|
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"` // 到期时间快照
|
ExpiredAt *time.Time `gorm:"column:expired_at;type:timestamptz" json:"expired_at"` // 到期时间快照
|
||||||
OperatorIdentity string `gorm:"column:operator_identity;type:varchar(36);not null;default:''" json:"operator_identity"` // 操作人标识
|
OperatorIdentity string `gorm:"column:operator_identity;type:varchar(36);not null;default:''" json:"operator_identity"` // 操作人标识
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import (
|
|||||||
type GasorderStatus struct {
|
type GasorderStatus struct {
|
||||||
Entity // 公共实体字段
|
Entity // 公共实体字段
|
||||||
GasorderBasicID uint64 `gorm:"column:gasorder_basic_id;not null;index" json:"gasorder_basic_id"` // 订单自增主键
|
GasorderBasicID uint64 `gorm:"column:gasorder_basic_id;not null;index" json:"gasorder_basic_id"` // 订单自增主键
|
||||||
FromStatus string `gorm:"column:from_status;type:varchar(32);not null;default:''" json:"from_status"` // 原状态
|
FromStatus int `gorm:"column:from_status;not null;default:0" json:"from_status"` // 原状态
|
||||||
ToStatus string `gorm:"column:to_status;type:varchar(32);not null;index" json:"to_status"` // 新状态
|
ToStatus int `gorm:"column:to_status;not null;index" json:"to_status"` // 新状态
|
||||||
OperatorIdentity string `gorm:"column:operator_identity;type:varchar(36);not null;default:''" json:"operator_identity"` // 操作人标识
|
OperatorIdentity string `gorm:"column:operator_identity;type:varchar(36);not null;default:''" json:"operator_identity"` // 操作人标识
|
||||||
OperatorName string `gorm:"column:operator_name;type:varchar(64);not null;default:''" json:"operator_name"` // 操作人姓名快照
|
OperatorName string `gorm:"column:operator_name;type:varchar(64);not null;default:''" json:"operator_name"` // 操作人姓名快照
|
||||||
OccurredAt time.Time `gorm:"column:occurred_at;type:timestamptz;not null;index" json:"occurred_at"` // 发生时间
|
OccurredAt time.Time `gorm:"column:occurred_at;type:timestamptz;not null;index" json:"occurred_at"` // 发生时间
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
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" }
|
|
||||||
@@ -9,7 +9,6 @@ func TestPlatformModelTableNames(t *testing.T) {
|
|||||||
want string
|
want string
|
||||||
}{
|
}{
|
||||||
{name: "account", table: &PlatformAccount{}, want: "platform_account"},
|
{name: "account", table: &PlatformAccount{}, want: "platform_account"},
|
||||||
{name: "menu", table: &PlatformMenu{}, want: "platform_menu"},
|
|
||||||
{name: "role", table: &PlatformRole{}, want: "platform_role"},
|
{name: "role", table: &PlatformRole{}, want: "platform_role"},
|
||||||
{name: "role menu", table: &PlatformRoleMenu{}, want: "platform_role_menu"},
|
{name: "role menu", table: &PlatformRoleMenu{}, want: "platform_role_menu"},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ import (
|
|||||||
"git.apinb.com/bsm-sdk/core/database"
|
"git.apinb.com/bsm-sdk/core/database"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PlatformRoleMenu 对应 platform_role_menu,记录角色拥有的菜单权限。
|
// PlatformRoleMenu 对应 platform_role_menu,记录角色拥有的静态菜单权限。
|
||||||
type PlatformRoleMenu struct {
|
type PlatformRoleMenu struct {
|
||||||
ID uint64 `gorm:"column:id;primaryKey;autoIncrement" json:"id"` // 数据库自增主键
|
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"` // 角色自增主键
|
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"` // 菜单自增主键
|
MenuCode string `gorm:"column:menu_code;type:varchar(64);not null;uniqueIndex:uk_platform_role_menu" json:"menu_code"` // 静态菜单编码
|
||||||
CreatedAt time.Time `gorm:"column:created_at;type:timestamptz;not null" json:"created_at"` // 创建时间
|
CreatedAt time.Time `gorm:"column:created_at;type:timestamptz;not null" json:"created_at"` // 创建时间
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ type ProductRepair struct {
|
|||||||
StartedAt time.Time `gorm:"column:started_at;type:timestamptz;not null" json:"started_at"` // 开始时间
|
StartedAt time.Time `gorm:"column:started_at;type:timestamptz;not null" json:"started_at"` // 开始时间
|
||||||
CompletedAt *time.Time `gorm:"column:completed_at;type:timestamptz" json:"completed_at"` // 完成时间
|
CompletedAt *time.Time `gorm:"column:completed_at;type:timestamptz" json:"completed_at"` // 完成时间
|
||||||
Result string `gorm:"column:result;type:varchar(32);not null;default:'pending'" json:"result"` // 检修结果
|
Result string `gorm:"column:result;type:varchar(32);not null;default:'pending'" json:"result"` // 检修结果
|
||||||
TargetStatus string `gorm:"column:target_status;type:varchar(32);not null;default:''" json:"target_status"` // 完成后的产品状态
|
TargetStatus int `gorm:"column:target_status;not null;default:0" json:"target_status"` // 完成后的产品状态
|
||||||
Content string `gorm:"column:content;type:text;not null;default:''" json:"content"` // 检修内容
|
Content string `gorm:"column:content;type:text;not null;default:''" json:"content"` // 检修内容
|
||||||
Operator string `gorm:"column:operator;type:varchar(64);not null;default:''" json:"operator"` // 检修人员
|
Operator string `gorm:"column:operator;type:varchar(64);not null;default:''" json:"operator"` // 检修人员
|
||||||
Remark string `gorm:"column:remark;type:text;not null;default:''" json:"remark"` // 备注
|
Remark string `gorm:"column:remark;type:text;not null;default:''" json:"remark"` // 备注
|
||||||
|
|||||||
@@ -13,16 +13,16 @@ type DashboardOverview struct {
|
|||||||
// GetDashboardOverview 通过独立查询返回首页概览指标。
|
// GetDashboardOverview 通过独立查询返回首页概览指标。
|
||||||
func GetDashboardOverview() (DashboardOverview, error) {
|
func GetDashboardOverview() (DashboardOverview, error) {
|
||||||
var overview DashboardOverview
|
var overview DashboardOverview
|
||||||
if err := impl.DBService.Model(&GasBasic{}).Where("status = ?", "enabled").Count(&overview.GasBasicCount).Error; err != nil {
|
if err := impl.DBService.Model(&GasBasic{}).Where("status = ?", 1).Count(&overview.GasBasicCount).Error; err != nil {
|
||||||
return DashboardOverview{}, err
|
return DashboardOverview{}, err
|
||||||
}
|
}
|
||||||
if err := impl.DBService.Model(&DeliveryBasic{}).Where("status = ?", "enabled").Count(&overview.DeliveryBasicCount).Error; err != nil {
|
if err := impl.DBService.Model(&DeliveryBasic{}).Where("status = ?", 1).Count(&overview.DeliveryBasicCount).Error; err != nil {
|
||||||
return DashboardOverview{}, err
|
return DashboardOverview{}, err
|
||||||
}
|
}
|
||||||
if err := impl.DBService.Model(&StaffAccount{}).Where("work_status = ?", "on_duty").Count(&overview.StaffCount).Error; err != nil {
|
if err := impl.DBService.Model(&StaffAccount{}).Where("work_status = ?", "on_duty").Count(&overview.StaffCount).Error; err != nil {
|
||||||
return DashboardOverview{}, err
|
return DashboardOverview{}, err
|
||||||
}
|
}
|
||||||
if err := impl.DBService.Model(&UserAccount{}).Where("status = ?", "enabled").Count(&overview.UserCount).Error; err != nil {
|
if err := impl.DBService.Model(&UserAccount{}).Where("status = ?", 1).Count(&overview.UserCount).Error; err != nil {
|
||||||
return DashboardOverview{}, err
|
return DashboardOverview{}, err
|
||||||
}
|
}
|
||||||
return overview, nil
|
return overview, nil
|
||||||
|
|||||||
@@ -208,11 +208,7 @@ func registerPlatformRoute(group *gin.RouterGroup) {
|
|||||||
role.PUT("/:identity/menu", platformlogic.ReplacePlatformRoleMenus)
|
role.PUT("/:identity/menu", platformlogic.ReplacePlatformRoleMenus)
|
||||||
menu := group.Group("/platform_menu")
|
menu := group.Group("/platform_menu")
|
||||||
menu.GET("", platformlogic.ListPlatformMenu)
|
menu.GET("", platformlogic.ListPlatformMenu)
|
||||||
menu.POST("", platformlogic.CreatePlatformMenu)
|
|
||||||
menu.GET("/:identity", platformlogic.GetPlatformMenu)
|
menu.GET("/:identity", platformlogic.GetPlatformMenu)
|
||||||
menu.PUT("/:identity", platformlogic.UpdatePlatformMenu)
|
|
||||||
menu.PATCH("/:identity/status", platformlogic.UpdatePlatformMenuStatus)
|
|
||||||
menu.DELETE("/:identity", platformlogic.ArchivePlatformMenu)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func registerFinanceRoute(group *gin.RouterGroup) {
|
func registerFinanceRoute(group *gin.RouterGroup) {
|
||||||
|
|||||||
@@ -87,13 +87,16 @@ func TestPlatformOrganizationAndAccountRoutesExposeResourceCRUD(t *testing.T) {
|
|||||||
"/user_service_relation",
|
"/user_service_relation",
|
||||||
"/platform_account",
|
"/platform_account",
|
||||||
"/platform_role",
|
"/platform_role",
|
||||||
"/platform_menu",
|
|
||||||
} {
|
} {
|
||||||
assertRouteMethods(t, routes, "/heqi/platform/v1"+resource, http.MethodGet, http.MethodPost)
|
assertRouteMethods(t, routes, "/heqi/platform/v1"+resource, http.MethodGet, http.MethodPost)
|
||||||
assertRouteMethods(t, routes, "/heqi/platform/v1"+resource+"/:identity", http.MethodGet, http.MethodPut, http.MethodDelete)
|
assertRouteMethods(t, routes, "/heqi/platform/v1"+resource+"/:identity", http.MethodGet, http.MethodPut, http.MethodDelete)
|
||||||
assertRouteMethods(t, routes, "/heqi/platform/v1"+resource+"/:identity/status", http.MethodPatch)
|
assertRouteMethods(t, routes, "/heqi/platform/v1"+resource+"/:identity/status", http.MethodPatch)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assertRouteMethods(t, routes, "/heqi/platform/v1/platform_menu", http.MethodGet)
|
||||||
|
assertRouteMethods(t, routes, "/heqi/platform/v1/platform_menu/:identity", http.MethodGet)
|
||||||
|
assertNoRouteMethods(t, routes, "/heqi/platform/v1/platform_menu", http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete)
|
||||||
|
assertNoRouteMethods(t, routes, "/heqi/platform/v1/platform_menu/:identity", http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete)
|
||||||
assertRouteMethods(t, routes, "/heqi/platform/v1/platform_role/:identity/menu", http.MethodGet, http.MethodPut)
|
assertRouteMethods(t, routes, "/heqi/platform/v1/platform_role/:identity/menu", http.MethodGet, http.MethodPut)
|
||||||
assertNoRouteMethods(t, routes, "/heqi/platform/v1/platform_role/:identity/menus", http.MethodGet, http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete)
|
assertNoRouteMethods(t, routes, "/heqi/platform/v1/platform_role/:identity/menus", http.MethodGet, http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete)
|
||||||
assertNoRouteMethods(t, routes, "/heqi/platform/v1/platfrom_account", http.MethodGet, http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete)
|
assertNoRouteMethods(t, routes, "/heqi/platform/v1/platfrom_account", http.MethodGet, http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"git.apinb.com/heqiapp/platforms/backend/api/internal/logic/common"
|
||||||
"git.apinb.com/heqiapp/platforms/backend/api/internal/models"
|
"git.apinb.com/heqiapp/platforms/backend/api/internal/models"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
@@ -27,7 +28,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
|
|
||||||
return database.Transaction(func(tx *gorm.DB) error {
|
return database.Transaction(func(tx *gorm.DB) error {
|
||||||
gas := models.GasBasic{
|
gas := models.GasBasic{
|
||||||
Entity: entity(1, "enabled"), Code: "MOCK-GAS-001", Name: "和气示例气站",
|
Entity: entity(1, common.StatusEnable), Code: "MOCK-GAS-001", Name: "和气示例气站",
|
||||||
CreditCode: "91310000MOCKGAS001", Principal: "张站长",
|
CreditCode: "91310000MOCKGAS001", Principal: "张站长",
|
||||||
Address: "上海市浦东新区示例路 1 号", Longitude: "121.5440", Latitude: "31.2210",
|
Address: "上海市浦东新区示例路 1 号", Longitude: "121.5440", Latitude: "31.2210",
|
||||||
}
|
}
|
||||||
@@ -36,7 +37,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gasAccount := models.GasAccount{
|
gasAccount := models.GasAccount{
|
||||||
Entity: entity(2, "enabled"), GasBasicID: gas.ID, Username: "mock_gas_admin",
|
Entity: entity(2, common.StatusEnable), GasBasicID: gas.ID, Username: "mock_gas_admin",
|
||||||
DisplayName: "示例气站管理员", PasswordHash: string(passwordHash), RoleCode: "admin",
|
DisplayName: "示例气站管理员", PasswordHash: string(passwordHash), RoleCode: "admin",
|
||||||
}
|
}
|
||||||
if err := put(tx, &gasAccount); err != nil {
|
if err := put(tx, &gasAccount); err != nil {
|
||||||
@@ -44,7 +45,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
delivery := models.DeliveryBasic{
|
delivery := models.DeliveryBasic{
|
||||||
Entity: entity(3, "enabled"), DeliveryCode: "MOCK-DELIVERY-001",
|
Entity: entity(3, common.StatusEnable), DeliveryCode: "MOCK-DELIVERY-001",
|
||||||
GasBasicID: gas.ID, Name: "和气示例配送点", Principal: "李主管",
|
GasBasicID: gas.ID, Name: "和气示例配送点", Principal: "李主管",
|
||||||
Address: "上海市浦东新区示例路 18 号",
|
Address: "上海市浦东新区示例路 18 号",
|
||||||
}
|
}
|
||||||
@@ -53,7 +54,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deliveryAccount := models.DeliveryAccount{
|
deliveryAccount := models.DeliveryAccount{
|
||||||
Entity: entity(4, "enabled"), DeliveryBasicID: delivery.ID,
|
Entity: entity(4, common.StatusEnable), DeliveryBasicID: delivery.ID,
|
||||||
Username: "mock_delivery_admin", DisplayName: "示例配送点管理员",
|
Username: "mock_delivery_admin", DisplayName: "示例配送点管理员",
|
||||||
PasswordHash: string(passwordHash), RoleCode: "admin",
|
PasswordHash: string(passwordHash), RoleCode: "admin",
|
||||||
}
|
}
|
||||||
@@ -62,7 +63,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
staff := models.StaffAccount{
|
staff := models.StaffAccount{
|
||||||
Entity: entity(5, "enabled"), Username: "mock_driver", PasswordHash: string(passwordHash),
|
Entity: entity(5, common.StatusEnable), Username: "mock_driver", PasswordHash: string(passwordHash),
|
||||||
Name: "王师傅", Phone: "13900000001", RoleCode: "driver",
|
Name: "王师傅", Phone: "13900000001", RoleCode: "driver",
|
||||||
GasBasicID: gas.ID, DeliveryBasicID: delivery.ID, WorkStatus: "on_duty",
|
GasBasicID: gas.ID, DeliveryBasicID: delivery.ID, WorkStatus: "on_duty",
|
||||||
}
|
}
|
||||||
@@ -71,7 +72,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
credential := models.StaffCredential{
|
credential := models.StaffCredential{
|
||||||
Entity: entity(6, "enabled"), StaffAccountID: staff.ID,
|
Entity: entity(6, common.StatusEnable), StaffAccountID: staff.ID,
|
||||||
CredentialType: "delivery", CredentialNo: "MOCK-CERT-001", ExpiredAt: &nextYear,
|
CredentialType: "delivery", CredentialNo: "MOCK-CERT-001", ExpiredAt: &nextYear,
|
||||||
}
|
}
|
||||||
if err := put(tx, &credential); err != nil {
|
if err := put(tx, &credential); err != nil {
|
||||||
@@ -79,7 +80,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
user := models.UserAccount{
|
user := models.UserAccount{
|
||||||
Entity: entity(7, "enabled"), Username: "mock_customer", PasswordHash: string(passwordHash),
|
Entity: entity(7, common.StatusEnable), Username: "mock_customer", PasswordHash: string(passwordHash),
|
||||||
Name: "陈女士", Phone: "13800000001", RealName: "陈示例",
|
Name: "陈女士", Phone: "13800000001", RealName: "陈示例",
|
||||||
}
|
}
|
||||||
if err := put(tx, &user); err != nil {
|
if err := put(tx, &user); err != nil {
|
||||||
@@ -87,7 +88,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
address := models.UserAddress{
|
address := models.UserAddress{
|
||||||
Entity: entity(8, "enabled"), UserAccountID: user.ID,
|
Entity: entity(8, common.StatusEnable), UserAccountID: user.ID,
|
||||||
Address: "上海市浦东新区客户路 88 号", Longitude: "121.5500",
|
Address: "上海市浦东新区客户路 88 号", Longitude: "121.5500",
|
||||||
Latitude: "31.2250", IsDefault: true,
|
Latitude: "31.2250", IsDefault: true,
|
||||||
}
|
}
|
||||||
@@ -96,7 +97,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
serviceRelation := models.UserServiceRelation{
|
serviceRelation := models.UserServiceRelation{
|
||||||
Entity: entity(9, "enabled"), UserAccountID: user.ID, GasBasicID: gas.ID,
|
Entity: entity(9, common.StatusEnable), UserAccountID: user.ID, GasBasicID: gas.ID,
|
||||||
DeliveryBasicID: delivery.ID, StaffAccountID: staff.ID,
|
DeliveryBasicID: delivery.ID, StaffAccountID: staff.ID,
|
||||||
}
|
}
|
||||||
if err := put(tx, &serviceRelation); err != nil {
|
if err := put(tx, &serviceRelation); err != nil {
|
||||||
@@ -104,14 +105,14 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
productType := models.ProductType{
|
productType := models.ProductType{
|
||||||
Entity: entity(10, "enabled"), Code: "MOCK-LPG-15KG", Name: "15kg 液化气钢瓶",
|
Entity: entity(10, common.StatusEnable), Code: "MOCK-LPG-15KG", Name: "15kg 液化气钢瓶",
|
||||||
}
|
}
|
||||||
if err := put(tx, &productType); err != nil {
|
if err := put(tx, &productType); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
warehouse := models.ProductWarehouse{
|
warehouse := models.ProductWarehouse{
|
||||||
Entity: entity(11, "enabled"), Code: "MOCK-WH-001", Name: "示例中心库房",
|
Entity: entity(11, common.StatusEnable), Code: "MOCK-WH-001", Name: "示例中心库房",
|
||||||
Address: gas.Address, Manager: "赵库管", Phone: "13700000001", IsEnabled: true,
|
Address: gas.Address, Manager: "赵库管", Phone: "13700000001", IsEnabled: true,
|
||||||
}
|
}
|
||||||
if err := put(tx, &warehouse); err != nil {
|
if err := put(tx, &warehouse); err != nil {
|
||||||
@@ -120,7 +121,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
|
|
||||||
enabledAt := yesterday
|
enabledAt := yesterday
|
||||||
productInfo := models.ProductInfo{
|
productInfo := models.ProductInfo{
|
||||||
Entity: entity(12, "enabled"), Code: "MOCK-CYLINDER-001", Name: "示例液化气钢瓶",
|
Entity: entity(12, common.StatusEnable), Code: "MOCK-CYLINDER-001", Name: "示例液化气钢瓶",
|
||||||
ProductTypeID: productType.ID, Params: `{"weight":"15kg","medium":"LPG"}`,
|
ProductTypeID: productType.ID, Params: `{"weight":"15kg","medium":"LPG"}`,
|
||||||
WarehouseID: warehouse.ID, GasBasicID: gas.ID, ProducedAt: now.AddDate(-1, 0, 0),
|
WarehouseID: warehouse.ID, GasBasicID: gas.ID, ProducedAt: now.AddDate(-1, 0, 0),
|
||||||
IsEnabled: true, EnabledAt: &enabledAt,
|
IsEnabled: true, EnabledAt: &enabledAt,
|
||||||
@@ -130,7 +131,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
productOwner := models.ProductOwner{
|
productOwner := models.ProductOwner{
|
||||||
Entity: entity(13, "enabled"), ProductInfoID: productInfo.ID,
|
Entity: entity(13, common.StatusEnable), ProductInfoID: productInfo.ID,
|
||||||
WarehouseID: warehouse.ID, GasBasicID: gas.ID, Action: "stock_in",
|
WarehouseID: warehouse.ID, GasBasicID: gas.ID, Action: "stock_in",
|
||||||
OccurredAt: yesterday, Reason: "模拟数据初始化", OperatorName: "系统",
|
OccurredAt: yesterday, Reason: "模拟数据初始化", OperatorName: "系统",
|
||||||
}
|
}
|
||||||
@@ -140,9 +141,9 @@ func MockData(database *gorm.DB) error {
|
|||||||
|
|
||||||
completedAt := yesterday.Add(2 * time.Hour)
|
completedAt := yesterday.Add(2 * time.Hour)
|
||||||
productRepair := models.ProductRepair{
|
productRepair := models.ProductRepair{
|
||||||
Entity: entity(14, "completed"), ProductInfoID: productInfo.ID,
|
Entity: entity(14, common.StatusCompleted), ProductInfoID: productInfo.ID,
|
||||||
RepairNo: "MOCK-REPAIR-001", RepairType: "inspection", StartedAt: yesterday,
|
RepairNo: "MOCK-REPAIR-001", RepairType: "inspection", StartedAt: yesterday,
|
||||||
CompletedAt: &completedAt, Result: "passed", TargetStatus: "enabled",
|
CompletedAt: &completedAt, Result: "passed", TargetStatus: common.StatusEnable,
|
||||||
Content: "外观、阀门与气密性检查", Operator: staff.Name,
|
Content: "外观、阀门与气密性检查", Operator: staff.Name,
|
||||||
}
|
}
|
||||||
if err := put(tx, &productRepair); err != nil {
|
if err := put(tx, &productRepair); err != nil {
|
||||||
@@ -150,7 +151,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
contract := models.GasorderContract{
|
contract := models.GasorderContract{
|
||||||
Entity: entity(15, "active"), ContractNo: "MOCK-CONTRACT-001",
|
Entity: entity(15, common.StatusActive), ContractNo: "MOCK-CONTRACT-001",
|
||||||
UserAccountID: user.ID, GasBasicID: gas.ID, DeliveryBasicID: delivery.ID,
|
UserAccountID: user.ID, GasBasicID: gas.ID, DeliveryBasicID: delivery.ID,
|
||||||
Title: "居民瓶装气配送示例合同", Terms: "按需配送,安全使用。",
|
Title: "居民瓶装气配送示例合同", Terms: "按需配送,安全使用。",
|
||||||
DefaultDeliveryFee: 500, SignedAt: yesterday, EffectiveAt: yesterday, ExpiredAt: &nextYear,
|
DefaultDeliveryFee: 500, SignedAt: yesterday, EffectiveAt: yesterday, ExpiredAt: &nextYear,
|
||||||
@@ -160,8 +161,8 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
contractRevision := models.GasorderContractRevision{
|
contractRevision := models.GasorderContractRevision{
|
||||||
Entity: entity(16, "active"), GasorderContractID: contract.ID, Action: "activate",
|
Entity: entity(16, common.StatusActive), GasorderContractID: contract.ID, Action: "activate",
|
||||||
ContractStatus: "active", EffectiveAt: contract.EffectiveAt, ExpiredAt: contract.ExpiredAt,
|
ContractStatus: common.StatusActive, EffectiveAt: contract.EffectiveAt, ExpiredAt: contract.ExpiredAt,
|
||||||
OperatorIdentity: gasAccount.Identity, OperatorName: gasAccount.DisplayName,
|
OperatorIdentity: gasAccount.Identity, OperatorName: gasAccount.DisplayName,
|
||||||
OccurredAt: yesterday, Reason: "模拟合同启用",
|
OccurredAt: yesterday, Reason: "模拟合同启用",
|
||||||
}
|
}
|
||||||
@@ -170,7 +171,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
contractProduct := models.GasorderContractProduct{
|
contractProduct := models.GasorderContractProduct{
|
||||||
Entity: entity(17, "active"), GasorderContractID: contract.ID,
|
Entity: entity(17, common.StatusActive), GasorderContractID: contract.ID,
|
||||||
ProductInfoID: productInfo.ID, ProductCode: productInfo.Code,
|
ProductInfoID: productInfo.ID, ProductCode: productInfo.Code,
|
||||||
ProductTypeName: productType.Name, ProductParams: productInfo.Params,
|
ProductTypeName: productType.Name, ProductParams: productInfo.Params,
|
||||||
UnitPrice: 9800, BoundAt: yesterday,
|
UnitPrice: 9800, BoundAt: yesterday,
|
||||||
@@ -180,7 +181,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gasOrder := models.GasorderBasic{
|
gasOrder := models.GasorderBasic{
|
||||||
Entity: entity(18, "completed"), OrderNo: "MOCK-GASORDER-001",
|
Entity: entity(18, common.StatusCompleted), OrderNo: "MOCK-GASORDER-001",
|
||||||
RequestNo: "MOCK-REQ-GASORDER-001", GasorderContractID: contract.ID,
|
RequestNo: "MOCK-REQ-GASORDER-001", GasorderContractID: contract.ID,
|
||||||
UserAccountID: user.ID, CreatorType: "user", CreatorID: user.ID,
|
UserAccountID: user.ID, CreatorType: "user", CreatorID: user.ID,
|
||||||
CreatorIdentity: user.Identity, GasBasicID: gas.ID, DeliveryBasicID: delivery.ID,
|
CreatorIdentity: user.Identity, GasBasicID: gas.ID, DeliveryBasicID: delivery.ID,
|
||||||
@@ -194,7 +195,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gasOrderItem := models.GasorderItem{
|
gasOrderItem := models.GasorderItem{
|
||||||
Entity: entity(19, "completed"), GasorderBasicID: gasOrder.ID,
|
Entity: entity(19, common.StatusCompleted), GasorderBasicID: gasOrder.ID,
|
||||||
GasorderContractProductID: contractProduct.ID, ProductInfoID: productInfo.ID,
|
GasorderContractProductID: contractProduct.ID, ProductInfoID: productInfo.ID,
|
||||||
ProductCode: productInfo.Code, ProductTypeName: productType.Name,
|
ProductCode: productInfo.Code, ProductTypeName: productType.Name,
|
||||||
ProductParams: productInfo.Params, UnitPrice: contractProduct.UnitPrice,
|
ProductParams: productInfo.Params, UnitPrice: contractProduct.UnitPrice,
|
||||||
@@ -204,7 +205,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assignment := models.GasorderAssign{
|
assignment := models.GasorderAssign{
|
||||||
Entity: entity(20, "completed"), GasorderBasicID: gasOrder.ID, GasBasicID: gas.ID,
|
Entity: entity(20, common.StatusCompleted), GasorderBasicID: gasOrder.ID, GasBasicID: gas.ID,
|
||||||
DeliveryBasicID: delivery.ID, StaffAccountID: staff.ID,
|
DeliveryBasicID: delivery.ID, StaffAccountID: staff.ID,
|
||||||
AssignerIdentity: deliveryAccount.Identity, AssignerName: deliveryAccount.DisplayName,
|
AssignerIdentity: deliveryAccount.Identity, AssignerName: deliveryAccount.DisplayName,
|
||||||
AssignedAt: now.Add(-2 * time.Hour), Reason: "系统示例派单",
|
AssignedAt: now.Add(-2 * time.Hour), Reason: "系统示例派单",
|
||||||
@@ -214,8 +215,8 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
orderStatus := models.GasorderStatus{
|
orderStatus := models.GasorderStatus{
|
||||||
Entity: entity(21, "completed"), GasorderBasicID: gasOrder.ID,
|
Entity: entity(21, common.StatusCompleted), GasorderBasicID: gasOrder.ID,
|
||||||
FromStatus: "delivering", ToStatus: "completed",
|
FromStatus: common.StatusDelivering, ToStatus: common.StatusCompleted,
|
||||||
OperatorIdentity: staff.Identity, OperatorName: staff.Name,
|
OperatorIdentity: staff.Identity, OperatorName: staff.Name,
|
||||||
OccurredAt: now, Reason: "用户已签收",
|
OccurredAt: now, Reason: "用户已签收",
|
||||||
}
|
}
|
||||||
@@ -225,7 +226,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
|
|
||||||
trackCompletedAt := now.Add(-10 * time.Minute)
|
trackCompletedAt := now.Add(-10 * time.Minute)
|
||||||
track := models.GasorderTrack{
|
track := models.GasorderTrack{
|
||||||
Entity: entity(22, "completed"), GasorderBasicID: gasOrder.ID,
|
Entity: entity(22, common.StatusCompleted), GasorderBasicID: gasOrder.ID,
|
||||||
StaffAccountID: staff.ID, AttemptNo: 1, StartedAt: now.Add(-90 * time.Minute),
|
StaffAccountID: staff.ID, AttemptNo: 1, StartedAt: now.Add(-90 * time.Minute),
|
||||||
CompletedAt: &trackCompletedAt,
|
CompletedAt: &trackCompletedAt,
|
||||||
}
|
}
|
||||||
@@ -234,7 +235,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
trackPoint := models.GasorderTrackPoint{
|
trackPoint := models.GasorderTrackPoint{
|
||||||
Entity: entity(23, "completed"), GasorderTrackID: track.ID,
|
Entity: entity(23, common.StatusCompleted), GasorderTrackID: track.ID,
|
||||||
Longitude: address.Longitude, Latitude: address.Latitude,
|
Longitude: address.Longitude, Latitude: address.Latitude,
|
||||||
OccurredAt: trackCompletedAt, Source: "gps", Accuracy: "10m",
|
OccurredAt: trackCompletedAt, Source: "gps", Accuracy: "10m",
|
||||||
}
|
}
|
||||||
@@ -243,7 +244,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
confirmation := models.GasorderConfirm{
|
confirmation := models.GasorderConfirm{
|
||||||
Entity: entity(24, "completed"), GasorderBasicID: gasOrder.ID,
|
Entity: entity(24, common.StatusCompleted), GasorderBasicID: gasOrder.ID,
|
||||||
ConfirmType: "signature", RecipientName: user.Name, RecipientPhone: user.Phone,
|
ConfirmType: "signature", RecipientName: user.Name, RecipientPhone: user.Phone,
|
||||||
ProofURI: "/mock/proofs/gasorder-001.png", ConfirmedAt: now, Remark: "模拟签收",
|
ProofURI: "/mock/proofs/gasorder-001.png", ConfirmedAt: now, Remark: "模拟签收",
|
||||||
}
|
}
|
||||||
@@ -252,14 +253,14 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
category := models.EcCategory{
|
category := models.EcCategory{
|
||||||
Entity: entity(25, "enabled"), Name: "瓶装燃气", SortNo: 10,
|
Entity: entity(25, common.StatusEnable), Name: "瓶装燃气", SortNo: 10,
|
||||||
}
|
}
|
||||||
if err := put(tx, &category); err != nil {
|
if err := put(tx, &category); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ecProduct := models.EcProduct{
|
ecProduct := models.EcProduct{
|
||||||
Entity: entity(26, "enabled"), EcCategoryID: category.ID,
|
Entity: entity(26, common.StatusEnable), EcCategoryID: category.ID,
|
||||||
ProductCode: "MOCK-EC-LPG-001", Name: "15kg 液化气配送服务",
|
ProductCode: "MOCK-EC-LPG-001", Name: "15kg 液化气配送服务",
|
||||||
PriceAmount: 10300, StockQuantity: 50,
|
PriceAmount: 10300, StockQuantity: 50,
|
||||||
}
|
}
|
||||||
@@ -268,7 +269,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
attribute := models.EcProductAttribute{
|
attribute := models.EcProductAttribute{
|
||||||
Entity: entity(27, "enabled"), EcProductID: ecProduct.ID,
|
Entity: entity(27, common.StatusEnable), EcProductID: ecProduct.ID,
|
||||||
Name: "规格", Value: "15kg/瓶", SortNo: 1,
|
Name: "规格", Value: "15kg/瓶", SortNo: 1,
|
||||||
}
|
}
|
||||||
if err := put(tx, &attribute); err != nil {
|
if err := put(tx, &attribute); err != nil {
|
||||||
@@ -276,7 +277,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
image := models.EcProductImage{
|
image := models.EcProductImage{
|
||||||
Entity: entity(28, "enabled"), EcProductID: ecProduct.ID,
|
Entity: entity(28, common.StatusEnable), EcProductID: ecProduct.ID,
|
||||||
ImageURI: "/mock/products/lpg-15kg.png", SortNo: 1, IsCover: true,
|
ImageURI: "/mock/products/lpg-15kg.png", SortNo: 1, IsCover: true,
|
||||||
}
|
}
|
||||||
if err := put(tx, &image); err != nil {
|
if err := put(tx, &image); err != nil {
|
||||||
@@ -284,7 +285,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cart := models.EcCart{
|
cart := models.EcCart{
|
||||||
Entity: entity(29, "enabled"), UserAccountID: user.ID,
|
Entity: entity(29, common.StatusEnable), UserAccountID: user.ID,
|
||||||
EcProductID: ecProduct.ID, Quantity: 1, Selected: true,
|
EcProductID: ecProduct.ID, Quantity: 1, Selected: true,
|
||||||
}
|
}
|
||||||
if err := put(tx, &cart); err != nil {
|
if err := put(tx, &cart); err != nil {
|
||||||
@@ -292,7 +293,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ecOrder := models.EcOrder{
|
ecOrder := models.EcOrder{
|
||||||
Entity: entity(30, "paid"), OrderNo: "MOCK-ECORDER-001",
|
Entity: entity(30, common.StatusPaid), OrderNo: "MOCK-ECORDER-001",
|
||||||
UserAccountID: user.ID, GasStationID: gas.ID, DeliveryPointID: delivery.ID,
|
UserAccountID: user.ID, GasStationID: gas.ID, DeliveryPointID: delivery.ID,
|
||||||
TotalAmount: ecProduct.PriceAmount,
|
TotalAmount: ecProduct.PriceAmount,
|
||||||
}
|
}
|
||||||
@@ -301,7 +302,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ecOrderItem := models.EcOrderItem{
|
ecOrderItem := models.EcOrderItem{
|
||||||
Entity: entity(31, "paid"), EcOrderID: ecOrder.ID, EcProductID: ecProduct.ID,
|
Entity: entity(31, common.StatusPaid), EcOrderID: ecOrder.ID, EcProductID: ecProduct.ID,
|
||||||
ProductSnapshot: `{"code":"MOCK-EC-LPG-001","name":"15kg 液化气配送服务"}`,
|
ProductSnapshot: `{"code":"MOCK-EC-LPG-001","name":"15kg 液化气配送服务"}`,
|
||||||
Quantity: 1, SaleAmount: ecProduct.PriceAmount,
|
Quantity: 1, SaleAmount: ecProduct.PriceAmount,
|
||||||
}
|
}
|
||||||
@@ -310,7 +311,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
review := models.EcReview{
|
review := models.EcReview{
|
||||||
Entity: entity(32, "published"), EcOrderID: ecOrder.ID,
|
Entity: entity(32, common.StatusPublished), EcOrderID: ecOrder.ID,
|
||||||
EcProductID: ecProduct.ID, UserAccountID: user.ID,
|
EcProductID: ecProduct.ID, UserAccountID: user.ID,
|
||||||
Score: 5, Content: "配送及时,服务规范。",
|
Score: 5, Content: "配送及时,服务规范。",
|
||||||
}
|
}
|
||||||
@@ -319,7 +320,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
wallet := models.WalletBasic{
|
wallet := models.WalletBasic{
|
||||||
Entity: entity(33, "enabled"), OwnerType: "user", OwnerID: user.ID,
|
Entity: entity(33, common.StatusEnable), OwnerType: "user", OwnerID: user.ID,
|
||||||
OwnerIdentity: user.Identity, AlipayID: "mock@example.com", AlipayName: user.Name,
|
OwnerIdentity: user.Identity, AlipayID: "mock@example.com", AlipayName: user.Name,
|
||||||
WxpayID: "mock_customer", WxpayName: user.Name,
|
WxpayID: "mock_customer", WxpayName: user.Name,
|
||||||
PayPasswordHash: string(passwordHash), Balance: 50000, WithdrawalBalance: 30000,
|
PayPasswordHash: string(passwordHash), Balance: 50000, WithdrawalBalance: 30000,
|
||||||
@@ -329,7 +330,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bank := models.WalletBank{
|
bank := models.WalletBank{
|
||||||
Entity: entity(34, "enabled"), WalletBasicID: wallet.ID,
|
Entity: entity(34, common.StatusEnable), WalletBasicID: wallet.ID,
|
||||||
CardNoCiphertext: "mock-ciphertext-card", CardFingerprint: "mock-card-fingerprint-001",
|
CardNoCiphertext: "mock-ciphertext-card", CardFingerprint: "mock-card-fingerprint-001",
|
||||||
CardNoLast4: "8888", BankName: "示例银行", CardOwner: user.RealName,
|
CardNoLast4: "8888", BankName: "示例银行", CardOwner: user.RealName,
|
||||||
IDCardCiphertext: "mock-ciphertext-id", PhoneCiphertext: "mock-ciphertext-phone",
|
IDCardCiphertext: "mock-ciphertext-id", PhoneCiphertext: "mock-ciphertext-phone",
|
||||||
@@ -340,7 +341,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
walletPayment := models.WalletPayment{
|
walletPayment := models.WalletPayment{
|
||||||
Entity: entity(35, "success"), WalletBasicID: wallet.ID,
|
Entity: entity(35, common.StatusSuccess), WalletBasicID: wallet.ID,
|
||||||
PaymentNo: "MOCK-PAYMENT-001", OrderNo: gasOrder.OrderNo,
|
PaymentNo: "MOCK-PAYMENT-001", OrderNo: gasOrder.OrderNo,
|
||||||
TradeNo: "MOCK-TRADE-001", PaymentType: "gasorder",
|
TradeNo: "MOCK-TRADE-001", PaymentType: "gasorder",
|
||||||
PayChannel: "balance", PayType: "wallet", Amount: gasOrder.PayableAmount,
|
PayChannel: "balance", PayType: "wallet", Amount: gasOrder.PayableAmount,
|
||||||
@@ -351,7 +352,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
walletRecord := models.WalletRecord{
|
walletRecord := models.WalletRecord{
|
||||||
Entity: entity(36, "completed"), WalletBasicID: wallet.ID,
|
Entity: entity(36, common.StatusCompleted), WalletBasicID: wallet.ID,
|
||||||
RecordNo: "MOCK-RECORD-001", RequestNo: "MOCK-REQ-RECORD-001",
|
RecordNo: "MOCK-RECORD-001", RequestNo: "MOCK-REQ-RECORD-001",
|
||||||
Direction: "in", TradeType: "recharge", Amount: 50000,
|
Direction: "in", TradeType: "recharge", Amount: 50000,
|
||||||
BalanceAfter: 50000, WithdrawalBalanceAfter: 30000,
|
BalanceAfter: 50000, WithdrawalBalanceAfter: 30000,
|
||||||
@@ -365,7 +366,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
|
|
||||||
refundCompletedAt := now
|
refundCompletedAt := now
|
||||||
refund := models.WalletRefund{
|
refund := models.WalletRefund{
|
||||||
Entity: entity(37, "completed"), WalletBasicID: wallet.ID,
|
Entity: entity(37, common.StatusCompleted), WalletBasicID: wallet.ID,
|
||||||
WalletPaymentID: walletPayment.ID, RefundNo: "MOCK-REFUND-001",
|
WalletPaymentID: walletPayment.ID, RefundNo: "MOCK-REFUND-001",
|
||||||
OrderIdentity: gasOrder.Identity, Amount: 1000, Reason: "模拟部分退款",
|
OrderIdentity: gasOrder.Identity, Amount: 1000, Reason: "模拟部分退款",
|
||||||
OrderInfo: `{"order_no":"MOCK-GASORDER-001"}`, Result: `{"status":"success"}`,
|
OrderInfo: `{"order_no":"MOCK-GASORDER-001"}`, Result: `{"status":"success"}`,
|
||||||
@@ -376,7 +377,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
applyCash := models.WalletApplyCash{
|
applyCash := models.WalletApplyCash{
|
||||||
Entity: entity(38, "approved"), WalletBasicID: wallet.ID, WalletBankID: bank.ID,
|
Entity: entity(38, common.StatusApproved), WalletBasicID: wallet.ID, WalletBankID: bank.ID,
|
||||||
CashNo: "MOCK-CASH-001", RequestNo: "MOCK-REQ-CASH-001", Amount: 5000,
|
CashNo: "MOCK-CASH-001", RequestNo: "MOCK-REQ-CASH-001", Amount: 5000,
|
||||||
Channel: "bank", TradeNo: "MOCK-CASH-TRADE-001", Remark: "模拟提现",
|
Channel: "bank", TradeNo: "MOCK-CASH-TRADE-001", Remark: "模拟提现",
|
||||||
ReviewerIdentity: gasAccount.Identity, ReviewerName: gasAccount.DisplayName,
|
ReviewerIdentity: gasAccount.Identity, ReviewerName: gasAccount.DisplayName,
|
||||||
@@ -387,7 +388,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gasOrderPayment := models.GasorderPayment{
|
gasOrderPayment := models.GasorderPayment{
|
||||||
Entity: entity(39, "success"), GasorderBasicID: gasOrder.ID,
|
Entity: entity(39, common.StatusSuccess), GasorderBasicID: gasOrder.ID,
|
||||||
WalletPaymentID: walletPayment.ID, AttemptNo: 1, Amount: gasOrder.PayableAmount,
|
WalletPaymentID: walletPayment.ID, AttemptNo: 1, Amount: gasOrder.PayableAmount,
|
||||||
}
|
}
|
||||||
if err := put(tx, &gasOrderPayment); err != nil {
|
if err := put(tx, &gasOrderPayment); err != nil {
|
||||||
@@ -395,7 +396,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
finPayment := models.FinPayment{
|
finPayment := models.FinPayment{
|
||||||
Entity: entity(40, "paid"), EcOrderID: ecOrder.ID,
|
Entity: entity(40, common.StatusPaid), EcOrderID: ecOrder.ID,
|
||||||
Channel: "wallet", Amount: ecOrder.TotalAmount, PaidAt: &now,
|
Channel: "wallet", Amount: ecOrder.TotalAmount, PaidAt: &now,
|
||||||
}
|
}
|
||||||
if err := put(tx, &finPayment); err != nil {
|
if err := put(tx, &finPayment); err != nil {
|
||||||
@@ -403,7 +404,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
settlement := models.FinSettlement{
|
settlement := models.FinSettlement{
|
||||||
Entity: entity(41, "completed"), SettlementNo: "MOCK-SETTLEMENT-001",
|
Entity: entity(41, common.StatusCompleted), SettlementNo: "MOCK-SETTLEMENT-001",
|
||||||
SubjectType: "gas", SubjectID: gas.ID,
|
SubjectType: "gas", SubjectID: gas.ID,
|
||||||
PeriodStart: now.AddDate(0, 0, -30), PeriodEnd: now,
|
PeriodStart: now.AddDate(0, 0, -30), PeriodEnd: now,
|
||||||
}
|
}
|
||||||
@@ -412,7 +413,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
reconciliation := models.FinReconciliation{
|
reconciliation := models.FinReconciliation{
|
||||||
Entity: entity(42, "matched"), Channel: "wallet",
|
Entity: entity(42, common.StatusMatched), Channel: "wallet",
|
||||||
BillDate: now, DifferenceAmount: 0,
|
BillDate: now, DifferenceAmount: 0,
|
||||||
}
|
}
|
||||||
if err := put(tx, &reconciliation); err != nil {
|
if err := put(tx, &reconciliation); err != nil {
|
||||||
@@ -420,7 +421,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
content := models.CmsContent{
|
content := models.CmsContent{
|
||||||
Entity: entity(43, "enabled"), ContentType: "notice",
|
Entity: entity(43, common.StatusEnable), ContentType: "notice",
|
||||||
Title: "模拟数据使用说明", Body: "本内容由 platform-cli mock-data 生成。",
|
Title: "模拟数据使用说明", Body: "本内容由 platform-cli mock-data 生成。",
|
||||||
VersionNo: 1, PublishStatus: "published",
|
VersionNo: 1, PublishStatus: "published",
|
||||||
}
|
}
|
||||||
@@ -429,7 +430,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ticket := models.CsTicket{
|
ticket := models.CsTicket{
|
||||||
Entity: entity(44, "open"), TicketNo: "MOCK-TICKET-001",
|
Entity: entity(44, common.StatusOpen), TicketNo: "MOCK-TICKET-001",
|
||||||
UserAccountID: user.ID, Category: "delivery", Priority: "normal",
|
UserAccountID: user.ID, Category: "delivery", Priority: "normal",
|
||||||
}
|
}
|
||||||
if err := put(tx, &ticket); err != nil {
|
if err := put(tx, &ticket); err != nil {
|
||||||
@@ -437,7 +438,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
role := models.PlatformRole{
|
role := models.PlatformRole{
|
||||||
Entity: entity(45, "enabled"), RoleCode: "mock_operator",
|
Entity: entity(45, common.StatusEnable), RoleCode: "mock_operator",
|
||||||
Name: "模拟运营人员", DataScope: "global", IsSystem: false,
|
Name: "模拟运营人员", DataScope: "global", IsSystem: false,
|
||||||
}
|
}
|
||||||
if err := put(tx, &role); err != nil {
|
if err := put(tx, &role); err != nil {
|
||||||
@@ -445,7 +446,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
platformAccount := models.PlatformAccount{
|
platformAccount := models.PlatformAccount{
|
||||||
Entity: entity(46, "enabled"), Username: "mock_operator",
|
Entity: entity(46, common.StatusEnable), Username: "mock_operator",
|
||||||
DisplayName: "模拟运营人员", PasswordHash: string(passwordHash),
|
DisplayName: "模拟运营人员", PasswordHash: string(passwordHash),
|
||||||
PlatformRoleCode: role.RoleCode, Phone: "13600000001",
|
PlatformRoleCode: role.RoleCode, Phone: "13600000001",
|
||||||
}
|
}
|
||||||
@@ -453,16 +454,12 @@ func MockData(database *gorm.DB) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var menu models.PlatformMenu
|
|
||||||
if err := tx.Where("menu_code = ?", "dashboard").First(&menu).Error; err != nil {
|
|
||||||
return fmt.Errorf("find dashboard menu: %w", err)
|
|
||||||
}
|
|
||||||
roleMenu := models.PlatformRoleMenu{
|
roleMenu := models.PlatformRoleMenu{
|
||||||
PlatformRoleID: role.ID, PlatformMenuID: menu.ID,
|
PlatformRoleID: role.ID, MenuCode: "dashboard",
|
||||||
}
|
}
|
||||||
if err := tx.Where(
|
if err := tx.Where(
|
||||||
"platform_role_id = ? AND platform_menu_id = ?",
|
"platform_role_id = ? AND menu_code = ?",
|
||||||
role.ID, menu.ID,
|
role.ID, roleMenu.MenuCode,
|
||||||
).FirstOrCreate(&roleMenu).Error; err != nil {
|
).FirstOrCreate(&roleMenu).Error; err != nil {
|
||||||
return fmt.Errorf("seed platform_role_menu: %w", err)
|
return fmt.Errorf("seed platform_role_menu: %w", err)
|
||||||
}
|
}
|
||||||
@@ -470,7 +467,7 @@ func MockData(database *gorm.DB) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func entity(sequence int, status string) models.Entity {
|
func entity(sequence int, status int) models.Entity {
|
||||||
return models.Entity{
|
return models.Entity{
|
||||||
Identity: fmt.Sprintf("%s%012d", mockIdentityPrefix, sequence),
|
Identity: fmt.Sprintf("%s%012d", mockIdentityPrefix, sequence),
|
||||||
Status: status,
|
Status: status,
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package seed
|
|||||||
import (
|
import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"git.apinb.com/heqiapp/platforms/backend/api/internal/logic/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMockEntityIdentitiesAreStableAndUnique(t *testing.T) {
|
func TestMockEntityIdentitiesAreStableAndUnique(t *testing.T) {
|
||||||
@@ -11,7 +13,7 @@ func TestMockEntityIdentitiesAreStableAndUnique(t *testing.T) {
|
|||||||
)
|
)
|
||||||
seen := make(map[string]struct{}, 46)
|
seen := make(map[string]struct{}, 46)
|
||||||
for sequence := 1; sequence <= 46; sequence++ {
|
for sequence := 1; sequence <= 46; sequence++ {
|
||||||
record := entity(sequence, "enabled")
|
record := entity(sequence, common.StatusEnable)
|
||||||
if !identityPattern.MatchString(record.Identity) {
|
if !identityPattern.MatchString(record.Identity) {
|
||||||
t.Fatalf("entity(%d) identity = %q", sequence, record.Identity)
|
t.Fatalf("entity(%d) identity = %q", sequence, record.Identity)
|
||||||
}
|
}
|
||||||
@@ -19,7 +21,7 @@ func TestMockEntityIdentitiesAreStableAndUnique(t *testing.T) {
|
|||||||
t.Fatalf("duplicate identity %q", record.Identity)
|
t.Fatalf("duplicate identity %q", record.Identity)
|
||||||
}
|
}
|
||||||
seen[record.Identity] = struct{}{}
|
seen[record.Identity] = struct{}{}
|
||||||
if record.Status != "enabled" || record.Version != 1 {
|
if record.Status != common.StatusEnable || record.Version != 1 {
|
||||||
t.Fatalf("entity(%d) has unexpected defaults: %#v", sequence, record)
|
t.Fatalf("entity(%d) has unexpected defaults: %#v", sequence, record)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { request } from './http';
|
|||||||
import { resourceApi } from './resource';
|
import { resourceApi } from './resource';
|
||||||
|
|
||||||
/** 平台角色、菜单、账号和工作台接口。 */
|
/** 平台角色、菜单、账号和工作台接口。 */
|
||||||
export type PlatformRole = { identity: string; role_code: string; name: string; data_scope: string; is_system: boolean; status: string };
|
export type PlatformRole = { identity: string; role_code: string; name: string; data_scope: string; is_system: boolean; status: number };
|
||||||
export type PlatformMenu = { identity: string; parent_identity?: string; menu_code: string; name: string; icon: string; path: string; sort_no: number };
|
export type PlatformMenu = { identity: string; parent_identity?: string; menu_code: string; name: string; icon: string; path: string; sort_no: number };
|
||||||
|
|
||||||
export const platformApi = {
|
export const platformApi = {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export const resourceApi = {
|
|||||||
detail: <T>(resource: string, identity: string) => request<T>(`${resource}/${identity}`),
|
detail: <T>(resource: string, identity: string) => request<T>(`${resource}/${identity}`),
|
||||||
create: <T>(resource: string, data: Record<string, unknown>) => request<T>(resource, { method: 'POST', body: JSON.stringify(data) }),
|
create: <T>(resource: string, data: Record<string, unknown>) => request<T>(resource, { method: 'POST', body: JSON.stringify(data) }),
|
||||||
update: <T>(resource: string, identity: string, data: Record<string, unknown>) => request<T>(`${resource}/${identity}`, { method: 'PUT', body: JSON.stringify(data) }),
|
update: <T>(resource: string, identity: string, data: Record<string, unknown>) => request<T>(`${resource}/${identity}`, { method: 'PUT', body: JSON.stringify(data) }),
|
||||||
updateStatus: (resource: string, identity: string, status: string) => request<{ updated: boolean }>(`${resource}/${identity}/status`, { method: 'PATCH', body: JSON.stringify({ status }) }),
|
updateStatus: (resource: string, identity: string, status: number) => request<{ updated: boolean }>(`${resource}/${identity}/status`, { method: 'PATCH', body: JSON.stringify({ status }) }),
|
||||||
archive: (resource: string, identity: string) => request<{ updated: boolean }>(`${resource}/${identity}`, { method: 'DELETE' }),
|
archive: (resource: string, identity: string) => request<{ updated: boolean }>(`${resource}/${identity}`, { method: 'DELETE' }),
|
||||||
action: <T>(resource: string, method: 'POST' | 'PUT' | 'PATCH', data: Record<string, unknown>) =>
|
action: <T>(resource: string, method: 'POST' | 'PUT' | 'PATCH', data: Record<string, unknown>) =>
|
||||||
request<T>(resource, { method, body: JSON.stringify(data) }),
|
request<T>(resource, { method, body: JSON.stringify(data) }),
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export type ResourceField = {
|
|||||||
type?: ResourceFieldType;
|
type?: ResourceFieldType;
|
||||||
required?: boolean;
|
required?: boolean;
|
||||||
relation?: string;
|
relation?: string;
|
||||||
options?: Array<{ label: string; value: string }>;
|
options?: Array<{ label: string; value: string | number }>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DetailAction = {
|
export type DetailAction = {
|
||||||
@@ -281,7 +281,7 @@ export const resources: ResourceUiDefinition[] = [
|
|||||||
define('product_type', '产品类型', 'editable', [f('code', { required: true }), f('name', { required: true })]),
|
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'), f('is_enabled')]),
|
define('product_warehouse', '库房', 'editable', [f('code', { required: true }), f('name', { required: true }), f('address'), f('manager'), f('phone'), f('is_enabled')]),
|
||||||
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 }), f('is_enabled')], 'list', [
|
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 }), f('is_enabled')], 'list', [
|
||||||
{ name: '修改启用状态', resource: '/product_info/:identity/status', method: 'PATCH', fields: [f('status', { required: true, type: 'select', options: [{ label: '启用', value: 'enabled' }, { label: '停用', value: 'disabled' }] })] },
|
{ name: '修改产品状态', resource: '/product_info/:identity/status', method: 'PATCH', fields: [f('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'), f('target_status'), f('content'), f('operator'), f('remark')]),
|
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'), f('target_status'), f('content'), f('operator'), f('remark')]),
|
||||||
define('product_owner', '产品归属记录', 'append_only', [relation('product_info_identity', '/product_info', 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('action', { required: true }), f('occurred_at', { required: true }), f('reason'), f('remark')]),
|
define('product_owner', '产品归属记录', 'append_only', [relation('product_info_identity', '/product_info', 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('action', { required: true }), f('occurred_at', { required: true }), f('reason'), f('remark')]),
|
||||||
@@ -322,7 +322,7 @@ export const resources: ResourceUiDefinition[] = [
|
|||||||
|
|
||||||
define('wallet_basic', '钱包', 'readonly', [f('owner_type'), f('owner_identity'), f('alipay_id'), f('alipay_name'), f('wxpay_id'), f('wxpay_name'), f('balance'), f('withdrawal_balance')], 'list', [
|
define('wallet_basic', '钱包', 'readonly', [f('owner_type'), f('owner_identity'), f('alipay_id'), f('alipay_name'), f('wxpay_id'), f('wxpay_name'), f('balance'), f('withdrawal_balance')], 'list', [
|
||||||
{ name: '后台充值', resource: '/wallet_basic/:identity/recharge', fields: [f('request_no', { required: true }), f('amount', { required: true }), f('withdrawable'), ...reason, f('remark')] },
|
{ name: '后台充值', resource: '/wallet_basic/:identity/recharge', fields: [f('request_no', { required: true }), f('amount', { required: true }), f('withdrawable'), ...reason, f('remark')] },
|
||||||
{ name: '修改钱包状态', resource: '/wallet_basic/:identity/status', method: 'PATCH', fields: [f('status', { required: true, type: 'select', options: [{ label: '启用', value: 'enabled' }, { label: '停用', value: 'disabled' }, { label: '冻结', value: 'frozen' }] })] },
|
{ name: '修改钱包状态', resource: '/wallet_basic/:identity/status', method: 'PATCH', fields: [f('status', { required: true, type: 'select', options: [{ label: '启用', value: 1 }, { label: '停用', value: 2 }, { label: '冻结', value: 4 }] })] },
|
||||||
]),
|
]),
|
||||||
define('wallet_bank', '银行卡', 'readonly', []),
|
define('wallet_bank', '银行卡', 'readonly', []),
|
||||||
define('wallet_payment', '钱包支付记录', 'readonly', []),
|
define('wallet_payment', '钱包支付记录', 'readonly', []),
|
||||||
@@ -342,7 +342,7 @@ export const resources: ResourceUiDefinition[] = [
|
|||||||
define('platform_role', '平台角色', 'writable', [f('role_code', { required: true }), f('name', { required: true }), f('data_scope', { required: true })], 'list', [
|
define('platform_role', '平台角色', 'writable', [f('role_code', { required: true }), f('name', { required: true }), f('data_scope', { required: true })], 'list', [
|
||||||
{ name: '分配菜单', resource: '/platform_role/:identity/menu', method: 'PUT', fields: [f('menu_identities', { type: 'identity-list', relation: '/platform_menu' })] },
|
{ name: '分配菜单', resource: '/platform_role/:identity/menu', method: 'PUT', fields: [f('menu_identities', { type: 'identity-list', relation: '/platform_menu' })] },
|
||||||
]),
|
]),
|
||||||
define('platform_menu', '平台菜单', 'writable', [relation('parent_identity', '/platform_menu'), f('menu_code', { required: true }), f('name', { required: true }), f('icon'), f('path'), f('sort_no')], 'tree'),
|
define('platform_menu', '平台菜单', 'readonly', [], 'tree'),
|
||||||
];
|
];
|
||||||
|
|
||||||
export const resourceByPath = Object.fromEntries(
|
export const resourceByPath = Object.fromEntries(
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -439,8 +439,8 @@ function openStatus(row: Row) {
|
|||||||
type: 'select',
|
type: 'select',
|
||||||
required: true,
|
required: true,
|
||||||
options: [
|
options: [
|
||||||
{ label: '启用', value: 'enabled' },
|
{ label: '启用', value: 1 },
|
||||||
{ label: '停用', value: 'disabled' },
|
{ label: '停用', value: 2 },
|
||||||
{ label: '归档', value: 'archived' },
|
{ label: '归档', value: 'archived' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -606,7 +606,7 @@ onMounted(async () => {
|
|||||||
if (props.definition.fields.some((field) => field.key === 'platform_role_code')) {
|
if (props.definition.fields.some((field) => field.key === 'platform_role_code')) {
|
||||||
const result = await platformApi.listRole();
|
const result = await platformApi.listRole();
|
||||||
roleOptions.value = result.list.filter(
|
roleOptions.value = result.list.filter(
|
||||||
(role) => !role.is_system && role.status === 'enabled',
|
(role) => !role.is_system && role.status === 1,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<a-space>
|
<a-space>
|
||||||
{{ node.title }}
|
{{ node.title }}
|
||||||
<a-button v-if="canEdit" size="mini" @click.stop="openEdit(node)">编辑</a-button>
|
<a-button v-if="canEdit" size="mini" @click.stop="openEdit(node)">编辑</a-button>
|
||||||
<a-button v-if="canChangeStatus" size="mini" @click.stop="confirmStatus(node)">{{ node.status === 'enabled' ? '停用' : '启用' }}</a-button>
|
<a-button v-if="canChangeStatus" size="mini" @click.stop="confirmStatus(node)">{{ node.status === 1 ? '停用' : '启用' }}</a-button>
|
||||||
<a-button v-if="canArchive" size="mini" status="danger" @click.stop="confirmArchive(node)">归档</a-button>
|
<a-button v-if="canArchive" size="mini" status="danger" @click.stop="confirmArchive(node)">归档</a-button>
|
||||||
</a-space>
|
</a-space>
|
||||||
</template>
|
</template>
|
||||||
@@ -89,10 +89,10 @@ function reset(data?: Node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function confirmStatus(node: Node) {
|
function confirmStatus(node: Node) {
|
||||||
const status = node.status === 'enabled' ? 'disabled' : 'enabled';
|
const status = node.status === 1 ? 2 : 1;
|
||||||
Modal.warning({
|
Modal.warning({
|
||||||
title: status === 'enabled' ? '确认启用' : '确认停用',
|
title: status === 1 ? '确认启用' : '确认停用',
|
||||||
content: `确定要${status === 'enabled' ? '启用' : '停用'}“${String(node.name ?? node.identity)}”吗?`,
|
content: `确定要${status === 1 ? '启用' : '停用'}“${String(node.name ?? node.identity)}”吗?`,
|
||||||
onOk: async () => {
|
onOk: async () => {
|
||||||
try {
|
try {
|
||||||
await resourceApi.updateStatus(
|
await resourceApi.updateStatus(
|
||||||
|
|||||||
Reference in New Issue
Block a user