package store import ( "context" "database/sql" "errors" ) type MemberIMIdentity struct { ID int64 `db:"id"` TenantID int64 `db:"tenant_id"` MemberID int64 `db:"member_id"` IMTenantCode string `db:"im_tenant_code"` IMUserID string `db:"im_user_id"` IMUsername string `db:"im_username"` IMPasswordCipher string `db:"im_password_cipher"` } type MemberIMProfile struct { MemberID int64 `db:"member_id"` Username string `db:"username"` MemberNo string `db:"member_no"` } func (s *Store) CustomerServiceByID(ctx context.Context, tenantID, serviceID int64) (*CustomerService, error) { if s == nil || s.db == nil { return nil, errors.New("store is unavailable") } var row CustomerService err := s.db.GetContext(ctx, &row, `SELECT id,service_code,name,avatar_url,work_time,online_status, service_url,backup_contact,im_tenant_code,COALESCE(im_user_id,'') AS im_user_id, COALESCE(im_username,'') AS im_username FROM hg_customer_service WHERE tenant_id=? AND id=? AND status=1 AND deleted_at IS NULL LIMIT 1`, tenantID, serviceID) if errors.Is(err, sql.ErrNoRows) { return nil, ErrResourceNotFound } return &row, err } func (s *Store) MemberIMIdentity(ctx context.Context, tenantID, memberID int64) (*MemberIMIdentity, error) { if s == nil || s.db == nil { return nil, errors.New("store is unavailable") } var row MemberIMIdentity err := s.db.GetContext(ctx, &row, `SELECT id,tenant_id,member_id,im_tenant_code,im_user_id,im_username,im_password_cipher FROM hg_app_member_im_identity WHERE tenant_id=? AND member_id=? LIMIT 1`, tenantID, memberID) if errors.Is(err, sql.ErrNoRows) { return nil, ErrResourceNotFound } return &row, err } func (s *Store) MemberIMProfile(ctx context.Context, tenantID, memberID int64) (*MemberIMProfile, error) { if s == nil || s.db == nil { return nil, errors.New("store is unavailable") } var row MemberIMProfile err := s.db.GetContext(ctx, &row, `SELECT id AS member_id,username,member_no FROM hg_app_member WHERE tenant_id=? AND id=? AND member_status=1 AND deleted_at IS NULL LIMIT 1`, tenantID, memberID) if errors.Is(err, sql.ErrNoRows) { return nil, ErrAccountNotFound } return &row, err } func (s *Store) SaveMemberIMIdentity(ctx context.Context, identity *MemberIMIdentity) (*MemberIMIdentity, error) { if s == nil || s.db == nil { return nil, errors.New("store is unavailable") } if identity == nil { return nil, errors.New("identity is required") } _, err := s.db.ExecContext(ctx, `INSERT INTO hg_app_member_im_identity (tenant_id,member_id,im_tenant_code,im_user_id,im_username,im_password_cipher,sync_status,last_error,created_at,updated_at) VALUES(?,?,?,?,?,?,1,'',UTC_TIMESTAMP(3),UTC_TIMESTAMP(3)) ON DUPLICATE KEY UPDATE im_user_id=VALUES(im_user_id),im_username=VALUES(im_username), im_password_cipher=VALUES(im_password_cipher),sync_status=1,last_error='',updated_at=UTC_TIMESTAMP(3)`, identity.TenantID, identity.MemberID, identity.IMTenantCode, identity.IMUserID, identity.IMUsername, identity.IMPasswordCipher) if err == nil { return s.MemberIMIdentity(ctx, identity.TenantID, identity.MemberID) } // A concurrent request may have completed the same deterministic mapping. existing, findErr := s.MemberIMIdentity(ctx, identity.TenantID, identity.MemberID) if findErr == nil { return existing, nil } return nil, err }