图片上传与鉴权预览:订单凭证的完整链路

项目中图片出现得很频繁:下单要上传订单和货品照片,签收要查看凭证,异常反馈要上传证据,个人中心还要维护头像。它们都叫“图片”,但业务类型、访问权限和生命周期并不相同。
1. 图片类型先于文件路径
订单凭证通过 proofType 区分:
| 类型 | 用途 |
|---|---|
ORDER_PHOTO | 订单或平台截图 |
GOODS_PHOTO | 货品实物照片 |
SIGN_PHOTO | 签收凭证 |
EXCEPTION_FEEDBACK | 异常证据 |
文件路径只说明图片在哪里,凭证类型才说明它在业务中代表什么。
2. 选择图片
小程序统一封装 wx.chooseMedia,页面只获得本地临时路径数组。取消选择不是错误,不弹失败提示;真正的权限或文件错误才提醒用户。
const remain = Math.max(0, 9 - images.value.length)const selected = await chooseImages({ count: remain })images.value.push(...selected)数量上限应在选择前计算,避免选择完成后再粗暴截断。
3. 上传依赖业务主键
新订单尚无 orderId,所以流程必须分两阶段:
提交订单 JSON ↓ 获得 orderId上传 multipart 图片并携带 orderId、proofType、sortNo不同类型可以组成任务数组并行上传:
const tasks = files.map((filePath, index) => DeliveryApi.uploadProof(filePath, { orderId, proofType, sortNo: index + 1 }))await Promise.all(tasks)若业务要求原子性,后端还需要提供回滚或草稿机制;前端不能假设第二阶段永远成功。
4. 编辑时区分远程图与新文件
编辑订单先通过鉴权接口把已有凭证下载为临时地址,并记录在 existing...Files 中。提交时只上传新增文件:
const newFiles = currentFiles.filter(path => !existingFiles.includes(path))如果把所有回显图再次上传,用户每编辑一次备注,凭证就复制一遍。
5. 删除已有图片
本地新图片可以直接从数组移除;服务端已有凭证必须调用删除接口。删除成功后重新获取凭证列表,失败则保留图片和错误提示,不能让页面与服务端各自认为不同结果。
6. 鉴权图片不能直接写 URL
订单凭证和头像需要 Authorization。小程序 <image> 标签无法方便地为 URL 加自定义 header,因此 getAuthenticatedImage 先下载文件并返回临时路径。
const tempPath = await getAuthenticatedImage('/manage/user/avatar', { cacheKey: 'current-user-avatar', force: true})管理端则由 AuthenticatedImage 组件统一请求 Blob、生成 Object URL,并处理加载与释放。
7. 缓存与竞态
头像适合按用户缓存,订单凭证可以按 proof ID 缓存。更新后必须使旧缓存失效。并发刷新时还要防止旧请求晚返回覆盖新图片,Auth Store 使用串行 Promise 链解决这一问题。
8. 失败体验
单张预览失败应显示占位和重试,不能让整个详情页失败;批量提交时则要明确哪些图片失败。图片压缩、格式和大小限制最好在选择后立即检查,而不是上传数秒后才告诉用户。
9. 本篇小结
图片功能并不止“选一张再传上去”。类型、主键、鉴权、缓存、回显和删除组成了完整生命周期。照片虽然不会说话,但如果 proofType 传错了,它确实会把业务讲成另一个故事。
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!





























