Files
boursecu_admin/src/utils/file.ts
T
2026-07-07 10:21:12 +03:30

217 lines
5.7 KiB
TypeScript

import { baseURL, baseURLStorage } from '@root/config'
import { getConfigApp } from '@/utils/config'
import type { FileResource } from '@/api/file'
export function unwrapApiRecord(payload: unknown): Record<string, any> | null {
if (!payload || typeof payload !== 'object') return null
const data = payload as Record<string, unknown>
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<string, any>
}
export function unwrapFileResource(payload: unknown): FileResource | null {
if (!payload || typeof payload !== 'object') return null
const data = payload as Record<string, unknown>
if (
typeof data.full_src === 'string' ||
typeof data.src === 'string' ||
typeof data.path === 'string' ||
typeof data.url === 'string'
) {
return normalizeFileResource(data as Record<string, any>)
}
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 fromConfig.replace(/\/$/, '')
}
const storageBase = baseURLStorage || baseURL
if (storageBase) {
return storageBase.replace(/\/$/, '')
}
if (typeof window !== 'undefined') {
return `${window.location.origin}/server`.replace(/\/$/, '')
}
return ''
}
/**
* 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 trimmed
}
const storageMatch = trimmed.match(/(?:^|\/)storage\/(.+)$/i)
if (storageMatch) {
const base = getFileBaseUrl()
if (base) {
return `${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 `${base}${trimmed}`
}
return `${base}/${trimmed.replace(/^\//, '')}`
}
function isBareFileName(value: string): boolean {
return !value.includes('/') && /\.[a-z0-9]+$/i.test(value)
}
export function normalizeFileResource(record: Record<string, any>): 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<string, any>): Record<string, any> | 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<string, any>
}
return null
}
export function resolveProductImageSrc(record: Record<string, any>): 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<string, any>): 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<string, any>)
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
}
]
}