Files
platforms/backend/api/internal/logic/platform/platform.go

387 lines
13 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Package platform 汇聚平台总后台的同步 HTTP 业务逻辑。
package platform
import (
"errors"
"git.apinb.com/bsm-sdk/core/errcode"
"git.apinb.com/bsm-sdk/core/infra"
"git.apinb.com/bsm-sdk/core/utils"
"git.apinb.com/heqiapp/platforms/backend/api/internal/impl"
"git.apinb.com/heqiapp/platforms/backend/api/internal/models"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
// PingHello 返回匿名健康状态。
func PingHello(ctx *gin.Context) {
infra.Response.Success(ctx, gin.H{"service": "platform-api", "status": "ok"})
}
// DashboardOverview 返回平台总后台的运营概览数据。
func DashboardOverview(ctx *gin.Context) {
overview, err := models.GetDashboardOverview()
if err != nil {
infra.Response.Error(ctx, err)
return
}
infra.Response.Success(ctx, overview)
}
// ListGasBasic 查询可燃气体站分页列表。
func ListGasBasic(ctx *gin.Context) { listPage[models.GasBasic](ctx) }
// GetGasBasic 查询一个可燃气体站。
func GetGasBasic(ctx *gin.Context) { getByIdentity[models.GasBasic](ctx) }
// CreateGasBasic 创建可燃气体站档案。
func CreateGasBasic(ctx *gin.Context) {
var request models.GasBasic
if err := ctx.ShouldBindJSON(&request); err != nil || request.Code == "" || request.Name == "" {
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
return
}
request.Entity = newEntity("draft")
if err := impl.DBService.Create(&request).Error; err != nil {
infra.Response.Error(ctx, err)
return
}
infra.Response.Success(ctx, request)
}
// UpdateGasBasic 更新可燃气体站基础资料。
func UpdateGasBasic(ctx *gin.Context) {
var request struct {
Name string `json:"name" binding:"required,max=128"`
CreditCode string `json:"credit_code" binding:"max=64"`
Principal string `json:"principal" binding:"max=64"`
Address string `json:"address" binding:"max=255"`
Longitude string `json:"longitude" binding:"max=32"`
Latitude string `json:"latitude" binding:"max=32"`
}
if err := ctx.ShouldBindJSON(&request); err != nil {
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
return
}
updateByIdentity(ctx, &models.GasBasic{}, gin.H{"name": request.Name, "credit_code": request.CreditCode, "principal": request.Principal, "address": request.Address, "longitude": request.Longitude, "latitude": request.Latitude})
}
// ListDeliveryBasic 查询配送点分页列表。
func ListDeliveryBasic(ctx *gin.Context) { listPage[models.DeliveryBasic](ctx) }
// GetDeliveryBasic 查询一个配送点。
func GetDeliveryBasic(ctx *gin.Context) { getByIdentity[models.DeliveryBasic](ctx) }
// CreateDeliveryBasic 创建配送点档案。
func CreateDeliveryBasic(ctx *gin.Context) {
var request models.DeliveryBasic
if err := ctx.ShouldBindJSON(&request); err != nil || request.DeliveryCode == "" || request.Name == "" {
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
return
}
request.Entity = newEntity("draft")
if err := impl.DBService.Create(&request).Error; err != nil {
infra.Response.Error(ctx, err)
return
}
infra.Response.Success(ctx, request)
}
// UpdateDeliveryBasic 更新配送点基础资料。
func UpdateDeliveryBasic(ctx *gin.Context) {
var request struct {
GasBasicID uint64 `json:"gas_basic_id"`
Name string `json:"name" binding:"required,max=128"`
Principal string `json:"principal" binding:"max=64"`
Address string `json:"address" binding:"max=255"`
}
if err := ctx.ShouldBindJSON(&request); err != nil {
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
return
}
updateByIdentity(ctx, &models.DeliveryBasic{}, gin.H{"gas_basic_id": request.GasBasicID, "name": request.Name, "principal": request.Principal, "address": request.Address})
}
// ListStaff 查询服务人员分页列表。
func ListStaff(ctx *gin.Context) { listPage[models.StaffAccount](ctx) }
// GetStaff 查询一个服务人员档案。
func GetStaff(ctx *gin.Context) { getByIdentity[models.StaffAccount](ctx) }
// CreateStaff 创建服务人员档案。
func CreateStaff(ctx *gin.Context) {
var request models.StaffAccount
if err := ctx.ShouldBindJSON(&request); err != nil || request.Name == "" {
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
return
}
request.Entity = newEntity("draft")
if request.WorkStatus == "" {
request.WorkStatus = "off_duty"
}
if err := impl.DBService.Create(&request).Error; err != nil {
infra.Response.Error(ctx, err)
return
}
infra.Response.Success(ctx, request)
}
// UpdateStaff 更新服务人员档案。
func UpdateStaff(ctx *gin.Context) {
var request struct {
Name string `json:"name" binding:"required,max=64"`
Phone string `json:"phone" binding:"max=32"`
Avatar string `json:"avatar" binding:"max=512"`
RoleCode string `json:"role_code" binding:"max=64"`
GasBasicID uint64 `json:"gas_basic_id"`
DeliveryBasicID uint64 `json:"delivery_basic_id"`
WorkStatus string `json:"work_status" binding:"max=32"`
}
if err := ctx.ShouldBindJSON(&request); err != nil {
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
return
}
updateByIdentity(ctx, &models.StaffAccount{}, gin.H{"name": request.Name, "phone": request.Phone, "avatar": request.Avatar, "role_code": request.RoleCode, "gas_basic_id": request.GasBasicID, "delivery_basic_id": request.DeliveryBasicID, "work_status": request.WorkStatus})
}
// ListUser 查询业主客户分页列表。
func ListUser(ctx *gin.Context) { listPage[models.UserAccount](ctx) }
// GetUser 查询一个业主客户档案。
func GetUser(ctx *gin.Context) { getByIdentity[models.UserAccount](ctx) }
// CreateUser 创建业主客户档案。
func CreateUser(ctx *gin.Context) {
var request models.UserAccount
if err := ctx.ShouldBindJSON(&request); err != nil || request.Name == "" {
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
return
}
request.Entity = newEntity("enabled")
if err := impl.DBService.Create(&request).Error; err != nil {
infra.Response.Error(ctx, err)
return
}
infra.Response.Success(ctx, request)
}
// UpdateUser 更新业主客户档案。
func UpdateUser(ctx *gin.Context) {
var request struct {
Name string `json:"name" binding:"required,max=64"`
Phone string `json:"phone" binding:"max=32"`
Avatar string `json:"avatar" binding:"max=512"`
RealName string `json:"real_name" binding:"max=64"`
}
if err := ctx.ShouldBindJSON(&request); err != nil {
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
return
}
updateByIdentity(ctx, &models.UserAccount{}, gin.H{"name": request.Name, "phone": request.Phone, "avatar": request.Avatar, "real_name": request.RealName})
}
// ListPlatformRole 查询平台角色分页列表。
func ListPlatformRole(ctx *gin.Context) { listPage[models.PlatformRole](ctx) }
// GetPlatformRole 查询一个平台角色。
func GetPlatformRole(ctx *gin.Context) { getByIdentity[models.PlatformRole](ctx) }
// CreatePlatformRole 创建非内置平台角色。
func CreatePlatformRole(ctx *gin.Context) {
var request models.PlatformRole
if err := ctx.ShouldBindJSON(&request); err != nil || request.RoleCode == "" || request.Name == "" || request.RoleCode == "root" {
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
return
}
request.Entity = newEntity("enabled")
request.IsSystem = false
if request.DataScope == "" {
request.DataScope = "global"
}
if err := impl.DBService.Create(&request).Error; err != nil {
infra.Response.Error(ctx, err)
return
}
infra.Response.Success(ctx, request)
}
// UpdatePlatformRole 更新非内置平台角色。
func UpdatePlatformRole(ctx *gin.Context) {
var request struct {
Name string `json:"name" binding:"required,max=64"`
DataScope string `json:"data_scope" binding:"required,max=32"`
}
if err := ctx.ShouldBindJSON(&request); err != nil {
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
return
}
var role models.PlatformRole
if err := impl.DBService.Where("identity = ?", ctx.Param("identity")).First(&role).Error; err != nil {
respondRecordError(ctx, err)
return
}
if role.IsSystem {
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
return
}
if err := impl.DBService.Model(&role).Updates(gin.H{"name": request.Name, "data_scope": request.DataScope}).Error; err != nil {
infra.Response.Error(ctx, err)
return
}
infra.Response.Success(ctx, role)
}
// UpdatePlatformRoleStatus 更新非内置平台角色状态root 等系统角色始终受保护。
func UpdatePlatformRoleStatus(ctx *gin.Context) {
var request struct {
Status string `json:"status" binding:"required,max=32"`
}
if err := ctx.ShouldBindJSON(&request); err != nil {
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
return
}
var role models.PlatformRole
if err := impl.DBService.Where("identity = ?", ctx.Param("identity")).First(&role).Error; err != nil {
respondRecordError(ctx, err)
return
}
if role.IsSystem {
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
return
}
if err := impl.DBService.Model(&role).Update("status", request.Status).Error; err != nil {
infra.Response.Error(ctx, err)
return
}
infra.Response.Success(ctx, gin.H{"updated": true})
}
// ArchivePlatformRole 归档非内置平台角色root 等系统角色始终受保护。
func ArchivePlatformRole(ctx *gin.Context) {
var role models.PlatformRole
if err := impl.DBService.Where("identity = ?", ctx.Param("identity")).First(&role).Error; err != nil {
respondRecordError(ctx, err)
return
}
if role.IsSystem {
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
return
}
if err := impl.DBService.Model(&role).Update("status", "archived").Error; err != nil {
infra.Response.Error(ctx, err)
return
}
infra.Response.Success(ctx, gin.H{"updated": true})
}
// ListPlatformMenu 返回菜单树构建所需的有序菜单列表。
func ListPlatformMenu(ctx *gin.Context) {
var list []models.PlatformMenu
if err := impl.DBService.Order("sort_no asc, id asc").Find(&list).Error; err != nil {
infra.Response.Error(ctx, err)
return
}
infra.Response.Success(ctx, gin.H{"total": len(list), "list": list})
}
// UpdateRecordStatus 更新主表状态,停用和归档均保留历史记录。
func UpdateRecordStatus(ctx *gin.Context, model any) {
var request struct {
Status string `json:"status" binding:"required,max=32"`
}
if err := ctx.ShouldBindJSON(&request); err != nil {
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
return
}
updateByIdentity(ctx, model, gin.H{"status": request.Status})
}
// ArchiveRecord 通过 archived 状态实现逻辑删除,不物理删除主数据。
func ArchiveRecord(ctx *gin.Context, model any) {
updateByIdentity(ctx, model, gin.H{"status": "archived"})
}
// ListPlatfromAccount 查询平台账号列表,手机号在展示层脱敏。
func ListPlatfromAccount(ctx *gin.Context) {
page, size := pageSize(ctx)
list, total, err := models.ListPlatfromAccount(page, size)
if err != nil {
infra.Response.Error(ctx, err)
return
}
views := make([]gin.H, 0, len(list))
for _, item := range list {
views = append(views, gin.H{"identity": item.Identity, "username": item.Username, "display_name": item.DisplayName, "avatar": item.Avatar, "phone_masked": maskPhone(item.Phone), "platform_role_code": item.PlatformRoleCode, "status": item.Status})
}
infra.Response.Success(ctx, gin.H{"total": total, "list": views})
}
func newEntity(status string) models.Entity {
return models.Entity{Identity: models.NewIdentity(), Status: status, Version: 1}
}
func listPage[T any](ctx *gin.Context) {
page, size := pageSize(ctx)
var list []T
var total int64
databaseQuery := impl.DBService.Model(new(T))
if err := databaseQuery.Count(&total).Error; err != nil {
infra.Response.Error(ctx, err)
return
}
if err := databaseQuery.Order("created_at desc").Offset((page - 1) * size).Limit(size).Find(&list).Error; err != nil {
infra.Response.Error(ctx, err)
return
}
infra.Response.Success(ctx, gin.H{"total": total, "list": list})
}
func getByIdentity[T any](ctx *gin.Context) {
var data T
if err := impl.DBService.Where("identity = ?", ctx.Param("identity")).First(&data).Error; err != nil {
respondRecordError(ctx, err)
return
}
infra.Response.Success(ctx, data)
}
func updateByIdentity(ctx *gin.Context, model any, values map[string]any) {
result := impl.DBService.Model(model).Where("identity = ?", ctx.Param("identity")).Updates(values)
if result.Error != nil {
infra.Response.Error(ctx, result.Error)
return
}
if result.RowsAffected == 0 {
infra.Response.Error(ctx, errcode.ErrRecordNotFound)
return
}
infra.Response.Success(ctx, gin.H{"updated": true})
}
func respondRecordError(ctx *gin.Context, err error) {
if errors.Is(err, gorm.ErrRecordNotFound) {
infra.Response.Error(ctx, errcode.ErrRecordNotFound)
return
}
infra.Response.Error(ctx, err)
}
func pageSize(ctx *gin.Context) (int, int) {
page := utils.String2Int(ctx.DefaultQuery("page", "1"))
size := utils.String2Int(ctx.DefaultQuery("size", "20"))
if page < 1 {
page = 1
}
if size < 1 || size > 100 {
size = 20
}
return page, size
}
func maskPhone(phone string) string {
if len(phone) < 7 {
return "***"
}
return phone[:3] + "****" + phone[len(phone)-4:]
}