upload.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. /**
  2. * 小程序拍照凭证上传(OpenSpec 基线)
  3. * chooseImage → uni.uploadFile → 收集 URL → 业务接口再传 imageUrls
  4. */
  5. import { API_BASE, TOKEN_KEY, UPLOAD_API } from '@/config/api'
  6. function parseUploadBody(raw) {
  7. try {
  8. return JSON.parse(typeof raw === 'string' ? raw : String(raw || ''))
  9. } catch {
  10. return {}
  11. }
  12. }
  13. function extractUrl(body) {
  14. const data = body && body.data
  15. if (!data || typeof data !== 'object') return ''
  16. const url = data.url || data.fileUrl || data.file_url
  17. return url != null ? String(url).trim() : ''
  18. }
  19. function getToken() {
  20. const raw = uni.getStorageSync(TOKEN_KEY)
  21. return typeof raw === 'string' ? raw.trim() : raw ? String(raw).trim() : ''
  22. }
  23. /**
  24. * @param {{ folder?: string, maxCount?: number, currentUrls?: string[], uploadUrl?: string }} opts
  25. * @returns {Promise<string[]>} 本次新上传成功的 URL 列表
  26. */
  27. export async function chooseAndUploadImages(opts = {}) {
  28. const folder = opts.folder || 'mini-evidence'
  29. const maxCount = opts.maxCount != null ? opts.maxCount : 6
  30. const currentUrls = Array.isArray(opts.currentUrls) ? opts.currentUrls : []
  31. const uploadUrl = opts.uploadUrl || `${API_BASE}${UPLOAD_API.IMAGE}`
  32. const remain = maxCount - currentUrls.length
  33. if (remain <= 0) {
  34. uni.showToast({ title: `最多上传${maxCount}张`, icon: 'none' })
  35. return []
  36. }
  37. const choose = await new Promise((resolve) => {
  38. uni.chooseImage({
  39. count: remain,
  40. sizeType: ['compressed'],
  41. sourceType: ['album', 'camera'],
  42. success: (res) => resolve(res),
  43. fail: () => resolve(null)
  44. })
  45. })
  46. if (!choose?.tempFilePaths?.length) return []
  47. const token = getToken()
  48. const urls = []
  49. uni.showLoading({ title: '上传中...' })
  50. try {
  51. for (const filePath of choose.tempFilePaths) {
  52. const uploadRes = await new Promise((ok, fail) => {
  53. uni.uploadFile({
  54. url: uploadUrl,
  55. filePath,
  56. name: 'file',
  57. header: {
  58. Authorization: token ? `Bearer ${token}` : ''
  59. },
  60. formData: { folder },
  61. success: ok,
  62. fail
  63. })
  64. })
  65. if (uploadRes.statusCode === 401) {
  66. uni.showToast({ title: '登录已失效,请重新登录', icon: 'none' })
  67. break
  68. }
  69. const body = parseUploadBody(uploadRes.data)
  70. const url = extractUrl(body)
  71. if (body.code !== 200 || !url) {
  72. uni.showToast({ title: body.message || '上传失败', icon: 'none' })
  73. break
  74. }
  75. urls.push(url)
  76. }
  77. } catch (e) {
  78. uni.showToast({
  79. title: e instanceof Error ? e.message : '上传失败',
  80. icon: 'none'
  81. })
  82. } finally {
  83. uni.hideLoading()
  84. }
  85. return urls
  86. }
  87. export function previewImages(urls, current) {
  88. const list = (urls || []).map((u) => String(u || '').trim()).filter(Boolean)
  89. if (!list.length) return
  90. uni.previewImage({
  91. urls: list,
  92. current: current || list[0]
  93. })
  94. }