package platform import ( "context" "fmt" "time" "github.com/google/uuid" "github.com/jackc/pgx/v5/pgxpool" ) // Repository 封装平台总后台首期需要的 PostgreSQL 查询。 type Repository struct { pool *pgxpool.Pool } // NewRepository 创建平台领域数据访问实例。 func NewRepository(pool *pgxpool.Pool) *Repository { return &Repository{pool: pool} } // DashboardOverview 返回平台总后台首页所需的聚合指标。 func (repository *Repository) DashboardOverview(ctx context.Context) (map[string]int, error) { queries := map[string]string{ "gasStationCount": `SELECT count(*) FROM org_gas_station WHERE status = 'enabled'`, "deliveryPointCount": `SELECT count(*) FROM org_delivery_point WHERE status = 'enabled'`, "servicePersonCount": `SELECT count(*) FROM org_service_person WHERE work_status = 'on_duty'`, "userCount": `SELECT count(*) FROM idn_account WHERE account_type = 'user' AND status = 'enabled'`, "pendingSafetyCount": `SELECT count(*) FROM saf_event WHERE status = 'pending'`, } result := make(map[string]int, len(queries)) for key, query := range queries { var count int if err := repository.pool.QueryRow(ctx, query).Scan(&count); err != nil { return nil, err } result[key] = count } return result, nil } // ListOrgGasStation 查询可燃气体站列表。 func (repository *Repository) ListOrgGasStation(ctx context.Context) ([]OrgGasStation, error) { rows, err := repository.pool.Query(ctx, `SELECT identity, station_code, name, principal, service_area, status, created_at FROM org_gas_station ORDER BY created_at DESC`) if err != nil { return nil, err } defer rows.Close() items := make([]OrgGasStation, 0) for rows.Next() { var item OrgGasStation if err := rows.Scan(&item.Identity, &item.StationCode, &item.Name, &item.Principal, &item.ServiceArea, &item.Status, &item.CreatedAt); err != nil { return nil, err } items = append(items, item) } return items, rows.Err() } // CreateOrgGasStation 创建可燃气体站并写入不可变审计记录。 func (repository *Repository) CreateOrgGasStation(ctx context.Context, stationCode, name, principal, serviceArea string) (OrgGasStation, error) { identity, err := uuid.NewV7() if err != nil { return OrgGasStation{}, err } now := time.Now().UTC() item := OrgGasStation{Identity: identity.String(), StationCode: stationCode, Name: name, Principal: principal, ServiceArea: serviceArea, Status: "draft", CreatedAt: now} tx, err := repository.pool.Begin(ctx) if err != nil { return OrgGasStation{}, err } defer func() { _ = tx.Rollback(ctx) }() _, err = tx.Exec(ctx, `INSERT INTO org_gas_station (identity, station_code, name, principal, service_area, status, created_at, updated_at) VALUES ($1,$2,$3,$4,$5,$6,$7,$7)`, identity, stationCode, name, principal, serviceArea, item.Status, now) if err != nil { return OrgGasStation{}, fmt.Errorf("创建气站失败: %w", err) } _, err = tx.Exec(ctx, `INSERT INTO aud_operation_log (identity, action, object_type, object_identity, detail, created_at) VALUES ($1,$2,$3,$4,$5,$6)`, newIdentity(), "create", "org_gas_station", identity, `{"channel":"platform_admin"}`, now) if err != nil { return OrgGasStation{}, err } if err = tx.Commit(ctx); err != nil { return OrgGasStation{}, err } return item, nil } // ListOrgDeliveryPoint 查询配送点及其气站归属。 func (repository *Repository) ListOrgDeliveryPoint(ctx context.Context) ([]OrgDeliveryPoint, error) { rows, err := repository.pool.Query(ctx, `SELECT d.identity, d.delivery_code, d.name, COALESCE(g.name, ''), d.service_area, d.status FROM org_delivery_point d LEFT JOIN org_gas_station g ON d.gas_station_identity = g.identity ORDER BY d.created_at DESC`) if err != nil { return nil, err } defer rows.Close() items := make([]OrgDeliveryPoint, 0) for rows.Next() { var item OrgDeliveryPoint if err := rows.Scan(&item.Identity, &item.DeliveryCode, &item.Name, &item.GasStationName, &item.ServiceArea, &item.Status); err != nil { return nil, err } items = append(items, item) } return items, rows.Err() } // ListOrgServicePerson 查询服务人员并在 API 层完成手机号脱敏。 func (repository *Repository) ListOrgServicePerson(ctx context.Context) ([]OrgServicePerson, error) { rows, err := repository.pool.Query(ctx, `SELECT p.identity, p.name, a.phone, p.roles, p.work_status, p.credential_status FROM org_service_person p JOIN idn_account a ON p.account_identity = a.identity ORDER BY p.created_at DESC`) if err != nil { return nil, err } defer rows.Close() items := make([]OrgServicePerson, 0) for rows.Next() { var item OrgServicePerson var phone string if err := rows.Scan(&item.Identity, &item.Name, &phone, &item.Roles, &item.WorkStatus, &item.Credential); err != nil { return nil, err } item.PhoneMasked = maskPhone(phone) items = append(items, item) } return items, rows.Err() } // ListIdnAccount 查询用户最小必要视图,不返回完整手机号。 func (repository *Repository) ListIdnAccount(ctx context.Context) ([]IdnAccount, error) { rows, err := repository.pool.Query(ctx, `SELECT identity, phone, account_type, status, service_area FROM idn_account WHERE account_type = 'user' ORDER BY created_at DESC`) if err != nil { return nil, err } defer rows.Close() items := make([]IdnAccount, 0) for rows.Next() { var item IdnAccount var phone string if err := rows.Scan(&item.Identity, &phone, &item.AccountType, &item.Status, &item.ServiceArea); err != nil { return nil, err } item.PhoneMasked = maskPhone(phone) items = append(items, item) } return items, rows.Err() } // ListSafEvent 查询安全事件列表,供平台安全运营中心使用。 func (repository *Repository) ListSafEvent(ctx context.Context) ([]SafEvent, error) { rows, err := repository.pool.Query(ctx, `SELECT identity, event_code, level, title, status, created_at FROM saf_event ORDER BY level ASC, created_at DESC`) if err != nil { return nil, err } defer rows.Close() items := make([]SafEvent, 0) for rows.Next() { var item SafEvent if err := rows.Scan(&item.Identity, &item.EventCode, &item.Level, &item.Title, &item.Status, &item.CreatedAt); err != nil { return nil, err } items = append(items, item) } return items, rows.Err() } // maskPhone 按最小必要原则返回脱敏手机号。 func maskPhone(phone string) string { if len(phone) < 7 { return "***" } return phone[:3] + "****" + phone[len(phone)-4:] } // newIdentity 生成审计记录使用的 UUID V7。 func newIdentity() uuid.UUID { identity, err := uuid.NewV7() if err != nil { panic(err) } return identity }