Files
zt-closet-wxmini-frontend/miniprogram/pages/upload/upload.ts
T
2026-09-13 01:51:09 +08:00

144 lines
4.1 KiB
TypeScript

import { request, uploadFile, NOT_LOGIN_CODE } from '../../utils/request'
import { ProcessStatus } from '../../utils/config'
Page({
data: {
state: 'idle' as 'idle' | 'processing' | 'failed',
imagePath: '',
clothesUuid: '',
failReason: '',
step: 0,
},
onChoose() {
wx.showActionSheet({
itemList: ['拍照', '从相册选择'],
success: (res) => {
const sourceType: Array<'camera' | 'album'> = res.tapIndex === 0 ? ['camera'] : ['album']
this.chooseImage(sourceType)
},
fail: () => {}, // 取消选择属正常操作,不必抛错日志
})
},
chooseImage(sourceType: Array<'camera' | 'album'>) {
wx.chooseMedia({
count: 1,
mediaType: ['image'],
sourceType,
success: (res) => {
const file = res.tempFiles[0]
this.startUpload(file.tempFilePath)
},
})
},
startUpload(filePath: string) {
this.setData({ state: 'processing', imagePath: filePath, step: 0, failReason: '' })
uploadFile<{ clothes_uuid: string; image_process_status: number }>(filePath)
.then((res) => {
this.setData({ clothesUuid: res.clothes_uuid })
this.askNextAction()
})
.catch((e: any) => {
this.setData({ state: 'idle' })
if (e && e.code === 80000) {
this.showQuotaModal()
return
}
// uploadFile 已统一 toast 业务错误与网络错误;未登录时请求并未发出,需补一次提示
if (e && e.code === NOT_LOGIN_CODE) {
wx.showToast({ title: '请先登录', icon: 'none' })
}
})
},
askNextAction() {
// 后台继续轮询,仅用于更新步骤进度(不再自动跳详情)
this.pollStatus(this.data.clothesUuid)
// 立即弹窗让用户选择下一步,避免干等
wx.showModal({
title: '衣物已上传',
content: 'AI 正在识别中,可在衣橱查看进度',
confirmText: '继续上传',
cancelText: '回到衣橱',
success: (res) => {
this.clearTimer()
if (res.confirm) {
this.setData({ state: 'idle', imagePath: '', clothesUuid: '', step: 0, failReason: '' })
} else {
wx.navigateBack({
delta: 1,
fail: () => wx.switchTab({ url: '/pages/wardrobe/wardrobe' }),
})
}
},
})
},
pollStatus(uuid: string) {
let count = 0
;(this as any).pollTimer = setInterval(() => {
count++
request<{ image_process_status: number; fail_reason: string }>({
url: `/clothes/${uuid}/status`,
showError: false,
})
.then((res) => {
const status = res.image_process_status
if (status === ProcessStatus.MATTING) {
this.setData({ step: 1 })
} else if (status === ProcessStatus.CLASSIFYING) {
this.setData({ step: 2 })
} else if (status === ProcessStatus.SUCCESS) {
// 处理成功不再自动跳转,由用户自行从衣橱进入详情
this.clearTimer()
} else if (status === ProcessStatus.FAILED) {
this.clearTimer()
this.setData({ state: 'failed', failReason: res.fail_reason || '识别失败' })
}
})
.catch(() => {})
if (count >= 60) {
this.clearTimer()
this.setData({ state: 'failed', failReason: '处理超时,请重试' })
}
}, 1500)
},
clearTimer() {
const t = (this as any).pollTimer
if (t) {
clearInterval(t)
;(this as any).pollTimer = null
}
},
onUnload() {
this.clearTimer()
},
showQuotaModal() {
wx.showModal({
title: '上传额度不足',
content: '当前剩余 0 次,购买额度包后可继续上传',
confirmText: '去购买',
cancelText: '取消',
success: (res) => {
if (res.confirm) wx.navigateTo({ url: '/pages/mall/mall' })
},
})
},
onRetry() {
this.setData({ state: 'idle', imagePath: '', clothesUuid: '', failReason: '' })
},
onManualEdit() {
if (!this.data.clothesUuid) return
wx.redirectTo({ url: `/pages/clothes-detail/clothes-detail?uuid=${this.data.clothesUuid}` })
},
})