Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 

121 řádky
3.3 KiB

  1. /**
  2. * 图片上传 composable,完全对齐 ai_uniapp_v2/utils/upload.js
  3. *
  4. * - POST multipart/form-data 到 /api/common/uploadpic(走服务端代理)
  5. * - Header: { token, timestr, nonce }
  6. * - FormData: { file, token, mac, client:1, source, version, version_code, upload_type:1 }
  7. */
  8. import md5 from '~/utils/md5'
  9. export function useUpload() {
  10. const macCookie = useCookie('mac', { maxAge: 365 * 24 * 3600, path: '/' })
  11. const tokenCookie = useCookie('token', { path: '/' })
  12. const openIdCookie = useCookie('open_id', { path: '/' })
  13. const sourceCookie = useCookie('source', { path: '/' })
  14. function getNonce() {
  15. const timeStr = Date.now().toString()
  16. const str = md5(timeStr)
  17. const nonce = str.substring(4, 14)
  18. return { timeStr, nonce }
  19. }
  20. /**
  21. * 上传图片
  22. * @param {File} file - 浏览器 File 对象
  23. * @returns {Promise<{code: number, data: {url: string, width: number, height: number}, msg: string}>}
  24. */
  25. async function uploadImage(file) {
  26. if (!file) {
  27. throw new Error('请选择文件')
  28. }
  29. const timestamp = Math.floor(Date.now() / 1000)
  30. const { timeStr, nonce } = getNonce()
  31. const formData = new FormData()
  32. // 文件字段(最先添加)
  33. formData.append('file', file)
  34. // 公共参数(对齐 V2 upload.js)
  35. formData.append('token', tokenCookie.value || '')
  36. formData.append('uid', openIdCookie.value || '')
  37. formData.append('mac', macCookie.value || '')
  38. formData.append('base_timestamp', timestamp)
  39. formData.append('client', '1')
  40. formData.append('source', sourceCookie.value || '')
  41. formData.append('client_ios', '0')
  42. formData.append('version', '1.0.0')
  43. formData.append('version_code', '1')
  44. formData.append('upload_type', '1')
  45. // 走 /api 代理,对齐 V2
  46. const url = '/api/common/uploadpic'
  47. try {
  48. const result = await $fetch(url, {
  49. method: 'POST',
  50. headers: {
  51. token: tokenCookie.value || '',
  52. timestr: timeStr,
  53. nonce,
  54. },
  55. body: formData,
  56. // 不设置 Content-Type,让浏览器自动设置 multipart boundary
  57. })
  58. if (result.code === 0) {
  59. return result
  60. }
  61. if (result.code === 1009) {
  62. const { logout } = useUser()
  63. logout()
  64. const showLogin = useState('showLogin', () => false)
  65. showLogin.value = true
  66. }
  67. throw new Error(result.msg || '上传失败')
  68. } catch (e) {
  69. if (e.data) {
  70. const data = typeof e.data === 'string' ? JSON.parse(e.data) : e.data
  71. if (data && data.code !== undefined) {
  72. throw new Error(data.msg || '上传失败')
  73. }
  74. }
  75. throw e
  76. }
  77. }
  78. /**
  79. * 打开文件选择器并上传
  80. */
  81. function selectAndUpload(options = {}) {
  82. const { accept = 'image/*' } = options
  83. return new Promise((resolve, reject) => {
  84. const input = document.createElement('input')
  85. input.type = 'file'
  86. input.accept = accept
  87. input.onchange = async () => {
  88. const file = input.files[0]
  89. if (!file) {
  90. reject(new Error('未选择文件'))
  91. return
  92. }
  93. try {
  94. const result = await uploadImage(file)
  95. resolve(result)
  96. } catch (e) {
  97. reject(e)
  98. }
  99. }
  100. input.click()
  101. })
  102. }
  103. return {
  104. uploadImage,
  105. selectAndUpload,
  106. }
  107. }