93 lines
3.5 KiB
TypeScript
93 lines
3.5 KiB
TypeScript
/** 未设置头像时使用 `public/avatart.png` */
|
||
function joinPublicAsset(path: string): string {
|
||
const base = import.meta.env.BASE_URL || '/'
|
||
const prefix = base.endsWith('/') ? base : `${base}/`
|
||
return `${prefix}${path.replace(/^\//, '')}`
|
||
}
|
||
|
||
export const DEFAULT_USER_AVATAR_URL = joinPublicAsset('avatart.png')
|
||
|
||
/** 本地/部署环境由 .env 配置;docker 默认走 Nginx `/minio/zkxw` 反代 */
|
||
const minioBaseUrl = (import.meta.env.VITE_MINIO_BASE_URL || '/minio/zkxw').replace(/\/$/, '')
|
||
|
||
/** @deprecated 各角色默认已统一为默认头像图,保留参数仅为兼容旧调用 */
|
||
export function defaultAvatarPathByRole(_role: string | undefined): string {
|
||
return DEFAULT_USER_AVATAR_URL
|
||
}
|
||
|
||
/**
|
||
* 将库中头像值规范为存储相对路径(如 avatar/202606/04/xxx.jpeg)。
|
||
* 兼容历史数据里写入的完整 URL(如 https://www.chengyantek.cn/zkxw/avatar/...)。
|
||
*/
|
||
export function normalizeAvatarStorageKey(raw: string | null | undefined): string {
|
||
const u = raw != null ? String(raw).trim() : ''
|
||
if (!u) return ''
|
||
if (!/^https?:\/\//i.test(u) && !u.startsWith('/')) return u
|
||
|
||
const marker = '/avatar/'
|
||
const lower = u.toLowerCase()
|
||
const idx = lower.indexOf(marker)
|
||
if (idx >= 0) {
|
||
return `avatar/${u.slice(idx + marker.length)}`
|
||
}
|
||
|
||
if (u.startsWith('/')) {
|
||
const parts = u.split('/').filter(Boolean)
|
||
const avatarIdx = parts.findIndex((p) => p === 'avatar')
|
||
if (avatarIdx >= 0) return parts.slice(avatarIdx).join('/')
|
||
}
|
||
|
||
return u
|
||
}
|
||
|
||
/** 从用户信息对象读取原始头像字段(兼容 avatar / avatarUrl) */
|
||
export function pickUserAvatarRaw(
|
||
source: { avatarUrl?: string | null; avatar?: string | null } | null | undefined
|
||
): string {
|
||
if (!source) return ''
|
||
const raw = source.avatarUrl ?? source.avatar
|
||
return normalizeAvatarStorageKey(raw != null ? String(raw).trim() : '')
|
||
}
|
||
|
||
/** 是否已设置自定义头像(非空即视为已设置) */
|
||
export function hasCustomUserAvatar(avatarUrl: string | null | undefined): boolean {
|
||
return Boolean(normalizeAvatarStorageKey(avatarUrl))
|
||
}
|
||
|
||
/** 解析上传接口返回的图片地址 */
|
||
export function pickUploadAvatarUrl(res: unknown): string {
|
||
if (res == null) return ''
|
||
if (typeof res === 'string') return normalizeAvatarStorageKey(res)
|
||
const record = res as Record<string, unknown>
|
||
const nested = record.data as Record<string, unknown> | undefined
|
||
const raw =
|
||
record.url ?? record.fileUrl ?? record.file_url ?? nested?.url ?? nested?.fileUrl
|
||
return typeof raw === 'string' ? normalizeAvatarStorageKey(raw) : ''
|
||
}
|
||
|
||
/** MinIO 相对路径或完整 URL → 浏览器可访问地址 */
|
||
export function resolveStorageFileUrl(url: string | null | undefined): string {
|
||
const key = normalizeAvatarStorageKey(url)
|
||
if (!key) return ''
|
||
if (/^https?:\/\//i.test(key)) return key
|
||
if (key.startsWith('/')) return key
|
||
return `${minioBaseUrl}/${key.replace(/^\//, '')}`
|
||
}
|
||
|
||
/** 展示用头像:优先用户表头像,否则默认图 */
|
||
export function resolveUserAvatarUrl(
|
||
avatarUrl: string | null | undefined,
|
||
role: string | undefined
|
||
): string {
|
||
const key = normalizeAvatarStorageKey(avatarUrl)
|
||
if (key) return resolveStorageFileUrl(key)
|
||
return defaultAvatarPathByRole(role)
|
||
}
|
||
|
||
/** 从用户对象直接得到展示用头像 URL */
|
||
export function resolveUserAvatarFromInfo(
|
||
source: { avatarUrl?: string | null; avatar?: string | null; role?: string } | null | undefined
|
||
): string {
|
||
return resolveUserAvatarUrl(pickUserAvatarRaw(source), source?.role)
|
||
}
|