fix: close platform admin final audit findings
This commit is contained in:
@@ -54,7 +54,7 @@ func CreateGasAccount(ctx *gin.Context) {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
infra.Response.Success(ctx, resourceResponse(account))
|
||||
respondCreatedResource(ctx, account)
|
||||
}
|
||||
|
||||
func UpdateGasAccount(ctx *gin.Context) {
|
||||
@@ -95,7 +95,7 @@ func CreateDeliveryAccount(ctx *gin.Context) {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
infra.Response.Success(ctx, resourceResponse(account))
|
||||
respondCreatedResource(ctx, account)
|
||||
}
|
||||
|
||||
func UpdateDeliveryAccount(ctx *gin.Context) {
|
||||
|
||||
@@ -37,7 +37,7 @@ func CreateDeliveryBasic(ctx *gin.Context) {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
infra.Response.Success(ctx, resourceResponse(delivery))
|
||||
respondCreatedResource(ctx, delivery)
|
||||
}
|
||||
|
||||
// UpdateDeliveryBasic 更新配送点基础资料。
|
||||
|
||||
@@ -26,7 +26,7 @@ func CreateGasBasic(ctx *gin.Context) {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
infra.Response.Success(ctx, request)
|
||||
respondCreatedResource(ctx, request)
|
||||
}
|
||||
|
||||
// UpdateGasBasic 更新可燃气体站基础资料。
|
||||
|
||||
@@ -3,6 +3,8 @@ package platform
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/infra"
|
||||
@@ -38,7 +40,8 @@ func listPage[T any](ctx *gin.Context) {
|
||||
page, size := pageSize(ctx)
|
||||
var list []T
|
||||
var total int64
|
||||
databaseQuery := impl.DBService.Model(new(T))
|
||||
model := new(T)
|
||||
databaseQuery := applyKeywordFilter(ctx, impl.DBService.Model(model), model)
|
||||
if err := databaseQuery.Count(&total).Error; err != nil {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
@@ -55,6 +58,58 @@ func listPage[T any](ctx *gin.Context) {
|
||||
infra.Response.Success(ctx, gin.H{"total": total, "list": response})
|
||||
}
|
||||
|
||||
var keywordExcludedColumns = map[string]bool{
|
||||
"identity": true, "status": true, "password_hash": true,
|
||||
"longitude": true, "latitude": true, "payload": true,
|
||||
"before_data": true, "after_data": true,
|
||||
}
|
||||
|
||||
func applyKeywordFilter(ctx *gin.Context, query *gorm.DB, model any) *gorm.DB {
|
||||
keyword := strings.ToLower(strings.TrimSpace(ctx.Query("keyword")))
|
||||
if keyword == "" {
|
||||
return query
|
||||
}
|
||||
columns := keywordColumns(model)
|
||||
if len(columns) == 0 {
|
||||
return query
|
||||
}
|
||||
conditions := make([]string, 0, len(columns))
|
||||
arguments := make([]any, 0, len(columns))
|
||||
for _, column := range columns {
|
||||
conditions = append(conditions, `LOWER("`+column+`") LIKE ?`)
|
||||
arguments = append(arguments, "%"+keyword+"%")
|
||||
}
|
||||
return query.Where("("+strings.Join(conditions, " OR ")+")", arguments...)
|
||||
}
|
||||
|
||||
func keywordColumns(model any) []string {
|
||||
modelType := reflect.TypeOf(model)
|
||||
for modelType.Kind() == reflect.Pointer {
|
||||
modelType = modelType.Elem()
|
||||
}
|
||||
columns := make([]string, 0)
|
||||
for index := 0; index < modelType.NumField(); index++ {
|
||||
field := modelType.Field(index)
|
||||
if field.Anonymous || field.Type.Kind() != reflect.String {
|
||||
continue
|
||||
}
|
||||
column := gormColumn(field.Tag.Get("gorm"))
|
||||
if column != "" && !keywordExcludedColumns[column] {
|
||||
columns = append(columns, column)
|
||||
}
|
||||
}
|
||||
return columns
|
||||
}
|
||||
|
||||
func gormColumn(tag string) string {
|
||||
for _, part := range strings.Split(tag, ";") {
|
||||
if strings.HasPrefix(part, "column:") {
|
||||
return strings.TrimPrefix(part, "column:")
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getByIdentity[T any](ctx *gin.Context) {
|
||||
var data T
|
||||
if err := impl.DBService.Where("identity = ?", ctx.Param("identity")).First(&data).Error; err != nil {
|
||||
|
||||
@@ -77,7 +77,7 @@ func ExpectedResources() []ResourceContract {
|
||||
resourceContract("device", "dev_smart_cylinder_valve", Writable, "list"), resourceContract("device", "dev_device_binding", Writable, "list"), resourceContract("device", "dev_telemetry", ReadOnly, "list"),
|
||||
resourceContract("safety", "saf_rule", Writable, "list"), resourceContract("safety", "saf_event", Writable, "list"), resourceContract("safety", "saf_inspection", Writable, "list"), resourceContract("safety", "saf_event_disposal", AppendOnly, "list"),
|
||||
resourceContract("ec", "ec_category", Writable, "list"), resourceContract("ec", "ec_product", Writable, "list"), resourceContract("ec", "ec_product_attribute", Writable, "list"), resourceContract("ec", "ec_product_image", Writable, "list"), resourceContract("ec", "ec_cart", Writable, "list"), resourceContract("ec", "ec_order", Writable, "list"), resourceContract("ec", "ec_order_item", Writable, "list"), resourceContract("ec", "ec_review", Writable, "list"),
|
||||
resourceContract("delivery", "delivery_task", Writable, "list"), resourceContract("delivery", "delivery_track", Writable, "list"), resourceContract("delivery", "delivery_track_point", Writable, "list"),
|
||||
resourceContract("delivery", "delivery_task", Writable, "list"), resourceContract("delivery", "delivery_track", Writable, "list"), resourceContract("delivery", "delivery_track_point", ReadOnly, "list"),
|
||||
resourceContract("finance", "fin_payment", Writable, "list"), resourceContract("finance", "fin_settlement", Writable, "list"), resourceContract("finance", "fin_reconciliation", Writable, "list"),
|
||||
resourceContract("content", "cnt_content", Writable, "list"), resourceContract("notification", "ntf_template", Writable, "list"), resourceContract("customer_service", "cs_ticket", Writable, "list"),
|
||||
resourceContract("platform", "platfrom_account", Writable, "list"), resourceContract("platform", "platform_role", Writable, "list"), resourceContract("platform", "platform_menu", Writable, "tree"),
|
||||
|
||||
@@ -27,6 +27,7 @@ func TestExpectedResources(t *testing.T) {
|
||||
assertContract(t, ExpectedResources(), "safety", "saf_event", Writable, "list")
|
||||
assertContract(t, ExpectedResources(), "ec", "ec_order_item", Writable, "list")
|
||||
assertContract(t, ExpectedResources(), "wallet", "wallet_ledger", ReadOnly, "list")
|
||||
assertContract(t, ExpectedResources(), "delivery", "delivery_track_point", ReadOnly, "list")
|
||||
}
|
||||
|
||||
func TestResourceDefinitionAllowsOnlySupportedMethods(t *testing.T) {
|
||||
@@ -238,10 +239,37 @@ func TestCreateGasAccountResolvesGasBasicIdentityBeforePersisting(t *testing.T)
|
||||
mock.ExpectQuery(`INSERT INTO "gas_account"`).
|
||||
WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(uint64(1)))
|
||||
mock.ExpectCommit()
|
||||
mock.ExpectQuery(regexp.QuoteMeta(`SELECT "id","identity" FROM "gas_basic" WHERE id IN ($1)`)).
|
||||
WithArgs(uint64(8)).
|
||||
WillReturnRows(sqlmock.NewRows([]string{"id", "identity"}).AddRow(uint64(8), "gas-a"))
|
||||
|
||||
ctx, recorder := updateContext(http.MethodPost, "/gas/gas_account", "", []byte(`{"username":"operator","password":"password-123","gas_basic_identity":"gas-a"}`))
|
||||
CreateGasAccount(ctx)
|
||||
|
||||
assertResponseCode(t, recorder, 0)
|
||||
body := recorder.Body.String()
|
||||
if !strings.Contains(body, `"identity"`) || !strings.Contains(body, `"gas_basic_identity":"gas-a"`) {
|
||||
t.Fatalf("create response omitted public identities: %s", body)
|
||||
}
|
||||
if strings.Contains(body, `"gas_basic_id"`) || strings.Contains(body, `"password_hash"`) {
|
||||
t.Fatalf("create response exposed internal or sensitive fields: %s", body)
|
||||
}
|
||||
assertMockExpectations(t, mock)
|
||||
}
|
||||
|
||||
func TestListGasAccountAppliesKeywordToCountAndRows(t *testing.T) {
|
||||
_, mock := setupPlatformRoleDatabase(t)
|
||||
keywordWhere := ` WHERE (LOWER("username") LIKE $1 OR LOWER("display_name") LIKE $2 OR LOWER("role_code") LIKE $3)`
|
||||
mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(*) FROM "gas_account"`+keywordWhere)).
|
||||
WithArgs("%operator%", "%operator%", "%operator%").
|
||||
WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(0))
|
||||
mock.ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "gas_account"`+keywordWhere+` ORDER BY created_at desc LIMIT $4`)).
|
||||
WithArgs("%operator%", "%operator%", "%operator%", 20).
|
||||
WillReturnRows(sqlmock.NewRows([]string{"id", "identity", "created_at", "updated_at", "status", "version", "gas_basic_id", "username", "display_name", "password_hash", "role_code"}))
|
||||
|
||||
ctx, recorder := updateContext(http.MethodGet, "/gas/gas_account?keyword=Operator", "", nil)
|
||||
ListGasAccount(ctx)
|
||||
|
||||
assertResponseCode(t, recorder, 0)
|
||||
assertMockExpectations(t, mock)
|
||||
}
|
||||
@@ -276,6 +304,30 @@ func TestResourceResponseDoesNotExposeAutoIncrementRelationIDs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreatedResourceResponseMasksSensitiveFieldsAndKeepsIdentity(t *testing.T) {
|
||||
response := maskCreatedSensitiveFields(map[string]any{
|
||||
"identity": "user-a",
|
||||
"phone": "13800138000",
|
||||
"real_name": "张三",
|
||||
"credential_no": "CERT-123456",
|
||||
"longitude": "120.123456",
|
||||
"latitude": "30.456789",
|
||||
})
|
||||
encoded, err := json.Marshal(response)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
body := string(encoded)
|
||||
if !strings.Contains(body, `"identity":"user-a"`) || !strings.Contains(body, `"phone_masked":"138****8000"`) {
|
||||
t.Fatalf("created response omitted identity or masked phone: %s", body)
|
||||
}
|
||||
for _, forbidden := range []string{`"phone":`, `"real_name":`, `"credential_no":`, `"longitude":`, `"latitude":`, "张三", "CERT-123456", "120.123456", "30.456789"} {
|
||||
if strings.Contains(body, forbidden) {
|
||||
t.Fatalf("created response exposed sensitive field %s: %s", forbidden, body)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestListSafetyEventDisposalsReturnsOnlyTheRequestedEventHistory(t *testing.T) {
|
||||
_, mock := setupPlatformRoleDatabase(t)
|
||||
mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(*) FROM "saf_event_disposal" WHERE saf_event_identity = $1`)).
|
||||
@@ -392,6 +444,55 @@ func TestGetDeliveryTrackOrdersAndMasksPointsWithoutPreciseLocationScope(t *test
|
||||
assertMockExpectations(t, mock)
|
||||
}
|
||||
|
||||
func TestListDeliveryTrackPointsMasksCoordinatesWithoutPreciseLocationScope(t *testing.T) {
|
||||
_, mock := setupPlatformRoleDatabase(t)
|
||||
now := time.Now().UTC()
|
||||
mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(*) FROM "delivery_track_point"`)).
|
||||
WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1))
|
||||
mock.ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "delivery_track_point" ORDER BY created_at desc LIMIT $1`)).
|
||||
WithArgs(20).
|
||||
WillReturnRows(sqlmock.NewRows([]string{"id", "identity", "created_at", "updated_at", "status", "version", "delivery_track_id", "point_type", "occurred_at", "longitude", "latitude"}).
|
||||
AddRow(uint64(9), "point-a", now, now, "enabled", 1, uint64(7), "arrival", now, "120.123456", "30.456789"))
|
||||
mock.ExpectQuery(regexp.QuoteMeta(`SELECT "id","identity" FROM "delivery_track" WHERE id IN ($1)`)).
|
||||
WithArgs(uint64(7)).
|
||||
WillReturnRows(sqlmock.NewRows([]string{"id", "identity"}).AddRow(uint64(7), "track-a"))
|
||||
|
||||
ctx, recorder := updateContext(http.MethodGet, "/delivery/delivery_track_point", "", nil)
|
||||
listResource(ctx, &models.DeliveryTrackPoint{})
|
||||
|
||||
assertResponseCode(t, recorder, 0)
|
||||
body := recorder.Body.String()
|
||||
if strings.Contains(body, "120.123456") || strings.Contains(body, "30.456789") {
|
||||
t.Fatalf("track-point list exposed precise coordinates without scope: %s", body)
|
||||
}
|
||||
if !strings.Contains(body, `"delivery_track_identity":"track-a"`) {
|
||||
t.Fatalf("track-point list omitted its public relation identity: %s", body)
|
||||
}
|
||||
assertMockExpectations(t, mock)
|
||||
}
|
||||
|
||||
func TestGetDeliveryTrackPointReturnsCoordinatesWithPreciseLocationScope(t *testing.T) {
|
||||
_, mock := setupPlatformRoleDatabase(t)
|
||||
now := time.Now().UTC()
|
||||
mock.ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "delivery_track_point" WHERE identity = $1 ORDER BY "delivery_track_point"."id" LIMIT $2`)).
|
||||
WithArgs("point-a", 1).
|
||||
WillReturnRows(sqlmock.NewRows([]string{"id", "identity", "created_at", "updated_at", "status", "version", "delivery_track_id", "point_type", "occurred_at", "longitude", "latitude"}).
|
||||
AddRow(uint64(9), "point-a", now, now, "enabled", 1, uint64(7), "arrival", now, "120.123456", "30.456789"))
|
||||
mock.ExpectQuery(regexp.QuoteMeta(`SELECT "id","identity" FROM "delivery_track" WHERE id IN ($1)`)).
|
||||
WithArgs(uint64(7)).
|
||||
WillReturnRows(sqlmock.NewRows([]string{"id", "identity"}).AddRow(uint64(7), "track-a"))
|
||||
|
||||
ctx, recorder := updateContext(http.MethodGet, "/delivery/delivery_track_point/point-a", "point-a", nil)
|
||||
ctx.Set("Auth", &types.JwtClaims{Extend: map[string]string{"location_scope": "precise"}})
|
||||
getResource(ctx, &models.DeliveryTrackPoint{})
|
||||
|
||||
assertResponseCode(t, recorder, 0)
|
||||
if !strings.Contains(recorder.Body.String(), "120.123456") || !strings.Contains(recorder.Body.String(), "30.456789") {
|
||||
t.Fatalf("authorized track-point detail omitted precise coordinates: %s", recorder.Body.String())
|
||||
}
|
||||
assertMockExpectations(t, mock)
|
||||
}
|
||||
|
||||
func TestDisposeSafetyEventUpdatesEventAndAppendsOperatorActionTransactionally(t *testing.T) {
|
||||
_, mock := setupPlatformRoleDatabase(t)
|
||||
now := time.Now().UTC()
|
||||
|
||||
@@ -35,7 +35,7 @@ func CreatePlatformRole(ctx *gin.Context) {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
infra.Response.Success(ctx, request)
|
||||
respondCreatedResource(ctx, request)
|
||||
}
|
||||
|
||||
// UpdatePlatformRole 更新非内置平台角色。
|
||||
@@ -125,7 +125,7 @@ func CreatePlatformMenu(ctx *gin.Context) {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
infra.Response.Success(ctx, menu)
|
||||
respondCreatedResource(ctx, menu)
|
||||
}
|
||||
|
||||
func UpdatePlatformMenu(ctx *gin.Context) {
|
||||
@@ -243,8 +243,14 @@ func ListPlatformMenu(ctx *gin.Context) {
|
||||
// ListPlatfromAccount 查询平台账号列表,手机号在展示层脱敏。
|
||||
func ListPlatfromAccount(ctx *gin.Context) {
|
||||
page, size := pageSize(ctx)
|
||||
list, total, err := models.ListPlatfromAccount(page, size)
|
||||
if err != nil {
|
||||
var list []models.PlatfromAccount
|
||||
var total int64
|
||||
query := applyKeywordFilter(ctx, impl.DBService.Model(&models.PlatfromAccount{}), &models.PlatfromAccount{})
|
||||
if err := query.Count(&total).Error; err != nil {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
if err := query.Order("created_at desc").Offset((page - 1) * size).Limit(size).Find(&list).Error; err != nil {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ func CreateStaffCredential(ctx *gin.Context) {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
infra.Response.Success(ctx, resourceResponse(credential))
|
||||
respondCreatedResource(ctx, credential)
|
||||
}
|
||||
func UpdateStaffCredential(ctx *gin.Context) {
|
||||
var request staffCredentialRequest
|
||||
@@ -77,7 +77,7 @@ func CreateUserAddress(ctx *gin.Context) {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
infra.Response.Success(ctx, resourceResponse(address))
|
||||
respondCreatedResource(ctx, address)
|
||||
}
|
||||
func UpdateUserAddress(ctx *gin.Context) {
|
||||
var request userAddressRequest
|
||||
@@ -133,7 +133,7 @@ func CreateUserServiceRelation(ctx *gin.Context) {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
infra.Response.Success(ctx, resourceResponse(relation))
|
||||
respondCreatedResource(ctx, relation)
|
||||
}
|
||||
func UpdateUserServiceRelation(ctx *gin.Context) {
|
||||
var request userServiceRelationRequest
|
||||
|
||||
@@ -54,7 +54,7 @@ func CreateStaff(ctx *gin.Context) {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
infra.Response.Success(ctx, staff)
|
||||
respondCreatedResource(ctx, staff)
|
||||
}
|
||||
|
||||
// UpdateStaff 更新服务人员档案。
|
||||
|
||||
@@ -94,7 +94,7 @@ func listResource(ctx *gin.Context, model any) {
|
||||
page, size := pageSize(ctx)
|
||||
list := reflect.New(reflect.SliceOf(reflect.TypeOf(model).Elem()))
|
||||
var total int64
|
||||
query := impl.DBService.Model(model)
|
||||
query := applyKeywordFilter(ctx, impl.DBService.Model(model), model)
|
||||
if err := query.Count(&total).Error; err != nil {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
@@ -108,7 +108,7 @@ func listResource(ctx *gin.Context, model any) {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
infra.Response.Success(ctx, gin.H{"total": total, "list": response})
|
||||
infra.Response.Success(ctx, gin.H{"total": total, "list": protectPreciseLocation(ctx, model, response)})
|
||||
}
|
||||
|
||||
func getResource(ctx *gin.Context, model any) {
|
||||
@@ -122,7 +122,7 @@ func getResource(ctx *gin.Context, model any) {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
infra.Response.Success(ctx, response)
|
||||
infra.Response.Success(ctx, protectPreciseLocation(ctx, model, response))
|
||||
}
|
||||
|
||||
func createResource(ctx *gin.Context, model any, allowedFields []string, relations []ResourceRelation) {
|
||||
@@ -146,7 +146,88 @@ func createResource(ctx *gin.Context, model any, allowedFields []string, relatio
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
infra.Response.Success(ctx, resourceResponse(data.Interface()))
|
||||
respondCreatedResource(ctx, data.Interface())
|
||||
}
|
||||
|
||||
func respondCreatedResource(ctx *gin.Context, value any) {
|
||||
response, err := publicResourceResponse(value)
|
||||
if err != nil {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
infra.Response.Success(ctx, maskCreatedSensitiveFields(response))
|
||||
}
|
||||
|
||||
func maskCreatedSensitiveFields(value any) any {
|
||||
switch data := value.(type) {
|
||||
case map[string]any:
|
||||
if phone, ok := data["phone"].(string); ok {
|
||||
data["phone_masked"] = maskPhone(phone)
|
||||
delete(data, "phone")
|
||||
}
|
||||
if realName, ok := data["real_name"].(string); ok {
|
||||
data["real_name_masked"] = maskSecret(realName)
|
||||
delete(data, "real_name")
|
||||
}
|
||||
if credentialNo, ok := data["credential_no"].(string); ok {
|
||||
data["credential_no_masked"] = maskSecret(credentialNo)
|
||||
delete(data, "credential_no")
|
||||
}
|
||||
delete(data, "longitude")
|
||||
delete(data, "latitude")
|
||||
for key, item := range data {
|
||||
data[key] = maskCreatedSensitiveFields(item)
|
||||
}
|
||||
case []any:
|
||||
for index := range data {
|
||||
data[index] = maskCreatedSensitiveFields(data[index])
|
||||
}
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func maskSecret(value string) string {
|
||||
characters := []rune(value)
|
||||
if len(characters) <= 1 {
|
||||
return "*"
|
||||
}
|
||||
visible := 1
|
||||
if len(characters) > 4 {
|
||||
visible = 4
|
||||
}
|
||||
return strings.Repeat("*", len(characters)-visible) + string(characters[len(characters)-visible:])
|
||||
}
|
||||
|
||||
func protectPreciseLocation(ctx *gin.Context, model, value any) any {
|
||||
if reflect.TypeOf(model) != reflect.TypeOf(&models.DeliveryTrackPoint{}) || hasPreciseLocationScope(ctx) {
|
||||
return value
|
||||
}
|
||||
clearCoordinateFields(value)
|
||||
return value
|
||||
}
|
||||
|
||||
func hasPreciseLocationScope(ctx *gin.Context) bool {
|
||||
claims, err := middleware.ParseAuth(ctx)
|
||||
return err == nil && claims.Extend["location_scope"] == "precise"
|
||||
}
|
||||
|
||||
func clearCoordinateFields(value any) {
|
||||
switch data := value.(type) {
|
||||
case map[string]any:
|
||||
if _, ok := data["longitude"]; ok {
|
||||
data["longitude"] = ""
|
||||
}
|
||||
if _, ok := data["latitude"]; ok {
|
||||
data["latitude"] = ""
|
||||
}
|
||||
for _, item := range data {
|
||||
clearCoordinateFields(item)
|
||||
}
|
||||
case []any:
|
||||
for _, item := range data {
|
||||
clearCoordinateFields(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func updateResource(ctx *gin.Context, model any, allowedFields []string, relations []ResourceRelation) {
|
||||
@@ -521,11 +602,7 @@ func GetDeliveryTrack(ctx *gin.Context) {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
precise := false
|
||||
if claims, err := middleware.ParseAuth(ctx); err == nil {
|
||||
precise = claims.Extend["location_scope"] == "precise"
|
||||
}
|
||||
if !precise {
|
||||
if !hasPreciseLocationScope(ctx) {
|
||||
for index := range points {
|
||||
points[index].Longitude = ""
|
||||
points[index].Latitude = ""
|
||||
|
||||
@@ -38,7 +38,7 @@ func CreateUser(ctx *gin.Context) {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
infra.Response.Success(ctx, user)
|
||||
respondCreatedResource(ctx, user)
|
||||
}
|
||||
|
||||
// UpdateUser 更新业主客户档案。
|
||||
|
||||
@@ -8,13 +8,13 @@ import (
|
||||
|
||||
// AudApproval 对应 aud_approval,保存审批流与复核意见。
|
||||
type AudApproval struct {
|
||||
Entity
|
||||
BusinessType string `gorm:"column:business_type;type:varchar(64);not null" json:"business_type"`
|
||||
BusinessIdentity string `gorm:"column:business_identity;type:varchar(36);not null;index" json:"business_identity"`
|
||||
ApplicantIdentity string `gorm:"column:applicant_identity;type:varchar(36);not null;index" json:"applicant_identity"`
|
||||
Opinion string `gorm:"column:opinion;type:text;not null;default:''" json:"opinion"`
|
||||
HandlerIdentity string `gorm:"column:handler_identity;type:varchar(36);not null;default:'';index" json:"handler_identity"`
|
||||
HandledAt *time.Time `gorm:"column:handled_at;type:timestamptz" json:"handled_at"`
|
||||
Entity // 公共实体字段
|
||||
BusinessType string `gorm:"column:business_type;type:varchar(64);not null" json:"business_type"` // business_type 业务字段
|
||||
BusinessIdentity string `gorm:"column:business_identity;type:varchar(36);not null;index" json:"business_identity"` // business_identity 业务字段
|
||||
ApplicantIdentity string `gorm:"column:applicant_identity;type:varchar(36);not null;index" json:"applicant_identity"` // applicant_identity 业务字段
|
||||
Opinion string `gorm:"column:opinion;type:text;not null;default:''" json:"opinion"` // opinion 业务字段
|
||||
HandlerIdentity string `gorm:"column:handler_identity;type:varchar(36);not null;default:'';index" json:"handler_identity"` // handler_identity 业务字段
|
||||
HandledAt *time.Time `gorm:"column:handled_at;type:timestamptz" json:"handled_at"` // handled_at 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&AudApproval{}) }
|
||||
|
||||
@@ -7,12 +7,12 @@ import (
|
||||
|
||||
// AudExportLog 对应 aud_export_log,保存敏感导出审计。
|
||||
type AudExportLog struct {
|
||||
Entity
|
||||
ApplicantIdentity string `gorm:"column:applicant_identity;type:varchar(36);not null;index" json:"applicant_identity"`
|
||||
Purpose string `gorm:"column:purpose;type:varchar(255);not null" json:"purpose"`
|
||||
FieldScope string `gorm:"column:field_scope;type:jsonb;not null;default:'{}'" json:"field_scope"`
|
||||
ApprovedAt *time.Time `gorm:"column:approved_at;type:timestamptz" json:"approved_at"`
|
||||
FileURI string `gorm:"column:file_uri;type:varchar(512);not null;default:''" json:"file_uri"`
|
||||
Entity // 公共实体字段
|
||||
ApplicantIdentity string `gorm:"column:applicant_identity;type:varchar(36);not null;index" json:"applicant_identity"` // applicant_identity 业务字段
|
||||
Purpose string `gorm:"column:purpose;type:varchar(255);not null" json:"purpose"` // purpose 业务字段
|
||||
FieldScope string `gorm:"column:field_scope;type:jsonb;not null;default:'{}'" json:"field_scope"` // field_scope 业务字段
|
||||
ApprovedAt *time.Time `gorm:"column:approved_at;type:timestamptz" json:"approved_at"` // approved_at 业务字段
|
||||
FileURI string `gorm:"column:file_uri;type:varchar(512);not null;default:''" json:"file_uri"` // file_uri 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&AudExportLog{}) }
|
||||
|
||||
@@ -4,13 +4,13 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// AudOperationLog 对应 aud_operation_log,保存不可变操作审计。
|
||||
type AudOperationLog struct {
|
||||
Entity
|
||||
OperatorIdentity string `gorm:"column:operator_identity;type:varchar(36);not null;index" json:"operator_identity"`
|
||||
Action string `gorm:"column:action;type:varchar(64);not null" json:"action"`
|
||||
ObjectType string `gorm:"column:object_type;type:varchar(64);not null" json:"object_type"`
|
||||
ObjectIdentity string `gorm:"column:object_identity;type:varchar(36);not null;index" json:"object_identity"`
|
||||
BeforeData string `gorm:"column:before_data;type:jsonb;not null;default:'{}'" json:"before_data"`
|
||||
AfterData string `gorm:"column:after_data;type:jsonb;not null;default:'{}'" json:"after_data"`
|
||||
Entity // 公共实体字段
|
||||
OperatorIdentity string `gorm:"column:operator_identity;type:varchar(36);not null;index" json:"operator_identity"` // operator_identity 业务字段
|
||||
Action string `gorm:"column:action;type:varchar(64);not null" json:"action"` // action 业务字段
|
||||
ObjectType string `gorm:"column:object_type;type:varchar(64);not null" json:"object_type"` // object_type 业务字段
|
||||
ObjectIdentity string `gorm:"column:object_identity;type:varchar(36);not null;index" json:"object_identity"` // object_identity 业务字段
|
||||
BeforeData string `gorm:"column:before_data;type:jsonb;not null;default:'{}'" json:"before_data"` // before_data 业务字段
|
||||
AfterData string `gorm:"column:after_data;type:jsonb;not null;default:'{}'" json:"after_data"` // after_data 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&AudOperationLog{}) }
|
||||
|
||||
@@ -4,12 +4,12 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// CntContent 对应 cnt_content,保存公告与协议内容。
|
||||
type CntContent struct {
|
||||
Entity
|
||||
ContentType string `gorm:"column:content_type;type:varchar(32);not null" json:"content_type"`
|
||||
Title string `gorm:"column:title;type:varchar(256);not null" json:"title"`
|
||||
Body string `gorm:"column:body;type:text;not null;default:''" json:"body"`
|
||||
VersionNo int `gorm:"column:version_no;not null;default:1" json:"version_no"`
|
||||
PublishStatus string `gorm:"column:publish_status;type:varchar(32);not null;default:'draft'" json:"publish_status"`
|
||||
Entity // 公共实体字段
|
||||
ContentType string `gorm:"column:content_type;type:varchar(32);not null" json:"content_type"` // content_type 业务字段
|
||||
Title string `gorm:"column:title;type:varchar(256);not null" json:"title"` // title 业务字段
|
||||
Body string `gorm:"column:body;type:text;not null;default:''" json:"body"` // body 业务字段
|
||||
VersionNo int `gorm:"column:version_no;not null;default:1" json:"version_no"` // version_no 业务字段
|
||||
PublishStatus string `gorm:"column:publish_status;type:varchar(32);not null;default:'draft'" json:"publish_status"` // publish_status 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&CntContent{}) }
|
||||
|
||||
53
backend/api/internal/models/comments_test.go
Normal file
53
backend/api/internal/models/comments_test.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"os"
|
||||
"regexp"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var chineseText = regexp.MustCompile(`[\p{Han}]`)
|
||||
|
||||
func TestEveryModelFieldHasChineseComment(t *testing.T) {
|
||||
packages, err := parser.ParseDir(token.NewFileSet(), ".", func(info os.FileInfo) bool {
|
||||
return info.Name() != "comments_test.go"
|
||||
}, parser.ParseComments)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, file := range packages["models"].Files {
|
||||
ast.Inspect(file, func(node ast.Node) bool {
|
||||
typeSpec, ok := node.(*ast.TypeSpec)
|
||||
if !ok {
|
||||
return true
|
||||
}
|
||||
structType, ok := typeSpec.Type.(*ast.StructType)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
for _, field := range structType.Fields.List {
|
||||
name := "embedded field"
|
||||
if len(field.Names) > 0 {
|
||||
name = field.Names[0].Name
|
||||
if !ast.IsExported(name) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
comment := ""
|
||||
if field.Doc != nil {
|
||||
comment += field.Doc.Text()
|
||||
}
|
||||
if field.Comment != nil {
|
||||
comment += field.Comment.Text()
|
||||
}
|
||||
if !chineseText.MatchString(comment) {
|
||||
t.Errorf("%s.%s 缺少中文字段注释", typeSpec.Name.Name, name)
|
||||
}
|
||||
}
|
||||
return false
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -4,11 +4,11 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// CsTicket 对应 cs_ticket,保存客服工单。
|
||||
type CsTicket struct {
|
||||
Entity
|
||||
TicketNo string `gorm:"column:ticket_no;type:varchar(64);not null;uniqueIndex" json:"ticket_no"`
|
||||
UserAccountID uint64 `gorm:"column:user_account_id;not null;index" json:"user_account_id"`
|
||||
Category string `gorm:"column:category;type:varchar(64);not null" json:"category"`
|
||||
Priority string `gorm:"column:priority;type:varchar(16);not null;default:'normal'" json:"priority"`
|
||||
Entity // 公共实体字段
|
||||
TicketNo string `gorm:"column:ticket_no;type:varchar(64);not null;uniqueIndex" json:"ticket_no"` // ticket_no 业务字段
|
||||
UserAccountID uint64 `gorm:"column:user_account_id;not null;index" json:"user_account_id"` // user_account_id 业务字段
|
||||
Category string `gorm:"column:category;type:varchar(64);not null" json:"category"` // category 业务字段
|
||||
Priority string `gorm:"column:priority;type:varchar(16);not null;default:'normal'" json:"priority"` // priority 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&CsTicket{}) }
|
||||
|
||||
@@ -4,12 +4,12 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// DeliveryAccount 对应 delivery_account,保存配送点登录账户。
|
||||
type DeliveryAccount struct {
|
||||
Entity
|
||||
DeliveryBasicID uint64 `gorm:"column:delivery_basic_id;not null;index" json:"delivery_basic_id"`
|
||||
Username string `gorm:"column:username;type:varchar(64);not null;uniqueIndex" json:"username"`
|
||||
DisplayName string `gorm:"column:display_name;type:varchar(64);not null;default:''" json:"display_name"`
|
||||
PasswordHash string `gorm:"column:password_hash;type:varchar(255);not null" json:"-"`
|
||||
RoleCode string `gorm:"column:role_code;type:varchar(64);not null" json:"role_code"`
|
||||
Entity // 公共实体字段
|
||||
DeliveryBasicID uint64 `gorm:"column:delivery_basic_id;not null;index" json:"delivery_basic_id"` // delivery_basic_id 业务字段
|
||||
Username string `gorm:"column:username;type:varchar(64);not null;uniqueIndex" json:"username"` // username 业务字段
|
||||
DisplayName string `gorm:"column:display_name;type:varchar(64);not null;default:''" json:"display_name"` // display_name 业务字段
|
||||
PasswordHash string `gorm:"column:password_hash;type:varchar(255);not null" json:"-"` // PasswordHash 业务字段
|
||||
RoleCode string `gorm:"column:role_code;type:varchar(64);not null" json:"role_code"` // role_code 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&DeliveryAccount{}) }
|
||||
|
||||
@@ -4,7 +4,7 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// DeliveryBasic 对应 delivery_basic,保存配送点主档案。
|
||||
type DeliveryBasic struct {
|
||||
Entity
|
||||
Entity // 公共实体字段
|
||||
DeliveryCode string `gorm:"column:delivery_code;type:varchar(32);not null;uniqueIndex" json:"delivery_code"` // 配送点编码
|
||||
GasBasicID uint64 `gorm:"column:gas_basic_id;not null;default:0;index" json:"gas_basic_id"` // 所属可燃气体站自增主键,0 表示平台直属
|
||||
Name string `gorm:"column:name;type:varchar(128);not null" json:"name"` // 配送点名称
|
||||
|
||||
@@ -4,10 +4,10 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// DeliveryTask 对应 delivery_task,保存配送履约任务。
|
||||
type DeliveryTask struct {
|
||||
Entity
|
||||
EcOrderID uint64 `gorm:"column:ec_order_id;not null;index" json:"ec_order_id"`
|
||||
StaffAccountID uint64 `gorm:"column:staff_account_id;not null;default:0;index" json:"staff_account_id"`
|
||||
DeliveryPointID uint64 `gorm:"column:delivery_point_id;not null;index" json:"delivery_point_id"`
|
||||
Entity // 公共实体字段
|
||||
EcOrderID uint64 `gorm:"column:ec_order_id;not null;index" json:"ec_order_id"` // ec_order_id 业务字段
|
||||
StaffAccountID uint64 `gorm:"column:staff_account_id;not null;default:0;index" json:"staff_account_id"` // staff_account_id 业务字段
|
||||
DeliveryPointID uint64 `gorm:"column:delivery_point_id;not null;index" json:"delivery_point_id"` // delivery_point_id 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&DeliveryTask{}) }
|
||||
|
||||
@@ -7,10 +7,10 @@ import (
|
||||
|
||||
// DeliveryTrack 对应 delivery_track,保存配送轨迹摘要。
|
||||
type DeliveryTrack struct {
|
||||
Entity
|
||||
DeliveryTaskID uint64 `gorm:"column:delivery_task_id;not null;index" json:"delivery_task_id"`
|
||||
StartedAt *time.Time `gorm:"column:started_at;type:timestamptz" json:"started_at"`
|
||||
CompletedAt *time.Time `gorm:"column:completed_at;type:timestamptz" json:"completed_at"`
|
||||
Entity // 公共实体字段
|
||||
DeliveryTaskID uint64 `gorm:"column:delivery_task_id;not null;index" json:"delivery_task_id"` // delivery_task_id 业务字段
|
||||
StartedAt *time.Time `gorm:"column:started_at;type:timestamptz" json:"started_at"` // started_at 业务字段
|
||||
CompletedAt *time.Time `gorm:"column:completed_at;type:timestamptz" json:"completed_at"` // completed_at 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&DeliveryTrack{}) }
|
||||
|
||||
@@ -7,12 +7,12 @@ import (
|
||||
|
||||
// DeliveryTrackPoint 对应 delivery_track_point,保存配送节点和位置。
|
||||
type DeliveryTrackPoint struct {
|
||||
Entity
|
||||
DeliveryTrackID uint64 `gorm:"column:delivery_track_id;not null;index" json:"delivery_track_id"`
|
||||
PointType string `gorm:"column:point_type;type:varchar(32);not null" json:"point_type"`
|
||||
OccurredAt time.Time `gorm:"column:occurred_at;type:timestamptz;not null" json:"occurred_at"`
|
||||
Longitude string `gorm:"column:longitude;type:varchar(32);not null;default:''" json:"longitude"`
|
||||
Latitude string `gorm:"column:latitude;type:varchar(32);not null;default:''" json:"latitude"`
|
||||
Entity // 公共实体字段
|
||||
DeliveryTrackID uint64 `gorm:"column:delivery_track_id;not null;index" json:"delivery_track_id"` // delivery_track_id 业务字段
|
||||
PointType string `gorm:"column:point_type;type:varchar(32);not null" json:"point_type"` // point_type 业务字段
|
||||
OccurredAt time.Time `gorm:"column:occurred_at;type:timestamptz;not null" json:"occurred_at"` // occurred_at 业务字段
|
||||
Longitude string `gorm:"column:longitude;type:varchar(32);not null;default:''" json:"longitude"` // longitude 业务字段
|
||||
Latitude string `gorm:"column:latitude;type:varchar(32);not null;default:''" json:"latitude"` // latitude 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&DeliveryTrackPoint{}) }
|
||||
|
||||
@@ -7,11 +7,11 @@ import (
|
||||
|
||||
// DevDeviceBinding 对应 dev_device_binding,保存设备授权绑定。
|
||||
type DevDeviceBinding struct {
|
||||
Entity
|
||||
SmartCylinderValveID uint64 `gorm:"column:smart_cylinder_valve_id;not null;index" json:"smart_cylinder_valve_id"`
|
||||
UserAccountID uint64 `gorm:"column:user_account_id;not null;index" json:"user_account_id"`
|
||||
EffectiveAt time.Time `gorm:"column:effective_at;type:timestamptz;not null" json:"effective_at"`
|
||||
ExpiredAt *time.Time `gorm:"column:expired_at;type:timestamptz" json:"expired_at"`
|
||||
Entity // 公共实体字段
|
||||
SmartCylinderValveID uint64 `gorm:"column:smart_cylinder_valve_id;not null;index" json:"smart_cylinder_valve_id"` // smart_cylinder_valve_id 业务字段
|
||||
UserAccountID uint64 `gorm:"column:user_account_id;not null;index" json:"user_account_id"` // user_account_id 业务字段
|
||||
EffectiveAt time.Time `gorm:"column:effective_at;type:timestamptz;not null" json:"effective_at"` // effective_at 业务字段
|
||||
ExpiredAt *time.Time `gorm:"column:expired_at;type:timestamptz" json:"expired_at"` // expired_at 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&DevDeviceBinding{}) }
|
||||
|
||||
@@ -4,11 +4,11 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// DevSmartCylinderValve 对应 dev_smart_cylinder_valve,保存智能瓶阀档案。
|
||||
type DevSmartCylinderValve struct {
|
||||
Entity
|
||||
DeviceNo string `gorm:"column:device_no;type:varchar(64);not null;uniqueIndex" json:"device_no"`
|
||||
Model string `gorm:"column:model;type:varchar(64);not null;default:''" json:"model"`
|
||||
OnlineStatus string `gorm:"column:online_status;type:varchar(32);not null;default:'offline'" json:"online_status"`
|
||||
OwnerIdentity string `gorm:"column:owner_identity;type:varchar(36);not null;default:'';index" json:"owner_identity"`
|
||||
Entity // 公共实体字段
|
||||
DeviceNo string `gorm:"column:device_no;type:varchar(64);not null;uniqueIndex" json:"device_no"` // device_no 业务字段
|
||||
Model string `gorm:"column:model;type:varchar(64);not null;default:''" json:"model"` // model 业务字段
|
||||
OnlineStatus string `gorm:"column:online_status;type:varchar(32);not null;default:'offline'" json:"online_status"` // online_status 业务字段
|
||||
OwnerIdentity string `gorm:"column:owner_identity;type:varchar(36);not null;default:'';index" json:"owner_identity"` // owner_identity 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&DevSmartCylinderValve{}) }
|
||||
|
||||
@@ -7,11 +7,11 @@ import (
|
||||
|
||||
// DevTelemetry 对应 dev_telemetry,保存设备遥测摘要。
|
||||
type DevTelemetry struct {
|
||||
Entity
|
||||
SmartCylinderValveIdentity string `gorm:"column:smart_cylinder_valve_identity;type:varchar(36);not null;index" json:"smart_cylinder_valve_identity"`
|
||||
ReportedAt time.Time `gorm:"column:reported_at;type:timestamptz;not null;index" json:"reported_at"`
|
||||
Payload string `gorm:"column:payload;type:jsonb;not null;default:'{}'" json:"payload"`
|
||||
QualityFlag string `gorm:"column:quality_flag;type:varchar(32);not null;default:'normal'" json:"quality_flag"`
|
||||
Entity // 公共实体字段
|
||||
SmartCylinderValveIdentity string `gorm:"column:smart_cylinder_valve_identity;type:varchar(36);not null;index" json:"smart_cylinder_valve_identity"` // smart_cylinder_valve_identity 业务字段
|
||||
ReportedAt time.Time `gorm:"column:reported_at;type:timestamptz;not null;index" json:"reported_at"` // reported_at 业务字段
|
||||
Payload string `gorm:"column:payload;type:jsonb;not null;default:'{}'" json:"payload"` // payload 业务字段
|
||||
QualityFlag string `gorm:"column:quality_flag;type:varchar(32);not null;default:'normal'" json:"quality_flag"` // quality_flag 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&DevTelemetry{}) }
|
||||
|
||||
@@ -4,11 +4,11 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// EcCart 对应 ec_cart,保存用户购物车明细。
|
||||
type EcCart struct {
|
||||
Entity
|
||||
UserAccountID uint64 `gorm:"column:user_account_id;not null;index" json:"user_account_id"`
|
||||
EcProductID uint64 `gorm:"column:ec_product_id;not null;index" json:"ec_product_id"`
|
||||
Quantity int `gorm:"column:quantity;not null;default:1" json:"quantity"`
|
||||
Selected bool `gorm:"column:selected;not null;default:true" json:"selected"`
|
||||
Entity // 公共实体字段
|
||||
UserAccountID uint64 `gorm:"column:user_account_id;not null;index" json:"user_account_id"` // user_account_id 业务字段
|
||||
EcProductID uint64 `gorm:"column:ec_product_id;not null;index" json:"ec_product_id"` // ec_product_id 业务字段
|
||||
Quantity int `gorm:"column:quantity;not null;default:1" json:"quantity"` // quantity 业务字段
|
||||
Selected bool `gorm:"column:selected;not null;default:true" json:"selected"` // selected 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&EcCart{}) }
|
||||
|
||||
@@ -4,10 +4,10 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// EcCategory 对应 ec_category,保存商品分类树。
|
||||
type EcCategory struct {
|
||||
Entity
|
||||
ParentID uint64 `gorm:"column:parent_id;not null;default:0;index" json:"parent_id"`
|
||||
Name string `gorm:"column:name;type:varchar(128);not null" json:"name"`
|
||||
SortNo int `gorm:"column:sort_no;not null;default:0" json:"sort_no"`
|
||||
Entity // 公共实体字段
|
||||
ParentID uint64 `gorm:"column:parent_id;not null;default:0;index" json:"parent_id"` // parent_id 业务字段
|
||||
Name string `gorm:"column:name;type:varchar(128);not null" json:"name"` // name 业务字段
|
||||
SortNo int `gorm:"column:sort_no;not null;default:0" json:"sort_no"` // sort_no 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&EcCategory{}) }
|
||||
|
||||
@@ -4,12 +4,12 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// EcOrder 对应 ec_order,保存电商订单与组织快照。
|
||||
type EcOrder struct {
|
||||
Entity
|
||||
OrderNo string `gorm:"column:order_no;type:varchar(64);not null;uniqueIndex" json:"order_no"`
|
||||
UserAccountID uint64 `gorm:"column:user_account_id;not null;index" json:"user_account_id"`
|
||||
GasStationID uint64 `gorm:"column:gas_station_id;not null;default:0;index" json:"gas_station_id"`
|
||||
DeliveryPointID uint64 `gorm:"column:delivery_point_id;not null;default:0;index" json:"delivery_point_id"`
|
||||
TotalAmount int64 `gorm:"column:total_amount;not null;default:0" json:"total_amount"`
|
||||
Entity // 公共实体字段
|
||||
OrderNo string `gorm:"column:order_no;type:varchar(64);not null;uniqueIndex" json:"order_no"` // order_no 业务字段
|
||||
UserAccountID uint64 `gorm:"column:user_account_id;not null;index" json:"user_account_id"` // user_account_id 业务字段
|
||||
GasStationID uint64 `gorm:"column:gas_station_id;not null;default:0;index" json:"gas_station_id"` // gas_station_id 业务字段
|
||||
DeliveryPointID uint64 `gorm:"column:delivery_point_id;not null;default:0;index" json:"delivery_point_id"` // delivery_point_id 业务字段
|
||||
TotalAmount int64 `gorm:"column:total_amount;not null;default:0" json:"total_amount"` // total_amount 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&EcOrder{}) }
|
||||
|
||||
@@ -4,12 +4,12 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// EcOrderItem 对应 ec_order_item,保存订单商品快照。
|
||||
type EcOrderItem struct {
|
||||
Entity
|
||||
EcOrderID uint64 `gorm:"column:ec_order_id;not null;index" json:"ec_order_id"`
|
||||
EcProductID uint64 `gorm:"column:ec_product_id;not null;index" json:"ec_product_id"`
|
||||
ProductSnapshot string `gorm:"column:product_snapshot;type:jsonb;not null;default:'{}'" json:"product_snapshot"`
|
||||
Quantity int `gorm:"column:quantity;not null;default:1" json:"quantity"`
|
||||
SaleAmount int64 `gorm:"column:sale_amount;not null;default:0" json:"sale_amount"`
|
||||
Entity // 公共实体字段
|
||||
EcOrderID uint64 `gorm:"column:ec_order_id;not null;index" json:"ec_order_id"` // ec_order_id 业务字段
|
||||
EcProductID uint64 `gorm:"column:ec_product_id;not null;index" json:"ec_product_id"` // ec_product_id 业务字段
|
||||
ProductSnapshot string `gorm:"column:product_snapshot;type:jsonb;not null;default:'{}'" json:"product_snapshot"` // product_snapshot 业务字段
|
||||
Quantity int `gorm:"column:quantity;not null;default:1" json:"quantity"` // quantity 业务字段
|
||||
SaleAmount int64 `gorm:"column:sale_amount;not null;default:0" json:"sale_amount"` // sale_amount 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&EcOrderItem{}) }
|
||||
|
||||
@@ -4,12 +4,12 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// EcProduct 对应 ec_product,保存可燃气体商品与服务。
|
||||
type EcProduct struct {
|
||||
Entity
|
||||
EcCategoryID uint64 `gorm:"column:ec_category_id;not null;index" json:"ec_category_id"`
|
||||
ProductCode string `gorm:"column:product_code;type:varchar(64);not null;uniqueIndex" json:"product_code"`
|
||||
Name string `gorm:"column:name;type:varchar(128);not null" json:"name"`
|
||||
PriceAmount int64 `gorm:"column:price_amount;not null;default:0" json:"price_amount"`
|
||||
StockQuantity int `gorm:"column:stock_quantity;not null;default:0" json:"stock_quantity"`
|
||||
Entity // 公共实体字段
|
||||
EcCategoryID uint64 `gorm:"column:ec_category_id;not null;index" json:"ec_category_id"` // ec_category_id 业务字段
|
||||
ProductCode string `gorm:"column:product_code;type:varchar(64);not null;uniqueIndex" json:"product_code"` // product_code 业务字段
|
||||
Name string `gorm:"column:name;type:varchar(128);not null" json:"name"` // name 业务字段
|
||||
PriceAmount int64 `gorm:"column:price_amount;not null;default:0" json:"price_amount"` // price_amount 业务字段
|
||||
StockQuantity int `gorm:"column:stock_quantity;not null;default:0" json:"stock_quantity"` // stock_quantity 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&EcProduct{}) }
|
||||
|
||||
@@ -4,11 +4,11 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// EcProductAttribute 对应 ec_product_attribute,保存商品属性。
|
||||
type EcProductAttribute struct {
|
||||
Entity
|
||||
EcProductID uint64 `gorm:"column:ec_product_id;not null;index" json:"ec_product_id"`
|
||||
Name string `gorm:"column:name;type:varchar(64);not null" json:"name"`
|
||||
Value string `gorm:"column:value;type:varchar(255);not null" json:"value"`
|
||||
SortNo int `gorm:"column:sort_no;not null;default:0" json:"sort_no"`
|
||||
Entity // 公共实体字段
|
||||
EcProductID uint64 `gorm:"column:ec_product_id;not null;index" json:"ec_product_id"` // ec_product_id 业务字段
|
||||
Name string `gorm:"column:name;type:varchar(64);not null" json:"name"` // name 业务字段
|
||||
Value string `gorm:"column:value;type:varchar(255);not null" json:"value"` // value 业务字段
|
||||
SortNo int `gorm:"column:sort_no;not null;default:0" json:"sort_no"` // sort_no 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&EcProductAttribute{}) }
|
||||
|
||||
@@ -4,11 +4,11 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// EcProductImage 对应 ec_product_image,保存商品受控图片资源。
|
||||
type EcProductImage struct {
|
||||
Entity
|
||||
EcProductID uint64 `gorm:"column:ec_product_id;not null;index" json:"ec_product_id"`
|
||||
ImageURI string `gorm:"column:image_uri;type:varchar(512);not null" json:"image_uri"`
|
||||
SortNo int `gorm:"column:sort_no;not null;default:0" json:"sort_no"`
|
||||
IsCover bool `gorm:"column:is_cover;not null;default:false" json:"is_cover"`
|
||||
Entity // 公共实体字段
|
||||
EcProductID uint64 `gorm:"column:ec_product_id;not null;index" json:"ec_product_id"` // ec_product_id 业务字段
|
||||
ImageURI string `gorm:"column:image_uri;type:varchar(512);not null" json:"image_uri"` // image_uri 业务字段
|
||||
SortNo int `gorm:"column:sort_no;not null;default:0" json:"sort_no"` // sort_no 业务字段
|
||||
IsCover bool `gorm:"column:is_cover;not null;default:false" json:"is_cover"` // is_cover 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&EcProductImage{}) }
|
||||
|
||||
@@ -4,12 +4,12 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// EcReview 对应 ec_review,保存商品评论与审核状态。
|
||||
type EcReview struct {
|
||||
Entity
|
||||
EcOrderID uint64 `gorm:"column:ec_order_id;not null;index" json:"ec_order_id"`
|
||||
EcProductID uint64 `gorm:"column:ec_product_id;not null;index" json:"ec_product_id"`
|
||||
UserAccountID uint64 `gorm:"column:user_account_id;not null;index" json:"user_account_id"`
|
||||
Score int `gorm:"column:score;not null;default:5" json:"score"`
|
||||
Content string `gorm:"column:content;type:text;not null;default:''" json:"content"`
|
||||
Entity // 公共实体字段
|
||||
EcOrderID uint64 `gorm:"column:ec_order_id;not null;index" json:"ec_order_id"` // ec_order_id 业务字段
|
||||
EcProductID uint64 `gorm:"column:ec_product_id;not null;index" json:"ec_product_id"` // ec_product_id 业务字段
|
||||
UserAccountID uint64 `gorm:"column:user_account_id;not null;index" json:"user_account_id"` // user_account_id 业务字段
|
||||
Score int `gorm:"column:score;not null;default:5" json:"score"` // score 业务字段
|
||||
Content string `gorm:"column:content;type:text;not null;default:''" json:"content"` // content 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&EcReview{}) }
|
||||
|
||||
@@ -7,11 +7,11 @@ import (
|
||||
|
||||
// FinPayment 对应 fin_payment,保存支付与退款记录。
|
||||
type FinPayment struct {
|
||||
Entity
|
||||
EcOrderID uint64 `gorm:"column:ec_order_id;not null;index" json:"ec_order_id"`
|
||||
Channel string `gorm:"column:channel;type:varchar(32);not null" json:"channel"`
|
||||
Amount int64 `gorm:"column:amount;not null;default:0" json:"amount"`
|
||||
PaidAt *time.Time `gorm:"column:paid_at;type:timestamptz" json:"paid_at"`
|
||||
Entity // 公共实体字段
|
||||
EcOrderID uint64 `gorm:"column:ec_order_id;not null;index" json:"ec_order_id"` // ec_order_id 业务字段
|
||||
Channel string `gorm:"column:channel;type:varchar(32);not null" json:"channel"` // channel 业务字段
|
||||
Amount int64 `gorm:"column:amount;not null;default:0" json:"amount"` // amount 业务字段
|
||||
PaidAt *time.Time `gorm:"column:paid_at;type:timestamptz" json:"paid_at"` // paid_at 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&FinPayment{}) }
|
||||
|
||||
@@ -7,10 +7,10 @@ import (
|
||||
|
||||
// FinReconciliation 对应 fin_reconciliation,保存渠道对账记录。
|
||||
type FinReconciliation struct {
|
||||
Entity
|
||||
Channel string `gorm:"column:channel;type:varchar(32);not null;index" json:"channel"`
|
||||
BillDate time.Time `gorm:"column:bill_date;type:date;not null" json:"bill_date"`
|
||||
DifferenceAmount int64 `gorm:"column:difference_amount;not null;default:0" json:"difference_amount"`
|
||||
Entity // 公共实体字段
|
||||
Channel string `gorm:"column:channel;type:varchar(32);not null;index" json:"channel"` // channel 业务字段
|
||||
BillDate time.Time `gorm:"column:bill_date;type:date;not null" json:"bill_date"` // bill_date 业务字段
|
||||
DifferenceAmount int64 `gorm:"column:difference_amount;not null;default:0" json:"difference_amount"` // difference_amount 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&FinReconciliation{}) }
|
||||
|
||||
@@ -7,12 +7,12 @@ import (
|
||||
|
||||
// FinSettlement 对应 fin_settlement,保存结算单。
|
||||
type FinSettlement struct {
|
||||
Entity
|
||||
SettlementNo string `gorm:"column:settlement_no;type:varchar(64);not null;uniqueIndex" json:"settlement_no"`
|
||||
SubjectType string `gorm:"column:subject_type;type:varchar(32);not null" json:"subject_type"`
|
||||
SubjectID uint64 `gorm:"column:subject_id;not null;index" json:"subject_id"`
|
||||
PeriodStart time.Time `gorm:"column:period_start;type:timestamptz;not null" json:"period_start"`
|
||||
PeriodEnd time.Time `gorm:"column:period_end;type:timestamptz;not null" json:"period_end"`
|
||||
Entity // 公共实体字段
|
||||
SettlementNo string `gorm:"column:settlement_no;type:varchar(64);not null;uniqueIndex" json:"settlement_no"` // settlement_no 业务字段
|
||||
SubjectType string `gorm:"column:subject_type;type:varchar(32);not null" json:"subject_type"` // subject_type 业务字段
|
||||
SubjectID uint64 `gorm:"column:subject_id;not null;index" json:"subject_id"` // subject_id 业务字段
|
||||
PeriodStart time.Time `gorm:"column:period_start;type:timestamptz;not null" json:"period_start"` // period_start 业务字段
|
||||
PeriodEnd time.Time `gorm:"column:period_end;type:timestamptz;not null" json:"period_end"` // period_end 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&FinSettlement{}) }
|
||||
|
||||
@@ -4,7 +4,7 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// GasAccount 对应 gas_account,保存可燃气体站登录账户。
|
||||
type GasAccount struct {
|
||||
Entity
|
||||
Entity // 公共实体字段
|
||||
GasBasicID uint64 `gorm:"column:gas_basic_id;not null;index" json:"gas_basic_id"` // 可燃气体站主键
|
||||
Username string `gorm:"column:username;type:varchar(64);not null;uniqueIndex" json:"username"` // 登录名称
|
||||
DisplayName string `gorm:"column:display_name;type:varchar(64);not null;default:''" json:"display_name"` // 展示名称
|
||||
|
||||
@@ -4,7 +4,7 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// GasBasic 对应 gas_basic,保存可燃气体站的主体主档案。
|
||||
type GasBasic struct {
|
||||
Entity
|
||||
Entity // 公共实体字段
|
||||
Code string `gorm:"column:code;type:varchar(32);not null;uniqueIndex" json:"code"` // 站点编码
|
||||
Name string `gorm:"column:name;type:varchar(128);not null" json:"name"` // 站点名称
|
||||
CreditCode string `gorm:"column:credit_code;type:varchar(64);not null;default:''" json:"credit_code"` // 统一社会信用代码
|
||||
|
||||
@@ -4,10 +4,10 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// NtfTemplate 对应 ntf_template,保存通知模板。
|
||||
type NtfTemplate struct {
|
||||
Entity
|
||||
TemplateCode string `gorm:"column:template_code;type:varchar(64);not null;uniqueIndex" json:"template_code"`
|
||||
Channel string `gorm:"column:channel;type:varchar(32);not null" json:"channel"`
|
||||
Content string `gorm:"column:content;type:text;not null" json:"content"`
|
||||
Entity // 公共实体字段
|
||||
TemplateCode string `gorm:"column:template_code;type:varchar(64);not null;uniqueIndex" json:"template_code"` // template_code 业务字段
|
||||
Channel string `gorm:"column:channel;type:varchar(32);not null" json:"channel"` // channel 业务字段
|
||||
Content string `gorm:"column:content;type:text;not null" json:"content"` // content 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&NtfTemplate{}) }
|
||||
|
||||
@@ -4,7 +4,7 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// PlatformMenu 对应 platform_menu,定义平台总后台的菜单树和访问路由。
|
||||
type PlatformMenu struct {
|
||||
Entity
|
||||
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"` // 菜单名称
|
||||
|
||||
@@ -4,7 +4,7 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// PlatformRole 对应 platform_role,定义平台总后台的数据范围与菜单权限角色。
|
||||
type PlatformRole struct {
|
||||
Entity
|
||||
Entity // 公共实体字段
|
||||
RoleCode string `gorm:"column:role_code;type:varchar(64);not null;uniqueIndex" json:"role_code"` // 角色编码
|
||||
Name string `gorm:"column:name;type:varchar(64);not null" json:"name"` // 角色名称
|
||||
DataScope string `gorm:"column:data_scope;type:varchar(32);not null;default:'global'" json:"data_scope"` // 数据权限范围
|
||||
|
||||
@@ -4,7 +4,7 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// PlatfromAccount 对应 platfrom_account,表示平台总后台登录账号。
|
||||
type PlatfromAccount struct {
|
||||
Entity
|
||||
Entity // 公共实体字段
|
||||
Username string `gorm:"column:username;type:varchar(64);uniqueIndex;not null" json:"username"` // 登录用户名
|
||||
DisplayName string `gorm:"column:display_name;type:varchar(64);not null;default:''" json:"display_name"` // 用户展示名称
|
||||
Avatar string `gorm:"column:avatar;type:varchar(512);not null;default:''" json:"avatar"` // 头像资源地址
|
||||
|
||||
@@ -7,11 +7,11 @@ import (
|
||||
|
||||
// Report 对应 report,保存统计报表档案。
|
||||
type Report struct {
|
||||
Entity
|
||||
ReportCode string `gorm:"column:report_code;type:varchar(64);not null;uniqueIndex" json:"report_code"`
|
||||
ReportType string `gorm:"column:report_type;type:varchar(32);not null" json:"report_type"`
|
||||
StatPeriod string `gorm:"column:stat_period;type:varchar(64);not null" json:"stat_period"`
|
||||
GeneratedAt time.Time `gorm:"column:generated_at;type:timestamptz;not null" json:"generated_at"`
|
||||
Entity // 公共实体字段
|
||||
ReportCode string `gorm:"column:report_code;type:varchar(64);not null;uniqueIndex" json:"report_code"` // report_code 业务字段
|
||||
ReportType string `gorm:"column:report_type;type:varchar(32);not null" json:"report_type"` // report_type 业务字段
|
||||
StatPeriod string `gorm:"column:stat_period;type:varchar(64);not null" json:"stat_period"` // stat_period 业务字段
|
||||
GeneratedAt time.Time `gorm:"column:generated_at;type:timestamptz;not null" json:"generated_at"` // generated_at 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&Report{}) }
|
||||
|
||||
@@ -4,11 +4,11 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// ReportItem 对应 report_item,保存报表维度明细。
|
||||
type ReportItem struct {
|
||||
Entity
|
||||
ReportID uint64 `gorm:"column:report_id;not null;index" json:"report_id"`
|
||||
Dimension string `gorm:"column:dimension;type:varchar(128);not null" json:"dimension"`
|
||||
MetricCode string `gorm:"column:metric_code;type:varchar(64);not null" json:"metric_code"`
|
||||
MetricValue string `gorm:"column:metric_value;type:varchar(128);not null" json:"metric_value"`
|
||||
Entity // 公共实体字段
|
||||
ReportID uint64 `gorm:"column:report_id;not null;index" json:"report_id"` // report_id 业务字段
|
||||
Dimension string `gorm:"column:dimension;type:varchar(128);not null" json:"dimension"` // dimension 业务字段
|
||||
MetricCode string `gorm:"column:metric_code;type:varchar(64);not null" json:"metric_code"` // metric_code 业务字段
|
||||
MetricValue string `gorm:"column:metric_value;type:varchar(128);not null" json:"metric_value"` // metric_value 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&ReportItem{}) }
|
||||
|
||||
@@ -7,12 +7,12 @@ import (
|
||||
|
||||
// ReportMetricSnapshot 对应 report_metric_snapshot,保存指标快照。
|
||||
type ReportMetricSnapshot struct {
|
||||
Entity
|
||||
MetricCode string `gorm:"column:metric_code;type:varchar(64);not null;index" json:"metric_code"`
|
||||
ScopeType string `gorm:"column:scope_type;type:varchar(32);not null" json:"scope_type"`
|
||||
ScopeID uint64 `gorm:"column:scope_id;not null;default:0;index" json:"scope_id"`
|
||||
StatAt time.Time `gorm:"column:stat_at;type:timestamptz;not null;index" json:"stat_at"`
|
||||
MetricValue string `gorm:"column:metric_value;type:varchar(128);not null" json:"metric_value"`
|
||||
Entity // 公共实体字段
|
||||
MetricCode string `gorm:"column:metric_code;type:varchar(64);not null;index" json:"metric_code"` // metric_code 业务字段
|
||||
ScopeType string `gorm:"column:scope_type;type:varchar(32);not null" json:"scope_type"` // scope_type 业务字段
|
||||
ScopeID uint64 `gorm:"column:scope_id;not null;default:0;index" json:"scope_id"` // scope_id 业务字段
|
||||
StatAt time.Time `gorm:"column:stat_at;type:timestamptz;not null;index" json:"stat_at"` // stat_at 业务字段
|
||||
MetricValue string `gorm:"column:metric_value;type:varchar(128);not null" json:"metric_value"` // metric_value 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&ReportMetricSnapshot{}) }
|
||||
|
||||
@@ -7,12 +7,12 @@ import (
|
||||
|
||||
// SafEvent 对应 saf_event,保存安全事件统一入口。
|
||||
type SafEvent struct {
|
||||
Entity
|
||||
EventCode string `gorm:"column:event_code;type:varchar(64);not null;uniqueIndex" json:"event_code"`
|
||||
Level int `gorm:"column:level;not null;default:3" json:"level"`
|
||||
Title string `gorm:"column:title;type:varchar(256);not null;default:''" json:"title"`
|
||||
SmartCylinderValveIdentity string `gorm:"column:smart_cylinder_valve_identity;type:varchar(36);not null;default:'';index" json:"smart_cylinder_valve_identity"`
|
||||
SLAAt *time.Time `gorm:"column:sla_at;type:timestamptz" json:"sla_at"`
|
||||
Entity // 公共实体字段
|
||||
EventCode string `gorm:"column:event_code;type:varchar(64);not null;uniqueIndex" json:"event_code"` // event_code 业务字段
|
||||
Level int `gorm:"column:level;not null;default:3" json:"level"` // level 业务字段
|
||||
Title string `gorm:"column:title;type:varchar(256);not null;default:''" json:"title"` // title 业务字段
|
||||
SmartCylinderValveIdentity string `gorm:"column:smart_cylinder_valve_identity;type:varchar(36);not null;default:'';index" json:"smart_cylinder_valve_identity"` // smart_cylinder_valve_identity 业务字段
|
||||
SLAAt *time.Time `gorm:"column:sla_at;type:timestamptz" json:"sla_at"` // sla_at 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&SafEvent{}) }
|
||||
|
||||
@@ -4,11 +4,11 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// SafEventDisposal 对应 saf_event_disposal,保存安全处置记录。
|
||||
type SafEventDisposal struct {
|
||||
Entity
|
||||
SafEventIdentity string `gorm:"column:saf_event_identity;type:varchar(36);not null;index" json:"saf_event_identity"`
|
||||
Action string `gorm:"column:action;type:varchar(64);not null" json:"action"`
|
||||
Reason string `gorm:"column:reason;type:text;not null;default:''" json:"reason"`
|
||||
OperatorIdentity string `gorm:"column:operator_identity;type:varchar(36);not null;default:''" json:"operator_identity"`
|
||||
Entity // 公共实体字段
|
||||
SafEventIdentity string `gorm:"column:saf_event_identity;type:varchar(36);not null;index" json:"saf_event_identity"` // saf_event_identity 业务字段
|
||||
Action string `gorm:"column:action;type:varchar(64);not null" json:"action"` // action 业务字段
|
||||
Reason string `gorm:"column:reason;type:text;not null;default:''" json:"reason"` // reason 业务字段
|
||||
OperatorIdentity string `gorm:"column:operator_identity;type:varchar(36);not null;default:''" json:"operator_identity"` // operator_identity 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&SafEventDisposal{}) }
|
||||
|
||||
@@ -4,11 +4,11 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// SafInspection 对应 saf_inspection,保存安检与复检记录。
|
||||
type SafInspection struct {
|
||||
Entity
|
||||
UserAccountID uint64 `gorm:"column:user_account_id;not null;index" json:"user_account_id"`
|
||||
StaffAccountID uint64 `gorm:"column:staff_account_id;not null;index" json:"staff_account_id"`
|
||||
Result string `gorm:"column:result;type:varchar(32);not null" json:"result"`
|
||||
EvidenceURI string `gorm:"column:evidence_uri;type:varchar(512);not null;default:''" json:"evidence_uri"`
|
||||
Entity // 公共实体字段
|
||||
UserAccountID uint64 `gorm:"column:user_account_id;not null;index" json:"user_account_id"` // user_account_id 业务字段
|
||||
StaffAccountID uint64 `gorm:"column:staff_account_id;not null;index" json:"staff_account_id"` // staff_account_id 业务字段
|
||||
Result string `gorm:"column:result;type:varchar(32);not null" json:"result"` // result 业务字段
|
||||
EvidenceURI string `gorm:"column:evidence_uri;type:varchar(512);not null;default:''" json:"evidence_uri"` // evidence_uri 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&SafInspection{}) }
|
||||
|
||||
@@ -4,12 +4,12 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// SafRule 对应 saf_rule,保存安全规则。
|
||||
type SafRule struct {
|
||||
Entity
|
||||
RuleCode string `gorm:"column:rule_code;type:varchar(64);not null;uniqueIndex" json:"rule_code"`
|
||||
VersionNo int `gorm:"column:version_no;not null;default:1" json:"version_no"`
|
||||
Threshold string `gorm:"column:threshold;type:jsonb;not null;default:'{}'" json:"threshold"`
|
||||
Action string `gorm:"column:action;type:varchar(64);not null" json:"action"`
|
||||
GrayScope string `gorm:"column:gray_scope;type:jsonb;not null;default:'{}'" json:"gray_scope"`
|
||||
Entity // 公共实体字段
|
||||
RuleCode string `gorm:"column:rule_code;type:varchar(64);not null;uniqueIndex" json:"rule_code"` // rule_code 业务字段
|
||||
VersionNo int `gorm:"column:version_no;not null;default:1" json:"version_no"` // version_no 业务字段
|
||||
Threshold string `gorm:"column:threshold;type:jsonb;not null;default:'{}'" json:"threshold"` // threshold 业务字段
|
||||
Action string `gorm:"column:action;type:varchar(64);not null" json:"action"` // action 业务字段
|
||||
GrayScope string `gorm:"column:gray_scope;type:jsonb;not null;default:'{}'" json:"gray_scope"` // gray_scope 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&SafRule{}) }
|
||||
|
||||
@@ -4,7 +4,7 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// StaffAccount 对应 staff_account,是服务人员唯一的档案和 App 登录账户。
|
||||
type StaffAccount struct {
|
||||
Entity
|
||||
Entity // 公共实体字段
|
||||
Username string `gorm:"column:username;type:varchar(64);not null;uniqueIndex" json:"username"` // 登录名称
|
||||
PasswordHash string `gorm:"column:password_hash;type:varchar(255);not null" json:"-"` // 密码哈希
|
||||
Name string `gorm:"column:name;type:varchar(64);not null" json:"name"` // 人员姓名
|
||||
|
||||
@@ -7,11 +7,11 @@ import (
|
||||
|
||||
// StaffCredential 对应 staff_credential,保存人员资质。
|
||||
type StaffCredential struct {
|
||||
Entity
|
||||
StaffAccountID uint64 `gorm:"column:staff_account_id;not null;index" json:"staff_account_id"`
|
||||
CredentialType string `gorm:"column:credential_type;type:varchar(64);not null" json:"credential_type"`
|
||||
CredentialNo string `gorm:"column:credential_no;type:varchar(128);not null;default:''" json:"credential_no"`
|
||||
ExpiredAt *time.Time `gorm:"column:expired_at;type:timestamptz" json:"expired_at"`
|
||||
Entity // 公共实体字段
|
||||
StaffAccountID uint64 `gorm:"column:staff_account_id;not null;index" json:"staff_account_id"` // staff_account_id 业务字段
|
||||
CredentialType string `gorm:"column:credential_type;type:varchar(64);not null" json:"credential_type"` // credential_type 业务字段
|
||||
CredentialNo string `gorm:"column:credential_no;type:varchar(128);not null;default:''" json:"credential_no"` // credential_no 业务字段
|
||||
ExpiredAt *time.Time `gorm:"column:expired_at;type:timestamptz" json:"expired_at"` // expired_at 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&StaffCredential{}) }
|
||||
|
||||
@@ -4,7 +4,7 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// UserAccount 对应 user_account,是业主客户唯一的档案和用户端登录账户。
|
||||
type UserAccount struct {
|
||||
Entity
|
||||
Entity // 公共实体字段
|
||||
Username string `gorm:"column:username;type:varchar(64);not null;uniqueIndex" json:"username"` // 登录名称
|
||||
PasswordHash string `gorm:"column:password_hash;type:varchar(255);not null" json:"-"` // 密码哈希
|
||||
Name string `gorm:"column:name;type:varchar(64);not null" json:"name"` // 客户姓名
|
||||
|
||||
@@ -4,12 +4,12 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// UserAddress 对应 user_address,保存用户地址。
|
||||
type UserAddress struct {
|
||||
Entity
|
||||
UserAccountID uint64 `gorm:"column:user_account_id;not null;index" json:"user_account_id"`
|
||||
Address string `gorm:"column:address;type:varchar(255);not null" json:"address"`
|
||||
Longitude string `gorm:"column:longitude;type:varchar(32);not null;default:''" json:"longitude"`
|
||||
Latitude string `gorm:"column:latitude;type:varchar(32);not null;default:''" json:"latitude"`
|
||||
IsDefault bool `gorm:"column:is_default;not null;default:false" json:"is_default"`
|
||||
Entity // 公共实体字段
|
||||
UserAccountID uint64 `gorm:"column:user_account_id;not null;index" json:"user_account_id"` // user_account_id 业务字段
|
||||
Address string `gorm:"column:address;type:varchar(255);not null" json:"address"` // address 业务字段
|
||||
Longitude string `gorm:"column:longitude;type:varchar(32);not null;default:''" json:"longitude"` // longitude 业务字段
|
||||
Latitude string `gorm:"column:latitude;type:varchar(32);not null;default:''" json:"latitude"` // latitude 业务字段
|
||||
IsDefault bool `gorm:"column:is_default;not null;default:false" json:"is_default"` // is_default 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&UserAddress{}) }
|
||||
|
||||
@@ -4,11 +4,11 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// UserServiceRelation 对应 user_service_relation,保存用户服务归属快照。
|
||||
type UserServiceRelation struct {
|
||||
Entity
|
||||
UserAccountID uint64 `gorm:"column:user_account_id;not null;index" json:"user_account_id"`
|
||||
GasBasicID uint64 `gorm:"column:gas_basic_id;not null;default:0;index" json:"gas_basic_id"`
|
||||
DeliveryBasicID uint64 `gorm:"column:delivery_basic_id;not null;default:0;index" json:"delivery_basic_id"`
|
||||
StaffAccountID uint64 `gorm:"column:staff_account_id;not null;default:0;index" json:"staff_account_id"`
|
||||
Entity // 公共实体字段
|
||||
UserAccountID uint64 `gorm:"column:user_account_id;not null;index" json:"user_account_id"` // user_account_id 业务字段
|
||||
GasBasicID uint64 `gorm:"column:gas_basic_id;not null;default:0;index" json:"gas_basic_id"` // gas_basic_id 业务字段
|
||||
DeliveryBasicID uint64 `gorm:"column:delivery_basic_id;not null;default:0;index" json:"delivery_basic_id"` // delivery_basic_id 业务字段
|
||||
StaffAccountID uint64 `gorm:"column:staff_account_id;not null;default:0;index" json:"staff_account_id"` // staff_account_id 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&UserServiceRelation{}) }
|
||||
|
||||
@@ -4,11 +4,11 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// Wallet 对应 wallet,保存余额账户。
|
||||
type Wallet struct {
|
||||
Entity
|
||||
OwnerType string `gorm:"column:owner_type;type:varchar(32);not null" json:"owner_type"`
|
||||
OwnerID uint64 `gorm:"column:owner_id;not null;index" json:"owner_id"`
|
||||
BalanceAmount int64 `gorm:"column:balance_amount;not null;default:0" json:"balance_amount"`
|
||||
FrozenAmount int64 `gorm:"column:frozen_amount;not null;default:0" json:"frozen_amount"`
|
||||
Entity // 公共实体字段
|
||||
OwnerType string `gorm:"column:owner_type;type:varchar(32);not null" json:"owner_type"` // owner_type 业务字段
|
||||
OwnerID uint64 `gorm:"column:owner_id;not null;index" json:"owner_id"` // owner_id 业务字段
|
||||
BalanceAmount int64 `gorm:"column:balance_amount;not null;default:0" json:"balance_amount"` // balance_amount 业务字段
|
||||
FrozenAmount int64 `gorm:"column:frozen_amount;not null;default:0" json:"frozen_amount"` // frozen_amount 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&Wallet{}) }
|
||||
|
||||
@@ -4,12 +4,12 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// WalletLedger 对应 wallet_ledger,保存不可变资金流水。
|
||||
type WalletLedger struct {
|
||||
Entity
|
||||
WalletID uint64 `gorm:"column:wallet_id;not null;index" json:"wallet_id"`
|
||||
Amount int64 `gorm:"column:amount;not null" json:"amount"`
|
||||
Direction string `gorm:"column:direction;type:varchar(16);not null" json:"direction"`
|
||||
BalanceAfter int64 `gorm:"column:balance_after;not null" json:"balance_after"`
|
||||
ReferenceIdentity string `gorm:"column:reference_identity;type:varchar(36);not null;default:'';index" json:"reference_identity"`
|
||||
Entity // 公共实体字段
|
||||
WalletID uint64 `gorm:"column:wallet_id;not null;index" json:"wallet_id"` // wallet_id 业务字段
|
||||
Amount int64 `gorm:"column:amount;not null" json:"amount"` // amount 业务字段
|
||||
Direction string `gorm:"column:direction;type:varchar(16);not null" json:"direction"` // direction 业务字段
|
||||
BalanceAfter int64 `gorm:"column:balance_after;not null" json:"balance_after"` // balance_after 业务字段
|
||||
ReferenceIdentity string `gorm:"column:reference_identity;type:varchar(36);not null;default:'';index" json:"reference_identity"` // reference_identity 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&WalletLedger{}) }
|
||||
|
||||
@@ -4,10 +4,10 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// WalletRecharge 对应 wallet_recharge,保存充值记录。
|
||||
type WalletRecharge struct {
|
||||
Entity
|
||||
WalletID uint64 `gorm:"column:wallet_id;not null;index" json:"wallet_id"`
|
||||
Amount int64 `gorm:"column:amount;not null" json:"amount"`
|
||||
Channel string `gorm:"column:channel;type:varchar(32);not null" json:"channel"`
|
||||
Entity // 公共实体字段
|
||||
WalletID uint64 `gorm:"column:wallet_id;not null;index" json:"wallet_id"` // wallet_id 业务字段
|
||||
Amount int64 `gorm:"column:amount;not null" json:"amount"` // amount 业务字段
|
||||
Channel string `gorm:"column:channel;type:varchar(32);not null" json:"channel"` // channel 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&WalletRecharge{}) }
|
||||
|
||||
@@ -4,10 +4,10 @@ import "git.apinb.com/bsm-sdk/core/database"
|
||||
|
||||
// WalletWithdrawal 对应 wallet_withdrawal,保存提现记录。
|
||||
type WalletWithdrawal struct {
|
||||
Entity
|
||||
WalletID uint64 `gorm:"column:wallet_id;not null;index" json:"wallet_id"`
|
||||
Amount int64 `gorm:"column:amount;not null" json:"amount"`
|
||||
BankAccountMasked string `gorm:"column:bank_account_masked;type:varchar(128);not null;default:''" json:"bank_account_masked"`
|
||||
Entity // 公共实体字段
|
||||
WalletID uint64 `gorm:"column:wallet_id;not null;index" json:"wallet_id"` // wallet_id 业务字段
|
||||
Amount int64 `gorm:"column:amount;not null" json:"amount"` // amount 业务字段
|
||||
BankAccountMasked string `gorm:"column:bank_account_masked;type:varchar(128);not null;default:''" json:"bank_account_masked"` // bank_account_masked 业务字段
|
||||
}
|
||||
|
||||
func init() { database.AppendMigrate(&WalletWithdrawal{}) }
|
||||
|
||||
@@ -48,7 +48,7 @@ func registerDeliveryRoute(group *gin.RouterGroup) {
|
||||
trackRelations := []platform.ResourceRelation{requiredRelation("delivery_task_identity", "delivery_task_id", &models.DeliveryTask{})}
|
||||
list, create, _, update := platform.ResourceHandlers(&models.DeliveryTrack{}, []string{"started_at", "completed_at"}, []string{"started_at", "completed_at"}, trackRelations...)
|
||||
registerWritableResource(group, "/delivery/delivery_track", list, create, platform.GetDeliveryTrack, update, &models.DeliveryTrack{})
|
||||
registerRestrictedWritableResource(group, "/delivery/delivery_track_point", &models.DeliveryTrackPoint{}, []string{"point_type", "occurred_at", "longitude", "latitude"}, requiredRelation("delivery_track_identity", "delivery_track_id", &models.DeliveryTrack{}))
|
||||
registerReadOnlyResource(group, "/delivery/delivery_track_point", &models.DeliveryTrackPoint{})
|
||||
}
|
||||
|
||||
func registerDeviceRoute(group *gin.RouterGroup) {
|
||||
|
||||
@@ -102,13 +102,20 @@ func TestPlatformDeviceSafetyCommerceAndDeliveryRoutesFollowTheirContracts(t *te
|
||||
"/device/dev_smart_cylinder_valve", "/device/dev_device_binding",
|
||||
"/safety/saf_rule", "/safety/saf_event", "/safety/saf_inspection",
|
||||
"/ec/ec_category", "/ec/ec_product", "/ec/ec_product_attribute", "/ec/ec_product_image", "/ec/ec_cart", "/ec/ec_order", "/ec/ec_order_item", "/ec/ec_review",
|
||||
"/delivery/delivery_task", "/delivery/delivery_track", "/delivery/delivery_track_point",
|
||||
"/delivery/delivery_task", "/delivery/delivery_track",
|
||||
} {
|
||||
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/status", http.MethodPatch)
|
||||
}
|
||||
|
||||
trackPoint := "/heqi/platform/v1/delivery/delivery_track_point"
|
||||
assertRouteMethods(t, routes, trackPoint, http.MethodGet)
|
||||
assertRouteMethods(t, routes, trackPoint+"/:identity", http.MethodGet)
|
||||
assertNoRouteMethods(t, routes, trackPoint, http.MethodPost)
|
||||
assertNoRouteMethods(t, routes, trackPoint+"/:identity", http.MethodPut, http.MethodDelete)
|
||||
assertNoRouteMethods(t, routes, trackPoint+"/:identity/status", http.MethodPatch)
|
||||
|
||||
telemetry := "/heqi/platform/v1/device/dev_telemetry"
|
||||
assertRouteMethods(t, routes, telemetry, http.MethodGet)
|
||||
assertRouteMethods(t, routes, telemetry+"/:identity", http.MethodGet)
|
||||
|
||||
Reference in New Issue
Block a user