user-avatar.ts 3.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. /** 未设置头像时使用 `public/avatart.jpg` */
  2. function joinPublicAsset(path: string): string {
  3. const base = import.meta.env.BASE_URL || '/'
  4. const prefix = base.endsWith('/') ? base : `${base}/`
  5. return `${prefix}${path.replace(/^\//, '')}`
  6. }
  7. export const DEFAULT_USER_AVATAR_URL = joinPublicAsset('avatart.jpg')
  8. /** 本地/部署环境由 .env 配置;docker 默认走 Nginx `/minio/zkxw` 反代 */
  9. const minioBaseUrl = (import.meta.env.VITE_MINIO_BASE_URL || '/minio/zkxw').replace(/\/$/, '')
  10. /** @deprecated 各角色默认已统一为默认头像图,保留参数仅为兼容旧调用 */
  11. export function defaultAvatarPathByRole(_role: string | undefined): string {
  12. return DEFAULT_USER_AVATAR_URL
  13. }
  14. /**
  15. * 将库中头像值规范为存储相对路径(如 avatar/202606/04/xxx.jpeg)。
  16. * 兼容历史数据里写入的完整 URL(如 https://www.chengyantek.cn/zkxw/avatar/...)。
  17. */
  18. export function normalizeAvatarStorageKey(raw: string | null | undefined): string {
  19. const u = raw != null ? String(raw).trim() : ''
  20. if (!u) return ''
  21. if (!/^https?:\/\//i.test(u) && !u.startsWith('/')) return u
  22. const marker = '/avatar/'
  23. const lower = u.toLowerCase()
  24. const idx = lower.indexOf(marker)
  25. if (idx >= 0) {
  26. return `avatar/${u.slice(idx + marker.length)}`
  27. }
  28. if (u.startsWith('/')) {
  29. const parts = u.split('/').filter(Boolean)
  30. const avatarIdx = parts.findIndex((p) => p === 'avatar')
  31. if (avatarIdx >= 0) return parts.slice(avatarIdx).join('/')
  32. }
  33. return u
  34. }
  35. /** 从用户信息对象读取原始头像字段(兼容 avatar / avatarUrl) */
  36. export function pickUserAvatarRaw(
  37. source: { avatarUrl?: string | null; avatar?: string | null } | null | undefined
  38. ): string {
  39. if (!source) return ''
  40. const raw = source.avatarUrl ?? source.avatar
  41. return normalizeAvatarStorageKey(raw != null ? String(raw).trim() : '')
  42. }
  43. /** 是否已设置自定义头像(非空即视为已设置) */
  44. export function hasCustomUserAvatar(avatarUrl: string | null | undefined): boolean {
  45. return Boolean(normalizeAvatarStorageKey(avatarUrl))
  46. }
  47. /** 解析上传接口返回的图片地址 */
  48. export function pickUploadAvatarUrl(res: unknown): string {
  49. if (res == null) return ''
  50. if (typeof res === 'string') return normalizeAvatarStorageKey(res)
  51. const record = res as Record<string, unknown>
  52. const nested = record.data as Record<string, unknown> | undefined
  53. const raw =
  54. record.url ?? record.fileUrl ?? record.file_url ?? nested?.url ?? nested?.fileUrl
  55. return typeof raw === 'string' ? normalizeAvatarStorageKey(raw) : ''
  56. }
  57. /** MinIO 相对路径或完整 URL → 浏览器可访问地址 */
  58. export function resolveStorageFileUrl(url: string | null | undefined): string {
  59. const key = normalizeAvatarStorageKey(url)
  60. if (!key) return ''
  61. if (/^https?:\/\//i.test(key)) return key
  62. if (key.startsWith('/')) return key
  63. return `${minioBaseUrl}/${key.replace(/^\//, '')}`
  64. }
  65. /** 展示用头像:优先用户表头像,否则默认图 */
  66. export function resolveUserAvatarUrl(
  67. avatarUrl: string | null | undefined,
  68. role: string | undefined
  69. ): string {
  70. const key = normalizeAvatarStorageKey(avatarUrl)
  71. if (key) return resolveStorageFileUrl(key)
  72. return defaultAvatarPathByRole(role)
  73. }
  74. /** 从用户对象直接得到展示用头像 URL */
  75. export function resolveUserAvatarFromInfo(
  76. source: { avatarUrl?: string | null; avatar?: string | null; role?: string } | null | undefined
  77. ): string {
  78. return resolveUserAvatarUrl(pickUserAvatarRaw(source), source?.role)
  79. }