/** * 图片地址解析:云存储 / 扩展存储(七牛)→ 可直接渲染的临时 URL * * 后台可能返回三种地址: * cloud:// uniCloud 云存储,用 uniCloud.getTempFileURL 换取临时地址 * qiniu:// 扩展存储(七牛),走 ext-storage-co 云对象 * http(s):// 已是公网地址,原样返回 * * 历史实现在 article.thumbnail 为空时会对 undefined 调 startsWith 直接抛错, * 导致列表页整页白屏,这里统一做空值防护。 */ function parseEditorImage(blocks = []) { const images = [] const list = Array.isArray(blocks) ? blocks : [blocks] for (const block of list) { if (!block) continue const { insert = {}, attributes = {} } = block const { 'data-custom': custom = '' } = attributes const parseCustom = custom.split('&').reduce((obj, item) => { const [key, value] = item.split('=') if (key && value) obj[key] = value return obj }, {}) if (!insert.image) continue images.push({ src: insert.image, source: parseCustom.source ? parseCustom.source : insert.image }) } return images } /** 归一化成去重后的字符串数组 */ function normalize(value) { const list = Array.isArray(value) ? value : value ? [value] : [] return list.filter((item) => typeof item === 'string' && item) } /** 把单个地址换成临时 URL;失败时退回原地址,不抛出 */ async function toTempUrl(src) { if (typeof src !== 'string' || !src) return src if (src.startsWith('cloud://')) { try { const res = await uniCloud.getTempFileURL({ fileList: [src] }) const file = res && res.fileList && res.fileList[0] return (file && file.tempFileURL) || src } catch (e) { console.error('云存储地址解析失败:', src, e) return src } } if (src.startsWith('qiniu://')) { try { const extCo = uniCloud.importObject('ext-storage-co') const res = await extCo.getTempFileURL({ src }) const file = res && res.fileList && res.fileList[0] return (file && file.tempFileURL) || src } catch (e) { console.error('扩展存储地址解析失败:', src, e) return src } } return src } /** * 解析媒体库 / 编辑器中的图片 * @param images 图片地址,字符串或数组 * @param type {string} 解析类型 media: 媒体库, editor: 编辑器 * @returns {Promise<{src: string, source: string}[]>} */ export async function parseImageUrl(images = [], type = 'media') { let list if (type === 'editor') { list = parseEditorImage(images).map((item) => item.source) } else { list = normalize(images) } if (!list.length) return [] const resolved = await Promise.all(list.map(toTempUrl)) return resolved.map((src, i) => ({ src: src || list[i], source: list[i] })) }