import { get, post } from '@/core/http/http-client'
import { buildRestPath } from '@/core/config/api-paths'
import parseHtml from '@/core/html/html-parser'
const ROUTE_DETAILS = buildRestPath('article/details')
const ROUTE_AD_DETAILS = buildRestPath('article/adDetails')
const ROUTE_LIST = buildRestPath('article/getList')
function unwrapListPageBody(data, raw) {
const candidates = [data, raw?.data, raw?.res?.data]
for (const c of candidates) {
if (!c || typeof c !== 'object' || Array.isArray(c)) continue
if (Array.isArray(c.data) || c.current_page != null || c.last_page != null) {
return c
}
if (c.data && typeof c.data === 'object' && !Array.isArray(c.data)) {
const inner = c.data
if (Array.isArray(inner.data) || inner.current_page != null) return inner
}
}
return { data: [], current_page: 1, last_page: 1, total: 0 }
}
function normalizeImages(images) {
if (Array.isArray(images)) return images.filter(Boolean)
if (typeof images === 'string') {
try {
const parsed = JSON.parse(images)
return Array.isArray(parsed) ? parsed.filter(Boolean) : []
} catch (_) {
return []
}
}
return []
}
export function normalizeArticleRow(item) {
if (!item || item.id == null) return null
const images = normalizeImages(item.images)
return {
...item,
images,
image: item.image || images[0] || ''
}
}
export function isExternalArticleUrl(value) {
return /^https?:\/\//i.test(String(value || '').trim())
}
function unwrapArticleBody(data, raw) {
if (!data || typeof data !== 'object') data = {}
if (data.id != null && (data.content != null || data.url != null || data.title != null)) {
return data
}
if (data.data && typeof data.data === 'object') {
const inner = data.data
if (inner.id != null || inner.content != null || inner.url != null) return inner
}
const env = raw?.res?.data ?? raw?.data
if (env && typeof env === 'object') {
if (env.id != null || env.content != null || env.url != null) return env
if (env.data && typeof env.data === 'object') {
const nested = env.data
if (nested.id != null || nested.content != null || nested.url != null) return nested
}
}
return data
}
function pickArticleContent(article) {
if (!article || typeof article !== 'object') return ''
return (
article.content ??
article.content_html ??
article.detail ??
article.body ??
''
)
}
/**
* @param {string} html
* @param {(src: string, w?: number, h?: number) => string} [ossFn]
* @param {{ hideImages?: boolean }} [opts]
* @returns {{ html: string, nodes: unknown[] }}
*/
export function formatArticleRichContent(html, ossFn, opts = {}) {
const raw = pickArticleContent(typeof html === 'object' ? html : { content: html })
if (!raw) return { html: '', nodes: [] }
let content = String(raw).replace(/\\/g, '')
if (opts.hideImages) {
content = content.replace(/
]*src=['"]([^'"]+)['"][^>]*>/gi, (match, capture) => {
const src = ossFn(capture, 500, 0)
return `
`
})
}
let nodes = []
try {
nodes = parseHtml(content)
} catch (_) {
nodes = [{ type: 'text', text: content.replace(/<[^>]+>/g, '') }]
}
return { html: content, nodes }
}
/** @deprecated 使用 formatArticleRichContent */
export function formatArticleHtmlNodes(html, ossFn, opts = {}) {
return formatArticleRichContent(html, ossFn, opts).nodes
}
export async function fetchArticleDetails(id) {
const { data, raw } = await get(ROUTE_DETAILS, { id })
const article = unwrapArticleBody(data, raw)
if (!article.content) {
const merged = pickArticleContent(article)
if (merged) article.content = merged
}
return article
}
export async function fetchAdvertDetails(id) {
const { data, raw } = await get(ROUTE_AD_DETAILS, { id })
return unwrapArticleBody(data, raw)
}
export async function fetchArticleListPage(page = 1, type = 'new') {
const { data, raw } = await post(ROUTE_LIST, { page, type })
const body = unwrapListPageBody(data, raw)
const rows = (Array.isArray(body.data) ? body.data : [])
.map(normalizeArticleRow)
.filter(Boolean)
return {
rows,
total: Number(body.total || rows.length),
currentPage: Number(body.current_page || page || 1),
lastPage: Number(body.last_page || body.current_page || 1)
}
}