Files
hjc-web/app/utils/image.ts
T
gxwebsoft 2b69686795 feat(app): 添加多模板关于我们页面及相关路由和404页面
- 新增404页面,优化未找到页面体验,避免被搜索引擎索引
- 增加文件代理接口,隐藏真实文件服务器地址,支持文件请求代理
- 实现/article、/case、/product及/page动态路由兼容列表与详情展示
- 添加动态CMS页面兼容入口处理旧式路径,统一路由与SEO设置
- 新增模板1、模板7、模板2、模板3关于我们页面,实现多模板支持
- 模板增强支持CMS单页内容加载及SEO信息动态设置
- 配置环境变量及Git忽略文件规则辅助开发和构建环境管理
2026-09-08 12:13:44 +08:00

112 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 图片压缩工具
*
* 与小程序端(src/utils/image.ts)保持相同 API
* 通过阿里云 OSS 的图片处理参数(x-oss-process)实现等比缩放 + 质量压缩,
* 适用于商品列表、卡片等缩略图场景。
*
* 与小程序端的区别:
* 小程序端图片直连 oss.wsdns.cnensureFullUrl 直接补全 OSS 域名;
* 网站端图片统一走 /api/file/ 代理(代理会透传 query 参数),
* 因此 ensureFullUrl 将相对路径补全为代理地址,压缩参数随之转发到后端 OSS 生效。
*/
/**
* 图片压缩参数配置
*/
export interface ImageCompressOptions {
/** 图片宽度(px),默认 300 */
width?: number
/** 图片质量 0-100,默认 90 */
quality?: number
/** 是否启用压缩,默认 true */
enabled?: boolean
}
/**
* 默认压缩参数
*/
const DEFAULT_OPTIONS: Required<ImageCompressOptions> = {
width: 300,
quality: 90,
enabled: true,
}
/**
* 确保图片 URL 为可访问路径
*
* 网站端约定:
* - 完整 URLhttp/https)原样返回(如直连 OSS 的 oss.wsdns.cn 地址)
* - 相对路径(如 /uploads/xxx.jpg)补全为 /api/file/ 代理地址
*
* @param url 原始图片 URL
* @returns 可访问的图片 URL
*
* @example
* ensureFullUrl('/uploads/xxx.jpg')
* // => '/api/file/uploads/xxx.jpg'
*
* @example
* ensureFullUrl('https://oss.wsdns.cn/xxx.jpg')
* // => 'https://oss.wsdns.cn/xxx.jpg'
*/
export function ensureFullUrl(url: string): string {
if (!url) return ''
if (url.startsWith('http://') || url.startsWith('https://')) {
return url
}
// 相对路径:走 /api/file/ 代理(与 useFileUrl 行为一致)
const cleanPath = url.startsWith('/') ? url.slice(1) : url
return `/api/file/${cleanPath}`
}
/**
* 获取 OSS 压缩后的图片 URL
*
* 给图片 URL 拼接阿里云 OSS 图片处理参数,实现等比缩放 + 质量压缩。
* 使用场景:商品列表、商品卡片等缩略图展示。
*
* 设计要点(前端优先):
* - 以「本次请求的 width/quality」为准重建参数,无论原始 URL 是否已带 x-oss-process。
* 这样即便上游(上传链路)已写入 x-oss-process,前端仍可按需向下压缩,
* 不会出现旧逻辑「已带参数就原样返回、压缩失效」的问题。
* - 仅剥离已有的 x-oss-process 段,保留 URL 上其它查询参数(如有,如 v=2)。
* - 注意:预览原图时不需要调用此函数,直接用原始 URL 即可。
*
* @param url 原始图片 URL
* @param options 压缩选项
* @returns 处理后的图片 URL
*
* @example
* // 默认压缩(宽300,质量90)
* getCompressedImageUrl('/uploads/xxx.jpg')
* // => '/api/file/uploads/xxx.jpg?x-oss-process=image/resize,w_300/quality,Q_90'
*
* @example
* // 已带 x-oss-process 的图,仍以本次请求为准向下压缩
* getCompressedImageUrl('https://oss.x/x.jpg?x-oss-process=image/resize,w_1600', { width: 800 })
* // => 'https://oss.x/x.jpg?x-oss-process=image/resize,w_800/quality,Q_90'
*
* @example
* // 关闭压缩
* getCompressedImageUrl('/uploads/xxx.jpg', { enabled: false })
* // => '/api/file/uploads/xxx.jpg'
*/
export function getCompressedImageUrl(url: string, options?: ImageCompressOptions): string {
const { width, quality, enabled } = { ...DEFAULT_OPTIONS, ...options }
// 先补全为可访问路径
const fullUrl = ensureFullUrl(url)
if (!fullUrl) return ''
// 未启用压缩,原样返回(仍走 ensureFullUrl 补全)
if (!enabled) return fullUrl
// 前端优先:剥离已有的 x-oss-process 段,用本次请求的宽/质重建
const base = fullUrl.split(/[?&]x-oss-process=/)[0]
// 保留 base 上其它查询参数,按需用 ? 或 & 拼接
const separator = base.includes('?') ? '&' : '?'
return `${base}${separator}x-oss-process=image/resize,w_${width}/quality,Q_${quality}`
}