avatar_urls.dart 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import '../config/app_config.dart';
  2. /// 与 Web `pickAvatarFromRecord` 对齐:头像 URL 可能在多字段或嵌套对象中。
  3. String? pickAvatarUrlFromRecord(Map<String, dynamic>? raw) {
  4. if (raw == null) {
  5. return null;
  6. }
  7. const directKeys = [
  8. 'avatar',
  9. 'headImg',
  10. 'head_img',
  11. 'headPortrait',
  12. 'head_portrait',
  13. 'portrait',
  14. 'photo',
  15. 'photoUrl',
  16. 'photo_url',
  17. 'faceUrl',
  18. 'face_url',
  19. 'icon',
  20. 'userAvatar',
  21. 'user_avatar',
  22. 'avatarUrl',
  23. 'avatarURL',
  24. 'logo',
  25. ];
  26. for (final k in directKeys) {
  27. final v = raw[k];
  28. if (v != null) {
  29. final s = v.toString().trim();
  30. if (s.isNotEmpty && s != 'null' && s != 'undefined') {
  31. return s;
  32. }
  33. }
  34. }
  35. const nestedKeys = [
  36. 'data',
  37. 'member',
  38. 'user',
  39. 'account',
  40. 'result',
  41. 'userInfo',
  42. 'user_info',
  43. ];
  44. for (final nk in nestedKeys) {
  45. final nested = raw[nk];
  46. if (nested is Map) {
  47. final found = pickAvatarUrlFromRecord(
  48. Map<String, dynamic>.from(nested),
  49. );
  50. if (found != null) {
  51. return found;
  52. }
  53. }
  54. }
  55. return null;
  56. }
  57. /// 将站内相对头像路径解析为可用绝对 URL(与 Web 外链 OSS 同源策略下的展示前提一致)。
  58. String? normalizeAvatarHttpUrl(String? raw) {
  59. if (raw == null) {
  60. return null;
  61. }
  62. final s = raw.trim();
  63. if (s.isEmpty || s == 'null' || s == 'undefined') {
  64. return null;
  65. }
  66. final lower = s.toLowerCase();
  67. if (lower.startsWith('http://') || lower.startsWith('https://')) {
  68. return s;
  69. }
  70. if (s.startsWith('//')) {
  71. return 'https:$s';
  72. }
  73. try {
  74. final baseUri = Uri.parse(AppConfig.effectiveApiBaseUrl);
  75. return baseUri.resolve(s).toString();
  76. } catch (_) {
  77. return s;
  78. }
  79. }
  80. /// pick + normalize,供界面与列表模型直接使用。
  81. String? resolvedAvatarUrlFromRecord(Map<String, dynamic>? raw) {
  82. return normalizeAvatarHttpUrl(pickAvatarUrlFromRecord(raw));
  83. }