// pages/index/component/PicturePanel/index.js const MAX_PICTURE = 6 const app = getApp() const API = app.globalData.api const SUFFIX = ["jpg", "jpeg", "png"] const MASK = false const MD5 = require('js-md5') Component({ /** * 组件的属性列表 */ properties: { paper: { type: Object }, cancelAll: { type: Boolean, observer: function(isCancelAll) { console.log("isCancelAll",isCancelAll) if (this.data.willSubmit && isCancelAll) { wx.hideLoading() } } } }, /** * 组件的初始数据 */ data: { size: 0, maxPicture: MAX_PICTURE, pictures: [], enableChoose: true, gridLoading: false, willSubmit: false, // 确定按钮是否已点击 mmd: MD5 }, timeoutHandler: null, /** * 组件的方法列表 */ methods: { reset: function() { this.setData({ pictures: [], willSubmit: false }) }, del: function(e) { if (this.data.willSubmit) { return false } var index = e.currentTarget.dataset.index; console.log(index); var pictures = this.data.pictures pictures.splice(index, 1) this.setData({ pictures: pictures }) }, choosePic: function(e) { if (this.data.willSubmit) { return false } if (this.data.pictures.length >= MAX_PICTURE) { return false } console.log('choosePic', this.data.enableChoose) if (!this.data.enableChoose) { return false } this.setData({ enableChoose: false, }) var that = this wx.showActionSheet({ itemList: ['拍照'], success: chooseResult => { console.log('showActionSheet',this.data.pictures.length) console.log('chooseResult.tapIndex1',chooseResult.tapIndex) if (this.data.pictures.length >= MAX_PICTURE) { wx.showToast({ title: '一次最多只能选择6张', icon: 'none', mask: MASK }) return } console.log('chooseResult.tapIndex2',chooseResult.tapIndex) that.setData({ gridLoading: true }) console.log('chooseResult.tapIndex3',chooseResult.tapIndex) switch (chooseResult.tapIndex) { case 0: wx.chooseMedia({ sourceType: ['camera'], sizeType: ['original'], mediaType: ['image'], camera: 'back', fail: e => { console.log('chooseMedia:fail:' + e.errMsg) }, success: res => { console.log(res); var pictures = that.data.pictures res.tempFiles.forEach(function (item, idx) { console.log(idx, item) item['suffix'] = item.tempFilePath.substring(item.tempFilePath.lastIndexOf(".") + 1, item.tempFilePath.length) item['err'] = SUFFIX.indexOf(item['suffix'].toLowerCase()) > -1 ? '' : '图片格式错误' if (item['err'] == '') { item['err'] = item.size > 1024 * 1024 * 10 ? '图片超过10M' : '' } console.log(item) }) console.log(res.tempFiles) Array.prototype.push.apply(pictures, res.tempFiles); console.log('pictures::' + pictures) that.setData({ pictures: pictures, }) }, complete: () => { that.setData({ gridLoading: false }) } }) break; case 1: wx.chooseMedia({ count: MAX_PICTURE - that.data.pictures.length, sizeType: ['original'], sourceType: ['album'], mediaType: ['image'], camera: 'back', success: res => { console.log(res); var pictures = that.data.pictures var pic = [] res.tempFiles.forEach(function (item, idx) { console.log(idx, item) if (that.data.pictures.length + idx + 1 <= MAX_PICTURE) { item['suffix'] = item.tempFilePath.substring(item.tempFilePath.lastIndexOf(".") + 1, item.tempFilePath.length) item['err'] = SUFFIX.indexOf(item['suffix'].toLowerCase()) > -1 ? '' : '图片格式错误' if (item['err'] == '') { item['err'] = item.size > 1024 * 1024 * 10 ? '图片超过10M' : '' } pic.push(item) console.log(item) } }) console.log(pic) Array.prototype.push.apply(pictures, pic); that.setData({ pictures: pictures, }) }, complete: () => { that.setData({ gridLoading: false }) } }) break; } }, complete: () => { that.setData({ enableChoose: true }) } }) }, submit: function(e) { const pictures = this.data.pictures var valid = true pictures.forEach(function(item, index) { pictures[index]['retry'] = 0 if (item.err) { valid = false return } }) if (!valid) { wx.showToast({ title: '仅支持10M以下的jpg、png、jpeg格式图片', icon: 'none', duration: 3000, mask: MASK }) return } if (this.data.willSubmit) { return false } this.setData({ willSubmit: true }) wx.showLoading({ title: '正在上传(0/' + this.data.pictures.length + ')', mask: MASK }) var that = this this.timeoutHandler = setTimeout(function() { console.log('timeout', new Date()) wx.hideLoading() that.setData({ willSubmit: false }) if (that.data.pictures.length > 0) { wx.showToast({ title: '上传失败', icon: 'none', duration: 2500, mask: MASK }) } }, 60000) this.checkUploadComplete() //TODO 断点上传 for (var index = 0; index < pictures.length; index++) { console.log('uploadImage:' + index) var retryTimes = 3 this.uploadImage(index, retryTimes) } }, checkFailed() { var _pics = this.data.pictures var retryFailedCount = _pics.filter(function (item) { return item != null && item.status == 'FAIL' && item.retry <= 0 }).length var failedCount = _pics.filter(function (item) { return item != null && item.status == 'FAIL' }).length console.log('checkFailed', new Date, retryFailedCount) var that = this if (failedCount > 0 && retryFailedCount == failedCount) { clearTimeout(this.timeoutHandler) wx.hideLoading() wx.showToast({ title: '上传失败', icon: 'none', duration: 2500, mask: MASK }) that.setData({ willSubmit: false }) } }, checkUploadComplete() { if (this.data.willSubmit && !this.data.cancelAll && !this.checkFailed()) { var _pics = this.data.pictures var uploadCount = _pics.filter(function(item) { return item != null && item.status == 'SUCCESS' }).length console.log('checkUploadComplete',_pics) if (uploadCount == this.data.pictures.length) { clearTimeout(this.timeoutHandler) this.timeoutHandler = setTimeout(function () { console.log('timeout', new Date()) wx.hideLoading() that.setData({ willSubmit: false }) if (that.data.pictures.length > 0) { wx.showToast({ title: '更新答案超时', icon: 'none', duration: 2500, mask: MASK }) } }, 30000) wx.showLoading({ title: '正在更新答案', mask: MASK }) // TODO 合并图片地址,保存地址到服务端,轮询获取保存状态 const imagePaths = this.data.pictures.map(function(item) { return item.url }).join(',') const that = this console.log('notifyServer') API.notifyServer(that.data.paper.examRecordDataId, that.data.paper.examStudentId, that.data.paper.questionOrder, imagePaths, 'PIC') .then(notifyResult => { console.log(notifyResult) const _startTime = new Date().getTime() var times = 10 // 轮询10次 const handler = setInterval(function() { // 10秒超时 API.getNotifyResult(notifyResult) .then(res => { console.log(res) if (res == 'CONFIRMED') { clearTimeout(that.timeoutHandler) clearInterval(handler) wx.hideLoading() wx.showToast({ title: '上传成功\n继续扫描下一题', icon: 'success', duration: 2500, mask: MASK }) setTimeout(function () { wx.reLaunch({ url: '/pages/index/index' }) }, 2500) } else if (res == 'DISCARDED') { clearTimeout(that.timeoutHandler) clearInterval(handler) wx.hideLoading() wx.showToast({ title: '题目已切换,请重新扫码', icon: 'none', duration: 2500, mask: MASK }) setTimeout(function () { wx.reLaunch({ url: '/pages/index/index' }) }, 2500) } else { throw '答案未同步' } }).catch(exceptions => { console.log('getNotifyResult:catch:', exceptions) times-- if (new Date().getTime() - _startTime >= 1000 * 10 || times < 0) { clearInterval(handler) clearTimeout(that.timeoutHandler) wx.hideLoading() wx.showToast({ title: '答案上传失败,请点击重试', icon: 'none', duration: 2500, mask: MASK }) that.setData({ willSubmit:false }) } }) }, 1000) }).catch(function(error) { clearTimeout(that.timeoutHandler) wx.hideLoading() wx.showToast({ title: error, icon: 'none', duration: 2500, mask: MASK }) that.setData({ willSubmit: false }) }) return true } else { console.log('正在上传(' + uploadCount + '/' + this.data.pictures.length + ')') wx.showLoading({ title: '正在上传(' + uploadCount + '/' + this.data.pictures.length + ')', mask: MASK }) return false } } }, uploadFail(that, filepath, md5, formParams, formUrl, accessUrl, index, retry) { var pic = that.data.pictures pic[index]['status'] = 'FAIL' pic[index]['retry'] = 3 - retry that.setData({ pictures: pic }) that.checkFailed() retry-- if (retry > 0) { that.uploadFile(filepath, md5, formParams, md5, formUrl, accessUrl, index, retry) } }, //上传文件,支持配置重试次数 uploadFile(filepath, md5, formParams, formUrl, accessUrl, index, retry) { console.log('uploadFile') if (this.data.cancelAll) { return } if (retry <= 0) { return } const that = this const c_md5 = wx.arrayBufferToBase64(new Uint8Array(md5.match(/[\da-f]{2}/gi).map(function (h) { return parseInt(h, 16) }))) console.log('uploadFile::start upload') const task = wx.uploadFile({ url: formUrl, filePath: filepath, name: 'file', formData: formParams, success: taskRes => { console.log('uploadFile::upload success', taskRes) var pic = that.data.pictures pic[index]['url'] = accessUrl pic[index]['status'] = 'SUCCESS' that.setData({ pictures: pic }) that.checkUploadComplete() }, fail: error => { console.log('uploadFile:uploadFile:catch', error) that.uploadFail(that, filepath, md5, formParams, formUrl, accessUrl, index, retry) } }) task.onHeadersReceived(res => { console.log('task header::', res, res.header['Content-MD5'], c_md5) if (c_md5 != res.header['Content-MD5']) { that.uploadFail(that, filepath, md5, formParams, formUrl, accessUrl, index, retry) } }) }, uploadImage(imageIndex, retry) { if (this.data.cancelAll) { return; } const img = this.data.pictures[imageIndex] console.log(img) if (img.status == 'SUCCESS') { // 已上传 return } const that = this if (retry > 0) { wx.compressImage({ src: img.tempFilePath, quality: 80, success: function(cf) { console.log('uploadImage:compressImage:success',cf) wx.getFileInfo({ filePath: cf.tempFilePath, success: function (fileRes) { console.log('uploadImage:compressImage:success>>getFileInfo:success', fileRes) // 获取上传签名 API.getSign(that.data.paper.examRecordDataId, that.data.paper.examStudentId, that.data.paper.questionOrder, fileRes.digest, 'jpeg') .then(signResult => { // 上传文件 var _retry = 3 that.uploadFile(cf.tempFilePath, fileRes.digest, signResult.formParams, signResult.formUrl, signResult.accessUrl, imageIndex, _retry) }).catch(exceptions => { var pic = that.data.pictures pic[imageIndex]['status'] = 'FAIL' pic[imageIndex]['retry'] = 3 - retry that.setData({ pictures: pic }) that.checkFailed() console.log('uploadImage:exceptions:', new Date(), pic, exceptions) that.uploadImage(imageIndex, --retry) }) } }) }, error: function() { var pic = that.data.pictures pic[imageIndex]['status'] = 'FAIL' pic[imageIndex]['retry'] = 3 - retry that.setData({ pictures: pic }) that.checkFailed() console.log('压缩失败') }, complete: function () { console.log('压缩complete') } }) } else { var pic = that.data.pictures pic[imageIndex]['status'] = 'FAIL' pic[imageIndex]['retry'] = 3 - retry that.setData({ pictures: pic }) that.checkFailed() } }, }, attached() { var result = wx.getSystemInfoSync(); this.setData({ size: (result.screenWidth - 20 * 2 - 10 * 4) / 3 }) } })