upload.js 3.1 KB

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