package analysisadminlogic import ( "context" "strconv" "strings" "lone-services/pkg/modelbase" "lone-services/pkg/utils" analysis "lone-services/rpc/analysis/pb" storepb "lone-services/rpc/store/pb" "lone-services/services/analysis/internal/dao" "lone-services/services/analysis/internal/logic/common" "lone-services/services/analysis/internal/model" "lone-services/services/analysis/internal/svc" "lone-services/services/analysis/validator" jsoniter "github.com/json-iterator/go" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" ) const adminImageTimeLayout = "2006-01-02 15:04" func outParams(msg string) *analysis.Response { return common.OutResponse(utils.ErrorParams, msg) } func formatGender(gender uint32) string { switch gender { case 1: return "男" case 2: return "女" default: return "" } } func userStatus(row dao.User) int { status := utils.NumberOne if row.IsRegistered == uint8(utils.StatusOk) { status = utils.NumberTwo } if row.IsFaceVerified == uint8(utils.StatusOk) { status = utils.NumberThree } if row.IsProfileCompleted == uint8(utils.StatusOk) { status = utils.NumberFour } return status } func idStrings(ids []int64) []string { out := make([]string, 0, len(ids)) for _, id := range ids { if id < utils.NumberOne { continue } out = append(out, strconv.FormatInt(id, utils.NumberTen)) } return out } func loadImageLogs(userIds []int64) (map[int64]dao.UserImageLog, error) { out := make(map[int64]dao.UserImageLog, len(userIds)) if len(userIds) == utils.NumberZero { return out, nil } var rows []dao.UserImageLog err := model.UserImageLogModel{}.Init().Items(modelbase.Params{ In: map[string][]string{"user_id": idStrings(userIds)}, Order: "detection_time desc", }, &rows) if err != nil { return nil, err } for _, row := range rows { if _, ok := out[row.UserId]; ok { continue } out[row.UserId] = row } return out, nil } func formatImageContents(data map[string]string) map[string]string { result := make(map[string]string, len(data)) for k, v := range data { switch k { case "health_score": parts := strings.Split(v, "/") result[k] = strings.TrimSpace(parts[0]) default: result[k] = strings.TrimSuffix(v, "%") } } return result } func buildImageDetail(detail *dao.Image) dao.ImageDetailResource { var images map[string]interface{} if detail.Images != utils.StringEmpty { _ = jsoniter.UnmarshalFromString(detail.Images, &images) } var contents map[string]string if detail.Contents != utils.StringEmpty { var raw map[string]string if err := jsoniter.UnmarshalFromString(detail.Contents, &raw); err == nil { contents = formatImageContents(raw) } else { contents = map[string]string{} } } return dao.ImageDetailResource{ Id: detail.Id, UserId: detail.UserId, TaskId: detail.TaskId, Images: images, Contents: contents, Cover: detail.Cover, CreateTime: detail.CreateTime.Format(adminImageTimeLayout), } } func outgoingWithIncomingMD(ctx context.Context) context.Context { md, ok := metadata.FromIncomingContext(ctx) if !ok { return ctx } return metadata.NewOutgoingContext(ctx, md.Copy()) } type storePageRow struct { Id int64 `json:"id"` Name string `json:"name"` UserName string `json:"user_name"` UserMobile string `json:"user_mobile"` District string `json:"district"` Address string `json:"address"` ProvinceName string `json:"province_name"` CityName string `json:"city_name"` CountyName string `json:"county_name"` } type storePageData struct { Count int64 `json:"count"` Items []storePageRow `json:"items"` } func loadStorePage(ctx context.Context, name string, page, size, storeStatus int32) (storePageData, error) { out := storePageData{Items: []storePageRow{}} svcName := utils.GetConfigString("services.store") if svcName == utils.StringEmpty { return out, status.Error(codes.FailedPrecondition, "store service empty") } cli, err := svc.GetRpcClient(svcName) if err != nil { return out, err } res, err := storepb.NewStoreClient(cli.Conn()).Items(outgoingWithIncomingMD(ctx), &storepb.ItemsRequest{ Name: name, Page: page, Size: size, Status: storeStatus, }) if err != nil { return out, err } if res.GetCode() != utils.Ok.Code { return out, status.Error(codes.Internal, res.GetMsg()) } if res.GetData() == utils.StringEmpty { return out, nil } if err = jsoniter.UnmarshalFromString(res.GetData(), &out); err != nil { return storePageData{}, err } if out.Items == nil { out.Items = []storePageRow{} } return out, nil } func loadStoresByIds(ctx context.Context, ids []int64) (map[int64]*storepb.InfoResponse, error) { out := make(map[int64]*storepb.InfoResponse, len(ids)) if len(ids) == utils.NumberZero { return out, nil } svcName := utils.GetConfigString("services.store") if svcName == utils.StringEmpty { return nil, status.Error(codes.FailedPrecondition, "store service empty") } cli, err := svc.GetRpcClient(svcName) if err != nil { return nil, err } res, err := storepb.NewStoreClient(cli.Conn()).GetInfoByIds(ctx, &storepb.IdsRequest{Ids: ids}) if err != nil { if st, ok := status.FromError(err); ok && st.Message() == utils.ErrorNotFund.Msg { return out, nil } return nil, err } for _, item := range res.GetItems() { out[item.GetId()] = item } return out, nil } func storeDistrictTextFromInfo(info *storepb.InfoResponse) string { if info == nil { return utils.StringEmpty } parts := make([]string, 0, 3) for _, name := range []string{info.GetProvinceName(), info.GetCityName(), info.GetCountyName()} { if name != utils.StringEmpty { parts = append(parts, name) } } return strings.Join(parts, "") } func pageSlice[T any](items []T, page, size int32) (int64, []T) { total := int64(len(items)) p := int(page) s := int(size) if p < modelbase.DefaultPage { p = modelbase.DefaultPage } if s < utils.NumberOne { s = modelbase.DefaultSize } start := (p - 1) * s if start >= len(items) { return total, []T{} } end := start + s if end > len(items) { end = len(items) } return total, items[start:end] } func queryAdminImageLogs(userId int64, page, size int32) ([]dao.ImageLogResource, error) { var rows []dao.Image _, err := model.ImageModel{}.Init().Page(modelbase.Params{ Eq: map[string]string{ "user_id": strconv.FormatInt(userId, utils.NumberTen), "status": strconv.Itoa(utils.StatusOk), }, Order: "id desc", Page: int(page), Size: int(size), }, &rows) if err != nil { return nil, err } if len(rows) == utils.NumberZero { return nil, nil } list := make([]dao.ImageLogResource, 0, len(rows)) for _, row := range rows { contents := map[string]string{} if row.Contents != utils.StringEmpty { var raw map[string]string if err = jsoniter.UnmarshalFromString(row.Contents, &raw); err == nil { if formatted := formatImageContents(raw); formatted != nil { contents = formatted } } } list = append(list, dao.ImageLogResource{ Id: row.Id, UserId: row.UserId, Cover: row.Cover, Contents: contents, TaskId: row.TaskId, CreateTime: row.CreateTime.Format(adminImageTimeLayout), }) } return list, nil } func toAdminGraphTitles(items []*analysis.AdminGraphTitleItem) []validator.AdminGraphTitleItem { out := make([]validator.AdminGraphTitleItem, 0, len(items)) for _, item := range items { if item == nil { continue } out = append(out, validator.AdminGraphTitleItem{ Name: item.GetName(), Content: item.GetContent(), }) } return out } func toAdminGraphImages(items []*analysis.AdminGraphImageItem) []validator.AdminGraphImageItem { out := make([]validator.AdminGraphImageItem, 0, len(items)) for _, item := range items { if item == nil { continue } out = append(out, validator.AdminGraphImageItem{ Url: item.GetUrl(), Text: item.GetText(), }) } return out } func toDaoGraphTitles(items []validator.AdminGraphTitleItem) []dao.GraphTitleItem { out := make([]dao.GraphTitleItem, 0, len(items)) for _, item := range items { out = append(out, dao.GraphTitleItem{Name: item.Name, Content: item.Content}) } return out } func toDaoGraphImages(items []validator.AdminGraphImageItem) []dao.GraphImageItem { out := make([]dao.GraphImageItem, 0, len(items)) for _, item := range items { out = append(out, dao.GraphImageItem{Url: item.Url, Text: item.Text}) } return out }