import { baseURL, baseURLStorage } from '@root/config' import { getConfigApp } from '@/utils/config' import type { FileResource } from '@/api/file' export function unwrapApiRecord(payload: unknown): Record | null { if (!payload || typeof payload !== 'object') return null const data = payload as Record if (data.data && typeof data.data === 'object') { return unwrapApiRecord(data.data) } if (data.product && typeof data.product === 'object') { return unwrapApiRecord(data.product) } if (data.row && typeof data.row === 'object') { return unwrapApiRecord(data.row) } return data as Record } export function unwrapFileResource(payload: unknown): FileResource | null { if (!payload || typeof payload !== 'object') return null const data = payload as Record if ( typeof data.full_src === 'string' || typeof data.src === 'string' || typeof data.path === 'string' || typeof data.url === 'string' ) { return normalizeFileResource(data as Record) } if (data.data && typeof data.data === 'object') { return unwrapFileResource(data.data) } if (data.file && typeof data.file === 'object') { return unwrapFileResource(data.file) } return null } /** Site domain + API base, e.g. https://example.ir/server */ export function getFileBaseUrl(): string { const fromConfig = getConfigApp('node_server') || getConfigApp('storage_url') || getConfigApp('storage') || getConfigApp('file_url') || getConfigApp('file_base') if (typeof fromConfig === 'string' && fromConfig.trim()) { return preferHttpsFileUrl(fromConfig.replace(/\/$/, '')) } const storageBase = baseURLStorage || baseURL if (storageBase) { return preferHttpsFileUrl(storageBase.replace(/\/$/, '')) } if (typeof window !== 'undefined') { return `${window.location.origin}/server`.replace(/\/$/, '') } return '' } /** صفحهٔ ادمین https است؛ URLهای http پشت CDN در پیش‌نمایش بلاک می‌شوند. */ export function preferHttpsFileUrl(url: string): string { if (/localhost|127\.0\.0\.1/i.test(url)) return url return url.replace(/^http:\/\//i, 'https://') } /** * Turns API paths like "storage/1405/02/27/file.jpg" into a full URL. */ export function toAbsoluteFileUrl(path?: string | null): string | undefined { if (!path?.trim()) return undefined const trimmed = path.trim() if (/^https?:\/\//i.test(trimmed)) { return preferHttpsFileUrl(trimmed) } const storageMatch = trimmed.match(/(?:^|\/)storage\/(.+)$/i) if (storageMatch) { const base = getFileBaseUrl() if (base) { return preferHttpsFileUrl(`${base}/storage/${storageMatch[1]}`) } } if (/^[a-z0-9.-]+(?:\/server)?\/storage\//i.test(trimmed)) { return `https://${trimmed.replace(/^\/+/, '')}` } const base = getFileBaseUrl() if (!base) return undefined if (trimmed.startsWith('/')) { return preferHttpsFileUrl(`${base}${trimmed}`) } return preferHttpsFileUrl(`${base}/${trimmed.replace(/^\//, '')}`) } function isBareFileName(value: string): boolean { return !value.includes('/') && /\.[a-z0-9]+$/i.test(value) } export function normalizeFileResource(record: Record): FileResource | null { const src = typeof record.src === 'string' ? record.src : typeof record.path === 'string' ? record.path : typeof record.storage_path === 'string' ? record.storage_path : undefined if (!src && !record.full_src) return null const absoluteUrl = toAbsoluteFileUrl(record.full_src || src) if (!absoluteUrl) return null return { id: record.id != null ? Number(record.id) : undefined, name: record.title || record.original_name || record.name, src, full_src: absoluteUrl } } /** Normalize upload API response: { id, src: "storage/...", title, ... } */ export function normalizeUploadFileResponse(response: unknown): FileResource | null { const record = unwrapApiRecord(response) if (!record) return null return normalizeFileResource(record) } export function resolveFileImageUrl(file?: FileResource | null): string | undefined { if (!file) return undefined if (file.full_src) return file.full_src return toAbsoluteFileUrl(file.src || file.path) } export function pickRawFileFromRecord(record: Record): Record | null { for (const key of ['file', 'original_image', 'image', 'index_image', 'product_image']) { const value = record[key] if (value && typeof value === 'object') return value as Record } return null } export function resolveProductImageSrc(record: Record): string | undefined { const fromRelation = resolveFileImageUrl(pickImageFromRecord(record)) if (fromRelation) return fromRelation const rawFile = pickRawFileFromRecord(record) if (rawFile?.src) return toAbsoluteFileUrl(rawFile.src) if (typeof record.file_src === 'string') return toAbsoluteFileUrl(record.file_src) if (typeof record.image_src === 'string') return toAbsoluteFileUrl(record.image_src) return undefined } export function pickImageFromRecord(record: Record): FileResource | null { const keys = [ 'file', 'original_image', 'image', 'index_image', 'product_image', 'image_file', 'uploaded_file' ] for (const key of keys) { const value = record[key] const resource = unwrapFileResource(value) if (resource) return resource if (value && typeof value === 'object') { const normalized = normalizeFileResource(value as Record) if (normalized) return normalized } } if (typeof record.src === 'string') { return normalizeFileResource(record) } return null } export function applyFileToUploadList( fileId: number | string, file?: FileResource | null, fallbackName = 'image' ) { const imageSrc = resolveFileImageUrl(file) if (!imageSrc) return [] return [ { uid: String(fileId), name: file?.name || fallbackName, status: 'done', url: imageSrc, thumbUrl: imageSrc } ] }